diff --git a/assets/app/view/game/discard_trains.rb b/assets/app/view/game/discard_trains.rb index b80dc1418b..d333b3ee68 100644 --- a/assets/app/view/game/discard_trains.rb +++ b/assets/app/view/game/discard_trains.rb @@ -7,10 +7,6 @@ module Game class DiscardTrains < Snabberb::Component include Actionable - def current_entity_actions - @current_entity_actions ||= @game.round.actions_for(@game.round.active_step&.current_entity) || [] - end - def render block_props = { style: { @@ -39,7 +35,9 @@ def render h(:div, trains), ]) end - overflow << h(ScrapTrains, corporation: @current_entity) if current_entity_actions.include?('scrap_train') + overflow << h(ScrapTrains, corporation: @current_entity) if @game.round.actions_for( + @game.round.active_step&.current_entity + )&.include?('scrap_train') overflow << h(Map, game: @game) if @game.round.is_a?(Engine::Round::Operating) h(:div, [ diff --git a/assets/app/view/game/scrap_trains.rb b/assets/app/view/game/scrap_trains.rb index 7c98ed06c0..1897af398b 100644 --- a/assets/app/view/game/scrap_trains.rb +++ b/assets/app/view/game/scrap_trains.rb @@ -10,11 +10,32 @@ class ScrapTrains < Snabberb::Component def render @corporation ||= @game.round.active_step.current_entity - step = @game.round.active_step + step = @game.round.step_for(@corporation, 'scrap_train') scrappable_trains = step.scrappable_trains(@corporation) return nil if scrappable_trains.empty? + if step.scrap_trains_button_only? + render_button(scrappable_trains) + else + render_section(scrappable_trains) + end + end + + def render_button(scrappable_trains) + step = @game.round.step_for(@corporation, 'scrap_train') + h(:div, scrappable_trains.flat_map do |train| + scrap = lambda do + process_action(Engine::Action::ScrapTrain.new( + @corporation, + train: train, + )) + end + h(:button, { on: { click: scrap } }, step.scrap_info(train)) + end) + end + + def render_section(scrappable_trains) div_props = { style: { display: 'grid', @@ -23,17 +44,13 @@ def render alignItems: 'center', }, } - if @game.use_compact_scrap_trains_view - h(:div, scrap_trains(scrappable_trains)) - else - h(:div, - [h(:h3, 'Trains to Scrap'), - h(:div, div_props, scrap_trains(scrappable_trains))]) - end + h(:div, + [h(:h3, 'Trains to Scrap'), + h(:div, div_props, scrap_trains(scrappable_trains))]) end def scrap_trains(scrappable_trains) - step = @game.round.active_step + step = @game.round.step_for(@corporation, 'scrap_train') scrappable_trains.flat_map do |train| scrap = lambda do process_action(Engine::Action::ScrapTrain.new( @@ -41,14 +58,10 @@ def scrap_trains(scrappable_trains) train: train, )) end - if @game.use_compact_scrap_trains_view - h(:button, { on: { click: scrap } }, step.scrap_info(train)) - else - [h(:div, train.name), - h('div.nowrap', train.owner.name), - h('div.right', step.scrap_info(train)), - h('button.no_margin', { on: { click: scrap } }, step.scrap_button_text(train))] - end + [h(:div, train.name), + h('div.nowrap', train.owner.name), + h('div.right', step.scrap_info(train)), + h('button.no_margin', { on: { click: scrap } }, step.scrap_button_text(train))] end end end diff --git a/assets/app/view/game_page.rb b/assets/app/view/game_page.rb index 7d05e2c82b..713a300a1b 100644 --- a/assets/app/view/game_page.rb +++ b/assets/app/view/game_page.rb @@ -419,7 +419,7 @@ def render_action h(Game::Round::Auction, game: @game, user: @user) when Engine::Round::Merger if !(%w[buy_train scrap_train reassign_trains] & current_entity_actions).empty? && - @game.use_1840_style_merger_round_scrap_trains? + @game.train_actions_always_use_operating_round_view? h(Game::Round::Operating, game: @game) else h(Game::Round::Merger, game: @game) diff --git a/lib/engine/game/base.rb b/lib/engine/game/base.rb index ebd03ea44c..4f8cc4ae50 100644 --- a/lib/engine/game/base.rb +++ b/lib/engine/game/base.rb @@ -2778,13 +2778,13 @@ def show_map_legend? # This is a bit of a hack to get around how 1840 and 18USA have different and incompatible opinions on what the # option to use the scrap_trains action in a merger round means - def use_1840_style_merger_round_scrap_trains? - true - end - - # If true, instead of doing a relatively big view with a header and corporation context for scrapping trains, only a - # button [{scrap}] will be displayed, where {scrap} is taken from the current step's scrap_info(train) method - def use_compact_scrap_trains_view + # If a game overrides this to true, then if the possible actions for the current entity include any of: + # * buy_train + # * scrap_train + # * reassign_train + # then the Operating view will be used instead of the Merger round view in a merger round. + # See https://github.com/tobymao/18xx/issues/7169 + def train_actions_always_use_operating_round_view? false end end diff --git a/lib/engine/game/g_1840/game.rb b/lib/engine/game/g_1840/game.rb index 0ff6db7f7c..f431d44f32 100644 --- a/lib/engine/game/g_1840/game.rb +++ b/lib/engine/game/g_1840/game.rb @@ -930,6 +930,10 @@ def timeline 'Pink → Yellow: -200 | Orange: -100 | Red: -50 ', 'Purple → Yellow: -400 | Orange: -300 | Red: -100 | Purple +200 '].freeze end + + def train_actions_always_use_operating_round_view? + true + end end end end diff --git a/lib/engine/game/g_1840/step/buy_train.rb b/lib/engine/game/g_1840/step/buy_train.rb index cffe1272ee..8111fc1a6c 100644 --- a/lib/engine/game/g_1840/step/buy_train.rb +++ b/lib/engine/game/g_1840/step/buy_train.rb @@ -47,6 +47,10 @@ def process_scrap_train(action) @game.scrap_train(action.train, action.entity) end + def scrap_trains_button_only? + false + end + def must_buy_train?(entity) scrappable_trains(entity).size.zero? end diff --git a/lib/engine/game/g_1840/step/route.rb b/lib/engine/game/g_1840/step/route.rb index ac78399189..27e6892a1d 100644 --- a/lib/engine/game/g_1840/step/route.rb +++ b/lib/engine/game/g_1840/step/route.rb @@ -80,6 +80,10 @@ def scrap_button_text(_train) def process_scrap_train(action) @game.scrap_train(action.train, action.entity) end + + def scrap_trains_button_only? + false + end end end end diff --git a/lib/engine/game/g_1873/step/buy_train.rb b/lib/engine/game/g_1873/step/buy_train.rb index 8ecb407848..6d101bbc18 100644 --- a/lib/engine/game/g_1873/step/buy_train.rb +++ b/lib/engine/game/g_1873/step/buy_train.rb @@ -211,6 +211,10 @@ def scrappable_trains(entity) end end + def scrap_trains_button_only? + false + end + def process_buy_train(action) entity = action.entity train = action.train diff --git a/lib/engine/game/g_18_ny/step/buy_train.rb b/lib/engine/game/g_18_ny/step/buy_train.rb index d03e0f406f..5461a02cf1 100644 --- a/lib/engine/game/g_18_ny/step/buy_train.rb +++ b/lib/engine/game/g_18_ny/step/buy_train.rb @@ -43,6 +43,10 @@ def scrap_button_text(_train) 'Salvage' end + def scrap_trains_button_only? + false + end + def can_take_loan?(entity) !can_afford_train?(entity) && entity.trains.empty? && !@train_salvaged && @game.can_take_loan?(entity) end diff --git a/lib/engine/game/g_18_usa/game.rb b/lib/engine/game/g_18_usa/game.rb index c082b8e477..16c52b2178 100644 --- a/lib/engine/game/g_18_usa/game.rb +++ b/lib/engine/game/g_18_usa/game.rb @@ -652,7 +652,7 @@ def operating_round(round_num) G1817::Step::CashCrisis, G18USA::Step::ObsoleteTrain, G18USA::Step::Loan, - G18USA::Step::ScrapTrain, + G18USA::Step::DiscardTrain, G18USA::Step::SpecialTrack, G18USA::Step::SpecialToken, G18USA::Step::SpecialBuyTrain, @@ -663,65 +663,16 @@ def operating_round(round_num) G18USA::Step::BuyPullman, G18USA::Step::Route, G18USA::Step::Dividend, - G18USA::Step::DiscardTrain, G18USA::Step::BuyTrain, ], round_num: round_num) end - def pullman_scrap_value - 50 - end - - def scrap_info - "Scrap Pullman for #{format_currency(pullman_scrap_value)}" - end - - def scrap_button_text - 'Scrap Pullman' - end - - def use_compact_scrap_trains_view - true - end - - def use_1840_style_merger_round_scrap_trains? - false - end - def crowded_corps - @crowded_corps ||= corporations.select do |c| - trains = self.class::OBSOLETE_TRAINS_COUNT_FOR_LIMIT ? c.trains.size : c.trains.count { |t| !t.obsolete } - trains > train_limit(c) || c.trains.count { |t| pullman_train?(t) } > 1 - end - end - - # owner is the alleged corporation scrapping a pullman - def scrap_train_by_corporation(action, _owner) - entity = action.entity - raise GameError, "#{entity.name} cannot scrap a train now" unless entity == current_entity - - train = action.train - raise GameError, "#{entity.name} cannot scrap a #{train.name} train" unless pullman_train?(train) - - scrap_train(train) - end - - # owner is the alleged owner of the company scrapping a pullman - def scrap_train_by_owner(action, _owner) - entity = action.entity - raise GameError, "#{entity.name} cannot scrap a train now" unless entity&.owner == current_entity - - train = action.train - raise GameError, "#{entity.name} cannot scrap a #{train.name} train" unless pullman_train?(train) - - scrap_train(train) + @crowded_corps ||= super | corporations.select { |c| c.trains.count { |t| pullman_train?(t) } > 1 } end - # Do error checking before calling this. - def scrap_train(train) - @bank.spend(pullman_scrap_value, train.owner) - @log << "#{train.owner.name} scraps a pullman for #{format_currency(pullman_scrap_value)}" - @depot.reclaim_train(train) + def reset_crowded_corps + @crowded_corps = nil end def next_round! @@ -734,11 +685,6 @@ def next_round! reorder_players new_operating_round when Engine::Round::Operating - # The normal export logic which plays nicely with privates exists in first_turn_housekeeping but it does not - # work in the edgecase where there are 0 entities acting in an operating round - this exists to cover this - # edge case. Since there are no corporatiosn, there is nobody who could use a private to save a train from - # rusting prematurely so this is fine. - export_train if @round.entities.empty? # Store the share price of each corp to determine if they can be acted upon in the AR @stock_prices_start_merger = @corporations.to_h { |corp| [corp, corp.share_price] } @log << "-- #{round_description('Merger and Conversion', @round.round_num)} --" diff --git a/lib/engine/game/g_18_usa/round/operating.rb b/lib/engine/game/g_18_usa/round/operating.rb index d7e339bdf6..8f0f939cb5 100644 --- a/lib/engine/game/g_18_usa/round/operating.rb +++ b/lib/engine/game/g_18_usa/round/operating.rb @@ -22,6 +22,14 @@ def finished? true end + + def pay_interest!(entity) + # 1817's pay_interest! does a 'return unless step_passed?(Engine::Step::BuyTrain)' which unintentionally + # passes for the 18USA BuyPullmanStep - here we check that 18USA BuyTrain is passed before continuing + return unless step_passed?(G18USA::Step::BuyTrain) + + super + end end end end diff --git a/lib/engine/game/g_18_usa/step/acquire.rb b/lib/engine/game/g_18_usa/step/acquire.rb index 0e866d5b2d..9dd1d470da 100644 --- a/lib/engine/game/g_18_usa/step/acquire.rb +++ b/lib/engine/game/g_18_usa/step/acquire.rb @@ -10,7 +10,7 @@ class Acquire < G1817::Step::Acquire include ScrapTrainModule def actions(entity) actions = super - if entity.corporation? && entity == @buyer && entity.trains.any? { |t| @game.pullman_train?(t) } + if entity == @buyer && can_scrap_train?(entity) actions = %w[pass] if actions.empty? actions << 'scrap_train' end @@ -18,39 +18,18 @@ def actions(entity) end def pass_description - if @offer - 'Pass (Offer for Sale)' - elsif @auctioning - 'Pass (Bid)' - elsif @buyer && can_take_loan?(@buyer) - 'Pass (Take Loan)' - elsif @buyer && can_payoff?(@buyer) - 'Pass (On payoff Loan)' - elsif @buyer - 'Pass (Scrap Train)' - end + return 'Pass (Scrap Train)' if @buyer && !can_take_loan?(@buyer) && !can_payoff?(@buyer) + + super end def process_pass(action) - if @offer - @game.log << "#{@offer.owner.name} declines to put #{@offer.name} up for sale" - @round.offering.delete(@offer) - @offer = nil - setup_auction - elsif @buyer && can_take_loan?(@buyer) - @passed_take_loans = true - @game.log << "#{@buyer.name} passes taking additional loans" - acquire_post_loan - elsif @buyer && can_payoff?(@buyer) - @passed_payoff_loans = true - @game.log << "#{@buyer.name} passes paying off additional loans" - acquire_post_loan - elsif @buyer + if @buyer && !can_take_loan?(@buyer) && !can_payoff?(@buyer) @passed_scrap_trains = true @game.log << "#{@buyer.name} passes scrapping trains" acquire_post_loan else - pass_auction(action.entity) + super end end @@ -60,14 +39,10 @@ def acquire_post_loan super end + # This version is needed to reference @passed_scrap_trains def can_scrap_train?(entity) return true if entity.corporation? && !@passed_scrap_trains && entity.trains.find { |t| @game.pullman_train?(t) } end - - def process_scrap_train(action) - @corporate_action = action - @game.scrap_train_by_corporation(action, current_entity) - end end end end diff --git a/lib/engine/game/g_18_usa/step/assign.rb b/lib/engine/game/g_18_usa/step/assign.rb index 4bb2a274d6..2451a6fd47 100644 --- a/lib/engine/game/g_18_usa/step/assign.rb +++ b/lib/engine/game/g_18_usa/step/assign.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true require_relative '../../../step/assign' -require_relative 'scrap_train_module' + module Engine module Game module G18USA module Step class Assign < Engine::Step::Assign - include ScrapTrainModule def process_assign(action) company = action.entity target = action.target diff --git a/lib/engine/game/g_18_usa/step/buy_pullman.rb b/lib/engine/game/g_18_usa/step/buy_pullman.rb index 14e8defc18..cf33d4f76e 100644 --- a/lib/engine/game/g_18_usa/step/buy_pullman.rb +++ b/lib/engine/game/g_18_usa/step/buy_pullman.rb @@ -1,54 +1,37 @@ # frozen_string_literal: true -require_relative '../../../step/base' -require_relative '../../../step/train' -require_relative 'scrap_train_module' +require_relative '../../../step/buy_train' module Engine module Game module G18USA module Step - class BuyPullman < Engine::Step::Base - include Engine::Step::Train - include ScrapTrainModule # Why would you scrap a pullman so you can buy a pullman!? - def actions(entity) - return [] if entity != current_entity - - if @game.depot.upcoming.any? { |t| t.name == 'P' } && can_buy_train?(entity) && @game.pullmans_available? && \ - entity.runnable_trains.none? { |t| @game.pullman_train?(t) } - return %w[buy_train pass] - end - - [] - end - + class BuyPullman < Engine::Step::BuyTrain def description - 'Buy Pullman (Early)' + 'Buy Pullman' end def pass_description 'Skip (Pullman)' end - def process_buy_train(action) - check_spend(action) - buy_train_action(action) - pass! if !can_buy_train?(action.entity) && pass_if_cannot_buy_train?(action.entity) + def must_buy_train?(_) + false end - def check_spend(action) - return if action.train.price <= buying_power(action.entity) + def president_may_contribute?(_) + false + end - raise GameError, "#{action.entity.name} may not spend "\ - "#{@game.format_currency(action.price)} on "\ - "#{action.train.owner.name}'s #{action.train.name} "\ - "train; may only spend #{@game.format_currency(buying_power(action.entity))}." + def can_buy_train?(entity, _shell = nil) + @game.pullmans_available? && entity.runnable_trains.none? { |t| @game.pullman_train?(t) } end def buyable_trains(entity) # Can't buy a second pullman and can't buy a pullman if it's not legal to well, buy pullmans. - [] if entity.runnable_trains.any? { |t| @game.pullman_train?(t) } || !@game.pullmans_available? + return [] unless can_buy_train?(entity) + # Cannot buy a pullman if you have a pullman - Array(@game.depot.upcoming.find { |t| @game.pullman_train?(t) }) + (@depot.depot_trains & super).select { |t| @game.pullman_train?(t) } end end end diff --git a/lib/engine/game/g_18_usa/step/buy_sell_par_shares.rb b/lib/engine/game/g_18_usa/step/buy_sell_par_shares.rb index be646bc2b4..a2e53e11e0 100644 --- a/lib/engine/game/g_18_usa/step/buy_sell_par_shares.rb +++ b/lib/engine/game/g_18_usa/step/buy_sell_par_shares.rb @@ -1,54 +1,24 @@ # frozen_string_literal: true require_relative '../../g_1817/step/buy_sell_par_shares' +require_relative 'scrap_train_module' module Engine module Game module G18USA module Step class BuySellParShares < G1817::Step::BuySellParShares + include ScrapTrainModule MIN_BID = 100 MAX_BID = 100_000 MAX_PAR_PRICE = 200 def corporate_actions(entity) - return [] if @winning_bid - - return [] if @corporate_action && @corporate_action.entity != entity - - actions = [] - if @round.current_actions.none? - actions << 'take_loan' if @game.can_take_loan?(entity) && !@corporate_action.is_a?(Action::BuyShares) - actions << 'buy_shares' unless @game.redeemable_shares(entity).empty? - actions << 'scrap_train' if can_scrap_train?(entity) - end + actions = super + actions << 'scrap_train' if !@winning_bid && @round.current_actions.none? && can_scrap_train?(entity) actions end - def can_scrap_train?(entity) - return false unless entity.corporation? - return false unless entity.owned_by?(current_entity) - - entity.trains.find { |t| @game.pullman_train?(t) } - end - - def scrappable_trains(entity) - entity.trains.select { |t| t.name == 'P' } - end - - def scrap_info(_) - @game.scrap_info - end - - def scrap_button_text(_) - @game.scrap_button_text - end - - def process_scrap_train(action) - @corporate_action = action - @game.scrap_train_by_owner(action, current_entity) - end - def auto_actions(entity) return [Engine::Action::Pass.new(entity)] if @auctioning && max_bid(entity, @auctioning) < min_bid(@auctioning) diff --git a/lib/engine/game/g_18_usa/step/buy_train.rb b/lib/engine/game/g_18_usa/step/buy_train.rb index 4325db91e6..5a116a22c6 100644 --- a/lib/engine/game/g_18_usa/step/buy_train.rb +++ b/lib/engine/game/g_18_usa/step/buy_train.rb @@ -1,25 +1,20 @@ # frozen_string_literal: true require_relative '../../g_1817/step/buy_train' -require_relative 'scrap_train_module' module Engine module Game module G18USA module Step class BuyTrain < G1817::Step::BuyTrain - include ScrapTrainModule def should_buy_train?(entity) :liquidation if entity.trains.reject { |t| @game.pullman_train?(t) }.empty? end def buyable_trains(entity) buyable_trains = super - # Cannot buy pullmans from the bank/depot? # TODO: Confirm if this is true and if false, remove this line. - # https://github.com/tobymao/18xx/issues/7097 - buyable_trains.reject! { |t| @game.pullman_train?(t) && t.from_depot? } # Cannot buy a pullman if you have a pullman - buyable_trains.reject! { |t| @game.pullman_train?(t) } if entity.runnable_trains&.any? { |t| @game.pullman_train?(t) } + buyable_trains.reject! { |t| @game.pullman_train?(t) } if entity.trains&.any? { |t| @game.pullman_train?(t) } buyable_trains end end diff --git a/lib/engine/game/g_18_usa/step/conversion.rb b/lib/engine/game/g_18_usa/step/conversion.rb index 9e6cd10b2e..20e972967e 100644 --- a/lib/engine/game/g_18_usa/step/conversion.rb +++ b/lib/engine/game/g_18_usa/step/conversion.rb @@ -10,22 +10,9 @@ class Conversion < G1817::Step::Conversion include ScrapTrainModule def actions(entity) actions = super - actions << 'scrap_train' if entity.corporation? && entity.trains.any? { |t| @game.pullman_train?(t) } && - !actions.empty? + actions << 'scrap_train' if can_scrap_train? actions end - - def can_scrap_train?(entity) - return false unless entity.corporation? - return false unless entity.owned_by?(current_entity) - - entity.trains.find { |t| @game.pullman_train?(t) } - end - - def process_scrap_train(action) - @corporate_action = action - @game.scrap_train_by_corporation(action, current_entity) - end end end end diff --git a/lib/engine/game/g_18_usa/step/denver_track.rb b/lib/engine/game/g_18_usa/step/denver_track.rb index ab659fb2ad..a12266e72c 100644 --- a/lib/engine/game/g_18_usa/step/denver_track.rb +++ b/lib/engine/game/g_18_usa/step/denver_track.rb @@ -2,7 +2,6 @@ require_relative '../../../step/base' require_relative '../../../step/tracker' -require_relative 'scrap_train_module' module Engine module Game @@ -10,7 +9,6 @@ module G18USA module Step class DenverTrack < Engine::Step::Base include Engine::Step::Tracker - include ScrapTrainModule ACTIONS = %w[lay_tile].freeze def actions(entity) diff --git a/lib/engine/game/g_18_usa/step/discard_train.rb b/lib/engine/game/g_18_usa/step/discard_train.rb index 683b989426..98e58713ef 100644 --- a/lib/engine/game/g_18_usa/step/discard_train.rb +++ b/lib/engine/game/g_18_usa/step/discard_train.rb @@ -10,23 +10,10 @@ class DiscardTrain < Engine::Step::DiscardTrain include ScrapTrainModule def actions(entity) actions = super - actions << 'scrap_train' if entity.corporation? && entity.trains.any? { |t| @game.pullman_train?(t) } && - !actions.empty? + actions << 'scrap_train' if can_scrap_train?(entity) actions end - def can_scrap_train?(entity) - return false unless entity.corporation? - return false unless entity.owned_by?(current_entity) - - entity.trains.find { |t| @game.pullman_train?(t) } - end - - def process_scrap_train(action) - @corporate_action = action - @game.scrap_train_by_corporation(action, current_entity) - end - def trains(corporation) return super unless corporation.trains.count { |t| @game.pullman_train?(t) } > 1 diff --git a/lib/engine/game/g_18_usa/step/dividend.rb b/lib/engine/game/g_18_usa/step/dividend.rb index 07e5cbd5bd..d27ab92bfd 100644 --- a/lib/engine/game/g_18_usa/step/dividend.rb +++ b/lib/engine/game/g_18_usa/step/dividend.rb @@ -2,13 +2,12 @@ require_relative '../../../step/half_pay' require_relative '../../g_1817/step/dividend' -require_relative 'scrap_train_module' + module Engine module Game module G18USA module Step class Dividend < G1817::Step::Dividend - include ScrapTrainModule DIVIDEND_TYPES = %i[payout half withhold].freeze include Engine::Step::HalfPay diff --git a/lib/engine/game/g_18_usa/step/loan.rb b/lib/engine/game/g_18_usa/step/loan.rb index 04a0beebe5..3bb49374fc 100644 --- a/lib/engine/game/g_18_usa/step/loan.rb +++ b/lib/engine/game/g_18_usa/step/loan.rb @@ -1,12 +1,20 @@ # frozen_string_literal: true require_relative '../../g_1817/step/loan' +require_relative 'scrap_train_module' module Engine module Game module G18USA module Step class Loan < G1817::Step::Loan + include ScrapTrainModule + def actions(entity) + actions = super + actions << 'scrap_train' if entity == current_entity && can_scrap_train?(current_entity) + actions + end + def can_payoff?(entity) super && !@loan_taken end diff --git a/lib/engine/game/g_18_usa/step/obsolete_train.rb b/lib/engine/game/g_18_usa/step/obsolete_train.rb index ba07312676..81d92a2031 100644 --- a/lib/engine/game/g_18_usa/step/obsolete_train.rb +++ b/lib/engine/game/g_18_usa/step/obsolete_train.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true require_relative '../../../step/base' -require_relative 'scrap_train_module' + module Engine module Game module G18USA module Step class ObsoleteTrain < Engine::Step::Base - include ScrapTrainModule ACTIONS = %w[choose pass].freeze def actions(entity) diff --git a/lib/engine/game/g_18_usa/step/post_conversion_loans.rb b/lib/engine/game/g_18_usa/step/post_conversion_loans.rb index c6392be007..3801f5df51 100644 --- a/lib/engine/game/g_18_usa/step/post_conversion_loans.rb +++ b/lib/engine/game/g_18_usa/step/post_conversion_loans.rb @@ -11,22 +11,9 @@ class PostConversionLoans < G1817::Step::PostConversionLoans include ScrapTrainModule def actions(entity) actions = super - actions << 'scrap_train' if entity.corporation? && entity.trains.any? { |t| @game.pullman_train?(t) } && - !actions.empty? + actions << 'scrap_train' if can_scrap_train?(entity) actions end - - def can_scrap_train?(entity) - return false unless entity.corporation? - return false unless entity.owned_by?(current_entity) - - entity.trains.find { |t| @game.pullman_train?(t) } - end - - def process_scrap_train(action) - @corporate_action = action - @game.scrap_train_by_corporation(action, current_entity) - end end end end diff --git a/lib/engine/game/g_18_usa/step/reduce_tokens.rb b/lib/engine/game/g_18_usa/step/reduce_tokens.rb index b3568a49a0..fdb1773780 100644 --- a/lib/engine/game/g_18_usa/step/reduce_tokens.rb +++ b/lib/engine/game/g_18_usa/step/reduce_tokens.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true require_relative '../../../step/reduce_tokens' -require_relative 'scrap_train_module' + module Engine module Game module G18USA module Step class ReduceTokens < Engine::Step::ReduceTokens - include ScrapTrainModule def actions(entity) actions = super.dup actions << 'choose' if !actions.empty? && owns_p8?(entity) diff --git a/lib/engine/game/g_18_usa/step/route.rb b/lib/engine/game/g_18_usa/step/route.rb index de503378fd..50d9b24ce3 100644 --- a/lib/engine/game/g_18_usa/step/route.rb +++ b/lib/engine/game/g_18_usa/step/route.rb @@ -1,13 +1,11 @@ # frozen_string_literal: true require_relative '../../../step/route' -require_relative 'scrap_train_module' module Engine module Game module G18USA module Step class Route < Engine::Step::Route - include ScrapTrainModule def actions(entity) return [] if !entity.operator? || @game.route_trains(entity).empty? || !@game.can_run_route?(entity) diff --git a/lib/engine/game/g_18_usa/step/scrap_train.rb b/lib/engine/game/g_18_usa/step/scrap_train.rb deleted file mode 100644 index 2bb4f17fbd..0000000000 --- a/lib/engine/game/g_18_usa/step/scrap_train.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../../step/base' -require_relative 'scrap_train_module' -module Engine - module Game - module G18USA - module Step - class ScrapTrain < Engine::Step::Base - include ScrapTrainModule - def actions(entity) - actions = [] - actions << 'scrap_train' if entity == current_entity && entity.corporation? && - entity.trains.any? { |t| @game.pullman_train?(t) } - actions << 'pass' if blocks? - actions - end - - def blocks? - @round.paid_loans[current_entity] && can_scrap_train?(current_entity) - end - - def description - 'Scrap Pullman' - end - - def pass_description - 'Skip Scrap Pullman' - end - - def can_scrap_train?(entity) - return false unless entity.corporation? - return false unless entity.owned_by?(current_entity) - - entity.trains.find { |t| @game.pullman_train?(t) } - end - - def process_scrap_train(action) - @corporate_action = action - @game.scrap_train_by_corporation(action, current_entity) - end - end - end - end - end -end diff --git a/lib/engine/game/g_18_usa/step/scrap_train_module.rb b/lib/engine/game/g_18_usa/step/scrap_train_module.rb index 0c4f328d70..9bfc7f2654 100644 --- a/lib/engine/game/g_18_usa/step/scrap_train_module.rb +++ b/lib/engine/game/g_18_usa/step/scrap_train_module.rb @@ -10,11 +10,51 @@ def scrappable_trains(entity) end def scrap_info(_) - @game.scrap_info + "Scrap Pullman for #{@game.format_currency(pullman_scrap_value)}" end def scrap_button_text(_) - @game.scrap_button_text + 'Scrap Pullman' + end + + def pullman_scrap_value + 50 + end + + def scrap_trains_button_only? + true + end + + # owner is the alleged owner of the company scrapping a pullman + def scrap_train_by_owner(action, _owner) + entity = action.entity + raise GameError, "#{entity.name} cannot scrap a train now" unless entity.owned_by?(current_entity) + + train = action.train + raise GameError, "#{entity.name} cannot scrap a #{train.name} train" unless @game.pullman_train?(train) + + scrap_train(train) + end + + # Do error checking before calling this. + def scrap_train(train) + @game.bank.spend(pullman_scrap_value, train.owner) + @game.log << "#{train.owner.name} scraps a pullman for #{@game.format_currency(pullman_scrap_value)}" + @game.depot.reclaim_train(train) + @game.reset_crowded_corps + end + + def can_scrap_train?(entity) + return false unless entity + return false unless entity.corporation? + return false unless entity.owned_by?(current_entity) + + entity.trains.find { |t| @game.pullman_train?(t) } + end + + def process_scrap_train(action) + @corporate_action = action + scrap_train_by_owner(action, current_entity) end end end diff --git a/lib/engine/game/g_18_usa/step/special_buy_train.rb b/lib/engine/game/g_18_usa/step/special_buy_train.rb index 1be4bf9446..58c37e607e 100644 --- a/lib/engine/game/g_18_usa/step/special_buy_train.rb +++ b/lib/engine/game/g_18_usa/step/special_buy_train.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true require_relative '../../../step/special_buy_train' -require_relative 'scrap_train_module' + module Engine module Game module G18USA module Step class SpecialBuyTrain < Engine::Step::SpecialBuyTrain - include ScrapTrainModule def must_buy_train?(_entity) false end diff --git a/lib/engine/game/g_18_usa/step/special_token.rb b/lib/engine/game/g_18_usa/step/special_token.rb index b632f94edb..fb9366f64b 100644 --- a/lib/engine/game/g_18_usa/step/special_token.rb +++ b/lib/engine/game/g_18_usa/step/special_token.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true require_relative '../../../step/special_token' -require_relative 'scrap_train_module' module Engine module Game module G18USA module Step class SpecialToken < Engine::Step::SpecialToken - include ScrapTrainModule def process_place_token(action) super diff --git a/lib/engine/game/g_18_usa/step/special_track.rb b/lib/engine/game/g_18_usa/step/special_track.rb index ccc72396d8..c67bd43cb9 100644 --- a/lib/engine/game/g_18_usa/step/special_track.rb +++ b/lib/engine/game/g_18_usa/step/special_track.rb @@ -2,7 +2,6 @@ require_relative '../../../step/special_track' require_relative 'resource_track' -require_relative 'scrap_train_module' module Engine module Game @@ -10,7 +9,6 @@ module G18USA module Step class SpecialTrack < Engine::Step::SpecialTrack include ResourceTrack - include ScrapTrainModule def actions(entity) return [] if entity&.id == 'P16' && !@game.phase.tiles.include?(:brown) diff --git a/lib/engine/game/g_18_usa/step/token.rb b/lib/engine/game/g_18_usa/step/token.rb index 72fce7df01..98ca95f232 100644 --- a/lib/engine/game/g_18_usa/step/token.rb +++ b/lib/engine/game/g_18_usa/step/token.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true require_relative '../../../step/token' -require_relative 'scrap_train_module' module Engine module Game module G18USA module Step class Token < Engine::Step::Token - include ScrapTrainModule def place_token(entity, city, token, connected: true, extra_action: false, special_ability: nil, check_tokenable: true, spender: nil) super diff --git a/lib/engine/game/g_18_usa/step/track.rb b/lib/engine/game/g_18_usa/step/track.rb index afbd29d0b4..e5fe03672b 100644 --- a/lib/engine/game/g_18_usa/step/track.rb +++ b/lib/engine/game/g_18_usa/step/track.rb @@ -3,7 +3,6 @@ require_relative '../../../step/track' require_relative '../../../step/upgrade_track_max_exits' require_relative 'resource_track' -require_relative 'scrap_train_module' module Engine module Game @@ -12,7 +11,6 @@ module Step class Track < Engine::Step::Track include Engine::Step::UpgradeTrackMaxExits include ResourceTrack - include ScrapTrainModule def can_lay_tile?(entity) super || can_place_token_with_p20?(entity) || can_assign_p6?(entity)