diff --git a/lib/engine/game/g_18_ka.rb b/lib/engine/game/g_18_ka.rb new file mode 100644 index 0000000000..b707cb791c --- /dev/null +++ b/lib/engine/game/g_18_ka.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Engine + module Game + module G18KA + end + end +end diff --git a/lib/engine/game/g_18_ka/game.rb b/lib/engine/game/g_18_ka/game.rb new file mode 100644 index 0000000000..ed4004d6b2 --- /dev/null +++ b/lib/engine/game/g_18_ka/game.rb @@ -0,0 +1,933 @@ +# frozen_string_literal: true + +require_relative 'meta' +require_relative '../base' +require_relative '../../game_error' +require_relative '../g_1856/game' + +module Engine + module Game + module G18KA + class Game < G1856::Game + include_meta(G18KA::Meta) + + CURRENCY_FORMAT_STR = '%dc' + + BANK_CASH = 12_000 + + CERT_LIMIT = { 2 => 20, 3 => 13, 4 => 10 }.freeze + def cert_limit + # cert limit isn't dynamic in 1836jr56 + CERT_LIMIT[@players.size] + end + + STARTING_CASH = { 3 => 560, 4 => 420, 5 => 336, 6 => 280, 7 => 240 }.freeze + + LAYOUT = :flat + # AXES = { x: :letter, y: :number }.freeze + + # colors + OL_LIGHT_GREEN = '#7bb137' + WM_CYAN = '#37b2e2' + KM_ORANGE = '#eb6f0e' + THARSIS_BROWN = '#881a1e' + NM_NAVY = '#004d95' + PMC_WHITE = '#FFF' + + NATIONAL_ = '#AA4444' + ATLAS_VIOLET = '#8811CC' + MARTIAN_RED = '#a1251b' + MOUNTAIN_ENGINEER = '#daa' + WATER_ENGINEER = '#cef' + IPM_MAIN = '#ccc' + JOVIAN_ORANGE = '#C99039' + ICTN_GREEN = '#228855' + MWM_BLUE = '#118' + CAN_RED = '#FF0000' + TITAN_RED = '#c43' + ICY_WATER = '#b0e1eb' + ASTEROID_GRAY = '#777' + # TILE_TYPE = :lawson + TILES = { + + '3' => 5, + '4' => 5, + '58' => 5, + + '5' => 4, + '6' => 4, + '57' => 8, + + '7' => 8, + '8' => 16, + '9' => 16, + + '59' => 2, + + '80' => 5, + '81' => 5, + '82' => 5, + '83' => 5, + + '141' => 5, + '142' => 5, + '143' => 5, + '144' => 5, + + '147' => 5, + '146' => 5, + '145' => 5, + + '64' => 1, + '65' => 1, + '66' => 1, + '67' => 1, + '68' => 1, + + '544' => 5, + '545' => 5, + '546' => 5, + + '14' => 5, + '15' => 5, + '619' => 5, + + '125' => 10, + + '51' => 5, + '915' => 5, + + '60' => 5, # + # OO tiles + 'OO1' => { + 'count' => 1, + 'color' => 'gray', + 'code' => 'city=revenue:60,slots:3;label=OO;'\ + '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', + }, + 'OO2' => { + 'count' => 1, + 'color' => 'gray', + 'code' => 'city=revenue:70,loc:0;city=revenue:70,loc:3;label=OO;'\ + 'path=a:0,b:_0;path=a:1,b:_0;path=a:4,b:_0;'\ + 'path=a:2,b:_1;path=a:3,b:_1;path=a:5,b:_1', + + }, + # NNNY + 'NNNY1' => { + 'count' => 1, + 'color' => 'green', + 'code' => + 'city=revenue:40;city=revenue:40;city=revenue:40;town=revenue:20;label=NNNY;'\ + 'path=a:1,b:_0;path=a:_0,b:_3;path=a:3,b:_1;path=a:_1,b:_3;path=a:5,b:_2;path=a:_2,b:_3;', + }, + 'NNNY2' => { + 'count' => 1, + 'color' => 'brown', + 'code' => + 'city=revenue:60;city=revenue:60;city=revenue:60;town=revenue:30,loc:center;label=NNNY;'\ + 'path=a:1,b:_0;path=a:_0,b:_3;path=a:3,b:_1;path=a:_1,b:_3;path=a:5,b:_2;path=a:_2,b:_3;path=a:2,b:_3', + }, + 'NNNY3' => { + 'count' => 1, + 'color' => 'gray', + 'code' => + 'city=revenue:80;city=revenue:80;city=revenue:80;town=revenue:40,loc:center;label=NNNY;'\ + 'path=a:1,b:_0;path=a:_0,b:_3;path=a:3,b:_1;path=a:_1,b:_3;path=a:5,b:_2;path=a:_2,b:_3;'\ + 'path=a:2,b:_3;path=a:4,b:_3', + }, + # Capitol Tiles + 'CAP1' => { + 'count' => 1, + 'color' => 'green', + 'code' => + 'city=revenue:60,loc:1.5;city=revenue:60,loc:4.5;label=C;'\ + 'path=a:1,b:_0;path=a:2,b:_0;path=a:4,b:_1;path=a:5,b:_1', + }, + 'CAP2' => { + 'count' => 1, + 'color' => 'brown', + 'code' => + 'city=revenue:80;city=revenue:80;city=revenue:40;label=C;'\ + 'path=a:1,b:_0;path=a:2,b:_0;path=a:4,b:_1;path=a:5,b:_1;'\ + 'path=a:0,b:_2;path=a:3,b:_2', + }, + 'CAP3' => { + 'count' => 1, + 'color' => 'gray', + 'code' => + 'city=revenue:100;city=revenue:100;city=revenue:50,slots:2;label=C;'\ + 'path=a:1,b:_0;path=a:2,b:_0;path=a:4,b:_1;path=a:5,b:_1;'\ + 'path=a:0,b:_2;path=a:3,b:_2', + }, + # Farm + 'FARM1' => { + 'count' => 1, + 'color' => 'green', + 'code' => + 'city=revenue:40;label=F;path=a:0,b:_0;path=a:2,b:_0', + }, + 'FARM2' => { + 'count' => 1, + 'color' => 'brown', + 'code' => + 'city=revenue:50,slots:2;label=F;path=a:0,b:_0;path=a:2,b:_0;path=a:4,b:_0', + }, + 'FARM3' => { + 'count' => 1, + 'color' => 'gray', + 'code' => + 'city=revenue:60,slots:3;label=F;path=a:0,b:_0;path=a:2,b:_0;path=a:4,b:_0;path=a:5,b:_0', + }, + # Space elevator + 'SE1' => { + 'count' => 1, + 'color' => 'green', + 'code' => + 'city=revenue:50;label=SE;path=a:0,b:_0;path=a:2,b:_0;path=a:4,b:_0', + }, + 'SE2' => { + 'count' => 1, + 'color' => 'brown', + 'code' => + 'city=revenue:70,slots:2;label=SE;path=a:0,b:_0;path=a:2,b:_0;path=a:4,b:_0;path=a:5,b:_0', + }, + 'SE3' => { + 'count' => 1, + 'color' => 'gray', + 'code' => + 'city=revenue:90,slots:3;label=SE;path=a:0,b:_0;path=a:2,b:_0;path=a:4,b:_0;path=a:5,b:_0;path=a:3,b:_0', + }, + # Port tile tech tree + 'PORT1' => { + 'count' => 4, + 'color' => 'yellow', + 'code' => 'city=revenue:30;label=P;path=a:0,b:_0;path=a:2,b:_0', + }, + 'PORT2a' => { + 'count' => 1, + 'color' => 'green', + 'code' => 'city=revenue:40,slots:2;label=P;path=a:0,b:_0;path=a:2,b:_0;path=a:1,b:_0;path=a:3,b:_0', + }, + 'PORT2b' => { + 'count' => 1, + 'color' => 'green', + 'code' => 'city=revenue:40;label=P;path=a:0,b:_0;path=a:2,b:_0;path=a:1,b:_0', + }, + 'PORT2c' => { + 'count' => 1, + 'color' => 'green', + 'code' => 'city=revenue:40;label=P;path=a:0,b:_0;path=a:2,b:_0;path=a:3,b:_0', + }, + 'PORT2d' => { + 'count' => 1, + 'color' => 'green', + 'code' => 'city=revenue:40;label=P;path=a:0,b:_0;path=a:2,b:_0;path=a:5,b:_0', + }, + 'PORT3' => { + 'count' => 4, + 'color' => 'brown', + 'code' => 'city=revenue:50,slots:2;label=P;path=a:0,b:_0;path=a:2,b:_0;path=a:1,b:_0;path=a:3,b:_0', + }, + 'PORT4a' => { + 'count' => 3, + 'color' => 'gray', + 'code' => 'city=revenue:60,slots:3;label=P;path=a:0,b:_0;path=a:2,b:_0;path=a:1,b:_0;path=a:3,b:_0', + }, + 'PORT4b' => { + 'count' => 3, + 'color' => 'gray', + 'code' => 'city=revenue:70,slots:2;label=P;path=a:0,b:_0;path=a:2,b:_0;path=a:1,b:_0;path=a:3,b:_0', + }, + }.freeze + + LOCATION_NAMES = { + 'E4' => 'Arcadian Bay', + 'I4' => 'Borealis Harbor', + 'M8' => 'Chryse Gulf', + 'I10' => 'Deimos Down', + 'C12' => 'Olympus Mons', + 'F13' => 'Ascreus', + 'N15' => 'Chryse Harbor', + 'A16' => 'Elysium', + 'E16' => 'Pavis', + 'D19' => 'Arsia', + 'N21' => 'Hellas Sea', + 'E24' => 'Southern Mines', + + }.freeze + + PHASES = [ + { + name: '2', + train_limit: 4, + tiles: [:yellow], + status: %w[escrow facing_2], + operating_rounds: 1, + }, + { + name: "2'", + on: "2+'", + train_limit: 4, + tiles: [:yellow], + status: %w[escrow facing_3], + operating_rounds: 1, + }, + { + name: '3', + on: '3', + train_limit: 4, + tiles: %i[yellow green], + operating_rounds: 2, + status: %w[escrow facing_3 can_buy_companies], + }, + { + name: "3'", + on: "3+'", + train_limit: 4, + tiles: %i[yellow green], + operating_rounds: 2, + status: %w[escrow facing_4 can_buy_companies], + }, + { + name: '4', + on: '4', + train_limit: 3, + tiles: %i[yellow green], + operating_rounds: 2, + status: %w[escrow facing_4 can_buy_companies], + }, + { + name: "4'", + on: "4+'", + train_limit: 3, + tiles: %i[yellow green], + operating_rounds: 2, + status: %w[incremental facing_5 can_buy_companies], + }, + { + name: '5', + on: '5', + train_limit: 2, + tiles: %i[yellow green brown], + status: %w[incremental facing_5], + operating_rounds: 3, + }, + { + name: "5'", + on: "5'", + train_limit: 2, + tiles: %i[yellow green brown], + status: %w[fullcap facing_6], + operating_rounds: 3, + }, + { + name: '6', + on: '6', + train_limit: 2, + tiles: %i[yellow green brown gray], + status: %w[fullcap facing_6 upgradable_towns], + operating_rounds: 3, + }, + { + name: '8', + on: '8', + train_limit: 2, + tiles: %i[yellow green brown gray black], + status: %w[fullcap facing_6 upgradable_towns], + operating_rounds: 3, + }, + ].freeze + + TRAINS = [{ name: '2', distance: 2, price: 100, rusts_on: '4', num: 4 }, + { + name: '2+1', + distance: [{ 'nodes' => %w[city offboard], 'pay' => 2, 'visit' => 2 }, + { 'nodes' => ['town'], 'pay' => 1, 'visit' => 1 }], + price: 125, + obsolete_on: '4', + num: 1, + }, + { + name: '2+1`', + distance: [{ 'nodes' => %w[city offboard], 'pay' => 2, 'visit' => 2 }, + { 'nodes' => ['town'], 'pay' => 1, 'visit' => 1 }], + price: 125, + obsolete_on: '4', + num: 1, + }, + { name: '3', distance: 3, price: 225, rusts_on: '6', num: 3 }, + { + name: '3+1', + distance: [{ 'nodes' => %w[city offboard], 'pay' => 3, 'visit' => 3 }, + { 'nodes' => ['town'], 'pay' => 1, 'visit' => 1 }], + price: 250, + obsolete_on: '6', + num: 1, + }, + { + name: "3+1'", + distance: [{ 'nodes' => %w[city offboard], 'pay' => 3, 'visit' => 3 }, + { 'nodes' => ['town'], 'pay' => 1, 'visit' => 1 }], + price: 250, + obsolete_on: '6', + num: 1, + }, + { name: '4', distance: 4, price: 350, rusts_on: '8', num: 2 }, + { + name: '4+1', + distance: [{ 'nodes' => %w[city offboard], 'pay' => 4, 'visit' => 4 }, + { 'nodes' => ['town'], 'pay' => 1, 'visit' => 1 }], + price: 375, + obsolete_on: '8', # also D + num: 1, + }, + { + name: "4+1'", + distance: [{ 'nodes' => %w[city offboard], 'pay' => 4, 'visit' => 4 }, + { 'nodes' => ['town'], 'pay' => 1, 'visit' => 1 }], + price: 375, + obsolete_on: '8', # also D + num: 1, + }, + { + name: '5', + distance: 5, + price: 550, + num: 1, + events: [{ 'type' => 'close_companies' }], + }, + { + name: "5'", + distance: 5, + price: 550, + num: 1, + events: [{ 'type' => 'no_more_incremental_corps' }], + }, + { + name: '6', + distance: 6, + price: 700, + num: 2, + events: [{ 'type' => 'nationalization' }, { 'type' => 'remove_tokens' }], + }, + { + name: '8', + distance: 8, + price: 1000, + num: 16, + available_on: '6', + discount: { '4' => 350, "4'" => 350, '5' => 350, "5'" => 350, '6' => 350 }, + variants: [ + { + name: 'D', + distance: 999, + price: 1250, + available_on: '6', + discount: { '4' => 350, "4'" => 350, '5' => 350, "5'" => 350, '6' => 350 }, + }, + ], + }].freeze + + COMPANIES = [ + { + name: 'Platinum Credit Card', + value: 10, + revenue: 0, + desc: 'The owning corporation can have 1 additional outstanding loan, beyond the usual limit', + sym: 'A', + }, + { + name: 'Deimos Drilling', + value: 20, + revenue: 5, + desc: 'The owning corporation gets 3 mountain Engineers and 1 mining Right. Other corporations can buy '\ + 'mining Rights from this corporation for 50c', + sym: 'B', + }, + { + name: 'Cosmic Corn Company', + value: 30, + revenue: 10, + desc: 'The owning corporation may place the Farm (F) tile on an equitorial hex as a bonus disconnected '\ + 'tile lay. In exchange for closing this private the corporation may token it for free', + sym: 'C', + }, + { + name: 'Bob\'s Better Bridges', + value: 40, + revenue: 10, + desc: 'This private comes with 2 water Engineers and 2 Harbor Rights. Other corporations can buy harbor '\ + 'Rights from this corporation for 50c', + sym: 'D', + }, + { + name: 'Planetary Espresso', + value: 50, + revenue: 10, + desc: 'The owning corporation may close this company to upgrade the NNNY hex/tile for free and the owning '\ + 'corporation may also place a token on the NNNY hex for free, even without a connection', + sym: 'E', + }, + { + name: 'Happy Happy Harbor', + value: 60, + revenue: 15, + desc: 'This private comes with 1 water Engineer and 2 Harbor Rights. When bought by a corporation, '\ + 'the owning corporation may lay a second harbor marker on an harbor hex, doubling the harbor right bonus '\ + 'for that hex. Other coproraitons can buy harbor rights from this corporation for 50c', + sym: 'F', + }, + { + name: 'Capitol Contract', + value: 70, + revenue: 15, + desc: 'The owning corporation may place the Capitol (C) tile on an equitorial hex as a bonus disconnected '\ + 'tile lay. In exchange for closing this private the corporation may token it for free', + sym: 'G', + }, + { + name: 'Mole People', + value: 80, + revenue: 20, + desc: 'The private comes with 1 mining Engineer and 2 mining Rights. THe owning corporation may close '\ + 'this private to place a mining token in an empty, connected station as a neutral token. Other '\ + 'coprorations can buy mining rights from this corproation for 50c', + sym: 'H', + }, + { + name: 'Space Elevator', + value: 90, + revenue: 20, + desc: 'The owning corporation may place the Space Elevator (SE) tile on an equitorial hex as a bonus '\ + 'disconnected tile lay. In exchange for closing this private the corporation may token it for free', + sym: 'I', + }, + { + name: 'Protoype Maglev', + value: 100, + revenue: 25, + desc: 'Comes with a 2T. The 2T train may be sold at any time (including SR) to any corporation '\ + '(whose president\'s share has been bought) for any price from 1c up to 100c with consent from the '\ + 'buyer and seller. The buying company may offer IPO shares as part of the sale counting at market price '\ + 'with no monetary compensation to the selling corporation. The private is closed at the '\ + 'end of the initial private auction', + sym: 'J', + }, + { + name: 'UPF Bribes', + value: 125, + revenue: 30, + desc: 'This private can be exchanged as a buy action during any stock round to buy an IPO share of a '\ + 'started corporation for free, with no compensation to the corporation', + sym: 'K', + }, + { + name: 'Underground Connections', + value: 150, + revenue: 35, + desc: 'The owning corporation can close this company to repalce an existing token with a token of the '\ + 'corporation, with exceptions. This private may not be sold to a corporation. In a stock round this '\ + 'private can be exchanged to buy the presidency of a corporation with this private as '\ + 'the only compensation to the corporation', + sym: 'L', + }, + ].freeze + + ASSIGNMENT_TOKENS = { + 'RdP' => '/icons/1846/sc_token.svg', + }.freeze + PORT_HEXES = %w[A9 B8 B10 D6 E5 E11 F4 F10 G7 H2 H4 H6 H10 I3 I9 J6 J8 K11].freeze + CORPORATIONS = [ + # Tier 1 + { + sym: 'OL', + name: 'Olympean Lines', + logo: '18_ka/OL', + simple_logo: '18_ka/OL.alt', + tokens: [0, 40, 80, 120], + coordinates: 'A12', + color: OL_LIGHT_GREEN, + text_color: 'black', + }, + { + sym: 'AF', + name: 'Atlas Freight', + logo: '18_ka/AF', + simple_logo: '18_ka/AF.alt', + tokens: [0, 40, 80, 120], + coordinates: 'G8', + color: ATLAS_VIOLET, + text_color: 'white', + }, + { + sym: 'KM', + name: 'Kasei Magway', + logo: '18_ka/KM', + simple_logo: '18_ka/KM.alt', + tokens: [0, 40, 80, 120], + coordinates: 'M20', + color: KM_ORANGE, + text_color: 'black', + }, + { + sym: 'WM', + name: 'Whitney Magway', + logo: '18_ka/WM', + simple_logo: '18_ka/WM.alt', + tokens: [0, 40, 80, 120], + coordinates: 'K14', + color: WM_CYAN, + text_color: 'black', + }, + + # Tier 2 + { + sym: 'C9S', + name: 'Cloud Nine Shipping', + logo: '18_ka/C9S', + simple_logo: '18_ka/C9S.alt', + tokens: [0, 40, 70, 100, 130], + coordinates: 'M12', + color: ICY_WATER, + text_color: 'black', + }, + { + sym: 'TL', + name: 'Tharsis Lines', + logo: '18_ka/TL', + simple_logo: '18_ka/TL.alt', + tokens: [0, 40, 70, 100, 130], + coordinates: 'E10', + color: THARSIS_BROWN, + text_color: 'white', + }, + { + sym: 'NM', + name: 'Noctis Magways', + logo: '18_ka/NM', + simple_logo: '18_ka/NM.alt', + tokens: [0, 40, 70, 100, 130], + coordinates: 'I19', + color: NM_NAVY, + text_color: 'white', + }, + { + sym: 'ATN', + name: 'Asteroid Transportation Network', + logo: '18_ka/ATN', + simple_logo: '18_ka/ATN.alt', + tokens: [0, 40, 70, 100, 130], + coordinates: 'D7', + color: ASTEROID_GRAY, + text_color: 'white', + }, + { + sym: 'PMC', + name: 'Polar Mining Corporation', + logo: '18_ka/PMC', + simple_logo: '18_ka/PMC.alt', + tokens: [0, 40, 70, 100, 130], + coordinates: 'L9', + color: PMC_WHITE, + text_color: 'black', + }, + + # Tier 3 + { + sym: 'CMM', + name: 'Canadian Martian Magway', + logo: '18_ka/CMM', + simple_logo: '18_ka/CMM.alt', + tokens: [0, 40, 60, 80, 100, 120], + coordinates: 'F19', + color: CAN_RED, + text_color: 'black', + }, + { + sym: 'IPM', + name: 'Inner Planets Magway', + logo: '18_ka/IPM', + simple_logo: '18_ka/IPM.alt', + tokens: [0, 40, 60, 80, 100, 120], + coordinates: 'C20', + color: IPM_MAIN, + text_color: 'black', + }, + { + sym: 'TiTaN', + name: 'Tharsis Transportation Network', + logo: '18_ka/TiTaN', + simple_logo: '18_ka/TiTaN.alt', + tokens: [0, 40, 60, 80, 100, 120], + coordinates: 'F15', + color: TITAN_RED, + text_color: 'white', + }, + { + sym: 'ICTN', + name: 'Indo-Chinese Transportation Network', + logo: '18_ka/ICTN', + simple_logo: '18_ka/ICTN.alt', + tokens: [0, 40, 60, 80, 100, 120], + coordinates: 'H13', + color: ICTN_GREEN, + text_color: 'white', + }, + { + sym: 'JA', + name: 'Jovian Alliance', + logo: '18_ka/JA', + simple_logo: '18_ka/JA.alt', + tokens: [0, 40, 60, 80, 100, 120], + coordinates: 'H6', + color: JOVIAN_ORANGE, + text_color: 'black', + }, + { + sym: 'MWM', + name: 'Milky Way Mining', + logo: '18_ka/MWM', + simple_logo: '18_ka/MWM.alt', + tokens: [0, 40, 60, 80, 100, 120], + coordinates: 'I8', + color: MWM_BLUE, + text_color: 'white', + }, + + { + sym: 'MGM', + logo: '18_ka/MGM', + simple_logo: '18_ka/MGM.alt', + name: 'Martian Global Magway', + tokens: [], + color: NATIONAL_, + text_color: 'white', + abilities: [ + { + type: 'train_buy', + description: 'Inter train buy/sell at face value', + face_value: true, + }, + { + type: 'train_limit', + increase: 99, + description: '3 train limit', + }, + { + type: 'borrow_train', + train_types: %w[8 D], + description: 'May borrow a train when trainless*', + }, + ], + reservation_color: nil, + }, + ].freeze + # TODO: Make location name optional and refactor into 1856 + def create_destinations(destinations) + @destinations = {} + destinations.each do |corp, dest| + dest_arr = Array(dest) + d_goals = Array(dest_arr.first) + d_start = dest_arr.size > 1 ? dest_arr.last : corporation_by_id(corp).coordinates + dest_arr.each do |d| + # Array(d).first allows us to treat 'E5' or %[O2 N3] identically + hex_by_id(Array(d).first).original_tile.icons << Part::Icon.new(icon_path(corp)) + end + @destinations[corp] = [d_start, d_goals].freeze + end + end + DESTINATIONS = { + 'AF' => 'I14', + 'KM' => 'K16', + 'OL' => 'E16', + 'WM' => %w[N21 N23], + + 'ATN' => 'I10', + 'C9S' => 'H11', + 'TL' => 'F15', + 'NM' => 'N15', + 'PMC' => 'M16', + + 'JA' => 'M8', + 'IPM' => 'C12', + 'ICTN' => 'G20', + 'CMM' => 'K20', + 'MWM' => %w[D5 E4], + 'TiTaN' => %w[E24 F25], + }.freeze + + # These cities upgrade to the common BarrieLondon green tile, + # but upgrade to specialized brown tiles + BARRIE_HEX = 'I3' + LONDON_HEX = 'H6' + HAMILTON_HEX = 'E5' + HEXES = { + gray: { + ['A10'] => 'path=a:0,b:4', + ['A14'] => 'path=a:5,b:3', + ['C22'] => 'path=a:4,b:3', + ['J21'] => 'path=a:2,b:4', + }, + white: { + %w[B17 C8 D15 E6 E8 E12 E20 E22 F5 F17 G22 H7 H15 H19 I6 I20 J13 J15 K10 L13 L15 L21] => 'blank', + %w[B15 C18 C20 D7 E10 F23 F19 G6 G18 H13 J19 K14 K20 L9] => 'city=revenue:0', + %w[H17 I18 J17 K18 L11 M10] => 'upgrade=cost:40,terrain:water', + %w[L19] => 'town=revenue:0;upgrade=cost:40,terrain:water', + %w[B19 J5 B9 D21 F21 F7 G12 H21 I14 K16 K12 L7 M14] => 'town=revenue:0', + %w[C10 B13 D11 E14 D13 D17 H9 J9 I12 G14 D17 E18 M22] => 'upgrade=cost:30,terrain:mountain', + %w[F15 I8 H11 J11] => 'city=revenue:0;upgrade=cost:30,terrain:mountain', + %w[K8 F9] => 'city=revenue:0;upgrade=cost:20,terrain:swamp', + %w[J7 K6 G10 F11] => 'upgrade=cost:20,terrain:swamp', + %w[B11 C14] => 'town=revenue:0;upgrade=cost:30,terrain:mountain', + %w[H5 A12 M12 M16 M20] => 'city=revenue:0;label=P', + %w[D19 E16 F13] => + 'town=revenue:0;upgrade=cost:60,terrain:mountain;icon=image:18_ka/plus_20,sticky:1', + }, + red: { + ['C12'] => 'offboard=revenue:yellow_30|brown_60|black_70;path=a:5,b:_0,terminal:1;'\ + 'path=a:0,b:_0,terminal:1;path=a:1,b:_0,terminal:1;path=a:2,b:_0,terminal:1;path=a:3,b:_0,terminal:1;'\ + 'path=a:4,b:_0,terminal:1', + ['I10'] => 'offboard=revenue:yellow_40|brown_30|black_20;path=a:5,b:_0,terminal:1;'\ + 'path=a:1,b:_0,terminal:1;path=a:3,b:_0,terminal:1;icon=image:18_ka/mine,sticky:1', + ['D5'] => + 'offboard=revenue:yellow_30|brown_40|black_50,hide:1,groups:Arcadian Bay;'\ + 'path=a:0,b:_0,terminal:1;path=a:5,b:_0,terminal:1;border=edge:4', + ['E4'] => + 'offboard=revenue:yellow_30|brown_40|black_50,groups:Arcadian Bay;'\ + 'path=a:0,b:_0,terminal:1;border=edge:1', + ['A16'] => + 'offboard=revenue:yellow_30|brown_40|black_60,hide:1,groups:Elysium;'\ + 'path=a:5,b:_0,terminal:1;path=a:4,b:_0,terminal:1;border=edge:0', + ['A18'] => + 'offboard=revenue:yellow_30|brown_40|black_60,groups:Elysium;'\ + 'path=a:5,b:_0,terminal:1;path=a:4,b:_0,terminal:1;border=edge:3', + ['E24'] => + 'offboard=revenue:yellow_40|brown_50|black_20,hide:1,groups:Southern Mines;'\ + 'path=a:3,b:_0,terminal:1;path=a:4,b:_0,terminal:1;border=edge:5', + ['F25'] => + 'offboard=revenue:yellow_40|brown_50|black_20,groups:Southern Mines;'\ + 'path=a:3,b:_0,terminal:1;border=edge:2;icon=image:18_ka/mine,sticky:1', + ['N21'] => + 'offboard=revenue:yellow_30|brown_40|black_50,hide:1,groups:Hellas Sea;'\ + 'path=a:1,b:_0,terminal:1;path=a:2,b:_0,terminal:1;border=edge:0', + ['N23'] => + 'offboard=revenue:yellow_30|brown_40|black_50,groups:Hellas Sea;'\ + 'path=a:2,b:_0,terminal:1;border=edge:3', + }, + blue: { + %w[A8] => 'border=edge:4', + %w[B7] => 'border=edge:4;border=edge:1', + %w[C6] => 'border=edge:1', + %w[F3] => 'border=edge:5', + %w[G4] => 'border=edge:2;border=edge:4', + %w[H3 J3] => 'border=edge:1;border=edge:5', + %w[K4 L5] => 'border=edge:2;border=edge:5', + ['I4'] => 'town=revenue:yellow_10|brown_20|black_30;path=a:1,b:_0;path=a:0,b:_0;path=a:5,b:_0;'\ + 'border=edge:2;border=edge:4;icon=image:port,sticky:1', + %w[M6] => 'border=edge:2;border=edge:0', + ['M8'] => 'offboard=revenue:yellow_20|brown_30|black_40;path=a:1,b:_0,terminal:1;path=a:2,b:_0,terminal:1;'\ + 'border=edge:3;border=edge:5;icon=image:port,sticky:1', + %w[N9] => 'border=edge:2;border=edge:0', + %w[N11 N13] => 'border=edge:3;border=edge:0', + ['N15'] => 'offboard=revenue:yellow_20|brown_30|black_60;path=a:1,b:_0,terminal:1;'\ + 'path=a:2,b:_0,terminal:1;border=edge:3;border=edge:0;icon=image:port,sticky:1', + ['N17'] => 'border=edge:3;border=edge:1;border=edge:0', + ['M18'] => 'border=edge:4;border=edge:5', + ['N19'] => 'border=edge:2;border=edge:3', + }, + yellow: { + ['L17'] => + 'city=revenue:20;town=revenue:20;path=a:2,b:_0;path=a:_0,b:_1;label=NNNY;upgrade=cost:40,terrain:water', + %w[D9 G8 G20] => 'city=revenue:0;city=revenue:0;label=OO', + %w[C16 G16] => 'city=revenue:0;label=E;', + %w[I16] => 'city=revenue:0;label=E;upgrade=cost:40,terrain:water', + }, + }.freeze + + LAKE_HEXES = [].freeze + + SELL_BUY_ORDER = :sell_buy_sell + TRACK_RESTRICTION = :permissive + TILE_RESERVATION_BLOCKS_OTHERS = true + def national + @national ||= corporation_by_id('MGM') + end + + def port + @port ||= company_by_id('RdP') + end + + def company_bought(company, entity) end + + def tunnel + raise GameError, "'tunnel' Should not be used" + end + + def bridge + raise GameError, "'bridge' Should not be used" + end + + def wsrc + raise GameError, "'wsrc' Should not be used" + end + + def setup + @straight_city ||= @tiles.find { |t| t.name == '57' } + @sharp_city ||= @tiles.find { |t| t.name == '5' } + @gentle_city ||= @tiles.find { |t| t.name == '6' } + + @straight_track ||= @tiles.find { |t| t.name == '9' } + @sharp_track ||= @tiles.find { |t| t.name == '7' } + @gentle_track ||= @tiles.find { |t| t.name == '8' } + + @x_city ||= @tiles.find { |t| t.name == '14' } + @k_city ||= @tiles.find { |t| t.name == '15' } + + @brown_london ||= @tiles.find { |t| t.name == '126' } + @brown_barrie ||= @tiles.find { |t| t.name == '127' } + + @gray_hamilton ||= @tiles.find { |t| t.name == '123' } + + @post_nationalization = false + @nationalization_train_discard_trigger = false + @national_formed = false + + @pre_national_percent_by_player = {} + @pre_national_market_percent = 0 + + @pre_national_market_prices = {} + @nationalized_corps = [] + + @bankrupted = false + + # Is the president of the national a "false" president? + # A false president gets the presidency with only one share; in this case the president gets + # the full president's certificate but is obligated to buy up to the full presidency in the + # following SR unless a different player becomes rightfully president during share exchange + # It is impossible for someone who didn't become president in + # exchange (1 share tops) to steal the presidency in the SR because + # they'd have to buy 2 shares in one action which is a no-no + # nil: Presidency not awarded yet at all + # not-nl: 1-share false presidency has been awarded to the player (value of var) + @false_national_president = nil + + # CGR flags + @national_ever_owned_permanent = false + + # Corp -> Borrowed Train + @borrowed_trains = {} + create_destinations(DESTINATIONS) + national.add_ability(self.class::NATIONAL_IMMOBILE_SHARE_PRICE_ABILITY) + national.add_ability(self.class::NATIONAL_FORCED_WITHHOLD_ABILITY) + end + + def icon_path(corp) + super if corp == national + + "../logos/18_ka/#{corp}" + end + end + end + end +end diff --git a/lib/engine/game/g_18_ka/meta.rb b/lib/engine/game/g_18_ka/meta.rb new file mode 100644 index 0000000000..06b8f1df0d --- /dev/null +++ b/lib/engine/game/g_18_ka/meta.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require_relative '../meta' + +module Engine + module Game + module G18KA + module Meta + include Game::Meta + + DEV_STAGE = :prealpha + PROTOTYPE = true + DEPENDS_ON = '1856' + + GAME_DESIGNER = 'Matthew Gilzinger' + GAME_INFO_URL = '' + GAME_LOCATION = 'Tharsis, Mars' + GAME_RULES_URL = '' + + PLAYER_RANGE = [3, 7].freeze + end + end + end +end diff --git a/public/icons/18_ka/mine.svg b/public/icons/18_ka/mine.svg new file mode 100644 index 0000000000..1f247be8b5 --- /dev/null +++ b/public/icons/18_ka/mine.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/icons/18_ka/plus_20.svg b/public/icons/18_ka/plus_20.svg new file mode 100644 index 0000000000..629f245794 --- /dev/null +++ b/public/icons/18_ka/plus_20.svg @@ -0,0 +1 @@ ++20c \ No newline at end of file diff --git a/public/logos/18_ka/AF.alt.svg b/public/logos/18_ka/AF.alt.svg new file mode 100644 index 0000000000..b123b2e0ba --- /dev/null +++ b/public/logos/18_ka/AF.alt.svg @@ -0,0 +1 @@ +AF \ No newline at end of file diff --git a/public/logos/18_ka/AF.svg b/public/logos/18_ka/AF.svg new file mode 100644 index 0000000000..36bb94b682 --- /dev/null +++ b/public/logos/18_ka/AF.svg @@ -0,0 +1,4 @@ + + +AF + diff --git a/public/logos/18_ka/ATN.alt.svg b/public/logos/18_ka/ATN.alt.svg new file mode 100644 index 0000000000..3349b34052 --- /dev/null +++ b/public/logos/18_ka/ATN.alt.svg @@ -0,0 +1 @@ +ATN \ No newline at end of file diff --git a/public/logos/18_ka/ATN.svg b/public/logos/18_ka/ATN.svg new file mode 100644 index 0000000000..1721423b19 --- /dev/null +++ b/public/logos/18_ka/ATN.svg @@ -0,0 +1,4 @@ + + +ATN + diff --git a/public/logos/18_ka/C9S.alt.svg b/public/logos/18_ka/C9S.alt.svg new file mode 100644 index 0000000000..317817c6d2 --- /dev/null +++ b/public/logos/18_ka/C9S.alt.svg @@ -0,0 +1 @@ +C9S \ No newline at end of file diff --git a/public/logos/18_ka/C9S.svg b/public/logos/18_ka/C9S.svg new file mode 100644 index 0000000000..aad1c2d183 --- /dev/null +++ b/public/logos/18_ka/C9S.svg @@ -0,0 +1,4 @@ + + +C9S + diff --git a/public/logos/18_ka/CMM.alt.svg b/public/logos/18_ka/CMM.alt.svg new file mode 100644 index 0000000000..d40407d8d0 --- /dev/null +++ b/public/logos/18_ka/CMM.alt.svg @@ -0,0 +1 @@ +CMM \ No newline at end of file diff --git a/public/logos/18_ka/CMM.svg b/public/logos/18_ka/CMM.svg new file mode 100644 index 0000000000..91a15105ca --- /dev/null +++ b/public/logos/18_ka/CMM.svg @@ -0,0 +1,4 @@ + + +CMM + diff --git a/public/logos/18_ka/ICTN.alt.svg b/public/logos/18_ka/ICTN.alt.svg new file mode 100644 index 0000000000..ebbb72da03 --- /dev/null +++ b/public/logos/18_ka/ICTN.alt.svg @@ -0,0 +1 @@ +ICTN \ No newline at end of file diff --git a/public/logos/18_ka/ICTN.svg b/public/logos/18_ka/ICTN.svg new file mode 100644 index 0000000000..a61a3f73dc --- /dev/null +++ b/public/logos/18_ka/ICTN.svg @@ -0,0 +1,4 @@ + + +ICTN + diff --git a/public/logos/18_ka/IPM.alt.svg b/public/logos/18_ka/IPM.alt.svg new file mode 100644 index 0000000000..1681dd7bda --- /dev/null +++ b/public/logos/18_ka/IPM.alt.svg @@ -0,0 +1 @@ +IPM \ No newline at end of file diff --git a/public/logos/18_ka/IPM.svg b/public/logos/18_ka/IPM.svg new file mode 100644 index 0000000000..2fa5e07d00 --- /dev/null +++ b/public/logos/18_ka/IPM.svg @@ -0,0 +1,4 @@ + + +IPM + diff --git a/public/logos/18_ka/JA.alt.svg b/public/logos/18_ka/JA.alt.svg new file mode 100644 index 0000000000..467fbe7be4 --- /dev/null +++ b/public/logos/18_ka/JA.alt.svg @@ -0,0 +1 @@ +JA \ No newline at end of file diff --git a/public/logos/18_ka/JA.svg b/public/logos/18_ka/JA.svg new file mode 100644 index 0000000000..da772a92db --- /dev/null +++ b/public/logos/18_ka/JA.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + JA + + + + diff --git a/public/logos/18_ka/KM.alt.svg b/public/logos/18_ka/KM.alt.svg new file mode 100644 index 0000000000..e8e30bf0ca --- /dev/null +++ b/public/logos/18_ka/KM.alt.svg @@ -0,0 +1 @@ +KM \ No newline at end of file diff --git a/public/logos/18_ka/KM.svg b/public/logos/18_ka/KM.svg new file mode 100644 index 0000000000..41aa244000 --- /dev/null +++ b/public/logos/18_ka/KM.svg @@ -0,0 +1,4 @@ + + +KM + diff --git a/public/logos/18_ka/MGM.alt.svg b/public/logos/18_ka/MGM.alt.svg new file mode 100644 index 0000000000..d21e4ce4f3 --- /dev/null +++ b/public/logos/18_ka/MGM.alt.svg @@ -0,0 +1 @@ +MGM \ No newline at end of file diff --git a/public/logos/18_ka/MGM.svg b/public/logos/18_ka/MGM.svg new file mode 100644 index 0000000000..f7210ead64 --- /dev/null +++ b/public/logos/18_ka/MGM.svg @@ -0,0 +1,4 @@ + + +MGM + diff --git a/public/logos/18_ka/MWM.alt.svg b/public/logos/18_ka/MWM.alt.svg new file mode 100644 index 0000000000..c5ed565f33 --- /dev/null +++ b/public/logos/18_ka/MWM.alt.svg @@ -0,0 +1 @@ +MWM \ No newline at end of file diff --git a/public/logos/18_ka/MWM.svg b/public/logos/18_ka/MWM.svg new file mode 100644 index 0000000000..298853c37c --- /dev/null +++ b/public/logos/18_ka/MWM.svg @@ -0,0 +1,4 @@ + + +MWM + diff --git a/public/logos/18_ka/NM.alt.svg b/public/logos/18_ka/NM.alt.svg new file mode 100644 index 0000000000..58318e0ac2 --- /dev/null +++ b/public/logos/18_ka/NM.alt.svg @@ -0,0 +1 @@ +NM \ No newline at end of file diff --git a/public/logos/18_ka/NM.svg b/public/logos/18_ka/NM.svg new file mode 100644 index 0000000000..a89ae15514 --- /dev/null +++ b/public/logos/18_ka/NM.svg @@ -0,0 +1,4 @@ + + +NM + diff --git a/public/logos/18_ka/OL.alt.svg b/public/logos/18_ka/OL.alt.svg new file mode 100644 index 0000000000..ec5840729e --- /dev/null +++ b/public/logos/18_ka/OL.alt.svg @@ -0,0 +1 @@ +OL \ No newline at end of file diff --git a/public/logos/18_ka/OL.svg b/public/logos/18_ka/OL.svg new file mode 100644 index 0000000000..f370039b47 --- /dev/null +++ b/public/logos/18_ka/OL.svg @@ -0,0 +1,4 @@ + + +OL + diff --git a/public/logos/18_ka/PMC.alt.svg b/public/logos/18_ka/PMC.alt.svg new file mode 100644 index 0000000000..bef66b8633 --- /dev/null +++ b/public/logos/18_ka/PMC.alt.svg @@ -0,0 +1 @@ +PMC \ No newline at end of file diff --git a/public/logos/18_ka/PMC.svg b/public/logos/18_ka/PMC.svg new file mode 100644 index 0000000000..78dd13b9ce --- /dev/null +++ b/public/logos/18_ka/PMC.svg @@ -0,0 +1,4 @@ + + +PMC + diff --git a/public/logos/18_ka/TL.alt.svg b/public/logos/18_ka/TL.alt.svg new file mode 100644 index 0000000000..a43b8e297b --- /dev/null +++ b/public/logos/18_ka/TL.alt.svg @@ -0,0 +1 @@ +TL \ No newline at end of file diff --git a/public/logos/18_ka/TL.svg b/public/logos/18_ka/TL.svg new file mode 100644 index 0000000000..5502404e12 --- /dev/null +++ b/public/logos/18_ka/TL.svg @@ -0,0 +1,4 @@ + + +TL + diff --git a/public/logos/18_ka/TiTaN.alt.svg b/public/logos/18_ka/TiTaN.alt.svg new file mode 100644 index 0000000000..f73b3c463b --- /dev/null +++ b/public/logos/18_ka/TiTaN.alt.svg @@ -0,0 +1 @@ +TiTaN \ No newline at end of file diff --git a/public/logos/18_ka/TiTaN.svg b/public/logos/18_ka/TiTaN.svg new file mode 100644 index 0000000000..3966461548 --- /dev/null +++ b/public/logos/18_ka/TiTaN.svg @@ -0,0 +1,4 @@ + + +TiTaN + diff --git a/public/logos/18_ka/WM.alt.svg b/public/logos/18_ka/WM.alt.svg new file mode 100644 index 0000000000..9bfeefa91c --- /dev/null +++ b/public/logos/18_ka/WM.alt.svg @@ -0,0 +1 @@ +WM \ No newline at end of file diff --git a/public/logos/18_ka/WM.svg b/public/logos/18_ka/WM.svg new file mode 100644 index 0000000000..dd61c87401 --- /dev/null +++ b/public/logos/18_ka/WM.svg @@ -0,0 +1,4 @@ + + +WM + diff --git a/public/logos/18_ka/mine.svg b/public/logos/18_ka/mine.svg new file mode 100644 index 0000000000..f517f22535 --- /dev/null +++ b/public/logos/18_ka/mine.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/logos/18_ka/plus_twenty.alt.svg b/public/logos/18_ka/plus_twenty.alt.svg new file mode 100644 index 0000000000..c474b42bd2 --- /dev/null +++ b/public/logos/18_ka/plus_twenty.alt.svg @@ -0,0 +1,4 @@ + + ++20 + diff --git a/public/logos/18_ka/port.svg b/public/logos/18_ka/port.svg new file mode 100644 index 0000000000..1b47a55109 --- /dev/null +++ b/public/logos/18_ka/port.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/logos/18_ka/template.svg b/public/logos/18_ka/template.svg new file mode 100644 index 0000000000..67cbe1cd4e --- /dev/null +++ b/public/logos/18_ka/template.svg @@ -0,0 +1,3 @@ + + +