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

[18Uruguay] Adding support for delivering goods #10207

Merged
Merged
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
46 changes: 20 additions & 26 deletions lib/engine/game/g_18_uruguay/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
require_relative 'loans'
require_relative '../../loan'
require_relative 'ability_ship'
require_relative 'goods'
require_relative 'step/route_rptla'

module Engine
module Game
Expand All @@ -26,9 +28,9 @@ class Game < Game::Base
include Phases
include InterestOnLoans
include Loans
include Goods

EBUY_SELL_MORE_THAN_NEEDED = true
GOODS_TRAIN = 'Goods'

register_colors(darkred: '#ff131a',
red: '#d1232a',
Expand All @@ -44,7 +46,6 @@ class Game < Game::Base
SELL_BUY_ORDER = :sell_buy
TILE_RESERVATION_BLOCKS_OTHERS = true
CURRENCY_FORMAT_STR = '$U%d'
GOODS_DESCRIPTION_STR = 'Number of goods: '

MUST_BUY_TRAIN = :always

Expand Down Expand Up @@ -173,6 +174,7 @@ def cattle_farm

def setup
super
goods_setup
@rptla = @corporations.find { |c| c.id == 'RPTLA' }
@fce = @corporations.find { |c| c.id == 'FCE' }

Expand Down Expand Up @@ -274,7 +276,8 @@ def operating_round(round_num)
Engine::Step::HomeToken,
Engine::Step::Track,
G18Uruguay::Step::Token,
Engine::Step::Route,
G18Uruguay::Step::Route,
G18Uruguay::Step::RouteRptla,
G18Uruguay::Step::Dividend,
G18Uruguay::Step::DiscardTrain,
G18Uruguay::Step::BuyTrain,
Expand Down Expand Up @@ -338,26 +341,6 @@ def perform_ebuy_loans(entity, remaining)
end
end

# Goods
def number_of_goods_at_harbor
ability = @rptla.abilities.find { |a| a.type == 'Goods' }
ability.description[/\d+/].to_i
end

def add_good_to_rptla
ability = @rptla.abilities.find { |a| a.type == 'Goods' }
count = number_of_goods_at_harbor + 1
ability.description = GOODS_DESCRIPTION_STR + count.to_s
end

def remove_goods_from_rptla(goods_count)
return if number_of_goods_at_harbor < goods_count

ability = @rptla.abilities.find { |a| a.type == 'Goods' }
count = number_of_goods_at_harbor - goods_count
ability.description = GOODS_DESCRIPTION_STR + count.to_s
end

def check_distance(route, visits, train = nil)
@round.current_routes[route.train] = route
if route.corporation != @rptla && !nationalized?
Expand All @@ -372,10 +355,21 @@ def check_distance(route, visits, train = nil)
end

# Revenue
def revenue_str_rptla(route)
count = goods_on_ship(route.train)
str = 'No goods'
str = count.to_s + ' good' if count.positive?
str += 's' if count > 1
str
end

def revenue_str(route)
return super unless route&.corporation == @rptla
return revenue_str_rptla(route) if route&.corporation == @rptla

'Ship'
good_hex = good_pickup_hex(route.train)
str = super
str += '+Good(' + good_hex.id + ')' unless good_hex.nil?
str
end

def rptla_revenue(corporation)
Expand All @@ -397,7 +391,7 @@ def revenue_for(route, stops)
return revenue unless route&.corporation == @rptla

train = route.train
revenue * goods_on_train(train)
revenue * goods_on_ship(train)
end

def or_round_finished
Expand Down
94 changes: 94 additions & 0 deletions lib/engine/game/g_18_uruguay/goods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# frozen_string_literal: true

module Engine
module Game
module G18Uruguay
module Goods
GOODS_DESCRIPTION_STR = 'Number of goods: '

def goods_setup
@pickup_hex_for_train = {}
@goods_on_ship = {}
@number_of_goods_at_harbor = 0
end

# Train delivery
def train_with_goods?(train)
return unless train

@pickup_hex_for_train.key?(train.id)
end

def attach_good_to_train(train, hex)
@pickup_hex_for_train[train.id] = hex
end

def good_pickup_hex(train)
@pickup_hex_for_train[train.id]
end

def unload_good(train)
@pickup_hex_for_train.delete(train.id) if train_with_goods?(train)
end

# Harbor
def visits_include_port?(visits)
visits.any? { |visit| self.class::PORTS.include?(visit.hex.id) }
end

def route_include_port?(route)
route.hexes.any? { |hex| self.class::PORTS.include?(hex.id) }
end

def check_for_goods_if_run_to_port(route, visits)
true if route.corporation == @rptla
visits_include_port?(visits) || !train_with_goods?(route.train)
end

def check_for_port_if_goods_attached(route, visits)
true if route.corporation == @rptla
!visits_include_port?(visits) || train_with_goods?(route.train)
end

def number_of_goods_at_harbor
@number_of_goods_at_harbor
end

def add_good_to_rptla
ability = @rptla.abilities.find { |a| a.type == :Goods }
return if ability.nil?

@number_of_goods_at_harbor += 1
ability.description = GOODS_DESCRIPTION_STR + @number_of_goods_at_harbor.to_s
end

def remove_goods_from_rptla(goods_count)
return if @number_of_goods_at_harbor < goods_count

ability = @rptla.abilities.find { |a| a.type == :Goods }
return if ability.nil?

@number_of_goods_at_harbor -= goods_count
ability.description = GOODS_DESCRIPTION_STR + count.to_s
end

# Ship gooods
def add_goods_to_ship(ship, count)
@goods_on_ship[ship.id] = count
end

def remove_goods_from_ship(ship)
return unless @goods_on_ship.key?(ship.id)

@goods_on_ship[ship.id] = 0
end

def goods_on_ship(ship)
return 0 unless @goods_on_ship.key?(ship.id)

@goods_on_ship[ship.id]
end
end
end
end
end
130 changes: 130 additions & 0 deletions lib/engine/game/g_18_uruguay/step/route.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# frozen_string_literal: true

require_relative '../../../step/route'

module Engine
module Game
module G18Uruguay
module Step
class Route < Engine::Step::Route
def setup
@round.current_routes = {}
end

def actions(entity)
return %w[].freeze if entity.corporation == @game.rptla
return [] if !entity.operator? || @game.route_trains(entity).empty? || [email protected]_run_route?(entity)
return [] if entity.corporation? && entity.type == :minor

actions = ACTIONS.dup
actions << 'choose' if choosing?(entity)
actions
end

def choosing?(_entity)
true
end

def choice_name
return 'Attach goods to ships' if current_entity == @game.rptla

'Attach good to a train'
end

def goods_hexes
@game.hexes.select do |hex|
hex.assignments.keys.find { |a| a.include? 'GOODS' }
end
end

def choices
choices = {}
goods_train_choices(current_entity).each_with_index do |train, _index|
hex = train['hex']
index_str = "train\##{train['train_index']}"
index_str += "_#{train['hex'].id}" unless hex.nil?
choices[index_str] = "#{train['train'].name} train\##{train['train_index']} (#{train['hex'].id})" unless hex.nil?
choices[index_str] = "#{train['train'].name} train\##{train['train_index']} unload" if hex.nil?
end
choices
end

def route_for_train(train)
@round.current_routes[train] unless train.nil?
end

def get_train_goods_combo(name)
str_split = name.split('_')
train_index = str_split[0].split('#')[1]
train = @game.route_trains(current_entity)[train_index.to_i - 1]
hex = @game.hex_by_id(str_split[1]) if str_split.size > 1
[train, hex]
end

def goods_train_choices(entity)
choices_array = []
@game.route_trains(entity).each_with_index do |train, index|
route = route_for_train(train)
if @game.train_with_goods?(train)
choices_array.push({ train: train, train_index: index + 1, hex: nil, loaded: true })
else
goods_hexes.each do |hex|
if route
val = { train: train, train_index: index + 1, hex: hex, loaded: false }
choices_array.push(val) if route.hexes.include?(hex)
end
end
end
end
choices_array
end

def process_choose(action)
entity = action.entity

train, hex = get_train_goods_combo(action.choice)

if hex
@log << "#{entity.id} attaches good from #{hex.id} to a #{train.name} train"

@game.attach_good_to_train(train, hex)
else
@log << "#{entity.id} remove good from #{train.name} train"
@game.unload_good(train)
end
end

def detach_goods(routes)
routes.each do |route|
train = route.train
next unless @game.train_with_goods?(train)

hex = @game.good_pickup_hex(train)
good = hex.assignments.keys.find { |a| a.include? 'GOODS' }
@game.unload_good(train)
raise NoToken, "No good token found at Hex #{hex&.id}" if good.nil?
raise NoToken, "Hex #{hex&.id} is not included in route for train #{train.name}" unless route.hexes.include?(hex)

hex.remove_assignment!(good)
@log << "#{current_entity.id} moves a good to the harbor"
@game.add_good_to_rptla unless good.nil?
end
end

def process_run_routes(action)
super
entity = action.entity
detach_goods(action.routes) unless action.entity == @game.rptla
@game.route_trains(entity)&.each do |train|
@game.unload_good(train)
end
end

def round_state
super.merge({ current_routes: {} })
end
end
end
end
end
end
Loading
Loading