From fe9531ede8d72384de1328a5987ee65974a38bab Mon Sep 17 00:00:00 2001 From: Phil Campeau Date: Tue, 2 Jan 2024 13:48:34 -0500 Subject: [PATCH] [1832] updates and corrects quite a bit of code --- lib/engine/game/g_1832/corporation.rb | 13 ++ lib/engine/game/g_1832/entities.rb | 17 +- lib/engine/game/g_1832/game.rb | 224 +++++++++++++++++---- lib/engine/game/g_1832/map.rb | 87 ++++---- lib/engine/game/g_1832/step/buy_company.rb | 23 +++ lib/engine/game/g_1832/step/track.rb | 89 ++++++++ 6 files changed, 374 insertions(+), 79 deletions(-) create mode 100644 lib/engine/game/g_1832/corporation.rb create mode 100644 lib/engine/game/g_1832/step/buy_company.rb create mode 100644 lib/engine/game/g_1832/step/track.rb diff --git a/lib/engine/game/g_1832/corporation.rb b/lib/engine/game/g_1832/corporation.rb new file mode 100644 index 0000000000..ce0adafe23 --- /dev/null +++ b/lib/engine/game/g_1832/corporation.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative '../../corporation' + +module Engine + module Game + module G1832 + class Corporation < Engine::Corporation + attr_accessor :coal_token + end + end + end +end diff --git a/lib/engine/game/g_1832/entities.rb b/lib/engine/game/g_1832/entities.rb index 92bc6d4cf7..f3c7dfd56f 100644 --- a/lib/engine/game/g_1832/entities.rb +++ b/lib/engine/game/g_1832/entities.rb @@ -28,6 +28,7 @@ module Entities type: 'major', text_color: 'white', coordinates: 'F10', + city: 1, }, { float_percent: 60, @@ -88,6 +89,7 @@ module Entities type: 'major', text_color: 'black', coordinates: 'F10', + city: 0, }, { float_percent: 60, @@ -214,10 +216,17 @@ module Entities value: 80, revenue: 15, sym: 'P5', - desc: 'This private company gives the owning company a WVCF token for free.'\ - ' When other companies connect to the coal fields, '\ - 'they may buy a WVCF token (if available) during their operating round for $80'\ - ' ($40 goes to the company owning the WVCF private company).', + abilities: [ + { + type: 'blocks_hexes', + owner_type: 'player', + hexes: %w[B12 B16 C13 C15], + }, + ], + desc: 'This private company gives the owning company a Coal token for free.'\ + ' When other companies connect to the Coalfields, '\ + 'they may buy a Coal token (if available) during their operating round for $80'\ + ' ($40 goes to the corporation owning the Coal private company).', }, { name: 'Central Railroad & Canal', diff --git a/lib/engine/game/g_1832/game.rb b/lib/engine/game/g_1832/game.rb index 5caf6b1c6c..43cf71d166 100644 --- a/lib/engine/game/g_1832/game.rb +++ b/lib/engine/game/g_1832/game.rb @@ -4,6 +4,8 @@ require_relative '../base' require_relative 'map' require_relative '../g_1870' +require_relative '../g_1850' +require_relative 'entities' module Engine module Game @@ -13,7 +15,7 @@ class Game < Game::Base include Entities include Map - attr_accessor :sell_queue, :connection_run, :reissued + attr_accessor :sell_queue, :reissued, :coal_token_counter, :coal_company_sold_or_closed CURRENCY_FORMAT_STR = '$%s' @@ -33,6 +35,7 @@ class Game < Game::Base CAPITALIZATION = :full MUST_SELL_IN_BLOCKS = true + CORPORATION_CLASS = G1832::Corporation MARKET = [ %w[64y 68 72 76 82 90 100p 110 120 140 160 180 200 225 250 275 300 325 350 375 400], @@ -94,7 +97,7 @@ class Game < Game::Base operating_rounds: 3, }, { - name: '23', + name: '12', on: '12', train_limit: 2, tiles: %i[yellow green brown], @@ -111,13 +114,13 @@ class Game < Game::Base num: 6, events: [{ 'type' => 'companies_buyable' }], }, - { name: '4', distance: 4, price: 300, rusts_on: '8', num: 5 }, + { name: '4', distance: 4, price: 300, rusts_on: '8', num: 4 }, { name: '5', distance: 5, price: 450, rusts_on: '12', - num: 4, + num: 3, events: [{ 'type' => 'close_companies' }], }, { @@ -127,13 +130,17 @@ class Game < Game::Base num: 3, events: [{ 'type' => 'remove_tokens' }], }, - { name: '8', distance: 8, price: 800, num: 3 }, + { + name: '8', + distance: 8, + price: 800, + num: 3, + events: [{ 'type' => 'remove_key_west_token' }], + }, { name: '10', distance: 10, price: 950, num: 2 }, { name: '12', distance: 12, price: 1100, num: 99 }, ].freeze - LAYOUT = :pointy - EBUY_OTHER_VALUE = false CLOSED_CORP_TRAINS_REMOVED = false @@ -149,9 +156,18 @@ class Game < Game::Base MULTIPLE_BUY_ONLY_FROM_MARKET = true + BOOMTOWN_HEXES = %w[D8 F14 G9 G9 H6 L14].freeze + + ASSIGNMENT_TOKENS = { + 'boomtown' => '/icons/1832/boomtown_token.svg', + 'P2' => '/icons/1846/sc_token.svg', + 'P3' => '/icons/1832/cotton_token.svg', + }.freeze + EVENTS_TEXT = Base::EVENTS_TEXT.merge( 'companies_buyable' => ['Companies become buyable', 'All companies may now be bought in by corporation'], - 'remove_tokens' => ['Remove Tokens', 'Remove private company tokens'] + 'remove_tokens' => ['Remove Tokens', 'Remove private company tokens'], + 'remove_key_west_token' => ['Remove Key West Token', 'FECR loses the Key West'] ).freeze MARKET_TEXT = Base::MARKET_TEXT.merge( @@ -160,7 +176,9 @@ class Game < Game::Base STATUS_TEXT = Base::STATUS_TEXT.merge( 'can_buy_companies_from_other_players' => ['Interplayer Company Buy', - 'Companies can be bought between players'] + 'Companies can be bought between players', + 'The West Virginia Coalfields private company can be bought in for '\ + 'up to face value from the owning player'], ).merge( 'companies_buyable' => ['Companies become buyable', 'All companies may now be bought in by corporation'], ) @@ -176,25 +194,25 @@ def stock_round G1870::Round::Stock.new(self, [ Engine::Step::DiscardTrain, G1870::Step::BuySellParShares, - G1870::Step::PriceProtection, + G1850::Step::PriceProtection, ]) end def operating_round(round_num) - G1870::Round::Operating.new(self, [ + Engine::Round::Operating.new(self, [ Engine::Step::Bankrupt, Engine::Step::Exchange, - G1870::Step::BuyCompany, + G1832::Step::BuyCompany, G1870::Step::Assign, G1870::Step::SpecialTrack, - G1870::Step::Track, + G1832::Step::Track, Engine::Step::Token, Engine::Step::Route, G1870::Step::Dividend, Engine::Step::DiscardTrain, G1870::Step::BuyTrain, - [G1870::Step::BuyCompany, { blocks: true }], - G1870::Step::PriceProtection, + [G1832::Step::BuyCompany, { blocks: true }], + G1850::Step::PriceProtection, ], round_num: round_num) end @@ -209,16 +227,44 @@ def ipo_reserved_name(_entity = nil) def setup @sell_queue = [] - @connection_run = {} @reissued = {} + @coal_token_counter = 5 coal_company.max_price = coal_company.value + + @sharp_city ||= @all_tiles.find { |t| t.name == '5' } + @gentle_city ||= @all_tiles.find { |t| t.name == '6' } + @straight_city ||= @all_tiles.find { |t| t.name == '57' } + + @tile_141 ||= @all_tiles.find { |t| t.name == '141' } + @tile_142 ||= @all_tiles.find { |t| t.name == '142' } + @tile_143 ||= @all_tiles.find { |t| t.name == '143' } + @tile_144 ||= @all_tiles.find { |t| t.name == '144' } end def event_companies_buyable! coal_company.max_price = 2 * coal_company.value end + def event_close_companies! + @log << '-- Event: Private companies close --' + company.close! + + @coal_company_sold_or_closed = true + end + + def event_close_remaining_companies! + @log << '-- Event: All remaining private companies close --' + @companies.each(&:close!) + end + + # can't run to or through the West Virginia Coalfied hex (B14) without a coal token + def check_distance(route, visits, _train = nil) + return super if visits.none? { |v| v.hex == coal_hex } || route.train.owner.coal_token + + raise GameError, 'Corporation must own coal token to enter West Virginia Coalfields' + end + def event_remove_tokens! removals = Hash.new { |h, k| h[k] = {} } @@ -247,10 +293,6 @@ def event_remove_tokens! end end - def coal_company - @river_company ||= company_by_id('P5') - end - def port_company @port_company ||= company_by_id('P2') end @@ -263,6 +305,14 @@ def can_hold_above_corp_limit?(_entity) true end + def coal_company + @coal_company ||= company_by_id('P5') + end + + def coal_hex + @coal_hex ||= hex_by_id('B14') + end + def revenue_for(route, stops) revenue = super @@ -298,33 +348,131 @@ def legal_tile_rotation?(_entity, _hex, _tile) true end - # CHECK IF THIS WORKS, IF NOT TRY IMPLEMENTING THIS OVER HERE VVVVV - # def upgrades_to?(from, to, _special = false, selected_company: nil) - # return false if to.name == '171K' && from.hex.name != 'B11' - # return false if to.name == '172L' && from.hex.name != 'C18' + def purchasable_companies(entity = nil) + entity ||= current_entity + return super unless @phase.name == '2' - # super - # end + coal_company + end - # def upgrades_to_correct_label?(from, to) - # return true if to.color != :brown + def after_sell_company(buyer, company, _price, _seller) + return unless company == coal_company - # super - # end + buyer.coal_token = true + @coal_token_counter -= 1 + @coal_company_sold_or_closed = true + log << "#{buyer.name} receives Coal token. #{@coal_token_counter} Coal tokens left in the game." + log << '-- Corporations can now buy Coal tokens --' + end + + def status_array(corporation) + return unless corporation.coal_token + + ['Coal Token'] + end + + def all_potential_upgrades(tile, tile_manifest: false, selected_company: nil) + upgrades = super + return upgrades unless tile_manifest + + upgrades |= [@sharp_city, @tile_141, @tile_142, @tile_143] if tile.name == '3' && tile.assigned?('boomtown') + upgrades |= [@straight_city, @tile_141, @tile_142] if tile.name == '4' && tile.assigned?('boomtown') + + if tile.name == '58' && tile.assigned?('boomtown') + upgrades |= [@gentle_city, @tile_141, @tile_142, @tile_143, @tile_144] + end + + upgrades + end def reissued?(corporation) @reissued[corporation] end - # TODO: LIST: - # Implement the bonuses for P2 and P3 - # Implement Share Count issues (1856) - # + def graph_skip_paths(entity) + return nil if entity.coal_token - ASSIGNMENT_TOKENS = { - 'P2' => '/icons/1846/sc_token.svg', - 'P3' => '/icons/1832/cotton_token.svg', - }.freeze + @skip_paths ||= {} + + return @skip_paths unless @skip_paths.empty? + + coal_hex.tile.paths.each do |path| + @skip_paths[path] = true + end + + @skip_paths + end + + # 1828 system code + # def create_system(corporations) + # return nil unless corporations.size == 2 + + # system_data = CORPORATIONS.find { |c| c[:sym] == corporations.first.id }.dup + # system_data[:sym] = corporations.map(&:name).join('-') + # system_data[:tokens] = [] + # system_data[:abilities] = [] + # system_data[:corporations] = corporations + # system = init_system(@stock_market, system_data) + + # @corporations << system + # @_corporations[system.id] = system + # system.shares.each { |share| @_shares[share.id] = share } + + # corporations.each { |corporation| transfer_assets_to_system(corporation, system) } + + # # Order tokens for better visual + # max_price = system.tokens.max_by(&:price).price + 1 + # system.tokens.sort_by! { |t| (t.used ? -max_price : max_price) + t.price } + + # place_system_blocking_tokens(system) + + # # Make sure the system will not own two coal markers + # if coal_markers(system).size > 1 + # remove_coal_marker(system) + # add_coal_marker_to_va_coalfields + # @log << "#{system.name} cannot have two coal markers, returning one to Virginia Coalfields" + # end + + # @stock_market.set_par(system, system_market_price(corporations)) + # system.ipoed = true + + # system + # end + + # def transfer_assets_to_system(corporation, system) + # corporation.spend(corporation.cash, system) if corporation.cash.positive? + + # # Transfer tokens + # used, unused = corporation.tokens.partition(&:used) + # used.each do |t| + # new_token = Engine::Token.new(system, price: t.price) + # system.tokens << new_token + # t.swap!(new_token, check_tokenable: false) + # end + # unused.sort_by(&:price).each { |t| system.tokens << Engine::Token.new(system, price: t.price) } + # corporation.tokens.clear + + # # Transfer companies + # corporation.companies.each do |company| + # company.owner = system + # system.companies << company + # end + # corporation.companies.clear + + # # Transfer abilities + # corporation.all_abilities.dup.each do |ability| + # corporation.remove_ability(ability) + # system.add_ability(ability) + # end + + # # Create shell and transfer + # shell = G1828::Shell.new(corporation.name, system) + # system.shells << shell + # corporation.trains.dup.each do |train| + # buy_train(system, train, :free) + # shell.trains << train + # end + # end end end end diff --git a/lib/engine/game/g_1832/map.rb b/lib/engine/game/g_1832/map.rb index b45c07b46f..bc83f25755 100644 --- a/lib/engine/game/g_1832/map.rb +++ b/lib/engine/game/g_1832/map.rb @@ -11,7 +11,7 @@ module Map 'A21' => 'Richmond', 'B2' => 'Kansas City', 'B14' => 'West Virgina Coal Fields', - 'B16' => 'Lynchburg', + 'B18' => 'Lynchburg', 'B24' => 'Norfolk', 'C3' => 'Jackson', 'C7' => 'Nashville', @@ -52,6 +52,7 @@ module Map '3' => 3, '4' => 4, '5' => 2, + '6' => 2, '7' => 7, '8' => 20, '9' => 20, @@ -79,7 +80,12 @@ module Map '142' => 1, '143' => 1, '144' => 1, - '190' => 1, + '190' => { + 'count' => 1, + 'color' => 'green', + 'code' => 'city=revenue:40;city=revenue:40;city=revenue:40;path=a:1,b:_0;path=a:4,b:_0;path=a:0,b:_1;path=a:3,b:_1'\ + 'path=a:2,b:_2;path=a:5,b:_2;label=Atl', + }, # brown '39' => 1, @@ -96,8 +102,16 @@ module Map '145' => 1, '146' => 1, '147' => 1, - '191' => 1, - '193' => 1, + '191' => { + 'count' => 1, + 'color' => 'brown', + 'code' => 'city=revenue:40,slots:2;path=a:0,b:_0;path=a:1,b:_0;path=a:2,b:_0;path=a:3,b:_0;label=S', + }, + '193' => { + 'count' => 1, + 'color' => 'brown', + 'code' => 'city=revenue:60,slots:4;path=a:0,b:_0;path=a:1,b:_0;path=a:2,b:_0;path=a:3,b:_0;path=a:4,b:_0', + }, '611' => { 'count' => 2, 'color' => 'brown', @@ -109,46 +123,45 @@ module Map white: { %w[B6 B8 B20 B22 C5 C19 C21 C23 D2 D14 D18 D22 E3 E5 E15 E19 F2 F4 F12 F16 F18 G5 G7 G13 H2 H4 H10 H12 H14 I5 I7 I9 I11 I13 J8 K13] => '', - %w[C7 D20 D16 F6] => 'city=revenue:0', - %w[B18 E17 G3 H8 J12] => 'town=revenue:0;', + %w[C7 D20 F6] => 'city=revenue:0', + %w[B18 E17 G3 H8 J12] => 'town=revenue:0', %w[M15 C17] => 'town=revenue:0;town=revenue:0', - %w[H6 G9 G11 L14] => 'town=revenue:0;icon=image:18_co/upgrade,sticky:1,name:upgrade;', - %w[D6 E7 E9 F8] => 'upgrade=cost:40,terrain:mountain;', - %w[B10 B12 C9 D10 E11] => 'upgrade=cost:60,terrain:mountain;', - %w[B16 C15] => 'upgrade=cost:70,terrain:mountain;', - %w[D12 C13] => 'upgrade=cost:80,terrain:mountain;', - %w[B4 E13 K15 L16] => 'upgrade=cost:40,terrain:water;', - %w[G15 I15 N14] => 'upgrade=cost:60,terrain:water;', - %w[E23 F20 G19 J6 K9 K11 L12 N12] => 'upgrade=cost:80,terrain:water;', - %w[D4 C3] => 'upgrade=cost:40,terrain:water;town=revenue:0', - ['C11'] => 'upgrade=cost:60,terrain:water;town=revenue:0', - %w[D8 F14] => 'upgrade=cost:40,terrain:water;icon=image:18_co/upgrade,sticky:1,name:upgrade;town=revenue:0;', - ['E21'] => 'icon=image:port,sticky:1;town=revenue:0', - ['G17'] => 'label=JC;icon=image:port,sticky:1;city=revenue:0;upgrade=cost:60,terrain:water;', - ['H16'] => 'label=S;icon=image:port,sticky:1;city=revenue:0;upgrade=cost:60,terrain:water;', - %w[I3 J10] => 'icon=image:port,sticky:1;city=revenue:0;', - ['J14'] => 'label=JC;icon=image:port,sticky:1;city=revenue:0;', - ['J4'] => 'icon=image:port,sticky:1;town=revenue:0;upgrade=cost:80,terrain:water;', - ['M13'] => 'icon=image:port,sticky:1;city=revenue:0;upgrade=cost:40,terrain:water;', + %w[H6 G9 G11 L14] => 'town=revenue:0,boom:1', + %w[D6 E7 E9 F8] => 'upgrade=cost:40,terrain:mountain', + %w[B10 B12 C9 D10 E11] => 'upgrade=cost:60,terrain:mountain', + %w[B16 C15] => 'upgrade=cost:70,terrain:mountain', + %w[D12 C13] => 'upgrade=cost:80,terrain:mountain', + %w[B4 E13 K15 L16] => 'upgrade=cost:40,terrain:water', + %w[G15 I15 N14] => 'upgrade=cost:60,terrain:water', + %w[E23 F20 G19 J6 K9 K11 L12 N12] => 'upgrade=cost:80,terrain:water', + %w[D4 C3] => 'town=revenue:0;upgrade=cost:40,terrain:water', + ['C11'] => 'city=revenue:0;upgrade=cost:60,terrain:water', + %w[D8 F14] => 'town=revenue:0,boom:1;upgrade=cost:40,terrain:water', + ['E21'] => 'town=revenue:0', + ['D16'] => 'city=revenue:0;label=JC', + ['G17'] => 'city=revenue:0;upgrade=cost:60,terrain:water;icon=image:port,sticky:1;label=JC', + ['H16'] => 'city=revenue:0;upgrade=cost:60,terrain:water;icon=image:port,sticky:1;label=S', + %w[I3 J10] => 'city=revenue:0;icon=image:port,sticky:1', + ['J14'] => 'city=revenue:0;icon=image:port,sticky:1;label=JC', + ['J4'] => 'town=revenue:0;upgrade=cost:80,terrain:water;icon=image:port,sticky:1', + ['M13'] => 'city=revenue:0;upgrade=cost:40,terrain:water;icon=image:port,sticky:1', }, red: { - %w[A7 A21] => 'offboard=revenue:yellow_30|brown_50;path=a:5,b:_0;path=a:0,b:_0;', - ['B2'] => 'offboard=revenue:yellow_30|brown_50|gray_60;path=a:5,b:_0;path=a:4,b:_0;', - ['N16'] => 'icon=image:port,sticky:1;'\ - 'offboard=revenue:yellow_20|brown_30|gray_50;path=a:1,b:_0;path=a:2,b:_0;path=a:3,b:_0;', + %w[A7 A21] => 'offboard=revenue:yellow_30|brown_50;path=a:5,b:_0;path=a:0,b:_0', + ['B2'] => 'offboard=revenue:yellow_30|brown_50|gray_60;path=a:5,b:_0;path=a:4,b:_0', + ['N16'] => 'offboard=revenue:yellow_20|brown_30|gray_50;path=a:1,b:_0;path=a:2,b:_0;path=a:3,b:_0;'\ + 'icon=image:port,sticky:1', }, yellow: { - ['F10'] => 'label=a;city=revenue:20;city=revenue:20;city=revenue:20;path=a:4,b:_0;path=a:0,b:_1;path=a:2,b:_2;', + ['F10'] => 'city=revenue:20;city=revenue:20;city=revenue:20;path=a:4,b:_0;path=a:0,b:_1;path=a:2,b:_2;label=Atl;', }, gray: { - ['B14'] => 'city=revenue:yellow_40|brown_60;path=a:0,b:_0;path=a:1,b:_0;path=a:4,b:_0;path=a:5,b:_0;' \ - 'icon=image:1828/coal;icon=image:1828/coal', - ['I1'] => 'path=a:4,b:5;', - ['B24'] => 'icon=image:port,sticky:1;city=revenue:yellow_20|brown_40|gray_50;'\ - 'path=a:1,b:_0;path=a:0,b:_0;', - ['J2'] => 'icon=image:port,sticky:1;city=revenue:yellow_20|brown_30|gray_50;'\ - 'path=a:2,b:_0;path=a:3,b:_0;path=a:4,b:_0;', - ['M17'] => 'path=a:2,b:0;', + ['B14'] => 'city=revenue:yellow_40|brown_60;path=a:0,b:_0;path=a:1,b:_0;path=a:4,b:_0;path=a:5,b:_0', + ['I1'] => 'path=a:4,b:5', + ['B24'] => 'city=revenue:yellow_20|brown_40|gray_50;path=a:1,b:_0;path=a:0,b:_0;icon=image:port,sticky:1', + ['J2'] => 'city=revenue:yellow_20|brown_30|gray_50;path=a:2,b:_0;path=a:3,b:_0;path=a:4,b:_0;'\ + 'icon=image:port,sticky:1', + ['M17'] => 'path=a:2,b:0', }, }.freeze end diff --git a/lib/engine/game/g_1832/step/buy_company.rb b/lib/engine/game/g_1832/step/buy_company.rb new file mode 100644 index 0000000000..8676c965c2 --- /dev/null +++ b/lib/engine/game/g_1832/step/buy_company.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require_relative '../../../step/buy_company' + +module Engine + module Game + module G1832 + module Step + class BuyCompany < Engine::Step::BuyCompany + def can_buy_company?(entity) + return super unless @game.phase.name == '2' + + companies = @game.purchasable_companies(entity) + + entity == current_entity && + !companies.empty? && + companies.map(&:min_price).min <= entity.cash + end + end + end + end + end +end diff --git a/lib/engine/game/g_1832/step/track.rb b/lib/engine/game/g_1832/step/track.rb new file mode 100644 index 0000000000..6963db6708 --- /dev/null +++ b/lib/engine/game/g_1832/step/track.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require_relative '../../../step/tracker' +require_relative '../../../step/track' + +module Engine + module Game + module G1832 + module Step + class Track < Engine::Step::Track + def process_lay_tile(action) + lay_tile_action(action) + + action.hex.remove_assignment!('boomtown') if action.hex.assigned?('boomtown') + + if action.hex.id.include?(Engine::Game::G1832::Game::BOOMTOWN_HEXES) && action.hex::COLOR == 'white' + action.hex.assign!('boomtown') + end + + pass! unless can_lay_tile?(action.entity) + end + + def actions(entity) + actions = super.dup + actions += %w[choose pass] if can_buy_coal_token?(entity) + + actions.uniq + end + + def choices + choices = [] + choices << ['Buy Coal Token'] if can_buy_coal_token?(current_entity) + choices + end + + def choice_name + 'Additional Track Actions' + end + + def pass! + super + @game.track_action_processed(current_entity) + end + + def process_choose(action) + buy_coal_token(action.entity) if action.choice == 'Buy Coal Token' + @round.num_laid_track += 1 + end + + def buy_coal_token(corporation) + total_cost = 80 + amount_to_owner = @game.coal_company.closed? ? 0 : 40 + amount_to_bank = amount_to_owner.positive? ? 40 : 80 + + corporation.spend(amount_to_bank, @game.bank) + corporation.spend(amount_to_owner, @game.coal_company.owner) if amount_to_owner.positive? + + @game.coal_token_counter -= 1 + + log_message = "#{corporation.name} buys a Coal token for #{@game.format_currency(total_cost)}. " + if amount_to_owner.positive? + log_message += "#{@game.coal_company.owner.name} receives #{@game.format_currency(amount_to_owner)}. " + end + log_message += "#{@game.coal_token_counter} Coal tokens left in the game" + @log << log_message + corporation.coal_token = true + @game.clear_token_graph_for_entity(corporation) + end + + def hex_neighbors(entity, hex) + connected = super + @game.clear_token_graph_for_entity(entity) if entity.tokens.none?(&:city) + connected + end + + def can_buy_coal_token?(entity) + entity.corporation? && + !entity.coal_token && + @game.coal_company_sold_or_closed && + @game.coal_token_counter.positive? && + entity.cash >= 80 && + hex_neighbors(entity, @game.coal_hex) && + get_tile_lay(entity) + end + end + end + end + end +end