Skip to content

Commit

Permalink
Merge branch 'upstream'
Browse files Browse the repository at this point in the history
  • Loading branch information
ollybh committed Apr 2, 2024
2 parents 33a0923 + c3b77e0 commit a25a8a6
Show file tree
Hide file tree
Showing 120 changed files with 17,442 additions and 12,229 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ Special thanks to all the [contributors](https://github.com/tobymao/18xx/graphs/

## Development

Please submit [issues](https://github.com/tobymao/18xx/issues) and [pull requests](https://github.com/tobymao/18xx/pulls). Most discussion about development happens on the [18xx Slack](https://join.slack.com/t/18xxgames/shared_invite/zt-27imtsj2u-vussFAqtecmACsycjdsIhg) in the #18xxgames and #18xxgamesdev channels. If you would like to add your game to the site, please contact us on Slack. For more information, see [`DEVELOPMENT.md`](DEVELOPMENT.md).
Please submit [issues](https://github.com/tobymao/18xx/issues) and [pull requests](https://github.com/tobymao/18xx/pulls). Most discussion about development happens on the [18xx Slack](https://18xxgames.slack.com/join/shared_invite/zt-2evbzlz86-fSip9Zr9W~OSQW_EbP4DGw#/shared-invite/email) in the #18xxgames and #18xxgamesdev channels. If you would like to add your game to the site, please contact us on Slack. For more information, see [`DEVELOPMENT.md`](DEVELOPMENT.md).
6 changes: 6 additions & 0 deletions assets/app/mail/turn.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# frozen_string_literal: true

# This file generates a backtick warning when running tests, but resolving it by adding
# the same warning suppression comment as other files breaks the e-mail notifications.
# See: https://github.com/tobymao/18xx/pull/10382
# https://github.com/tobymao/18xx/pull/10479
# https://github.com/tobymao/18xx/pull/10531

class Turn < Snabberb::Component
needs :game_url
needs :game_id
Expand Down
9 changes: 6 additions & 3 deletions assets/app/view/game/button/buy_share.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class BuyShare < Snabberb::Component
needs :action, default: Engine::Action::BuyShares
needs :purchase_for, default: nil
needs :borrow_from, default: nil
needs :discounter, default: nil

def render
step = @game.round.active_step
Expand All @@ -43,7 +44,8 @@ def render
process_buy = lambda do
do_buy = lambda do
buy_shares(@entity, bundle, share_price: modified_price, swap: @swap_share,
purchase_for: @purchase_for, borrow_from: @borrow_from)
purchase_for: @purchase_for, borrow_from: @borrow_from,
discounter: @discounter)
end

if (consenter = @game.consenter_for_buy_shares(@entity, bundle))
Expand All @@ -56,9 +58,10 @@ def render
h(:button, { on: { click: process_buy } }, text)
end

def buy_shares(entity, bundle, share_price: nil, swap: nil, purchase_for: nil, borrow_from: nil)
def buy_shares(entity, bundle, share_price: nil, swap: nil, purchase_for: nil, borrow_from: nil, discounter: nil)
process_action(@action.new(entity, shares: bundle.shares, swap: swap, purchase_for: purchase_for,
share_price: share_price, borrow_from: borrow_from))
share_price: share_price, borrow_from: borrow_from,
discounter: discounter))
end
end
end
Expand Down
22 changes: 18 additions & 4 deletions assets/app/view/game/buy_sell_shares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ def render_buy_shares
children.concat(render_other_player_shares)
children.concat(render_shares_for_others)
children.concat(render_price_protection)
children.concat(render_reduced_price_shares(@ipo_shares, source: @game.ipo_name(@corporation)))
children.concat(render_reduced_price_shares(@pool_shares))
children.concat(render_swap_shares(@ipo_shares, source: @game.ipo_name(@corporation)))
children.concat(render_swap_shares(@pool_shares))
children.concat(render_company_discounted_bundles)

children
end
Expand Down Expand Up @@ -233,7 +234,7 @@ def render_price_protection
[h(:button, { on: { click: protect } }, 'Protect Shares')]
end

def render_reduced_price_shares(shares, source: 'Market')
def render_swap_shares(shares, source: 'Market')
shares.map do |share|
next unless (swap_share = @step.swap_buy(@current_entity, @corporation, share))

Expand All @@ -246,6 +247,19 @@ def render_reduced_price_shares(shares, source: 'Market')
end
end

def render_company_discounted_bundles
return [] unless @step.respond_to?(:company_discounted_bundles)

@step.company_discounted_bundles(@corporation).map do |company, bundle|
h(Button::BuyShare,
share: bundle,
entity: @current_entity,
prefix: "#{company.name}: ",
discounter: company,
percentages_available: bundle.num_shares,)
end
end

def render_short
return [] unless @step.current_actions.include?('short')
return [] unless @step.can_short?(@current_entity, @corporation)
Expand All @@ -258,7 +272,7 @@ def render_short
# Allow privates or minors to be exchanged for shares if they have the ability
def render_exchanges
children = []
source_entities = @game.companies + @game.minors + @game.corporations
source_entities = @game.exchange_entities

source_entities.each do |entity|
@game.abilities(entity, :exchange) do |ability|
Expand Down
6 changes: 5 additions & 1 deletion assets/app/view/game/dividend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ def render
process_action(Engine::Action::Dividend.new(@step.current_entity, kind: type))
cleanup
end
button = h('td.no_padding', [h(:button, { style: { margin: '0.2rem 0' }, on: { click: click } }, text)])
button_id = text.downcase.tr(' ', '_') # Generate an ID based on the value of 'text'

button = h('td.no_padding', [
h(:button, { style: { margin: '0.2rem 0' }, on: { click: click }, attrs: { id: button_id } }, text),
])

h(:tr, [
button,
Expand Down
8 changes: 7 additions & 1 deletion assets/app/view/game/map_legend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@ class MapLegend < Snabberb::Component
needs :game, store: true

def render
table_props, header, *chart = @game.map_legend(
h(:div, @game.map_legends.map { |method| render_legend(method) })
end

def render_legend(method)
table_props, header, *chart = @game.send(
method,
color_for(:font),
color_for(:yellow),
color_for(:green),
color_for(:brown),
color_for(:gray),
color_for(:red),
action_processor: ->(a) { process_action(a) },
)

Expand Down
2 changes: 1 addition & 1 deletion assets/app/view/game/pass_button.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def render
}

for_text = @for_player ? " (#{@for_player.name})" : ''
h(:button, props, "#{@game.round.pass_description}#{for_text}")
h('button#pass', props, "#{@game.round.pass_description}#{for_text}")
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions assets/app/view/game/route_selector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,11 @@ def actions(render_halts)

buttons = [
h('button.small', { on: { click: clear } }, 'Clear Train'),
h('button.small', { on: { click: clear_all } }, 'Clear All'),
h('button.small', { attrs: { id: 'clearall' }, on: { click: clear_all } }, 'Clear All'),
h('button.small', { on: { click: reset_all } }, 'Reset'),
]
if @game_data.dig('settings', 'auto_routing') || @game_data['mode'] == :hotseat
buttons << h('button.small', { on: { click: auto } }, 'Auto')
buttons << h('button.small', { attrs: { id: 'autoroute' }, on: { click: auto } }, 'Auto')
end
if @game.adjustable_train_list?(current_entity)
buttons << h('button.small', { on: { click: add_train } }, "+#{@game.adjustable_train_label(current_entity)}")
Expand All @@ -335,7 +335,7 @@ def actions(render_halts)
end
h(:div, { style: { overflow: 'auto', marginBottom: '1rem' } }, [
h(:div, buttons),
h(:button, { style: submit_style, on: { click: submit } }, 'Submit ' + revenue_str),
h(:button, { style: submit_style, attrs: { id: 'submit' }, on: { click: submit } }, 'Submit ' + revenue_str),
])
end

Expand Down
2 changes: 1 addition & 1 deletion assets/app/view/game/track_conversion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def render
h(:tbody, trains),
]),
actions,
])
].compact)
end

def cleanup
Expand Down
9 changes: 9 additions & 0 deletions assets/app/view/game_page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,15 @@ def hotkey_check(event)
change_anchor('#tools')
when 'a'
change_anchor('#auto')
when '1'
button_click('pass')
when '2'
button_click('clearall')
when '3'
button_click('autoroute')
when 'Enter'
button_click('submit')
button_click('pay_out')
when 'c'
if (chatbar = Native(`document.getElementById('chatbar')`))
chatbar.focus
Expand Down
12 changes: 4 additions & 8 deletions assets/app/view/welcome.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ def render
def render_notification
message = <<~MESSAGE
<p><a href='https://www.kickstarter.com/projects/1840vienna/18esp/'>18ESP is now on Kickstarter</a>.</p>
<p><a href="https://github.com/tobymao/18xx/wiki/1868-Wyoming">1868 Wyoming</a> is in production.
<a href="https://github.com/tobymao/18xx/wiki/1822CA">1822CA</a> is in beta.
<a href="https://github.com/tobymao/18xx/wiki/1841">1841</a> is in beta.
<a href="https://github.com/tobymao/18xx/wiki/1847-AE">1847AE</a> is in beta.
<a href="https://github.com/tobymao/18xx/wiki/18ESP">18ESP</a> is in alpha.
</p>
<p><a href="https://github.com/tobymao/18xx/wiki/18Neb">18Neb</a> is in alpha.</p>
<p><a href="https://github.com/tobymao/18xx/wiki/18NL">18NL</a> is in production.</p>
<p>Report bugs and make feature requests <a href='https://github.com/tobymao/18xx/issues'>on GitHub</a>.</p>
MESSAGE
Expand All @@ -45,8 +41,8 @@ def render_introduction
message = <<~MESSAGE
<p>Check out the <a href='https://github.com/tobymao/18xx/wiki/FAQ'>FAQ</a>, <a href='https://github.com/tobymao/18xx/wiki/Power-User-Features'>keyboard shortcuts</a> and <a href='https://github.com/tobymao/18xx/wiki'>the Wiki</a></p>
<p>Find games in the chat or <a href='https://github.com/tobymao/18xx/wiki/18xx-Online-Communities%2C-Media%2C-and-Resources#community'>on (unofficial) Discord servers</a></p>
<p>Setup <a href='https://github.com/tobymao/18xx/wiki/Notifications'>turn notifications</a> via webhook to Slack, Discord, and Telegram</p>
<p>Ask questions in <code>#18xxgames</code> <a href='https://join.slack.com/t/18xxgames/shared_invite/zt-27imtsj2u-vussFAqtecmACsycjdsIhg'>on the 18XX Slack</a></p>
<p><a href='https://github.com/tobymao/18xx/wiki/Notifications'>Turn notifications</a> can be enabled via <a href='https://github.com/tobymao/18xx/wiki/Notifications#discord-notifications'>Discord</a>, <a href='https://github.com/tobymao/18xx/wiki/Notifications#slack-notifications'>Slack</a>, or <a href='https://github.com/tobymao/18xx/wiki/Notifications#telegram-notifications'>Telegram</a></p>
<p>Ask any questions about the site in <code>#18xxgames</code> <a href='https://18xxgames.slack.com/join/shared_invite/zt-2evbzlz86-fSip9Zr9W~OSQW_EbP4DGw#/shared-invite/email'>on the 18XX Slack</a></p>
<p>Buy physical copies of 18XX games from publishers:</br> #{Lib::Publisher.link_list.join}.</p>
<p>Keep the servers running by becoming a member <a href='https://www.patreon.com/18xxgames'>on Patreon</a></p>
MESSAGE
Expand Down
10 changes: 8 additions & 2 deletions lib/engine/ability/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class Base
:on_phase, :after_phase, :use_across_ors

def initialize(type:, description: nil, desc_detail: nil, owner_type: nil, count: nil, remove: nil,
use_across_ors: nil, count_per_or: nil, passive: nil, on_phase: nil, after_phase: nil, **opts)
use_across_ors: nil, count_per_or: nil, passive: nil, on_phase: nil, after_phase: nil,
remove_when_used_up: nil, **opts)
@type = type&.to_sym
@description = description&.to_s
@desc_detail = desc_detail&.to_s
Expand All @@ -30,6 +31,7 @@ def initialize(type:, description: nil, desc_detail: nil, owner_type: nil, count
@remove = remove&.to_s
@start_count = @count
@passive = passive.nil? ? @when.empty? : passive
@remove_when_used_up = remove_when_used_up.nil? ? true : remove_when_used_up

setup(**opts)
end
Expand All @@ -46,7 +48,7 @@ def use!(**_kwargs)
return unless @count

@count -= 1
owner.remove_ability(self) unless @count.positive?
owner.remove_ability(self) if !@count.positive? && @remove_when_used_up
end

def use_up!
Expand All @@ -60,6 +62,10 @@ def teardown; end
def when?(*times)
!(@when & times).empty?
end

def add_count!(amount)
@count += amount
end
end
end
end
7 changes: 5 additions & 2 deletions lib/engine/action/buy_shares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@
module Engine
module Action
class BuyShares < Base
attr_reader :entity, :bundle, :swap, :purchase_for, :borrow_from, :total_price
attr_reader :entity, :bundle, :swap, :purchase_for, :borrow_from, :total_price, :discounter

def initialize(entity, shares:, share_price: nil, percent: nil, swap: nil, purchase_for: nil,
borrow_from: nil, total_price: nil)
borrow_from: nil, total_price: nil, discounter: nil)
super(entity)
@bundle = ShareBundle.new(Array(shares), percent)
@bundle.share_price = share_price
@swap = swap
@purchase_for = purchase_for
@borrow_from = borrow_from
@total_price = total_price
@discounter = discounter
end

def self.h_to_args(h, game)
Expand All @@ -27,6 +28,7 @@ def self.h_to_args(h, game)
purchase_for: game.get(h['purchase_for_type'], h['purchase_for']),
borrow_from: game.get(h['borrow_from_type'], h['borrow_from']),
total_price: h['total_price'],
discounter: game.company_by_id(h['discounter']),
}
end

Expand All @@ -41,6 +43,7 @@ def args_to_h
'borrow_from_type' => type_s(@borrow_from),
'borrow_from' => @borrow_from&.id,
'total_price' => @total_price,
'discounter' => @discounter&.id,
}
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/engine/corporation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ def inspect

# Is it legal to hold percent shares in this corporation?
def holding_ok?(share_holder, extra_percent = 0)
return true if share_holder == self

common_percent = share_holder.common_percent_of(self) + extra_percent
%i[multiple_buy unlimited].include?(@share_price&.type) || common_percent <= @max_ownership_percent
end
Expand Down
10 changes: 6 additions & 4 deletions lib/engine/depot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,12 @@ def insert_train(train, index = 0)

def depot_trains(clear: false)
@depot_trains = nil if clear
@depot_trains ||= [
@upcoming.first,
*@upcoming.select { |t| @game.phase.available?(t.available_on) },
].compact.uniq(&:name) + @discarded.uniq(&:name)
@depot_trains ||= available_upcoming_trains + @discarded.uniq(&:name)
end

def available_upcoming_trains
[@upcoming.first,
*@upcoming.select { |t| @game.phase.available?(t.available_on) }].compact.uniq(&:name)
end

def available(corporation)
Expand Down
21 changes: 21 additions & 0 deletions lib/engine/game/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,11 @@ def all_bundles_for_corporation(share_holder, corporation, shares: nil)
all_bundles.sort_by(&:percent)
end

def can_gain_from_player?(entity, bundle)
(self.class::BUY_SHARE_FROM_OTHER_PLAYER && entity.player?) ||
(self.class::CORPORATE_BUY_SHARE_ALLOW_BUY_FROM_PRESIDENT && entity.corporation? && bundle.owner == entity.owner)
end

def partial_bundles_for_presidents_share(corporation, bundle, percent)
normal_percent = corporation.share_percent
difference = corporation.presidents_percent - normal_percent
Expand Down Expand Up @@ -1927,6 +1932,11 @@ def after_par(corporation)
place_home_token(corporation) if self.class::HOME_TOKEN_TIMING == :par
end

# This is a hook to do something before company is closed by using an ability
def company_closing_after_using_ability(company, silent = false)
@log << "#{company.name} closes" unless silent
end

def close_companies_on_event!(entity, event)
@companies.each do |company|
next if company.closed?
Expand Down Expand Up @@ -2129,6 +2139,11 @@ def exchange_partial_percent(_share)
nil
end

# Entities that can own an exchange ability.
def exchange_entities
companies + minors
end

def exchange_corporations(exchange_ability)
candidates = case exchange_ability.corporations
when 'any'
Expand Down Expand Up @@ -3109,6 +3124,8 @@ def ability_right_time?(ability, time, on_phase, passive_ok, strict_time)
@round.operating? && @round.current_operator&.player == ability.player
when 'owning_player_track'
@round.operating? && @round.current_operator&.player == ability.player && current_step.is_a?(Step::Track)
when 'owning_player_token'
@round.operating? && @round.current_operator&.player == ability.player && current_step.is_a?(Step::Token)
when 'owning_player_sr_turn'
@round.stock? && @round.current_entity == ability.player
when 'or_between_turns'
Expand Down Expand Up @@ -3221,6 +3238,10 @@ def show_map_legend_on_left?
false
end

def map_legends
[:map_legend]
end

def train_purchase_name(train)
train.name
end
Expand Down
2 changes: 1 addition & 1 deletion lib/engine/game/g_1817/game.rb
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ def redeemable_shares(entity)

def tokens_needed(corporation)
tokens_needed = { 2 => 1, 5 => 2, 10 => 4 }[corporation.total_shares] - corporation.tokens.size
tokens_needed += 1 if corporation.companies.any? { |c| c.id == 'TS' }
tokens_needed += 1 if corporation.companies.any? { |c| c.id == TRAIN_STATION_PRIVATE_NAME }
tokens_needed
end

Expand Down
2 changes: 0 additions & 2 deletions lib/engine/game/g_1817/step/buy_sell_par_shares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,6 @@ def use_on_assign_abilities(company)
corporation.tokens << Engine::Token.new(corporation)
ability.use!
@log << "#{corporation.name} acquires additonal token from #{company.name}"
@log << "#{company.name} closes"
company.close!
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/engine/game/g_1822_pnw/map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module Map
'F23' => 'Spokane',
'G2' => 'Clearwater',
'G8' => 'Quilcene',
'G12' => 'Mikilteo',
'G12' => 'Mukilteo',
'G14' => 'Snohomish',
'G16' => 'Park Place',
'G24' => 'Spokane',
Expand Down
Loading

0 comments on commit a25a8a6

Please sign in to comment.