mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-25 21:03:26 -07:00
Init
This commit is contained in:
324
worlds/civ_6/Civ6Client.py
Normal file
324
worlds/civ_6/Civ6Client.py
Normal file
@@ -0,0 +1,324 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import traceback
|
||||
from typing import Dict, List
|
||||
|
||||
from CommonClient import ClientCommandProcessor, CommonContext, get_base_parser, logger, server_loop, gui_enabled
|
||||
from .Data import get_progressive_districts_data
|
||||
from .DeathLink import handle_check_deathlink
|
||||
from NetUtils import ClientStatus
|
||||
import Utils
|
||||
from .CivVIInterface import CivVIInterface, ConnectionState
|
||||
from .Enum import CivVICheckType
|
||||
from .Items import CivVIItemData, generate_item_table, get_item_by_civ_name
|
||||
from .Locations import generate_era_location_table
|
||||
from .TunerClient import TunerErrorException, TunerTimeoutException
|
||||
|
||||
|
||||
class CivVICommandProcessor(ClientCommandProcessor):
|
||||
def __init__(self, ctx: CommonContext):
|
||||
super().__init__(ctx)
|
||||
|
||||
def _cmd_deathlink(self):
|
||||
"""Toggle deathlink from client. Overrides default setting."""
|
||||
if isinstance(self.ctx, CivVIContext):
|
||||
self.ctx.death_link_enabled = not self.ctx.death_link_enabled
|
||||
self.ctx.death_link_just_changed = True
|
||||
Utils.async_start(self.ctx.update_death_link(
|
||||
self.ctx.death_link_enabled), name="Update Deathlink")
|
||||
self.ctx.logger.info(
|
||||
f"Deathlink is now {'enabled' if self.ctx.death_link_enabled else 'disabled'}")
|
||||
|
||||
def _cmd_resync(self):
|
||||
"""Resends all items to client, and has client resend all locations to server. This can take up to a minute if the player has received a lot of items"""
|
||||
if isinstance(self.ctx, CivVIContext):
|
||||
logger.info("Resyncing...")
|
||||
asyncio.create_task(self.ctx.resync())
|
||||
|
||||
def _cmd_toggle_progressive_eras(self):
|
||||
"""If you get stuck for some reason and unable to continue your game, you can run this command to disable the defeat that comes from pushing past the max unlocked era """
|
||||
if isinstance(self.ctx, CivVIContext):
|
||||
print("Toggling progressive eras, stand by...")
|
||||
self.ctx.is_pending_toggle_progressive_eras = True
|
||||
|
||||
|
||||
class CivVIContext(CommonContext):
|
||||
is_pending_death_link_reset = False
|
||||
is_pending_toggle_progressive_eras = False
|
||||
command_processor = CivVICommandProcessor
|
||||
game = "Civilization VI"
|
||||
items_handling = 0b111
|
||||
tuner_sync_task = None
|
||||
game_interface: CivVIInterface
|
||||
location_name_to_civ_location = {}
|
||||
location_name_to_id = {}
|
||||
item_id_to_civ_item: Dict[int, CivVIItemData] = {}
|
||||
item_table: Dict[str, CivVIItemData] = {}
|
||||
processing_multiple_items = False
|
||||
received_death_link = False
|
||||
death_link_message = ""
|
||||
death_link_enabled = False
|
||||
|
||||
death_link_just_changed = False
|
||||
# Used to prevent the deathlink from triggering when someone re enables it
|
||||
|
||||
logger = logger
|
||||
progressive_items_by_type = get_progressive_districts_data()
|
||||
item_name_to_id = {
|
||||
item.name: item.code for item in generate_item_table().values()}
|
||||
connection_state = ConnectionState.DISCONNECTED
|
||||
|
||||
def __init__(self, server_address, password):
|
||||
super().__init__(server_address, password)
|
||||
self.game_interface = CivVIInterface(logger)
|
||||
location_by_era = generate_era_location_table()
|
||||
self.item_table = generate_item_table()
|
||||
|
||||
# Get tables formatted in a way that is easier to use here
|
||||
for era, locations in location_by_era.items():
|
||||
for item_name, location in locations.items():
|
||||
self.location_name_to_id[location.name] = location.code
|
||||
self.location_name_to_civ_location[location.name] = location
|
||||
|
||||
for item_name, item in self.item_table.items():
|
||||
self.item_id_to_civ_item[item.code] = item
|
||||
|
||||
async def resync(self):
|
||||
if self.processing_multiple_items:
|
||||
logger.info(
|
||||
"Waiting for items to finish processing, try again later")
|
||||
return
|
||||
await self.game_interface.resync()
|
||||
await handle_receive_items(self, -1)
|
||||
logger.info("Resynced")
|
||||
|
||||
def on_deathlink(self, data: Utils.Dict[str, Utils.Any]) -> None:
|
||||
super().on_deathlink(data)
|
||||
text = data.get("cause", "")
|
||||
if text:
|
||||
message = text
|
||||
else:
|
||||
message = f"Received from {data['source']}"
|
||||
self.death_link_message = message
|
||||
self.received_death_link = True
|
||||
|
||||
async def server_auth(self, password_requested: bool = False):
|
||||
if password_requested and not self.password:
|
||||
await super(CivVIContext, self).server_auth(password_requested)
|
||||
await self.get_username()
|
||||
await self.send_connect()
|
||||
|
||||
def run_gui(self):
|
||||
from kvui import GameManager
|
||||
|
||||
class CivVIManager(GameManager):
|
||||
logging_pairs = [
|
||||
("Client", "Archipelago")
|
||||
]
|
||||
base_title = "Archipelago Civlization VI Client"
|
||||
|
||||
self.ui = CivVIManager(self)
|
||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||
|
||||
def on_package(self, cmd: str, args: dict):
|
||||
if cmd == "Connected":
|
||||
self.slot_data = args["slot_data"]
|
||||
if "death_link" in args["slot_data"]:
|
||||
self.death_link_enabled = bool(args["slot_data"]["death_link"])
|
||||
Utils.async_start(self.update_death_link(
|
||||
bool(args["slot_data"]["death_link"])))
|
||||
|
||||
|
||||
def update_connection_status(ctx: CivVIContext, status):
|
||||
if ctx.connection_state == status:
|
||||
return
|
||||
elif status == ConnectionState.IN_GAME:
|
||||
ctx.logger.info("Connected to Civ VI")
|
||||
elif status == ConnectionState.IN_MENU:
|
||||
ctx.logger.info("Connected to Civ VI, waiting for game to start")
|
||||
elif status == ConnectionState.DISCONNECTED:
|
||||
ctx.logger.info("Disconnected from Civ VI, attempting to reconnect...")
|
||||
|
||||
ctx.connection_state = status
|
||||
|
||||
|
||||
async def tuner_sync_task(ctx: CivVIContext):
|
||||
logger.info("Starting CivVI connector")
|
||||
while not ctx.exit_event.is_set():
|
||||
if not ctx.slot:
|
||||
await asyncio.sleep(3)
|
||||
continue
|
||||
else:
|
||||
try:
|
||||
if ctx.processing_multiple_items == True:
|
||||
logger.debug("Waiting for items to finish processing")
|
||||
await asyncio.sleep(3)
|
||||
else:
|
||||
state = await ctx.game_interface.is_in_game()
|
||||
update_connection_status(ctx, state)
|
||||
if state == ConnectionState.IN_GAME:
|
||||
await _handle_game_ready(ctx)
|
||||
else:
|
||||
await asyncio.sleep(3)
|
||||
except TunerTimeoutException:
|
||||
logger.error(
|
||||
"Timeout occurred while receiving data from Civ VI, this usually isn't a problem unless you see it repeatedly")
|
||||
await asyncio.sleep(3)
|
||||
except Exception as e:
|
||||
if isinstance(e, TunerErrorException):
|
||||
logger.debug(str(e))
|
||||
else:
|
||||
logger.debug(traceback.format_exc())
|
||||
|
||||
await asyncio.sleep(3)
|
||||
continue
|
||||
|
||||
|
||||
async def handle_toggle_progressive_eras(ctx: CivVIContext):
|
||||
if ctx.is_pending_toggle_progressive_eras:
|
||||
ctx.is_pending_toggle_progressive_eras = False
|
||||
current = await ctx.game_interface.get_max_allowed_era()
|
||||
if current > -1:
|
||||
await ctx.game_interface.set_max_allowed_era(-1)
|
||||
logger.info("Disabled progressive eras")
|
||||
else:
|
||||
count = 0
|
||||
for _, network_item in enumerate(ctx.items_received):
|
||||
item: CivVIItemData = ctx.item_id_to_civ_item[network_item.item]
|
||||
if item.item_type == CivVICheckType.ERA:
|
||||
count += 1
|
||||
await ctx.game_interface.set_max_allowed_era(count)
|
||||
logger.info(f"Enabled progressive eras, set to {count}")
|
||||
|
||||
|
||||
async def handle_checked_location(ctx: CivVIContext):
|
||||
checked_locations = await ctx.game_interface.get_checked_locations()
|
||||
checked_location_ids = [location.code for location_name, location in ctx.location_name_to_civ_location.items(
|
||||
) if location_name in checked_locations]
|
||||
|
||||
await ctx.send_msgs([{"cmd": "LocationChecks", "locations": checked_location_ids}])
|
||||
|
||||
|
||||
async def handle_receive_items(ctx: CivVIContext, last_received_index_override: int = None):
|
||||
try:
|
||||
last_received_index = last_received_index_override or await ctx.game_interface.get_last_received_index()
|
||||
if len(ctx.items_received) - last_received_index > 1:
|
||||
logger.debug("Multiple items received")
|
||||
ctx.processing_multiple_items = True
|
||||
|
||||
progressive_districts: List[CivVIItemData] = []
|
||||
progressive_eras: List[CivVIItemData] = []
|
||||
for index, network_item in enumerate(ctx.items_received):
|
||||
|
||||
# Track these separately so if we replace "PROGRESSIVE_DISTRICT" with a specific tech, we can still check if need to add it to the list of districts
|
||||
item: CivVIItemData = ctx.item_id_to_civ_item[network_item.item]
|
||||
item_to_send: CivVIItemData = ctx.item_id_to_civ_item[network_item.item]
|
||||
if index > last_received_index:
|
||||
if item.item_type == CivVICheckType.PROGRESSIVE_DISTRICT:
|
||||
# if the item is progressive, then check how far in that progression type we are and send the appropriate item
|
||||
count = sum(
|
||||
1 for count_item in progressive_districts if count_item.civ_name == item.civ_name)
|
||||
|
||||
if count >= len(ctx.progressive_items_by_type[item.civ_name]):
|
||||
logger.error(
|
||||
f"Received more progressive items than expected for {item.civ_name}")
|
||||
continue
|
||||
|
||||
item_civ_name = ctx.progressive_items_by_type[item.civ_name][count]
|
||||
actual_item_name = get_item_by_civ_name(item_civ_name, ctx.item_table).name
|
||||
item_to_send = ctx.item_table[actual_item_name]
|
||||
|
||||
sender = ctx.player_names[network_item.player]
|
||||
if item.item_type == CivVICheckType.ERA:
|
||||
count = len(progressive_eras) + 1
|
||||
await ctx.game_interface.give_item_to_player(item_to_send, sender, count)
|
||||
elif item.item_type == CivVICheckType.GOODY:
|
||||
item_to_send.civ_vi_id = item_to_send.civ_name
|
||||
await ctx.game_interface.give_item_to_player(item_to_send, sender)
|
||||
else:
|
||||
await ctx.game_interface.give_item_to_player(item_to_send, sender)
|
||||
await asyncio.sleep(0.02)
|
||||
|
||||
if item.item_type == CivVICheckType.PROGRESSIVE_DISTRICT:
|
||||
progressive_districts.append(item)
|
||||
elif item.item_type == CivVICheckType.ERA:
|
||||
progressive_eras.append(item)
|
||||
|
||||
if ctx.processing_multiple_items:
|
||||
logger.debug("DONE")
|
||||
ctx.processing_multiple_items = False
|
||||
finally:
|
||||
# If something errors out, then unblock item processing
|
||||
ctx.processing_multiple_items = False
|
||||
|
||||
|
||||
async def handle_check_goal_complete(ctx: CivVIContext):
|
||||
# logger.debug("Sending Goal Complete")
|
||||
result = await ctx.game_interface.check_victory()
|
||||
if result:
|
||||
logger.info("Sending Victory to server!")
|
||||
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
|
||||
|
||||
|
||||
async def _handle_game_ready(ctx: CivVIContext):
|
||||
if ctx.server:
|
||||
if not ctx.slot:
|
||||
await asyncio.sleep(3)
|
||||
return
|
||||
|
||||
await handle_receive_items(ctx)
|
||||
await handle_checked_location(ctx)
|
||||
await handle_check_goal_complete(ctx)
|
||||
|
||||
if ctx.death_link_enabled:
|
||||
await handle_check_deathlink(ctx)
|
||||
|
||||
# process pending commands
|
||||
await handle_toggle_progressive_eras(ctx)
|
||||
await asyncio.sleep(3)
|
||||
else:
|
||||
logger.info("Waiting for player to connect to server")
|
||||
await asyncio.sleep(3)
|
||||
|
||||
|
||||
def main(connect=None, password=None, name=None):
|
||||
Utils.init_logging("Civilization VI Client")
|
||||
|
||||
async def _main(connect, password, name):
|
||||
ctx = CivVIContext(connect, password)
|
||||
ctx.auth = name
|
||||
ctx.server_task = asyncio.create_task(
|
||||
server_loop(ctx), name="ServerLoop")
|
||||
if gui_enabled:
|
||||
ctx.run_gui()
|
||||
await asyncio.sleep(1)
|
||||
|
||||
ctx.tuner_sync_task = asyncio.create_task(
|
||||
tuner_sync_task(ctx), name="TunerSync")
|
||||
|
||||
await ctx.exit_event.wait()
|
||||
ctx.server_address = None
|
||||
|
||||
await ctx.shutdown()
|
||||
|
||||
if ctx.tuner_sync_task:
|
||||
await asyncio.sleep(3)
|
||||
await ctx.tuner_sync_task
|
||||
|
||||
import colorama
|
||||
|
||||
colorama.init()
|
||||
asyncio.run(_main(connect, password, name))
|
||||
colorama.deinit()
|
||||
|
||||
|
||||
def debug_main():
|
||||
parser = get_base_parser()
|
||||
parser.add_argument('--name', default=None,
|
||||
help="Slot Name to connect as.")
|
||||
parser.add_argument('--debug', default=None,
|
||||
help="debug mode, additional logging")
|
||||
args = parser.parse_args()
|
||||
if args.debug:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
main(args.connect, args.password, args.name)
|
||||
118
worlds/civ_6/CivVIInterface.py
Normal file
118
worlds/civ_6/CivVIInterface.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from enum import Enum
|
||||
from logging import Logger
|
||||
from typing import List
|
||||
|
||||
from .Items import CivVIItemData
|
||||
from .TunerClient import TunerClient, TunerConnectionException, TunerTimeoutException
|
||||
|
||||
class ConnectionState(Enum):
|
||||
DISCONNECTED = 0
|
||||
IN_GAME = 1
|
||||
IN_MENU = 2
|
||||
|
||||
|
||||
|
||||
class CivVIInterface:
|
||||
logger: Logger
|
||||
tuner: TunerClient
|
||||
last_error: str = None
|
||||
|
||||
def __init__(self, logger: Logger):
|
||||
self.logger = logger
|
||||
self.tuner = TunerClient(logger)
|
||||
|
||||
async def is_in_game(self) -> ConnectionState:
|
||||
command = "IsInGame()"
|
||||
try:
|
||||
result = await self.tuner.send_game_command(command)
|
||||
if result == "false":
|
||||
return ConnectionState.IN_MENU
|
||||
self.last_error = None
|
||||
return ConnectionState.IN_GAME
|
||||
except TunerTimeoutException:
|
||||
self.print_connection_error(
|
||||
"Not connected to game, waiting for connection to be available")
|
||||
return ConnectionState.DISCONNECTED
|
||||
except TunerConnectionException as e:
|
||||
if "The remote computer refused the network connection" in str(e):
|
||||
self.print_connection_error(
|
||||
"Unable to connect to game. Verify that the tuner is enabled. Attempting to reconnect")
|
||||
else:
|
||||
self.print_connection_error(
|
||||
"Not connected to game, waiting for connection to be available")
|
||||
return ConnectionState.DISCONNECTED
|
||||
except Exception as e:
|
||||
if "attempt to index a nil valuestack traceback" in str(e) \
|
||||
or ".. is not supported for string .. nilstack traceback" in str(e):
|
||||
return ConnectionState.IN_MENU
|
||||
|
||||
def print_connection_error(self, error: str) -> None:
|
||||
if error != self.last_error:
|
||||
self.last_error = error
|
||||
self.logger.info(error)
|
||||
|
||||
async def give_item_to_player(self, item: CivVIItemData, sender: str = "", amount: int = 1) -> None:
|
||||
if isinstance(item.civ_vi_id, str):
|
||||
item_id = f'"{item.civ_vi_id}"'
|
||||
else:
|
||||
item_id = item.civ_vi_id
|
||||
|
||||
command = f"HandleReceiveItem({item_id}, \"{item.name}\", \"{item.item_type.value}\", \"{sender}\", {amount})"
|
||||
await self.tuner.send_game_command(command)
|
||||
|
||||
async def resync(self) -> None:
|
||||
"""Has the client resend all the checked locations"""
|
||||
command = "Resync()"
|
||||
await self.tuner.send_game_command(command)
|
||||
|
||||
async def check_victory(self) -> bool:
|
||||
command = "ClientGetVictory()"
|
||||
result = await self.tuner.send_game_command(command)
|
||||
return result == "true"
|
||||
|
||||
async def get_checked_locations(self) -> List[str]:
|
||||
command = "GetUnsentCheckedLocations()"
|
||||
result = await self.tuner.send_game_command(command, 2048 * 4)
|
||||
return result.split(",")
|
||||
|
||||
async def get_deathlink(self) -> str:
|
||||
"""returns either "false" or the name of the unit that killed the player's unit"""
|
||||
command = "ClientGetDeathLink()"
|
||||
result = await self.tuner.send_game_command(command)
|
||||
return result
|
||||
|
||||
async def kill_unit(self, message: str) -> None:
|
||||
command = f"KillUnit(\"{message}\")"
|
||||
await self.tuner.send_game_command(command)
|
||||
|
||||
async def get_last_received_index(self) -> int:
|
||||
command = "ClientGetLastReceivedIndex()"
|
||||
result = await self.tuner.send_game_command(command)
|
||||
return int(result)
|
||||
|
||||
async def send_notification(self, item: CivVIItemData, sender="someone") -> None:
|
||||
command = f"GameCore.NotificationManager:SendNotification(GameCore.NotificationTypes.USER_DEFINED_2, \"{item.name} Received\", \"You have received {item.name} from \" .. \"{sender}\", 0, {item.civ_vi_id})"
|
||||
await self.tuner.send_command(command)
|
||||
|
||||
async def decrease_gold_by_percent(self, percent: int, message: str) -> None:
|
||||
command = f"DecreaseGoldByPercent({percent}, \"{message}\")"
|
||||
await self.tuner.send_game_command(command)
|
||||
|
||||
async def decrease_faith_by_percent(self, percent: int, message: str) -> None:
|
||||
command = f"DecreaseFaithByPercent({percent}, \"{message}\")"
|
||||
await self.tuner.send_game_command(command)
|
||||
|
||||
async def decrease_era_score_by_amount(self, amount: int, message: str) -> None:
|
||||
command = f"DecreaseEraScoreByAmount({amount}, \"{message}\")"
|
||||
await self.tuner.send_game_command(command)
|
||||
|
||||
async def set_max_allowed_era(self, count: int) -> None:
|
||||
command = f"SetMaxAllowedEra(\"{count}\")"
|
||||
await self.tuner.send_game_command(command)
|
||||
|
||||
async def get_max_allowed_era(self) -> int:
|
||||
command = "ClientGetMaxAllowedEra()"
|
||||
result = await self.tuner.send_game_command(command)
|
||||
if result == "":
|
||||
return -1
|
||||
return int(result)
|
||||
58
worlds/civ_6/Civilization VI.yaml
Normal file
58
worlds/civ_6/Civilization VI.yaml
Normal file
@@ -0,0 +1,58 @@
|
||||
Civilization VI:
|
||||
progression_balancing: 50
|
||||
accessibility: items
|
||||
|
||||
# Determines what progressive items (if any) should be included.
|
||||
# districts_only: Each tech/civic that would normally unlock a district or district building now has a logical progression. Example: TECH_BRONZE_WORKING is now PROGRESSIVE_ENCAMPMENT
|
||||
# eras_and_districts: Players will be defeated if they play until the world era advances beyond the currently unlocked maximum era. A notification will be shown as the end of the era approaches letting the player know if they don't have enough progressive era items. Unlocked eras can be seen in both the tech and civic trees. Includes all progressive districts.
|
||||
# none: No progressive items will be included. This means you can get district upgrades that won't be usable until the relevant district is unlocked.
|
||||
progression_style: "districts_only"
|
||||
|
||||
# Shuffles the goody hut rewards. Goody huts will only contain junk items and location checks are received sequentially (GOODY_HUT_1, GOODY_HUT_2, etc).
|
||||
# true: goody hut rewards are shuffled in
|
||||
# false: goody hut rewards are not shuffled in and will behave as normal
|
||||
shuffle_goody_hut_rewards: true
|
||||
|
||||
# Boosts for Civics/Techs are location checks. Boosts can now be triggered even if
|
||||
# the item has already been researched. If it is dependent upon a unit that is now
|
||||
# obsolete, you can click toggle on/off the relevant tech in the tech tree.
|
||||
boostsanity: false
|
||||
|
||||
# Controls if/what items in the tech/civics trees are pre hinted for the multiworld.
|
||||
# all: All items in the tech & civics trees are pre hinted.
|
||||
# progression_items: Only locations in the trees containing progression items are pre hinted.
|
||||
# no_junk: Pre hint the progression and useful items.
|
||||
# none: No items are pre hinted.
|
||||
pre_hint_items: "progression_items"
|
||||
|
||||
# Controls the cost of techs and civics.
|
||||
# cheap: Techs and civics cost 50% of the normal cost.
|
||||
# default: Techs and civics cost the normal amount.
|
||||
# expensive: Techs and civics cost 150% of the normal cost.
|
||||
research_cost_multiplier: cheap
|
||||
|
||||
# If boostsanity is enabled, this will prevent any boosts that are 'missable' from having progression items. Disabling this will potentially require multiple playthroughs to complete the seed.
|
||||
exclude_missable_boosts: "true"
|
||||
|
||||
# Each Tech and Civic Location will have a title of 'Unrevealed' until its prereqs have been researched. Note that hints will still be pre collected if that option is enabled.
|
||||
hide_item_names: "false"
|
||||
|
||||
# If enabled, an advisor icon will be added to any location that contains a progression item
|
||||
advisor_show_progression_items: "true"
|
||||
|
||||
# 'true' or 'false'
|
||||
death_link: "false"
|
||||
|
||||
# Determines the effect that is applied when a player dies.
|
||||
# gold: The player's gold is reduced by the amount specified in death_link_effect_percent.
|
||||
# faith: The player's faith is reduced by the amount specified in death_link_effect_percent.
|
||||
# era_score: The player's era score is reduced by 1.
|
||||
death_link_effect: unit_killed
|
||||
|
||||
# The percentage of the effect that is applied for gold and faith. Era score decreases by 1 each time.
|
||||
# 0 - 100
|
||||
death_link_effect_percent: 20
|
||||
|
||||
description: "Generated by https://archipelago.gg."
|
||||
game: Civilization VI
|
||||
name: PlayerName
|
||||
231
worlds/civ_6/Container.py
Normal file
231
worlds/civ_6/Container.py
Normal file
@@ -0,0 +1,231 @@
|
||||
from dataclasses import dataclass
|
||||
import os
|
||||
from typing import TYPE_CHECKING, List
|
||||
import zipfile
|
||||
from BaseClasses import ItemClassification, Location
|
||||
from worlds.Files import APContainer
|
||||
|
||||
from .Enum import CivVICheckType
|
||||
from .Locations import CivVILocation, CivVILocationData
|
||||
from .Options import CivVIOptions
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from worlds.civ_6 import CivVIWorld
|
||||
|
||||
|
||||
# Python fstrings don't allow backslashes, so we use this workaround
|
||||
nl = "\n"
|
||||
tab = "\t"
|
||||
apo = "\'"
|
||||
|
||||
|
||||
@dataclass
|
||||
class CivTreeItem:
|
||||
name: str
|
||||
cost: int
|
||||
ui_tree_row: int
|
||||
|
||||
|
||||
class CivVIContainer(APContainer):
|
||||
"""
|
||||
Responsible for generating the dynamic mod files for the Civ VI multiworld
|
||||
"""
|
||||
game: str = "Civilization VI"
|
||||
|
||||
def __init__(self, patch_data: dict, base_path: str, output_directory: str,
|
||||
player=None, player_name: str = "", server: str = ""):
|
||||
self.patch_data = patch_data
|
||||
self.file_path = base_path
|
||||
container_path = os.path.join(output_directory, base_path + ".zip")
|
||||
super().__init__(container_path, player, player_name, server)
|
||||
|
||||
def write_contents(self, opened_zipfile: zipfile.ZipFile) -> None:
|
||||
for filename, yml in self.patch_data.items():
|
||||
opened_zipfile.writestr(filename, yml)
|
||||
super().write_contents(opened_zipfile)
|
||||
|
||||
|
||||
def get_cost(world, location: CivVILocationData) -> int:
|
||||
"""
|
||||
Returns the cost of the item based on the game options
|
||||
"""
|
||||
options: CivVIOptions = world.options
|
||||
multiplier = options.research_cost_multiplier
|
||||
return int(world.location_table[location.name].cost * multiplier)
|
||||
|
||||
|
||||
def get_formatted_player_name(world, player) -> str:
|
||||
"""
|
||||
Returns the name of the player in the world
|
||||
"""
|
||||
if player != world.player:
|
||||
return f"{world.multiworld.player_name[player]}{apo}s"
|
||||
else:
|
||||
return "Your"
|
||||
|
||||
|
||||
def get_advisor_type(world: 'CivVIWorld', location: Location) -> str:
|
||||
if world.options.advisor_show_progression_items.value and location.item.classification == ItemClassification.progression:
|
||||
return "ADVISOR_PROGRESSIVE"
|
||||
else:
|
||||
return "ADVISOR_GENERIC"
|
||||
|
||||
|
||||
def generate_new_items(world: 'CivVIWorld') -> str:
|
||||
"""
|
||||
Generates the XML for the new techs/civics as well as the blockers used to prevent players from researching their own items
|
||||
"""
|
||||
locations: List[CivVILocation] = world.multiworld.get_locations(
|
||||
world.player)
|
||||
techs = [location for location in locations if location.location_type ==
|
||||
CivVICheckType.TECH]
|
||||
civics = [location for location in locations if location.location_type ==
|
||||
CivVICheckType.CIVIC]
|
||||
|
||||
boost_techs = []
|
||||
boost_civics = []
|
||||
|
||||
hidden_techs = []
|
||||
hidden_civics = []
|
||||
if world.options.boostsanity.value:
|
||||
boost_techs = [location for location in locations if location.location_type == CivVICheckType.BOOST and location.name.split("_")[1] == "TECH"]
|
||||
boost_civics = [location for location in locations if location.location_type == CivVICheckType.BOOST and location.name.split("_")[1] == "CIVIC"]
|
||||
techs += boost_techs
|
||||
civics += boost_civics
|
||||
|
||||
if world.options.hide_item_names.value:
|
||||
hidden_techs = [tech.name for tech in techs]
|
||||
hidden_civics = [civic.name for civic in civics]
|
||||
|
||||
return f"""<?xml version="1.0" encoding="utf-8"?>
|
||||
<GameInfo>
|
||||
<Types>
|
||||
<Row Type="TECH_BLOCKER" Kind="KIND_TECH" />
|
||||
<Row Type="CIVIC_BLOCKER" Kind="KIND_CIVIC" />
|
||||
{"".join([f'{tab}<Row Type="{tech.name}" Kind="KIND_TECH" />{nl}' for
|
||||
tech in techs])}
|
||||
{"".join([f'{tab}<Row Type="{civic.name}" Kind="KIND_CIVIC" />{nl}' for
|
||||
civic in civics])}
|
||||
</Types>
|
||||
<Technologies>
|
||||
<Row TechnologyType="TECH_BLOCKER" Name="TECH_BLOCKER" EraType="ERA_ANCIENT" UITreeRow="0" Cost="99999" AdvisorType="ADVISOR_GENERIC" Description="Archipelago Tech created to prevent players from researching their own tech. If you can read this, then congrats you have reached the end of your tree before beating the game!"/>
|
||||
{"".join([f'{tab}<Row TechnologyType="{location.name}" '
|
||||
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
||||
f'{location.item.name}" '
|
||||
f'EraType="{world.location_table[location.name].era_type}" '
|
||||
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
||||
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
||||
f'Description="{location.name}" '
|
||||
f'AdvisorType="{get_advisor_type(world, location)}"'
|
||||
f'/>{nl}'
|
||||
for location in techs])}
|
||||
</Technologies>
|
||||
<TechnologyPrereqs>
|
||||
{"".join([f'{tab}<Row Technology="{location.name}" PrereqTech="TECH_BLOCKER" />{nl}' for location in boost_techs])}
|
||||
</TechnologyPrereqs>
|
||||
<Civics>
|
||||
<Row CivicType="CIVIC_BLOCKER" Name="CIVIC_BLOCKER" EraType="ERA_ANCIENT" UITreeRow="0" Cost="99999" AdvisorType="ADVISOR_GENERIC" Description="Archipelago Civic created to prevent players from researching their own civics. If you can read this, then congrats you have reached the end of your tree before beating the game!"/>
|
||||
{"".join([f'{tab}<Row CivicType="{location.name}" '
|
||||
f'Name="{get_formatted_player_name(world, location.item.player)} '
|
||||
f'{location.item.name}" '
|
||||
f'EraType="{world.location_table[location.name].era_type}" '
|
||||
f'UITreeRow="{world.location_table[location.name].uiTreeRow}" '
|
||||
f'Cost="{get_cost(world, world.location_table[location.name])}" '
|
||||
f'Description="{location.name}" '
|
||||
f'AdvisorType="{get_advisor_type(world, location)}"'
|
||||
f'/>{nl}'
|
||||
for location in civics])}
|
||||
</Civics>
|
||||
<CivicPrereqs>
|
||||
{"".join([f'{tab}<Row Civic="{location.name}" PrereqCivic="CIVIC_BLOCKER" />{nl}' for location in boost_civics])}
|
||||
</CivicPrereqs>
|
||||
|
||||
<Civics_XP2>
|
||||
{"".join([f'{tab}<Row CivicType="{location}" HiddenUntilPrereqComplete="true" RandomPrereqs="false"/>{nl}' for location in hidden_civics])}
|
||||
</Civics_XP2>
|
||||
|
||||
<Technologies_XP2>
|
||||
{"".join([f'{tab}<Row TechnologyType="{location}" HiddenUntilPrereqComplete="true" RandomPrereqs="false"/>{nl}' for location in hidden_techs])}
|
||||
</Technologies_XP2>
|
||||
|
||||
</GameInfo>
|
||||
"""
|
||||
|
||||
|
||||
def generate_setup_file(world) -> str:
|
||||
"""
|
||||
Generates the Lua for the setup file. This sets initial variables and state that affect gameplay around Progressive Eras
|
||||
"""
|
||||
setup = "-- Setup"
|
||||
if world.options.progression_style.current_key == "eras_and_districts":
|
||||
setup += f"""
|
||||
-- Init Progressive Era Value if it hasn't been set already
|
||||
if Game.GetProperty("MaxAllowedEra") == nil then
|
||||
print("Setting MaxAllowedEra to 0")
|
||||
Game.SetProperty("MaxAllowedEra", 0)
|
||||
end
|
||||
"""
|
||||
|
||||
if world.options.boostsanity.value:
|
||||
setup += f"""
|
||||
-- Init Boosts
|
||||
if Game.GetProperty("BoostsAsChecks") == nil then
|
||||
print("Setting Boosts As Checks to True")
|
||||
Game.SetProperty("BoostsAsChecks", true)
|
||||
end
|
||||
"""
|
||||
return setup
|
||||
|
||||
|
||||
def generate_goody_hut_sql(world) -> str:
|
||||
"""
|
||||
Generates the SQL for the goody huts or an empty string if they are disabled since the mod expects the file to be there
|
||||
"""
|
||||
|
||||
if world.options.shuffle_goody_hut_rewards.value:
|
||||
return f"""
|
||||
UPDATE GoodyHutSubTypes SET Description = NULL WHERE GoodyHut NOT IN ('METEOR_GOODIES', 'GOODYHUT_SAILOR_WONDROUS', 'DUMMY_GOODY_BUILDIER') AND Weight > 0;
|
||||
|
||||
INSERT INTO Modifiers
|
||||
(ModifierId, ModifierType, RunOnce, Permanent, SubjectRequirementSetId)
|
||||
SELECT ModifierID||'_AI', ModifierType, RunOnce, Permanent, 'PLAYER_IS_AI'
|
||||
FROM Modifiers
|
||||
WHERE EXISTS (
|
||||
SELECT ModifierId
|
||||
FROM GoodyHutSubTypes
|
||||
WHERE Modifiers.ModifierId = GoodyHutSubTypes.ModifierId AND GoodyHutSubTypes.GoodyHut NOT IN ('METEOR_GOODIES', 'GOODYHUT_SAILOR_WONDROUS', 'DUMMY_GOODY_BUILDIER') AND GoodyHutSubTypes.Weight > 0);
|
||||
|
||||
INSERT INTO ModifierArguments
|
||||
(ModifierId, Name, Type, Value)
|
||||
SELECT ModifierID||'_AI', Name, Type, Value
|
||||
FROM ModifierArguments
|
||||
WHERE EXISTS (
|
||||
SELECT ModifierId
|
||||
FROM GoodyHutSubTypes
|
||||
WHERE ModifierArguments.ModifierId = GoodyHutSubTypes.ModifierId AND GoodyHutSubTypes.GoodyHut NOT IN ('METEOR_GOODIES', 'GOODYHUT_SAILOR_WONDROUS', 'DUMMY_GOODY_BUILDIER') AND GoodyHutSubTypes.Weight > 0);
|
||||
|
||||
UPDATE GoodyHutSubTypes
|
||||
SET ModifierID = ModifierID||'_AI'
|
||||
WHERE GoodyHut NOT IN ('METEOR_GOODIES', 'GOODYHUT_SAILOR_WONDROUS', 'DUMMY_GOODY_BUILDIER') AND Weight > 0;
|
||||
|
||||
"""
|
||||
else:
|
||||
return "-- Goody Huts are disabled, no changes needed"
|
||||
|
||||
|
||||
def generate_update_boosts_sql(world) -> str:
|
||||
"""
|
||||
Generates the SQL for existing boosts in boostsanity or an empty string if they are disabled since the mod expects the file to be there
|
||||
"""
|
||||
|
||||
if world.options.boostsanity.value:
|
||||
return f"""
|
||||
UPDATE Boosts
|
||||
SET TechnologyType = 'BOOST_' || TechnologyType
|
||||
WHERE TechnologyType IS NOT NULL;
|
||||
UPDATE Boosts
|
||||
SET CivicType = 'BOOST_' || CivicType
|
||||
WHERE CivicType IS NOT NULL AND CivicType NOT IN ('CIVIC_CORPORATE_LIBERTARIANISM', 'CIVIC_DIGITAL_DEMOCRACY', 'CIVIC_SYNTHETIC_TECHNOCRACY', 'CIVIC_NEAR_FUTURE_GOVERNANCE');
|
||||
"""
|
||||
else:
|
||||
return "-- Boostsanity is disabled, no changes needed"
|
||||
79
worlds/civ_6/Data.py
Normal file
79
worlds/civ_6/Data.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
import os
|
||||
import pkgutil
|
||||
from typing import List
|
||||
|
||||
|
||||
_cache = {}
|
||||
|
||||
|
||||
def _get_data(key: str):
|
||||
global _cache
|
||||
if key not in _cache:
|
||||
path = os.path.join("data", f"{key}.json")
|
||||
_cache[key] = json.loads(
|
||||
pkgutil.get_data(__name__, path).decode())
|
||||
return _cache[key]
|
||||
|
||||
|
||||
def get_boosts_data():
|
||||
return _get_data("boosts")
|
||||
@dataclass
|
||||
class CivVIBoostData():
|
||||
Type: str
|
||||
EraType: str
|
||||
Prereq: List[str]
|
||||
PrereqRequiredCount: int
|
||||
Classification: str
|
||||
|
||||
|
||||
def get_boosts_data() -> List[CivVIBoostData]:
|
||||
boosts_json = _get_data("boosts")
|
||||
boosts = []
|
||||
for boost in boosts_json:
|
||||
boosts.append(CivVIBoostData(
|
||||
Type=boost['Type'],
|
||||
EraType=boost['EraType'],
|
||||
Prereq=boost['Prereq'],
|
||||
PrereqRequiredCount=boost['PrereqRequiredCount'],
|
||||
Classification=boost['Classification']
|
||||
))
|
||||
|
||||
return boosts
|
||||
|
||||
|
||||
def get_era_required_items_data():
|
||||
return _get_data("era_required_items")
|
||||
|
||||
|
||||
def get_existing_civics_data():
|
||||
return _get_data("existing_civics")
|
||||
|
||||
|
||||
def get_existing_techs_data():
|
||||
return _get_data("existing_tech")
|
||||
|
||||
|
||||
def get_goody_hut_rewards_data():
|
||||
return _get_data("goody_hut_rewards")
|
||||
|
||||
|
||||
def get_new_civic_prereqs_data():
|
||||
return _get_data("new_civic_prereqs")
|
||||
|
||||
|
||||
def get_new_civics_data():
|
||||
return _get_data("new_civics")
|
||||
|
||||
|
||||
def get_new_tech_prereqs_data():
|
||||
return _get_data("new_tech_prereqs")
|
||||
|
||||
|
||||
def get_new_techs_data():
|
||||
return _get_data("new_tech")
|
||||
|
||||
|
||||
def get_progressive_districts_data():
|
||||
return _get_data("progressive_districts")
|
||||
76
worlds/civ_6/DeathLink.py
Normal file
76
worlds/civ_6/DeathLink.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import random
|
||||
|
||||
from CommonClient import CommonContext
|
||||
|
||||
# any is also an option but should not be considered an effect
|
||||
DEATH_LINK_EFFECTS = ["Gold", "Faith", "Era Score", "Unit Killed"]
|
||||
|
||||
|
||||
async def handle_receive_deathlink(ctx: CommonContext, message):
|
||||
"""Resolves the effects of a deathlink received from the multiworld based on the options selected by the player"""
|
||||
chosen_effect = ctx.slot_data["death_link_effect"]
|
||||
effect: str = "Gold"
|
||||
if chosen_effect == "Any Except Era Score":
|
||||
effect = random.choice(
|
||||
[effect for effect in DEATH_LINK_EFFECTS if effect != "Era Score"])
|
||||
else:
|
||||
effect = chosen_effect if chosen_effect != "Any" else random.choice(
|
||||
DEATH_LINK_EFFECTS)
|
||||
|
||||
percent = ctx.slot_data["death_link_effect_percent"]
|
||||
if effect == "Gold":
|
||||
ctx.logger.info(f"Decreasing gold by {percent}%")
|
||||
await ctx.game_interface.decrease_gold_by_percent(percent, message)
|
||||
elif effect == "Faith":
|
||||
ctx.logger.info(f"Decreasing faith by {percent}%")
|
||||
await ctx.game_interface.decrease_faith_by_percent(percent, message)
|
||||
elif effect == "Era Score":
|
||||
ctx.logger.info("Decreasing era score by 1")
|
||||
await ctx.game_interface.decrease_era_score_by_amount(1, message)
|
||||
elif effect == "Unit Killed":
|
||||
ctx.logger.info("Destroying a random unit")
|
||||
await ctx.game_interface.kill_unit(message)
|
||||
|
||||
|
||||
async def handle_check_deathlink(ctx: CommonContext):
|
||||
"""Checks if the local player should send out a deathlink to the multiworld as well as if we should respond to any pending deathlinks sent to us """
|
||||
# check if we received a death link
|
||||
if ctx.received_death_link:
|
||||
ctx.received_death_link = False
|
||||
await handle_receive_deathlink(ctx, ctx.death_link_message)
|
||||
|
||||
# Check if we should send out a death link
|
||||
result = await ctx.game_interface.get_deathlink()
|
||||
if ctx.death_link_just_changed:
|
||||
ctx.death_link_just_changed = False
|
||||
return
|
||||
if result != "false":
|
||||
messages = [f"lost a unit to a {result}",
|
||||
f"offered a sacrifice to the great {result}",
|
||||
f"was killed by a {result}",
|
||||
f"made a donation to the {result} fund",
|
||||
f"made a tactical error",
|
||||
f"picked a fight with a {result} and lost",
|
||||
f"tried to befriend an enemy {result}",
|
||||
f"used a {result} to reduce their military spend",
|
||||
f"was defeated by a {result} in combat",
|
||||
f"bravely struck a {result} and paid the price",
|
||||
f"had a lapse in judgement against a {result}",
|
||||
f"learned at the hands of a {result}",
|
||||
f"attempted to non peacefully negotiate with a {result}",
|
||||
f"was outsmarted by a {result}",
|
||||
f"received a lesson from a {result}",
|
||||
f"now understands the importance of not fighting a {result}",
|
||||
f"let a {result} get the better of them",
|
||||
f"allowed a {result} to show them the error of their ways",
|
||||
f"heard the tragedy of Darth Plageuis the Wise from a {result}",
|
||||
f"refused to join a {result} in their quest for power",
|
||||
f"was tired of sitting in BK and decided to fight a {result} instead",
|
||||
f"purposely lost to a {result} as a cry for help",
|
||||
f"is wanting to remind everyone that they are here to have fun and not to win",
|
||||
f"is reconisdering their pursuit of a domination victory",
|
||||
f"had their plans toppled by a {result}",
|
||||
]
|
||||
player = ctx.player_names[ctx.slot]
|
||||
message = random.choice(messages)
|
||||
await ctx.send_death(f"{player} {message}")
|
||||
19
worlds/civ_6/Enum.py
Normal file
19
worlds/civ_6/Enum.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from enum import Enum
|
||||
class EraType(Enum):
|
||||
ERA_ANCIENT = "ERA_ANCIENT"
|
||||
ERA_CLASSICAL = "ERA_CLASSICAL"
|
||||
ERA_MEDIEVAL = "ERA_MEDIEVAL"
|
||||
ERA_RENAISSANCE = "ERA_RENAISSANCE"
|
||||
ERA_INDUSTRIAL = "ERA_INDUSTRIAL"
|
||||
ERA_MODERN = "ERA_MODERN"
|
||||
ERA_ATOMIC = "ERA_ATOMIC"
|
||||
ERA_INFORMATION = "ERA_INFORMATION"
|
||||
ERA_FUTURE = "ERA_FUTURE"
|
||||
|
||||
class CivVICheckType(Enum):
|
||||
TECH = "TECH"
|
||||
CIVIC = "CIVIC"
|
||||
PROGRESSIVE_DISTRICT = "PROGRESSIVE_DISTRICT"
|
||||
ERA = "ERA"
|
||||
GOODY = "GOODY"
|
||||
BOOST = "BOOST"
|
||||
299
worlds/civ_6/Items.py
Normal file
299
worlds/civ_6/Items.py
Normal file
@@ -0,0 +1,299 @@
|
||||
from enum import Enum
|
||||
import json
|
||||
import os
|
||||
import pkgutil
|
||||
import random
|
||||
from typing import Dict, List, Optional
|
||||
import typing
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from .Data import get_era_required_items_data, get_existing_civics_data, get_existing_techs_data, get_goody_hut_rewards_data, get_progressive_districts_data
|
||||
from .Enum import CivVICheckType, EraType
|
||||
from .ProgressiveDistricts import get_flat_progressive_districts
|
||||
CIV_VI_AP_ITEM_ID_BASE = 5041000
|
||||
|
||||
NON_PROGRESSION_DISTRICTS = [
|
||||
"PROGRESSIVE_PRESERVE",
|
||||
"PROGRESSIVE_NEIGHBORHOOD"
|
||||
]
|
||||
|
||||
|
||||
# Items required as progression for boostsanity mode
|
||||
BOOSTSANITY_PROGRESSION_ITEMS = [
|
||||
"TECH_THE_WHEEL",
|
||||
"TECH_MASONRY",
|
||||
"TECH_ARCHERY",
|
||||
"TECH_ENGINEERING",
|
||||
"TECH_CONSTRUCTION",
|
||||
"TECH_GUNPOWDER",
|
||||
"TECH_MACHINERY",
|
||||
"TECH_SIEGE_TACTICS",
|
||||
"TECH_STIRRUPS",
|
||||
"TECH_ASTRONOMY",
|
||||
"TECH_BALLISTICS",
|
||||
"TECH_STEAM_POWER",
|
||||
"TECH_SANITATION",
|
||||
"TECH_COMPUTERS",
|
||||
"TECH_COMBUSTION",
|
||||
"TECH_TELECOMMUNICATIONS",
|
||||
"TECH_ROBOTICS",
|
||||
"CIVIC_FEUDALISM",
|
||||
"CIVIC_GUILDS",
|
||||
"CIVIC_THE_ENLIGHTENMENT",
|
||||
"CIVIC_MERCANTILISM",
|
||||
"CIVIC_CONSERVATION",
|
||||
"CIVIC_CIVIL_SERVICE",
|
||||
"CIVIC_GLOBALIZATION",
|
||||
"CIVIC_COLD_WAR",
|
||||
"CIVIC_URBANIZATION",
|
||||
"CIVIC_NATIONALISM",
|
||||
"CIVIC_MOBILIZATION",
|
||||
"PROGRESSIVE_NEIGHBORHOOD",
|
||||
"PROGRESSIVE_PRESERVE"
|
||||
]
|
||||
|
||||
|
||||
class FillerItemRarity(Enum):
|
||||
COMMON = "COMMON"
|
||||
UNCOMMON = "UNCOMMON"
|
||||
RARE = "RARE"
|
||||
|
||||
|
||||
FILLER_DISTRIBUTION: Dict[FillerItemRarity, float] = {
|
||||
FillerItemRarity.RARE: 0.025,
|
||||
FillerItemRarity.UNCOMMON: .2,
|
||||
FillerItemRarity.COMMON: 0.775,
|
||||
}
|
||||
|
||||
|
||||
class FillerItemData:
|
||||
name: str
|
||||
type: str
|
||||
rarity: FillerItemRarity
|
||||
civ_name: str
|
||||
|
||||
def __init__(self, data: Dict[str, str]):
|
||||
self.name = data["Name"]
|
||||
self.rarity = FillerItemRarity(data["Rarity"])
|
||||
self.civ_name = data["Type"]
|
||||
|
||||
|
||||
def get_filler_item_data() -> Dict[str, FillerItemData]:
|
||||
"""
|
||||
Returns a dictionary of filler items with their data
|
||||
"""
|
||||
goody_huts: List[Dict[str, str]] = get_goody_hut_rewards_data()
|
||||
# Create a FillerItemData object for each item
|
||||
cached_filler_items = {item["Name"]: FillerItemData(item) for item in goody_huts}
|
||||
|
||||
return cached_filler_items
|
||||
|
||||
|
||||
class CivVIItemData:
|
||||
civ_vi_id: int
|
||||
classification: ItemClassification
|
||||
name: str
|
||||
code: int
|
||||
cost: int
|
||||
item_type: CivVICheckType
|
||||
progression_name: Optional[str]
|
||||
civ_name: Optional[str]
|
||||
|
||||
def __init__(self, name, civ_vi_id: int, cost: int, item_type: CivVICheckType, id_offset: int, classification: ItemClassification, progression_name: Optional[str], civ_name: Optional[str] = None):
|
||||
self.classification = classification
|
||||
self.civ_vi_id = civ_vi_id
|
||||
self.name = name
|
||||
self.code = civ_vi_id + CIV_VI_AP_ITEM_ID_BASE + id_offset
|
||||
self.cost = cost
|
||||
self.item_type = item_type
|
||||
self.progression_name = progression_name
|
||||
self.civ_name = civ_name
|
||||
|
||||
|
||||
class CivVIItem(Item):
|
||||
game: str = "Civilization VI"
|
||||
civ_vi_id: int
|
||||
item_type: CivVICheckType
|
||||
|
||||
def __init__(self, item: CivVIItemData, player: int, classification: ItemClassification = None):
|
||||
super().__init__(item.name, classification or item.classification, item.code, player)
|
||||
self.civ_vi_id = item.civ_vi_id
|
||||
self.item_type = item.item_type
|
||||
|
||||
|
||||
def format_item_name(name: str) -> str:
|
||||
name_parts = name.split("_")
|
||||
return " ".join([part.capitalize() for part in name_parts])
|
||||
|
||||
|
||||
def get_item_by_civ_name(item_name: typing.List[str], item_table: typing.Dict[str, 'CivVIItemData']) -> 'CivVIItemData':
|
||||
"""Gets the names of the items in the item_table"""
|
||||
for item in item_table.values():
|
||||
if item_name == item.civ_name:
|
||||
return item
|
||||
|
||||
raise Exception(f"Item {item_name} not found in item_table")
|
||||
|
||||
|
||||
def _generate_tech_items(id_base: int, required_items: List[str], progressive_items: Dict[str, str]) -> List[CivVIItemData]:
|
||||
# Generate Techs
|
||||
existing_techs = get_existing_techs_data()
|
||||
tech_table = {}
|
||||
|
||||
tech_id = 0
|
||||
for tech in existing_techs:
|
||||
classification = ItemClassification.useful
|
||||
name = tech["Name"]
|
||||
civ_name = tech["Type"]
|
||||
if civ_name in required_items:
|
||||
classification = ItemClassification.progression
|
||||
progression_name = None
|
||||
check_type = CivVICheckType.TECH
|
||||
if civ_name in progressive_items.keys():
|
||||
progression_name = format_item_name(progressive_items[civ_name])
|
||||
|
||||
tech_table[name] = CivVIItemData(
|
||||
name=name,
|
||||
civ_vi_id=tech_id,
|
||||
cost=tech["Cost"],
|
||||
item_type=check_type,
|
||||
id_offset=id_base,
|
||||
classification=classification,
|
||||
progression_name=progression_name,
|
||||
civ_name=civ_name
|
||||
)
|
||||
|
||||
tech_id += 1
|
||||
|
||||
return tech_table
|
||||
|
||||
|
||||
def _generate_civics_items(id_base: int, required_items: List[str], progressive_items: Dict[str, str]) -> List[CivVIItemData]:
|
||||
civic_id = 0
|
||||
civic_table = {}
|
||||
existing_civics = get_existing_civics_data()
|
||||
|
||||
for civic in existing_civics:
|
||||
name = civic["Name"]
|
||||
civ_name = civic["Type"]
|
||||
progression_name = None
|
||||
check_type = CivVICheckType.CIVIC
|
||||
|
||||
if civ_name in progressive_items.keys():
|
||||
progression_name = format_item_name(progressive_items[civ_name])
|
||||
|
||||
classification = ItemClassification.useful
|
||||
if civ_name in required_items:
|
||||
classification = ItemClassification.progression
|
||||
|
||||
civic_table[name] = CivVIItemData(
|
||||
name=name,
|
||||
civ_vi_id=civic_id,
|
||||
cost=civic["Cost"],
|
||||
item_type=check_type,
|
||||
id_offset=id_base,
|
||||
classification=classification,
|
||||
progression_name=progression_name,
|
||||
civ_name=civ_name
|
||||
)
|
||||
|
||||
civic_id += 1
|
||||
|
||||
return civic_table
|
||||
|
||||
|
||||
def _generate_progressive_district_items(id_base: int) -> List[CivVIItemData]:
|
||||
progressive_table = {}
|
||||
progressive_id_base = 0
|
||||
progressive_items = get_progressive_districts_data()
|
||||
for item_name in progressive_items.keys():
|
||||
progression = ItemClassification.progression
|
||||
if item_name in NON_PROGRESSION_DISTRICTS:
|
||||
progression = ItemClassification.useful
|
||||
name = format_item_name(item_name)
|
||||
progressive_table[name] = CivVIItemData(
|
||||
name=name,
|
||||
civ_vi_id=progressive_id_base,
|
||||
cost=0,
|
||||
item_type=CivVICheckType.PROGRESSIVE_DISTRICT,
|
||||
id_offset=id_base,
|
||||
classification=progression,
|
||||
progression_name=None,
|
||||
civ_name=item_name
|
||||
)
|
||||
progressive_id_base += 1
|
||||
return progressive_table
|
||||
|
||||
|
||||
def _generate_progressive_era_items(id_base: int) -> List[CivVIItemData]:
|
||||
"""Generates the single progressive district item"""
|
||||
era_table = {}
|
||||
# Generate progressive eras
|
||||
progressive_era_name = format_item_name("PROGRESSIVE_ERA")
|
||||
era_table[progressive_era_name] = CivVIItemData(
|
||||
name=progressive_era_name,
|
||||
civ_vi_id=0,
|
||||
cost=0,
|
||||
item_type=CivVICheckType.ERA,
|
||||
id_offset=id_base,
|
||||
classification=ItemClassification.progression,
|
||||
progression_name=None,
|
||||
civ_name="PROGRESSIVE_ERA"
|
||||
)
|
||||
return era_table
|
||||
|
||||
|
||||
def _generate_goody_hut_items(id_base: int) -> List[CivVIItemData]:
|
||||
# Generate goody hut items
|
||||
goody_huts = get_filler_item_data()
|
||||
goody_table = {}
|
||||
goody_base = 0
|
||||
for value in goody_huts.values():
|
||||
goody_table[value.name] = CivVIItemData(
|
||||
name=value.name,
|
||||
civ_vi_id=goody_base,
|
||||
cost=0,
|
||||
item_type=CivVICheckType.GOODY,
|
||||
id_offset=id_base,
|
||||
classification=ItemClassification.filler,
|
||||
progression_name=None,
|
||||
civ_name=value.civ_name
|
||||
)
|
||||
goody_base += 1
|
||||
return goody_table
|
||||
|
||||
|
||||
def generate_item_table() -> Dict[str, CivVIItemData]:
|
||||
era_required_items = get_era_required_items_data()
|
||||
required_items: List[str] = []
|
||||
for key, value in era_required_items.items():
|
||||
required_items += value
|
||||
|
||||
progressive_items = get_flat_progressive_districts()
|
||||
|
||||
item_table = {}
|
||||
|
||||
def get_id_base():
|
||||
return len(item_table.keys())
|
||||
|
||||
item_table = {**item_table, **_generate_tech_items(get_id_base(), required_items, progressive_items)}
|
||||
item_table = {**item_table, **_generate_civics_items(get_id_base(), required_items, progressive_items)}
|
||||
item_table = {**item_table, **_generate_progressive_district_items(get_id_base())}
|
||||
item_table = {**item_table, **_generate_progressive_era_items(get_id_base())}
|
||||
item_table = {**item_table, **_generate_goody_hut_items(get_id_base())}
|
||||
|
||||
return item_table
|
||||
|
||||
|
||||
def get_items_by_type(item_type: CivVICheckType, item_table: Dict[str, CivVIItemData]) -> List[CivVIItemData]:
|
||||
"""
|
||||
Returns a list of items that match the given item type
|
||||
"""
|
||||
return [item for item in item_table.values() if item.item_type == item_type]
|
||||
|
||||
|
||||
def get_random_filler_by_rarity(rarity: FillerItemRarity, item_table: Dict[str, CivVIItemData]) -> CivVIItemData:
|
||||
"""
|
||||
Returns a random filler item by rarity
|
||||
"""
|
||||
items = [item for item in get_filler_item_data().values() if item.rarity == rarity]
|
||||
return items[random.randint(0, len(items) - 1)]
|
||||
21
worlds/civ_6/LICENSE.md
Normal file
21
worlds/civ_6/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2024 tanjo3
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the “Software”), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
196
worlds/civ_6/Locations.py
Normal file
196
worlds/civ_6/Locations.py
Normal file
@@ -0,0 +1,196 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, List, Optional, Dict
|
||||
from BaseClasses import Location, LocationProgressType, Region
|
||||
|
||||
from .Data import get_boosts_data, get_new_civic_prereqs_data, get_new_civics_data, get_new_tech_prereqs_data, get_new_techs_data
|
||||
|
||||
from .Enum import CivVICheckType, EraType
|
||||
|
||||
CIV_VI_AP_LOCATION_ID_BASE = 5041000
|
||||
|
||||
# Locs that should have progression items (keypoint techs/civics, ~1 per era)
|
||||
PRIORITY_LOCATIONS = [
|
||||
"TECH_ANCEINT_09",
|
||||
"TECH_CLASSICAL_15",
|
||||
"TECH_MEDIEVAL_20",
|
||||
"TECH_RENAISSANCE_33",
|
||||
"TECH_INDUSTRIAL_35",
|
||||
"TECH_MODERN_47",
|
||||
"TECH_ATOMIC_51",
|
||||
"TECH_INFORMATION_59",
|
||||
|
||||
"CIVIC_ANCIENT_04",
|
||||
"CIVIC_CLASSICAL_08",
|
||||
"CIVIC_MEDIEVAL_19",
|
||||
"CIVIC_RENAISSANCE_26",
|
||||
"CIVIC_INDUSTRIAL_33",
|
||||
"CIVIC_MODERN_39",
|
||||
"CIVIC_ATOMIC_46",
|
||||
"CIVIC_INFORMATION_48",
|
||||
|
||||
"ERA_CLASSICAL",
|
||||
"ERA_MEDIEVAL",
|
||||
"ERA_RENAISSANCE",
|
||||
"ERA_INDUSTRIAL",
|
||||
"ERA_MODERN",
|
||||
"ERA_ATOMIC",
|
||||
"ERA_INFORMATION",
|
||||
"ERA_FUTURE"
|
||||
]
|
||||
|
||||
# Locs that should not have progression items (future techs/civics)
|
||||
EXCLUDED_LOCATIONS = [
|
||||
"GOODY_HUT_1",
|
||||
"GOODY_HUT_2",
|
||||
"GOODY_HUT_3",
|
||||
"GOODY_HUT_4",
|
||||
"GOODY_HUT_5",
|
||||
"GOODY_HUT_6",
|
||||
"GOODY_HUT_7",
|
||||
"GOODY_HUT_8",
|
||||
"GOODY_HUT_9",
|
||||
"GOODY_HUT_10",
|
||||
]
|
||||
|
||||
|
||||
class CivVILocationData():
|
||||
game: str = "Civilization VI"
|
||||
name: str
|
||||
cost: int
|
||||
uiTreeRow: int
|
||||
civ_id: int
|
||||
code: int
|
||||
era_type: EraType
|
||||
location_type: CivVICheckType
|
||||
pre_reqs: List[str]
|
||||
|
||||
def __init__(self, name: str, cost: int, uiTreeRow: int, id: int, era_type: EraType, location_type: CivVICheckType, pre_reqs: Optional[List[str]] = None):
|
||||
self.name = name
|
||||
self.cost = cost
|
||||
self.uiTreeRow = uiTreeRow
|
||||
self.civ_id = id
|
||||
self.code = id + CIV_VI_AP_LOCATION_ID_BASE
|
||||
self.era_type = era_type
|
||||
self.pre_reqs = pre_reqs
|
||||
self.location_type = location_type
|
||||
|
||||
|
||||
class CivVILocation(Location):
|
||||
game: str = "Civilization VI"
|
||||
location_type: CivVICheckType
|
||||
|
||||
def __init__(self, player: int, name: str = '', address: Optional[int] = None, parent: Optional[Region] = None):
|
||||
super().__init__(player, name, address, parent)
|
||||
if name.split("_")[0] == "TECH":
|
||||
self.location_type = CivVICheckType.TECH
|
||||
elif name.split("_")[0] == "CIVIC":
|
||||
self.location_type = CivVICheckType.CIVIC
|
||||
elif name.split("_")[0] == "ERA":
|
||||
self.location_type = CivVICheckType.ERA
|
||||
elif name.split("_")[0] == "GOODY":
|
||||
self.location_type = CivVICheckType.GOODY
|
||||
elif name.split("_")[0] == "BOOST":
|
||||
self.location_type = CivVICheckType.BOOST
|
||||
|
||||
if self.name in PRIORITY_LOCATIONS:
|
||||
self.progress_type = LocationProgressType.PRIORITY
|
||||
elif self.name in EXCLUDED_LOCATIONS:
|
||||
self.progress_type = LocationProgressType.EXCLUDED
|
||||
else:
|
||||
self.progress_type = LocationProgressType.DEFAULT
|
||||
|
||||
if self.location_type == CivVICheckType.BOOST:
|
||||
boost_data_list = get_boosts_data()
|
||||
boost_data = next((boost for boost in boost_data_list if boost.Type == name), None)
|
||||
if boost_data and boost_data.Classification == "EXCLUDED":
|
||||
self.progress_type = LocationProgressType.EXCLUDED
|
||||
|
||||
|
||||
|
||||
|
||||
def generate_flat_location_table() -> Dict[str, CivVILocationData]:
|
||||
"""
|
||||
Generates a flat location table in the following format:
|
||||
{
|
||||
"TECH_AP_ANCIENT_00": CivVILocationData,
|
||||
"TECH_AP_ANCIENT_01": CivVILocationData,
|
||||
"CIVIC_AP_ANCIENT_00": CivVILocationData,
|
||||
...
|
||||
}
|
||||
"""
|
||||
era_locations = generate_era_location_table()
|
||||
flat_locations = {}
|
||||
for era_type, locations in era_locations.items():
|
||||
for location_id, location_data in locations.items():
|
||||
flat_locations[location_id] = location_data
|
||||
return flat_locations
|
||||
|
||||
|
||||
def generate_era_location_table() -> Dict[EraType, Dict[str, CivVILocationData]]:
|
||||
"""
|
||||
Uses the data from existing_tech.json to generate a location table in the following format:
|
||||
{
|
||||
"ERA_ANCIENT": {
|
||||
"TECH_AP_ANCIENT_00": CivVILocationData,
|
||||
"TECH_AP_ANCIENT_01": CivVILocationData,
|
||||
"CIVIC_AP_ANCIENT_00": CivVILocationData,
|
||||
},
|
||||
...
|
||||
}
|
||||
"""
|
||||
new_tech_prereqs = get_new_tech_prereqs_data()
|
||||
|
||||
new_techs = get_new_techs_data()
|
||||
era_locations = {}
|
||||
id_base = 0
|
||||
# Techs
|
||||
for data in new_techs:
|
||||
era_type = data['EraType']
|
||||
if era_type not in era_locations:
|
||||
era_locations[era_type] = {}
|
||||
|
||||
prereq_data = [
|
||||
item for item in new_tech_prereqs if item['Technology'] == data['Type']]
|
||||
|
||||
era_locations[era_type][data["Type"]] = CivVILocationData(
|
||||
data["Type"], data['Cost'], data['UITreeRow'], id_base, era_type, CivVICheckType.TECH, prereq_data)
|
||||
id_base += 1
|
||||
# Civics
|
||||
new_civic_prereqs = get_new_civic_prereqs_data()
|
||||
new_civics = get_new_civics_data()
|
||||
|
||||
for data in new_civics:
|
||||
era_type = data['EraType']
|
||||
if era_type not in era_locations:
|
||||
era_locations[era_type] = {}
|
||||
prereq_data = [
|
||||
item for item in new_civic_prereqs if item['Civic'] == data['Type']]
|
||||
era_locations[era_type][data["Type"]] = CivVILocationData(
|
||||
data["Type"], data['Cost'], data['UITreeRow'], id_base, era_type, CivVICheckType.CIVIC, prereq_data)
|
||||
id_base += 1
|
||||
|
||||
# Eras
|
||||
eras = list(EraType)
|
||||
for i in range(len(EraType)):
|
||||
location_era = eras[i].name
|
||||
|
||||
if location_era == "ERA_ANCIENT":
|
||||
continue
|
||||
|
||||
era_locations[location_era][location_era] = CivVILocationData(
|
||||
location_era, 0, 0, id_base, location_era, CivVICheckType.ERA)
|
||||
id_base += 1
|
||||
# Goody Huts, defaults to 10 goody huts as location checks (rarely will a player get more than this)
|
||||
for i in range(10):
|
||||
era_locations[EraType.ERA_ANCIENT.value]["GOODY_HUT_" + str(i+1)] = CivVILocationData(
|
||||
"GOODY_HUT_" + str(i+1), 0, 0, id_base, EraType.ERA_ANCIENT, CivVICheckType.GOODY)
|
||||
id_base += 1
|
||||
# Boosts
|
||||
boosts = get_boosts_data()
|
||||
for boost in boosts:
|
||||
location = CivVILocationData(
|
||||
boost.Type, 0, 0, id_base, boost.EraType, CivVICheckType.BOOST, pre_reqs=boost.Prereq)
|
||||
era_locations[boost.EraType][boost.Type] = location
|
||||
id_base += 1
|
||||
|
||||
return era_locations
|
||||
105
worlds/civ_6/Options.py
Normal file
105
worlds/civ_6/Options.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from dataclasses import dataclass
|
||||
from Options import Choice, DeathLink, DefaultOnToggle, PerGameCommonOptions, Range, Toggle
|
||||
|
||||
|
||||
class ProgressionStyle(Choice):
|
||||
"""Determines what progressive items (if any) should be included.\n\n
|
||||
Districts Only: Each tech/civic that would normally unlock a district or district building now has a logical progression. Example: TECH_BRONZE_WORKING is now PROGRESSIVE_ENCAMPMENT\n\n
|
||||
Eras and Districts: Players will be defeated if they play until the world era advances beyond the currently unlocked maximum era.
|
||||
A notification will be shown as the end of the era approaches letting the player know if they don't have enough progressive era items.
|
||||
Unlocked eras can be seen in both the tech and civic trees. Includes all progressive districts.\n\n
|
||||
None: No progressive items will be included. This means you can get district upgrades that won't be usable until the relevant district is unlocked.
|
||||
"""
|
||||
display_name = "Progression Style"
|
||||
option_districts_only = "Districts Only"
|
||||
option_eras_and_districts = "Eras and Districts"
|
||||
option_none = "None"
|
||||
default = "districts_only"
|
||||
|
||||
|
||||
class ShuffleGoodyHuts(DefaultOnToggle):
|
||||
"""Shuffles the goody hut rewards. Goody huts will only contain junk items and location checks are received sequentially (GOODY_HUT_1, GOODY_HUT_2, etc)."""
|
||||
display_name = "Shuffle Goody Hut Rewards"
|
||||
default = True
|
||||
|
||||
|
||||
class BoostSanity(Toggle):
|
||||
"""Boosts for Civics/Techs are location checks. Boosts can now be triggered even if the item has already been researched. If it is dependent upon a unit that is now obsolete, you can click toggle on/off the relevant tech in the tech tree."""
|
||||
default = False
|
||||
|
||||
|
||||
class ExcludeMissableBoosts(Toggle):
|
||||
"""If boostsanity is enabled, this will prevent any boosts that are 'missable' from having progression items. Disabling this will potentially require multiple playthroughs to complete the seed."""
|
||||
default = True
|
||||
|
||||
|
||||
class ResearchCostMultiplier(Choice):
|
||||
"""Multiplier for research cost of techs and civics, higher values make research more expensive. Cheap = 0.5x, Expensive = 1.5x. Default is 1. """
|
||||
display_name = "Tech/Civic Cost Multiplier"
|
||||
option_cheap = 0.5
|
||||
option_default = 1
|
||||
option_expensive = 1.5
|
||||
default = 1
|
||||
|
||||
|
||||
class PreHintItems(Choice):
|
||||
"""Controls if/what items in the tech/civics trees are pre hinted for the multiworld.\n
|
||||
All : All items in the tech & civics trees are pre hinted.\n
|
||||
Progression items: Only locations in the trees containing progression items are pre hinted.\n
|
||||
No Junk: Pre hint the progression and useful items.\n
|
||||
None: No items are pre hinted.
|
||||
"""
|
||||
display_name = "Tech/Civic Tree Pre Hinted Items"
|
||||
option_all = "All Tree Locations"
|
||||
option_progression_items = "Progression Tree Locations"
|
||||
option_no_junk = "No Junk"
|
||||
option_none = "None"
|
||||
default = "progression_items"
|
||||
|
||||
|
||||
class HideItemNames(Toggle):
|
||||
"""Each Tech and Civic Location will have a title of 'Unrevealed' until its prereqs have been researched. Note that hints will still be pre collected if that option is enabled."""
|
||||
default = False
|
||||
|
||||
|
||||
class InGameFlagProgressionItems(DefaultOnToggle):
|
||||
"""If enabled, an advisor icon will be added to any location that contains a progression item"""
|
||||
default = True
|
||||
|
||||
|
||||
class DeathLinkEffect(Choice):
|
||||
"""What happens when a unit dies. Default is Unit Killed.\n
|
||||
Faith, and Gold will be decreased by the amount specified in 'Death Link Effect Percent'. \n
|
||||
Era score is decrased by 1.\n
|
||||
Any will select any of these options any time a death link is received."""
|
||||
display_name = "Death Link Effect"
|
||||
option_unit_killed = "Unit Killed"
|
||||
option_era_score = "Era Score"
|
||||
option_gold = "Gold"
|
||||
option_faith = "Faith"
|
||||
option_any = "Any"
|
||||
option_any_except_era_score = "Any Except Era Score"
|
||||
default = "unit_killed"
|
||||
|
||||
|
||||
class DeathLinkEffectPercent(Range):
|
||||
"""The percentage of the effect that will be applied. Only applicable for Gold and Faith effects. Default is 20%"""
|
||||
display_name = "Death Link Effect Percent"
|
||||
default = 20
|
||||
range_start = 1
|
||||
range_end = 100
|
||||
|
||||
|
||||
@dataclass
|
||||
class CivVIOptions(PerGameCommonOptions):
|
||||
progression_style: ProgressionStyle
|
||||
shuffle_goody_hut_rewards: ShuffleGoodyHuts
|
||||
boostsanity: BoostSanity
|
||||
exclude_missable_boosts: ExcludeMissableBoosts
|
||||
research_cost_multiplier: ResearchCostMultiplier
|
||||
pre_hint_items: PreHintItems
|
||||
hide_item_names: HideItemNames
|
||||
advisor_show_progression_items: InGameFlagProgressionItems
|
||||
death_link_effect: DeathLinkEffect
|
||||
death_link_effect_percent: DeathLinkEffectPercent
|
||||
death_link: DeathLink
|
||||
27
worlds/civ_6/ProgressiveDistricts.py
Normal file
27
worlds/civ_6/ProgressiveDistricts.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from typing import Dict, List
|
||||
|
||||
from .Data import get_progressive_districts_data
|
||||
|
||||
def get_flat_progressive_districts() -> Dict[str, str]:
|
||||
"""Returns a dictionary of all items that are associated with a progressive item.
|
||||
Key is the item name ("TECH_WRITING") and the value is the associated progressive
|
||||
item ("PROGRESSIVE_CAMPUS")"""
|
||||
progressive_districts = get_progressive_districts_data()
|
||||
flat_progressive_techs = {}
|
||||
for key, value in progressive_districts.items():
|
||||
for item in value:
|
||||
flat_progressive_techs[item] = key
|
||||
return flat_progressive_techs
|
||||
|
||||
|
||||
def convert_items_to_have_progression(items: List[str]):
|
||||
""" converts a list of items to instead be their associated progressive item if
|
||||
they have one. ["TECH_MINING", "TECH_WRITING"] -> ["TECH_MINING", "PROGRESSIVE_CAMPUS]"""
|
||||
flat_progressive_techs = get_flat_progressive_districts()
|
||||
new_list = []
|
||||
for item in items:
|
||||
if item in flat_progressive_techs.keys():
|
||||
new_list.append(flat_progressive_techs[item])
|
||||
else:
|
||||
new_list.append(item)
|
||||
return new_list
|
||||
53
worlds/civ_6/README.md
Normal file
53
worlds/civ_6/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Civlization 6 Archipelago
|
||||
|
||||
## Setup Guide
|
||||
For setup instructions go [here](./docs/setup_en.md).
|
||||
|
||||
## What does randomization do to this game?
|
||||
|
||||
In Civilization VI, the tech and civic trees are both shuffled. This presents some interesting ways to play the game in a non-standard way. If you are feeling adventurous, you can enable the `boostsanity` option in order to really change up the way you normally would play a Civ game. Details on the option can be found [here](./docs/boostsanity.md)
|
||||
|
||||
There are a few changes that the Archipelago mod introduces in order to make this playable/fun. These are detailed in the __FAQ__ section below.
|
||||
|
||||
## What is the goal of Civilization VI when randomized?
|
||||
The goal of randomized Civlization VI remains the same. Pursue any victory type you have enabled in your game settings, the one you normally go for may or may not be feasible based on how things have been changed up!
|
||||
|
||||
## Which items can be in another player's world?
|
||||
All technologies and civics can be found in another player's world.
|
||||
|
||||
## What does another world's item look like in Civilization VI?
|
||||
Each item from another world is represented as a researchable tech/civic in your normal tech/civic trees.
|
||||
|
||||
## When the player receives an item, what happens?
|
||||
A short period after receiving an item, you will get a notification indicating you have discovered the relevant tech/civic. You will also get the regular popup that details what the given item has unlocked for you.
|
||||
|
||||
## FAQs
|
||||
- Do I need the DLC to play this?
|
||||
- Yes, you need both Rise & Fall and Gathering Storm. If there is enough interest then I can eventually add support for Archipellago runs that don't require both expansions.
|
||||
|
||||
- Does this work with Multiplayer?
|
||||
- It does not and, despite my best efforts, probably won't until there's a new way for external programs to be able to interact with the game.
|
||||
|
||||
- Does my mod that reskins Barbarians as various Pro Wrestlers work with this??
|
||||
- Only one way to find out! Any mods that modify techs/civics will most likely cause issues, though.
|
||||
|
||||
- "Help! I can't see any of the items that have been sent to me!"
|
||||
- Both trees by default will show you the researchable Archipelago locations. To view the normal tree, you can click "Toggle Archipelago Tree" on the top left corner of the tree view.
|
||||
|
||||
- "Oh no! I received the Machinery tech and now instead of getting an Archer next turn, I have to wait an additional 10 turns to get a Crossbowman!"
|
||||
- Vanilla prevents you from building units of the same class from an earlier tech level after you have researched a later variant. For example, this could be problematic if someone unlocks Crossbowmen for you right out the gate since you won't be able to make Archers (which have a much lower production cost).
|
||||
|
||||
- Solution: You can now go in to the tech tree, click "Toggle Archipelago Tree" to view your unlocked techs, and then can click any tech you have unlocked to toggle whether it is currently active or not. __NOTE__: This is an experimental feature and may yield some unexpected behaviors. Please DM `@Hesto2` on Discord if you run into any issues.
|
||||
|
||||
- I enabled `progressive districts` but I have no idea techs/civics what items are locked behind progression now!
|
||||
- Any technology or civic that grants you a new building in a district (or grants you the district itself) is now locked behind a progressive item. For example, `PROGRESSIVE_CAMPUS` would give you these items in the following order:
|
||||
1. `TECH_WRITING`
|
||||
2. `TECH_EDUCATION`
|
||||
3. `TECH_CHEMISTRY`
|
||||
- If you want to see the details around each item, you can review [this file](./data/progressive_districts.json)
|
||||
|
||||
- "How does DeathLink work? Am I going to have to start a new game every time one of my friends dies??"
|
||||
- Heavens no, my fellow Archipelago appreciator. When configuring your Archipelago options for Civilization on the options page, there are several choices available for you to fine tune the way you'd like to be punished for the follies of your friends. These include: Having a random unit destroyed, losing a percentage of gold or faith, or even losing a point on your era score. If you can't make up your mind, you can elect to have any of them be selected every time a death link is sent your way.
|
||||
|
||||
- In the event you lose one of your units in combat (this means captured units don't count), then you will send a death link event to the rest of your friends.
|
||||
|
||||
185
worlds/civ_6/Regions.py
Normal file
185
worlds/civ_6/Regions.py
Normal file
@@ -0,0 +1,185 @@
|
||||
import typing
|
||||
from BaseClasses import CollectionState, LocationProgressType, Region
|
||||
from .Data import get_era_required_items_data, get_progressive_districts_data
|
||||
from .Items import format_item_name, get_item_by_civ_name
|
||||
from .Enum import CivVICheckType, EraType
|
||||
from .Locations import CivVILocation
|
||||
from .ProgressiveDistricts import get_flat_progressive_districts
|
||||
from .Options import CivVIOptions
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from . import CivVIWorld
|
||||
from Items import CivVIItemData
|
||||
|
||||
|
||||
def get_required_items_for_era(era: EraType):
|
||||
"""Gets the specific techs/civics that are required for the specified era"""
|
||||
era_required_items = {}
|
||||
era_required_items = get_era_required_items_data()
|
||||
return era_required_items[era.value]
|
||||
|
||||
|
||||
def get_cumulative_prereqs_for_era(end_era: EraType, exclude_progressive_items: bool = True, item_table: typing.Dict[str, 'CivVIItemData'] = None) -> typing.List['CivVIItemData']:
|
||||
"""Gets the specific techs/civics that are required for the specified era as well as all previous eras"""
|
||||
cumulative_prereqs = []
|
||||
era_required_items = {}
|
||||
era_required_items = get_era_required_items_data()
|
||||
|
||||
for era in EraType:
|
||||
cumulative_prereqs += era_required_items[era.value]
|
||||
if era == end_era:
|
||||
break
|
||||
# If we are excluding progressive items, we need to remove them from the list of expected items (TECH_BRONZE_WORKING won't be here since it will be PROGRESSIVE_ENCAMPMENT)
|
||||
if exclude_progressive_items:
|
||||
flat_progressive_items = get_flat_progressive_districts()
|
||||
prereqs_without_progressive_items = []
|
||||
for item in cumulative_prereqs:
|
||||
if item in flat_progressive_items:
|
||||
continue
|
||||
else:
|
||||
prereqs_without_progressive_items.append(item)
|
||||
|
||||
return [get_item_by_civ_name(prereq, item_table) for prereq in prereqs_without_progressive_items]
|
||||
|
||||
return [get_item_by_civ_name(prereq, item_table) for prereq in cumulative_prereqs]
|
||||
|
||||
|
||||
def has_required_progressive_districts(state: CollectionState, era: EraType, player: int):
|
||||
""" If player has progressive items enabled, it will count how many progressive techs it should have, otherwise return the default array"""
|
||||
progressive_districts = get_progressive_districts_data()
|
||||
|
||||
item_table = state.multiworld.worlds[player].item_table
|
||||
# Verify we can still reach non progressive items
|
||||
all_previous_items_no_progression = get_cumulative_prereqs_for_era(
|
||||
era, True, item_table)
|
||||
if not state.has_all([item.name for item in all_previous_items_no_progression], player):
|
||||
return False
|
||||
|
||||
# Verify we have the correct amount of progressive items
|
||||
all_previous_items = get_cumulative_prereqs_for_era(
|
||||
era, False, item_table)
|
||||
required_counts: typing.Dict[str, int] = {}
|
||||
|
||||
for key, value in progressive_districts.items():
|
||||
required_counts[key] = 0
|
||||
for item in all_previous_items:
|
||||
if item.civ_name in value:
|
||||
required_counts[key] += 1
|
||||
|
||||
for key, value in required_counts.items():
|
||||
has_amount = state.has(format_item_name(key), player, required_counts[key])
|
||||
if not has_amount:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def has_required_progressive_eras(state: CollectionState, era: EraType, player: int):
|
||||
"""Checks, for the given era, how many are required to proceed to the next era. Ancient = 1, Classical = 2, etc. Assumes 2 required for classical and starts from there so as to decrease odds of hard locking without the turns to get the items"""
|
||||
if era == EraType.ERA_FUTURE or era == EraType.ERA_INFORMATION:
|
||||
return True
|
||||
|
||||
eras = [e.value for e in EraType]
|
||||
era_index = eras.index(era.value)
|
||||
return state.has(format_item_name("PROGRESSIVE_ERA"), player, era_index + 2)
|
||||
|
||||
|
||||
def has_required_items(state: CollectionState, era: EraType, player: int, has_progressive_districts: bool, has_progressive_eras: bool):
|
||||
required_items = False
|
||||
required_eras = False
|
||||
if has_progressive_districts:
|
||||
required_items = has_required_progressive_districts(state, era, player)
|
||||
else:
|
||||
era_required_items = [get_item_by_civ_name(item, state.multiworld.worlds[player].item_table).name for item in get_era_required_items_data()[era.value]]
|
||||
required_items = state.has_all(era_required_items, player)
|
||||
|
||||
if has_progressive_eras:
|
||||
required_eras = has_required_progressive_eras(state, era, player)
|
||||
else:
|
||||
required_eras = True
|
||||
|
||||
return required_items and required_eras
|
||||
|
||||
|
||||
def create_regions(world: 'CivVIWorld', options: CivVIOptions, player: int):
|
||||
menu = Region("Menu", player, world.multiworld)
|
||||
world.multiworld.regions.append(menu)
|
||||
|
||||
has_progressive_items = options.progression_style.current_key != "none"
|
||||
has_progressive_eras = options.progression_style.current_key == "eras_and_districts"
|
||||
has_goody_huts = options.shuffle_goody_hut_rewards.value
|
||||
has_boosts = options.boostsanity.value
|
||||
|
||||
regions: typing.List[Region] = []
|
||||
for era in EraType:
|
||||
era_region = Region(era.value, player, world.multiworld)
|
||||
era_locations = {location.name: location.code for key,
|
||||
location in world.location_by_era[era.value].items()}
|
||||
|
||||
# If progressive_eras is not enabled, then era check types from the era_locations
|
||||
if not has_progressive_eras:
|
||||
era_locations = {key: value for key, value in era_locations.items() if key.split("_")[0] != "ERA"}
|
||||
if not has_goody_huts:
|
||||
era_locations = {key: value for key, value in era_locations.items() if key.split("_")[0] != "GOODY"}
|
||||
if not has_boosts:
|
||||
era_locations = {key: value for key, value in era_locations.items() if key.split("_")[0] != "BOOST"}
|
||||
|
||||
era_region.add_locations(era_locations, CivVILocation)
|
||||
|
||||
regions.append(era_region)
|
||||
world.multiworld.regions.append(era_region)
|
||||
|
||||
menu.connect(world.get_region(EraType.ERA_ANCIENT.value))
|
||||
|
||||
world.get_region(EraType.ERA_ANCIENT.value).connect(
|
||||
world.get_region(EraType.ERA_CLASSICAL.value), None,
|
||||
lambda state: has_required_items(
|
||||
state, EraType.ERA_ANCIENT, player, has_progressive_items, has_progressive_eras)
|
||||
)
|
||||
|
||||
world.get_region(EraType.ERA_CLASSICAL.value).connect(
|
||||
world.get_region(EraType.ERA_MEDIEVAL.value), None, lambda state: has_required_items(
|
||||
state, EraType.ERA_CLASSICAL, player, has_progressive_items, has_progressive_eras)
|
||||
)
|
||||
|
||||
world.get_region(EraType.ERA_MEDIEVAL.value).connect(
|
||||
world.get_region(EraType.ERA_RENAISSANCE.value), None, lambda state: has_required_items(
|
||||
state, EraType.ERA_MEDIEVAL, player, has_progressive_items, has_progressive_eras)
|
||||
)
|
||||
|
||||
world.get_region(EraType.ERA_RENAISSANCE.value).connect(
|
||||
world.get_region(EraType.ERA_INDUSTRIAL.value), None, lambda state: has_required_items(
|
||||
state, EraType.ERA_RENAISSANCE, player, has_progressive_items, has_progressive_eras)
|
||||
)
|
||||
|
||||
world.get_region(EraType.ERA_INDUSTRIAL.value).connect(
|
||||
world.get_region(EraType.ERA_MODERN.value), None, lambda state: has_required_items(
|
||||
state, EraType.ERA_INDUSTRIAL, player, has_progressive_items, has_progressive_eras)
|
||||
)
|
||||
|
||||
world.get_region(EraType.ERA_MODERN.value).connect(
|
||||
world.get_region(EraType.ERA_ATOMIC.value), None, lambda state: has_required_items(
|
||||
state, EraType.ERA_MODERN, player, has_progressive_items, has_progressive_eras)
|
||||
)
|
||||
|
||||
world.get_region(EraType.ERA_ATOMIC.value).connect(
|
||||
world.get_region(EraType.ERA_INFORMATION.value), None, lambda state: has_required_items(
|
||||
state, EraType.ERA_ATOMIC, player, has_progressive_items, has_progressive_eras)
|
||||
)
|
||||
|
||||
world.get_region(EraType.ERA_INFORMATION.value).connect(
|
||||
world.get_region(EraType.ERA_FUTURE.value), None, lambda state: has_required_items(state, EraType.ERA_INFORMATION, player, has_progressive_items, has_progressive_eras))
|
||||
|
||||
world.multiworld.completion_condition[player] = lambda state: state.can_reach(
|
||||
EraType.ERA_FUTURE.value, "Region", player)
|
||||
|
||||
if world.options.boostsanity.value and not world.options.exclude_missable_boosts.value:
|
||||
_update_boost_locations_to_include_missable(world)
|
||||
|
||||
|
||||
def _update_boost_locations_to_include_missable(world: 'CivVIWorld'):
|
||||
"""If the player has exclude missable boosts disabled, set them all to default if they are excluded"""
|
||||
for loc_data in world.location_table.values():
|
||||
if loc_data.location_type == CivVICheckType.BOOST:
|
||||
location = world.get_location(loc_data.name)
|
||||
if location.progress_type == LocationProgressType.EXCLUDED:
|
||||
location.progress_type = LocationProgressType.DEFAULT
|
||||
63
worlds/civ_6/Rules.py
Normal file
63
worlds/civ_6/Rules.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import CollectionState
|
||||
from .Items import get_item_by_civ_name
|
||||
from .Data import get_boosts_data
|
||||
from .Enum import CivVICheckType
|
||||
from .ProgressiveDistricts import convert_items_to_have_progression
|
||||
|
||||
from worlds.generic.Rules import forbid_item, set_rule
|
||||
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from . import CivVIWorld
|
||||
|
||||
|
||||
def generate_has_required_items_lambda(prereqs: typing.List[str], required_count: int, has_progressive_items: bool, player: int):
|
||||
def has_required_items_lambda(state: CollectionState):
|
||||
return has_required_items(state, prereqs, required_count, has_progressive_items, player)
|
||||
return has_required_items_lambda
|
||||
|
||||
|
||||
def create_boost_rules(world: 'CivVIWorld'):
|
||||
boost_data_list = get_boosts_data()
|
||||
boost_locations = [location for location in world.location_table.values() if location.location_type == CivVICheckType.BOOST]
|
||||
for location in boost_locations:
|
||||
boost_data = next((boost for boost in boost_data_list if boost.Type == location.name), None)
|
||||
world_location = world.multiworld.get_location(location.name, world.player)
|
||||
forbid_item(world_location, "Progressive Era", world.player)
|
||||
if not boost_data or boost_data.PrereqRequiredCount == 0:
|
||||
continue
|
||||
|
||||
has_progressive_items = world.options.progression_style.current_key != "none"
|
||||
set_rule(world_location,
|
||||
generate_has_required_items_lambda(boost_data.Prereq, boost_data.PrereqRequiredCount, has_progressive_items, world.player)
|
||||
)
|
||||
|
||||
|
||||
def has_required_items(state: CollectionState, prereqs: typing.List[str], required_count: int, has_progressive_items: bool, player: int):
|
||||
if has_progressive_items:
|
||||
items = [get_item_by_civ_name(item, state.multiworld.worlds[player].item_table).name for item in convert_items_to_have_progression(prereqs)]
|
||||
progressive_items: typing.Dict[str, int] = {}
|
||||
count = 0
|
||||
for item in items:
|
||||
if "Progressive" in item:
|
||||
if not progressive_items.get(item):
|
||||
progressive_items[item] = 0
|
||||
progressive_items[item] += 1
|
||||
else:
|
||||
if state.has(item, player):
|
||||
count += 1
|
||||
|
||||
for item, required_progressive_item_count in progressive_items.items():
|
||||
if state.count(item, player) >= required_progressive_item_count:
|
||||
count += required_progressive_item_count
|
||||
if count > 0:
|
||||
pass
|
||||
return count >= required_count
|
||||
else:
|
||||
count = 0
|
||||
for prereq in prereqs:
|
||||
if state.has(get_item_by_civ_name(prereq, state.multiworld.worlds[player].item_table).name, player):
|
||||
count += 1
|
||||
return count >= required_count
|
||||
108
worlds/civ_6/TunerClient.py
Normal file
108
worlds/civ_6/TunerClient.py
Normal file
@@ -0,0 +1,108 @@
|
||||
import asyncio
|
||||
from logging import Logger
|
||||
import select
|
||||
import socket
|
||||
|
||||
ADDRESS = "127.0.0.1"
|
||||
PORT = 4318
|
||||
|
||||
CLIENT_PREFIX = "APSTART:"
|
||||
CLIENT_POSTFIX = ":APEND"
|
||||
|
||||
|
||||
def decode_mixed_string(data):
|
||||
return ''.join(chr(b) if 32 <= b < 127 else '?' for b in data)
|
||||
|
||||
|
||||
class TunerException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TunerTimeoutException(TunerException):
|
||||
pass
|
||||
|
||||
|
||||
class TunerErrorException(TunerException):
|
||||
pass
|
||||
|
||||
|
||||
class TunerConnectionException(TunerException):
|
||||
pass
|
||||
|
||||
|
||||
class TunerClient:
|
||||
"""Interfaces with Civilization via the tuner socket"""
|
||||
logger: Logger
|
||||
|
||||
def __init__(self, logger):
|
||||
self.logger = logger
|
||||
|
||||
def __parse_response(self, response: str) -> str:
|
||||
"""Parses the response from the tuner socket"""
|
||||
split = response.split(CLIENT_PREFIX)
|
||||
if len(split) > 1:
|
||||
start = split[1]
|
||||
end = start.split(CLIENT_POSTFIX)[0]
|
||||
return end
|
||||
elif "ERR:" in response:
|
||||
raise TunerErrorException(response.replace("?", ""))
|
||||
else:
|
||||
return ""
|
||||
|
||||
async def send_game_command(self, command_string: str, size: int = 64):
|
||||
"""Small helper that prefixes a command with GameCore.Game."""
|
||||
return await self.send_command("GameCore.Game." + command_string, size)
|
||||
|
||||
async def send_command(self, command_string: str, size: int = 64):
|
||||
"""Send a raw commannd"""
|
||||
self.logger.debug("Sending Command: " + command_string)
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setblocking(False)
|
||||
|
||||
b_command_string = command_string.encode('utf-8')
|
||||
|
||||
# Send data to the server
|
||||
command_prefix = b"CMD:0:"
|
||||
delimiter = b"\x00"
|
||||
full_command = b_command_string
|
||||
message = command_prefix + full_command + delimiter
|
||||
message_length = len(message).to_bytes(1, byteorder='little')
|
||||
|
||||
# game expects this to be added before any command that is sent, indicates payload size
|
||||
message_header = message_length + b"\x00\x00\x00\x03\x00\x00\x00"
|
||||
data = message_header + command_prefix + full_command + delimiter
|
||||
|
||||
server_address = (ADDRESS, PORT)
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
await loop.sock_connect(sock, server_address)
|
||||
await loop.sock_sendall(sock, data)
|
||||
|
||||
# Add a delay before receiving data
|
||||
await asyncio.sleep(.02)
|
||||
|
||||
received_data = await self.async_recv(sock)
|
||||
response = decode_mixed_string(received_data)
|
||||
self.logger.debug('Received:')
|
||||
self.logger.debug(response)
|
||||
return self.__parse_response(response)
|
||||
|
||||
except socket.timeout:
|
||||
self.logger.debug('Timeout occurred while receiving data')
|
||||
raise TunerTimeoutException()
|
||||
except Exception as e:
|
||||
self.logger.debug(f'Error occurred while receiving data: {str(e)}')
|
||||
# check if No connection could be made is present in the error message
|
||||
connection_errors = [
|
||||
"The remote computer refused the network connection",
|
||||
]
|
||||
if any(error in str(e) for error in connection_errors):
|
||||
raise TunerConnectionException(e)
|
||||
else:
|
||||
raise TunerErrorException(e)
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
async def async_recv(self, sock, timeout=2.0, size=4096):
|
||||
response = await asyncio.wait_for(asyncio.get_event_loop().sock_recv(sock, size), timeout)
|
||||
return response
|
||||
195
worlds/civ_6/__init__.py
Normal file
195
worlds/civ_6/__init__.py
Normal file
@@ -0,0 +1,195 @@
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
from typing import Dict
|
||||
import typing
|
||||
|
||||
from .Data import get_boosts_data
|
||||
|
||||
from .Rules import create_boost_rules
|
||||
import Utils
|
||||
from .Container import CivVIContainer, generate_goody_hut_sql, generate_new_items, generate_setup_file, generate_update_boosts_sql
|
||||
from .Enum import CivVICheckType
|
||||
from .Items import BOOSTSANITY_PROGRESSION_ITEMS, FILLER_DISTRIBUTION, CivVIItemData, FillerItemRarity, generate_item_table, CivVIItem, get_random_filler_by_rarity
|
||||
from .Locations import CivVILocation, CivVILocationData, EraType, generate_era_location_table, generate_flat_location_table
|
||||
from .Options import CivVIOptions
|
||||
from .Regions import create_regions
|
||||
from BaseClasses import Item, ItemClassification, MultiWorld, Tutorial
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
from worlds.LauncherComponents import Component, SuffixIdentifier, Type, components, launch_subprocess
|
||||
|
||||
|
||||
def run_client():
|
||||
print("Running Civ6 Client")
|
||||
from .Civ6Client import main # lazy import
|
||||
launch_subprocess(main, name="Civ6Client")
|
||||
|
||||
|
||||
components.append(
|
||||
Component("Civ6 Client", func=run_client, component_type=Type.CLIENT,
|
||||
file_identifier=SuffixIdentifier(".apcivvi"))
|
||||
)
|
||||
|
||||
|
||||
class CivVIWeb(WebWorld):
|
||||
tutorials = [Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
"A guide to setting up Civlization VI for MultiWorld.",
|
||||
"English",
|
||||
"setup_en.md",
|
||||
"setup/en",
|
||||
["hesto2"]
|
||||
)]
|
||||
|
||||
|
||||
class CivVIWorld(World):
|
||||
"""
|
||||
Civilization VI is a turn-based strategy video game in which one or more players compete alongside computer-controlled AI opponents to grow their individual civilization from a small tribe to control the entire planet across several periods of development.
|
||||
"""
|
||||
|
||||
game: str = "Civilization VI"
|
||||
topology_present = False
|
||||
options_dataclass = CivVIOptions
|
||||
options: CivVIOptions
|
||||
|
||||
web = CivVIWeb()
|
||||
|
||||
item_name_to_id = {
|
||||
item.name: item.code for item in generate_item_table().values()}
|
||||
location_name_to_id = {
|
||||
location.name: location.code for location in generate_flat_location_table().values()}
|
||||
|
||||
item_table: Dict[str, CivVIItemData] = {}
|
||||
location_by_era: Dict[EraType, Dict[str, CivVILocationData]]
|
||||
|
||||
data_version = 1
|
||||
required_client_version = (0, 4, 5)
|
||||
|
||||
def __init__(self, multiworld: "MultiWorld", player: int):
|
||||
super().__init__(multiworld, player)
|
||||
self.location_by_era = generate_era_location_table()
|
||||
|
||||
self.location_table: Dict[str, CivVILocationData] = {}
|
||||
self.item_table = generate_item_table()
|
||||
|
||||
for _era, locations in self.location_by_era.items():
|
||||
for _item_name, location in locations.items():
|
||||
self.location_table[location.name] = location
|
||||
|
||||
def get_filler_item_name(self):
|
||||
return get_random_filler_by_rarity(FillerItemRarity.COMMON, self.item_table).name
|
||||
|
||||
def create_regions(self):
|
||||
create_regions(self, self.options, self.player)
|
||||
|
||||
def set_rules(self) -> None:
|
||||
if self.options.boostsanity.value:
|
||||
create_boost_rules(self)
|
||||
|
||||
def create_item(self, name: str) -> Item:
|
||||
item: CivVIItemData = self.item_table[name]
|
||||
classification = item.classification
|
||||
if self.options.boostsanity.value:
|
||||
if item.civ_name in BOOSTSANITY_PROGRESSION_ITEMS:
|
||||
classification = ItemClassification.progression
|
||||
|
||||
return CivVIItem(item, self.player, classification)
|
||||
|
||||
def create_items(self):
|
||||
progressive_era_item = None
|
||||
for item_name, data in self.item_table.items():
|
||||
# Don't add progressive items to the itempool here
|
||||
if data.item_type == CivVICheckType.PROGRESSIVE_DISTRICT:
|
||||
continue
|
||||
if data.item_type == CivVICheckType.ERA:
|
||||
# Don't add era items in this way
|
||||
progressive_era_item = data
|
||||
continue
|
||||
if data.item_type == CivVICheckType.GOODY:
|
||||
continue
|
||||
|
||||
# If we're using progressive districts, we need to check if we need to create a different item instead
|
||||
item_to_create = item_name
|
||||
if self.options.progression_style.current_key != "none":
|
||||
item: CivVIItemData = self.item_table[item_name]
|
||||
if item.progression_name != None:
|
||||
item_to_create = self.item_table[item.progression_name].name
|
||||
|
||||
self.multiworld.itempool += [self.create_item(
|
||||
item_to_create)]
|
||||
|
||||
# Era items
|
||||
if self.options.progression_style.current_key == "eras_and_districts":
|
||||
# Add one less than the total number of eras (start in ancient, don't need to find it)
|
||||
for era in EraType:
|
||||
if era.value == "ERA_ANCIENT":
|
||||
continue
|
||||
self.multiworld.itempool += [self.create_item(
|
||||
progressive_era_item.name)]
|
||||
|
||||
num_filler_items = 0
|
||||
# Goody items, create 10 by default if options are enabled
|
||||
if self.options.shuffle_goody_hut_rewards.value:
|
||||
num_filler_items += 10
|
||||
|
||||
if self.options.boostsanity.value:
|
||||
boost_data = get_boosts_data()
|
||||
num_filler_items += len(boost_data)
|
||||
|
||||
filler_count = {rarity: FILLER_DISTRIBUTION[rarity] * num_filler_items for rarity in FillerItemRarity.__reversed__()}
|
||||
min_count = 1
|
||||
# Add filler items by rarity
|
||||
total_created = 0
|
||||
for rarity, count in filler_count.items():
|
||||
for _ in range(max(min_count, math.ceil(count))):
|
||||
if total_created >= num_filler_items:
|
||||
break
|
||||
self.multiworld.itempool += [self.create_item(
|
||||
get_random_filler_by_rarity(rarity, self.item_table).name)]
|
||||
total_created += 1
|
||||
|
||||
def post_fill(self):
|
||||
if self.options.pre_hint_items.current_key == "none":
|
||||
return
|
||||
|
||||
show_flags = {
|
||||
ItemClassification.progression: self.options.pre_hint_items.current_key != "none",
|
||||
ItemClassification.useful: self.options.pre_hint_items.current_key == "no_junk" or self.options.pre_hint_items.current_key == "all",
|
||||
ItemClassification.filler: self.options.pre_hint_items.current_key == "all",
|
||||
}
|
||||
|
||||
start_location_hints: typing.Set[str] = self.options.start_location_hints.value
|
||||
for location_name, location_data in self.location_table.items():
|
||||
if location_data.location_type != CivVICheckType.CIVIC and location_data.location_type != CivVICheckType.TECH:
|
||||
continue
|
||||
|
||||
location: CivVILocation = self.multiworld.get_location(location_name, self.player)
|
||||
|
||||
if not location.item or not show_flags.get(location.item.classification, False):
|
||||
continue
|
||||
|
||||
start_location_hints.add(location_name)
|
||||
|
||||
def fill_slot_data(self):
|
||||
return {
|
||||
"progression_style": self.options.progression_style.current_key,
|
||||
"death_link": self.options.death_link.value,
|
||||
"research_cost_multiplier": self.options.research_cost_multiplier.value,
|
||||
"death_link_effect": self.options.death_link_effect.value,
|
||||
"death_link_effect_percent": self.options.death_link_effect_percent.value,
|
||||
|
||||
}
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
mod_name = f"AP-{self.multiworld.get_file_safe_player_name(self.player)}"
|
||||
mod_dir = os.path.join(
|
||||
output_directory, mod_name + "_" + Utils.__version__)
|
||||
mod_files = {
|
||||
f"NewItems.xml": generate_new_items(self),
|
||||
f"InitOptions.lua": generate_setup_file(self),
|
||||
f"GoodyHutOverride.sql": generate_goody_hut_sql(self),
|
||||
f"UpdateExistingBoosts.sql": generate_update_boosts_sql(self),
|
||||
}
|
||||
mod = CivVIContainer(mod_files, mod_dir, output_directory, self.player,
|
||||
self.multiworld.get_file_safe_player_name(self.player))
|
||||
mod.write()
|
||||
923
worlds/civ_6/data/boosts.json
Normal file
923
worlds/civ_6/data/boosts.json
Normal file
@@ -0,0 +1,923 @@
|
||||
[
|
||||
{
|
||||
"Type": "BOOST_TECH_SAILING",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ASTROLOGY",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_IRRIGATION",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ARCHERY",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_WRITING",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "PRIORITY"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_MASONRY",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": ["TECH_MINING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_BRONZE_WORKING",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_THE_WHEEL",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": ["TECH_MINING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_CELESTIAL_NAVIGATION",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_SAILING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_CURRENCY",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["CIVIC_FOREIGN_TRADE"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_HORSEBACK_RIDING",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_ANIMAL_HUSBANDRY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_IRON_WORKING",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_MINING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SHIPBUILDING",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_SAILING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_MATHEMATICS",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": [
|
||||
"TECH_CURRENCY",
|
||||
"TECH_BRONZE_WORKING",
|
||||
"TECH_CELESTIAL_NAVIGATION",
|
||||
"TECH_WRITING",
|
||||
"TECH_APPRENTICESHIP",
|
||||
"TECH_FLIGHT",
|
||||
"CIVIC_GAMES_RECREATION",
|
||||
"CIVIC_DRAMA_POETRY"
|
||||
],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_CONSTRUCTION",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_THE_WHEEL"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ENGINEERING",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_MASONRY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_MILITARY_TACTICS",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["TECH_BRONZE_WORKING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_APPRENTICESHIP",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["TECH_MINING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_MACHINERY",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["TECH_ARCHERY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_EDUCATION",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["TECH_WRITING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_STIRRUPS",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["CIVIC_FEUDALISM"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_MILITARY_ENGINEERING",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["TECH_ENGINEERING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_CASTLES",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": [
|
||||
"CIVIC_DIVINE_RIGHT",
|
||||
"CIVIC_EXPLORATION",
|
||||
"CIVIC_REFORMED_CHURCH",
|
||||
"CIVIC_SUFFRAGE",
|
||||
"CIVIC_TOTALITARIANISM",
|
||||
"CIVIC_CLASS_STRUGGLE",
|
||||
"CIVIC_DIGITAL_DEMOCRACY",
|
||||
"CIVIC_CORPORATE_LIBERTARIANISM",
|
||||
"CIVIC_SYNTHETIC_TECHNOCRACY"
|
||||
],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_CARTOGRAPHY",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_CELESTIAL_NAVIGATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_MASS_PRODUCTION",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_CONSTRUCTION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_BANKING",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["CIVIC_GUILDS"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_GUNPOWDER",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_BRONZE_WORKING", "TECH_MILITARY_ENGINEERING"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_PRINTING",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_WRITING", "TECH_EDUCATION"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SQUARE_RIGGING",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_GUNPOWDER"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ASTRONOMY",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_EDUCATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_METAL_CASTING",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_MACHINERY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SIEGE_TACTICS",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_MILITARY_ENGINEERING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_INDUSTRIALIZATION",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_APPRENTICESHIP"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SCIENTIFIC_THEORY",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["CIVIC_THE_ENLIGHTENMENT"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_BALLISTICS",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_SIEGE_TACTICS", "TECH_MILITARY_ENGINEERING"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_MILITARY_SCIENCE",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_STIRRUPS"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_STEAM_POWER",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_MASS_PRODUCTION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SANITATION",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["CIVIC_URBANIZATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ECONOMICS",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_CURRENCY", "TECH_BANKING"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_RIFLING",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_MINING", "TECH_MILITARY_ENGINEERING"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_FLIGHT",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_REPLACEABLE_PARTS",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_MILITARY_SCIENCE"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_STEEL",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_MINING", "TECH_STEAM_POWER", "TECH_INDUSTRIALIZATION"],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ELECTRICITY",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["CIVIC_MERCANTILISM", "TECH_CELESTIAL_NAVIGATION"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_RADIO",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["CIVIC_CONSERVATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_CHEMISTRY",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["CIVIC_CIVIL_SERVICE"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_COMBUSTION",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["CIVIC_NATURAL_HISTORY", "CIVIC_HUMANISM"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ADVANCED_FLIGHT",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["TECH_FLIGHT"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ROCKETRY",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["CIVIC_DIPLOMATIC_SERVICE"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ADVANCED_BALLISTICS",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": [
|
||||
"TECH_ELECTRICITY",
|
||||
"TECH_REFINING",
|
||||
"TECH_APPRENTICESHIP",
|
||||
"TECH_INDUSTRIALIZATION"
|
||||
],
|
||||
"PrereqRequiredCount": 4,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_COMBINED_ARMS",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": [
|
||||
"CIVIC_MOBILIZATION",
|
||||
"CIVIC_NATIONALISM"
|
||||
],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_PLASTICS",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["TECH_REFINING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_COMPUTERS",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": [
|
||||
"CIVIC_SUFFRAGE",
|
||||
"CIVIC_TOTALITARIANISM",
|
||||
"CIVIC_CLASS_STRUGGLE",
|
||||
"CIVIC_DIGITAL_DEMOCRACY",
|
||||
"CIVIC_CORPORATE_LIBERTARIANISM",
|
||||
"CIVIC_SYNTHETIC_TECHNOCRACY"
|
||||
],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_NUCLEAR_FISSION",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["CIVIC_DIPLOMATIC_SERVICE"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SYNTHETIC_MATERIALS",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["TECH_FLIGHT"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_TELECOMMUNICATIONS",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["CIVIC_DIPLOMATIC_SERVICE"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SATELLITES",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["CIVIC_DRAMA_POETRY", "CIVIC_HUMANISM", "TECH_RADIO"],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_GUIDANCE_SYSTEMS",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_LASERS",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["TECH_COMPUTERS"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_COMPOSITES",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["TECH_COMBUSTION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_STEALTH_TECHNOLOGY",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ROBOTICS",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["CIVIC_GLOBALIZATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_NANOTECHNOLOGY",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["TECH_MINING", "TECH_RADIO"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_NUCLEAR_FUSION",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": [
|
||||
"TECH_APPRENTICESHIP",
|
||||
"TECH_INDUSTRIALIZATION",
|
||||
"TECH_ELECTRICITY",
|
||||
"TECH_NUCLEAR_FISSION"
|
||||
],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_BUTTRESS",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_REFINING",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_INDUSTRIALIZATION", "TECH_MINING", "TECH_APPRENTICESHIP"],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SEASTEADS",
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ADVANCED_AI",
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_ADVANCED_POWER_CELLS",
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_CYBERNETICS",
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_SMART_MATERIALS",
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_PREDICTIVE_SYSTEMS",
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_TECH_OFFWORLD_MISSION",
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_CRAFTSMANSHIP",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [
|
||||
"TECH_IRRIGATION",
|
||||
"TECH_MINING",
|
||||
"TECH_CONSTRUCTION",
|
||||
"TECH_ANIMAL_HUSBANDRY",
|
||||
"TECH_SAILING"
|
||||
],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_FOREIGN_TRADE",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": ["TECH_CARTOGRAPHY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MILITARY_TRADITION",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_STATE_WORKFORCE",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [
|
||||
"TECH_CURRENCY",
|
||||
"TECH_BRONZE_WORKING",
|
||||
"TECH_CELESTIAL_NAVIGATION",
|
||||
"TECH_WRITING",
|
||||
"TECH_APPRENTICESHIP",
|
||||
"TECH_FLIGHT",
|
||||
"CIVIC_GAMES_RECREATION",
|
||||
"CIVIC_DRAMA_POETRY"
|
||||
],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_EARLY_EMPIRE",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MYSTICISM",
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_GAMES_RECREATION",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_CONSTRUCTION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_POLITICAL_PHILOSOPHY",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_DRAMA_POETRY",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MILITARY_TRAINING",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_BRONZE_WORKING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_DEFENSIVE_TACTICS",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_RECORDED_HISTORY",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_WRITING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_THEOLOGY",
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Prereq": ["TECH_ASTROLOGY"],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_NAVAL_TRADITION",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["TECH_SHIPBUILDING"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_FEUDALISM",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_CIVIL_SERVICE",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MERCENARIES",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MEDIEVAL_FAIRES",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["CIVIC_FOREIGN_TRADE", "TECH_CURRENCY"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_GUILDS",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["TECH_CURRENCY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_DIVINE_RIGHT",
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Prereq": ["CIVIC_THEOLOGY", "TECH_ASTROLOGY"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_EXPLORATION",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_CARTOGRAPHY", "TECH_CELESTIAL_NAVIGATION"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_HUMANISM",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["CIVIC_DRAMA_POETRY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_DIPLOMATIC_SERVICE",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_REFORMED_CHURCH",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_ASTROLOGY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MERCANTILISM",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": ["TECH_CURRENCY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_THE_ENLIGHTENMENT",
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_COLONIALISM",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_ASTRONOMY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_CIVIL_ENGINEERING",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": [
|
||||
"TECH_CURRENCY",
|
||||
"TECH_BRONZE_WORKING",
|
||||
"TECH_CELESTIAL_NAVIGATION",
|
||||
"TECH_WRITING",
|
||||
"TECH_APPRENTICESHIP",
|
||||
"TECH_FLIGHT",
|
||||
"CIVIC_GAMES_RECREATION",
|
||||
"CIVIC_DRAMA_POETRY"
|
||||
],
|
||||
"PrereqRequiredCount": 8,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_NATIONALISM",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_OPERA_BALLET",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["CIVIC_HUMANISM", "CIVIC_DRAMA_POETRY"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_NATURAL_HISTORY",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["CIVIC_HUMANISM", "CIVIC_DRAMA_POETRY"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_SCORCHED_EARTH",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": ["TECH_BALLISTICS"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_URBANIZATION",
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_CONSERVATION",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["CIVIC_URBANIZATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_CAPITALISM",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_CURRENCY", "TECH_BANKING", "TECH_ECONOMICS"],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_NUCLEAR_PROGRAM",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_WRITING", "TECH_EDUCATION", "TECH_CHEMISTRY"],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MASS_MEDIA",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_RADIO"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_MOBILIZATION",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["CIVIC_NATIONALISM"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_SUFFRAGE",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_SANITATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_TOTALITARIANISM",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": [
|
||||
"TECH_BRONZE_WORKING",
|
||||
"TECH_MILITARY_ENGINEERING",
|
||||
"TECH_MILITARY_SCIENCE"
|
||||
],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_CLASS_STRUGGLE",
|
||||
"EraType": "ERA_MODERN",
|
||||
"Prereq": ["TECH_APPRENTICESHIP", "TECH_INDUSTRIALIZATION"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_COLD_WAR",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["TECH_NUCLEAR_FISSION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_PROFESSIONAL_SPORTS",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["CIVIC_GAMES_RECREATION"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_CULTURAL_HERITAGE",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": [],
|
||||
"PrereqRequiredCount": 0,
|
||||
"Classification": "EXCLUDED"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_RAPID_DEPLOYMENT",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["TECH_FLIGHT", "TECH_CARTOGRAPHY", "TECH_SHIPBUILDING"],
|
||||
"PrereqRequiredCount": 3,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_SPACE_RACE",
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Prereq": ["TECH_ROCKETRY"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_GLOBALIZATION",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["TECH_FLIGHT", "TECH_ADVANCED_FLIGHT"],
|
||||
"PrereqRequiredCount": 2,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_SOCIAL_MEDIA",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["TECH_TELECOMMUNICATIONS"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
},
|
||||
{
|
||||
"Type": "BOOST_CIVIC_ENVIRONMENTALISM",
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Prereq": ["TECH_SATELLITES"],
|
||||
"PrereqRequiredCount": 1,
|
||||
"Classification": "DEFAULT"
|
||||
}
|
||||
]
|
||||
72
worlds/civ_6/data/era_required_items.json
Normal file
72
worlds/civ_6/data/era_required_items.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"ERA_ANCIENT": [
|
||||
"TECH_MINING",
|
||||
"TECH_BRONZE_WORKING",
|
||||
"TECH_ASTROLOGY",
|
||||
"TECH_WRITING",
|
||||
"TECH_IRRIGATION",
|
||||
"TECH_SAILING",
|
||||
"TECH_ANIMAL_HUSBANDRY",
|
||||
"CIVIC_STATE_WORKFORCE",
|
||||
"CIVIC_FOREIGN_TRADE"
|
||||
],
|
||||
"ERA_CLASSICAL": [
|
||||
"TECH_CELESTIAL_NAVIGATION",
|
||||
"TECH_CURRENCY",
|
||||
"TECH_MATHEMATICS",
|
||||
"TECH_SHIPBUILDING",
|
||||
"CIVIC_GAMES_RECREATION",
|
||||
"CIVIC_POLITICAL_PHILOSOPHY",
|
||||
"CIVIC_DRAMA_POETRY",
|
||||
"CIVIC_THEOLOGY"
|
||||
],
|
||||
"ERA_MEDIEVAL": [
|
||||
"TECH_APPRENTICESHIP",
|
||||
"TECH_EDUCATION",
|
||||
"TECH_MILITARY_ENGINEERING",
|
||||
"CIVIC_DIVINE_RIGHT"
|
||||
],
|
||||
"ERA_RENAISSANCE": [
|
||||
"TECH_MASS_PRODUCTION",
|
||||
"TECH_BANKING",
|
||||
"CIVIC_EXPLORATION",
|
||||
"CIVIC_HUMANISM",
|
||||
"CIVIC_REFORMED_CHURCH",
|
||||
"CIVIC_DIPLOMATIC_SERVICE",
|
||||
"TECH_CARTOGRAPHY"
|
||||
],
|
||||
"ERA_INDUSTRIAL": [
|
||||
"TECH_INDUSTRIALIZATION",
|
||||
"TECH_MILITARY_SCIENCE",
|
||||
"TECH_ECONOMICS",
|
||||
"CIVIC_NATIONALISM",
|
||||
"CIVIC_NATURAL_HISTORY"
|
||||
],
|
||||
"ERA_MODERN": [
|
||||
"TECH_FLIGHT",
|
||||
"TECH_REFINING",
|
||||
"TECH_ELECTRICITY",
|
||||
"TECH_RADIO",
|
||||
"TECH_CHEMISTRY",
|
||||
"CIVIC_SUFFRAGE",
|
||||
"CIVIC_TOTALITARIANISM",
|
||||
"CIVIC_CLASS_STRUGGLE"
|
||||
],
|
||||
"ERA_ATOMIC": [
|
||||
"TECH_ADVANCED_FLIGHT",
|
||||
"TECH_ROCKETRY",
|
||||
"TECH_COMBINED_ARMS",
|
||||
"TECH_PLASTICS",
|
||||
"TECH_NUCLEAR_FISSION",
|
||||
"CIVIC_PROFESSIONAL_SPORTS"
|
||||
],
|
||||
"ERA_INFORMATION": [
|
||||
"TECH_SATELLITES",
|
||||
"TECH_NANOTECHNOLOGY",
|
||||
"TECH_SMART_MATERIALS",
|
||||
"CIVIC_CORPORATE_LIBERTARIANISM",
|
||||
"CIVIC_DIGITAL_DEMOCRACY",
|
||||
"CIVIC_SYNTHETIC_TECHNOCRACY"
|
||||
],
|
||||
"ERA_FUTURE": []
|
||||
}
|
||||
429
worlds/civ_6/data/existing_civics.json
Normal file
429
worlds/civ_6/data/existing_civics.json
Normal file
@@ -0,0 +1,429 @@
|
||||
[
|
||||
{
|
||||
"Type": "CIVIC_CODE_OF_LAWS",
|
||||
"Name": "Code of Laws",
|
||||
"Cost": 20,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CRAFTSMANSHIP",
|
||||
"Name": "Craftsmanship",
|
||||
"Cost": 40,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"UITreeRow": -2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_FOREIGN_TRADE",
|
||||
"Name": "Foreign Trade",
|
||||
"Cost": 40,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MILITARY_TRADITION",
|
||||
"Name": "Military Tradition",
|
||||
"Cost": 50,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_STATE_WORKFORCE",
|
||||
"Name": "State Workforce",
|
||||
"Cost": 70,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_EARLY_EMPIRE",
|
||||
"Name": "Early Empire",
|
||||
"Cost": 70,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MYSTICISM",
|
||||
"Name": "Mysticism",
|
||||
"Cost": 50,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"UITreeRow": 3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_GAMES_RECREATION",
|
||||
"Name": "Games Recreation",
|
||||
"Cost": 110,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"UITreeRow": -2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_POLITICAL_PHILOSOPHY",
|
||||
"Name": "Political Philosophy",
|
||||
"Cost": 110,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_DRAMA_POETRY",
|
||||
"Name": "Drama and Poetry",
|
||||
"Cost": 110,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MILITARY_TRAINING",
|
||||
"Name": "Military Training",
|
||||
"Cost": 120,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_DEFENSIVE_TACTICS",
|
||||
"Name": "Defensive Tactics",
|
||||
"Cost": 175,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_RECORDED_HISTORY",
|
||||
"Name": "Recorded History",
|
||||
"Cost": 175,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_THEOLOGY",
|
||||
"Name": "Theology",
|
||||
"Cost": 120,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"UITreeRow": 3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_NAVAL_TRADITION",
|
||||
"Name": "Naval Tradition",
|
||||
"Cost": 220,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"UITreeRow": -2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_FEUDALISM",
|
||||
"Name": "Feudalism",
|
||||
"Cost": 300,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CIVIL_SERVICE",
|
||||
"Name": "Civil Service",
|
||||
"Cost": 300,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MERCENARIES",
|
||||
"Name": "Mercenaries",
|
||||
"Cost": 340,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MEDIEVAL_FAIRES",
|
||||
"Name": "Medieval Faires",
|
||||
"Cost": 420,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_GUILDS",
|
||||
"Name": "Guilds",
|
||||
"Cost": 420,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_DIVINE_RIGHT",
|
||||
"Name": "Divine Right",
|
||||
"Cost": 340,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"UITreeRow": 3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_EXPLORATION",
|
||||
"Name": "Exploration",
|
||||
"Cost": 440,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_HUMANISM",
|
||||
"Name": "Humanism",
|
||||
"Cost": 600,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_DIPLOMATIC_SERVICE",
|
||||
"Name": "Diplomatic Service",
|
||||
"Cost": 600,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_REFORMED_CHURCH",
|
||||
"Name": "Reformed Church",
|
||||
"Cost": 440,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"UITreeRow": 3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MERCANTILISM",
|
||||
"Name": "Mercantilism",
|
||||
"Cost": 720,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_THE_ENLIGHTENMENT",
|
||||
"Name": "The Enlightenment",
|
||||
"Cost": 720,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_COLONIALISM",
|
||||
"Name": "Colonialism",
|
||||
"Cost": 800,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CIVIL_ENGINEERING",
|
||||
"Name": "Civil Engineering",
|
||||
"Cost": 1010,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_NATIONALISM",
|
||||
"Name": "Nationalism",
|
||||
"Cost": 1010,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_OPERA_BALLET",
|
||||
"Name": "Opera and Ballet",
|
||||
"Cost": 800,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_NATURAL_HISTORY",
|
||||
"Name": "Natural History",
|
||||
"Cost": 1050,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_SCORCHED_EARTH",
|
||||
"Name": "Scorched Earth",
|
||||
"Cost": 1210,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_URBANIZATION",
|
||||
"Name": "Urbanization",
|
||||
"Cost": 1210,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CONSERVATION",
|
||||
"Name": "Conservation",
|
||||
"Cost": 1540,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CAPITALISM",
|
||||
"Name": "Capitalism",
|
||||
"Cost": 1580,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": -2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_NUCLEAR_PROGRAM",
|
||||
"Name": "Nuclear Program",
|
||||
"Cost": 1715,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": -2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MASS_MEDIA",
|
||||
"Name": "Mass Media",
|
||||
"Cost": 1540,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_MOBILIZATION",
|
||||
"Name": "Mobilization",
|
||||
"Cost": 1540,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_IDEOLOGY",
|
||||
"Name": "Ideology",
|
||||
"Cost": 1640,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_SUFFRAGE",
|
||||
"Name": "Suffrage",
|
||||
"Cost": 1640,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_TOTALITARIANISM",
|
||||
"Name": "Totalitarianism",
|
||||
"Cost": 1640,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CLASS_STRUGGLE",
|
||||
"Name": "Class Struggle",
|
||||
"Cost": 1640,
|
||||
"EraType": "ERA_MODERN",
|
||||
"UITreeRow": 3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_COLD_WAR",
|
||||
"Name": "Cold War",
|
||||
"Cost": 2185,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_PROFESSIONAL_SPORTS",
|
||||
"Name": "Professional Sports",
|
||||
"Cost": 2185,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CULTURAL_HERITAGE",
|
||||
"Name": "Cultural Heritage",
|
||||
"Cost": 1955,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"UITreeRow": -3
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_RAPID_DEPLOYMENT",
|
||||
"Name": "Rapid Deployment",
|
||||
"Cost": 2415,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_SPACE_RACE",
|
||||
"Name": "Space Race",
|
||||
"Cost": 2415,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_GLOBALIZATION",
|
||||
"Name": "Globalization",
|
||||
"Cost": 2880,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_SOCIAL_MEDIA",
|
||||
"Name": "Social Media",
|
||||
"Cost": 2880,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_FUTURE_CIVIC",
|
||||
"Name": "Future Civic",
|
||||
"Cost": 3500,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_ENVIRONMENTALISM",
|
||||
"Name": "Environmentalism",
|
||||
"Cost": 2880,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"UITreeRow": -2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CORPORATE_LIBERTARIANISM",
|
||||
"Name": "Corporate Libertarianism",
|
||||
"Cost": 3000,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_DIGITAL_DEMOCRACY",
|
||||
"Name": "Digital Democracy",
|
||||
"Cost": 3000,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_SYNTHETIC_TECHNOCRACY",
|
||||
"Name": "Synthetic Technocracy",
|
||||
"Cost": 3000,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"UITreeRow": 2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_NEAR_FUTURE_GOVERNANCE",
|
||||
"Name": "Near Future Governance",
|
||||
"Cost": 3100,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_GLOBAL_WARMING_MITIGATION",
|
||||
"Name": "Global Warming Mitigation",
|
||||
"Cost": 3200,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"UITreeRow": -2
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_SMART_POWER_DOCTRINE",
|
||||
"Name": "Smart Power Doctrine",
|
||||
"Cost": 3200,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"UITreeRow": -1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_INFORMATION_WARFARE",
|
||||
"Name": "Information Warfare",
|
||||
"Cost": 3200,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"UITreeRow": 0
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_EXODUS_IMPERATIVE",
|
||||
"Name": "Exodus Imperative",
|
||||
"Cost": 3200,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"UITreeRow": 1
|
||||
},
|
||||
{
|
||||
"Type": "CIVIC_CULTURAL_HEGEMONY",
|
||||
"Name": "Cultural Hegemony",
|
||||
"Cost": 3200,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"UITreeRow": 2
|
||||
}
|
||||
]
|
||||
541
worlds/civ_6/data/existing_tech.json
Normal file
541
worlds/civ_6/data/existing_tech.json
Normal file
@@ -0,0 +1,541 @@
|
||||
[
|
||||
{
|
||||
"Type": "TECH_POTTERY",
|
||||
"Cost": 25,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Pottery"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ANIMAL_HUSBANDRY",
|
||||
"Cost": 25,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Animal Husbandry"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MINING",
|
||||
"Cost": 25,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Mining"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SAILING",
|
||||
"Cost": 50,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Sailing"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ASTROLOGY",
|
||||
"Cost": 50,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Astrology"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_IRRIGATION",
|
||||
"Cost": 50,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Irrigation"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ARCHERY",
|
||||
"Cost": 50,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Archery"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_WRITING",
|
||||
"Cost": 50,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Writing"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MASONRY",
|
||||
"Cost": 80,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Masonry"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_BRONZE_WORKING",
|
||||
"Cost": 80,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "Bronze Working"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_THE_WHEEL",
|
||||
"Cost": 80,
|
||||
"UITreeRow": 4,
|
||||
"EraType": "ERA_ANCIENT",
|
||||
"Name": "The Wheel"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_CELESTIAL_NAVIGATION",
|
||||
"Cost": 120,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Celestial Navigation"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_CURRENCY",
|
||||
"Cost": 120,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Currency"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_HORSEBACK_RIDING",
|
||||
"Cost": 120,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Horseback Riding"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_IRON_WORKING",
|
||||
"Cost": 120,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Iron Working"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SHIPBUILDING",
|
||||
"Cost": 200,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Shipbuilding"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MATHEMATICS",
|
||||
"Cost": 200,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Mathematics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_CONSTRUCTION",
|
||||
"Cost": 200,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Construction"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ENGINEERING",
|
||||
"Cost": 200,
|
||||
"UITreeRow": 4,
|
||||
"EraType": "ERA_CLASSICAL",
|
||||
"Name": "Engineering"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MILITARY_TACTICS",
|
||||
"Cost": 300,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Military Tactics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_APPRENTICESHIP",
|
||||
"Cost": 300,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Apprenticeship"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MACHINERY",
|
||||
"Cost": 300,
|
||||
"UITreeRow": 4,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Machinery"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_EDUCATION",
|
||||
"Cost": 390,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Education"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_STIRRUPS",
|
||||
"Cost": 390,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Stirrups"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MILITARY_ENGINEERING",
|
||||
"Cost": 390,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Military Engineering"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_CASTLES",
|
||||
"Cost": 390,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Castles"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_CARTOGRAPHY",
|
||||
"Cost": 600,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Cartography"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MASS_PRODUCTION",
|
||||
"Cost": 600,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Mass Production"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_BANKING",
|
||||
"Cost": 600,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Banking"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_GUNPOWDER",
|
||||
"Cost": 600,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Gunpowder"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_PRINTING",
|
||||
"Cost": 600,
|
||||
"UITreeRow": 4,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Printing"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SQUARE_RIGGING",
|
||||
"Cost": 730,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Square Rigging"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ASTRONOMY",
|
||||
"Cost": 730,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Astronomy"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_METAL_CASTING",
|
||||
"Cost": 730,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Metal Casting"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SIEGE_TACTICS",
|
||||
"Cost": 730,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_RENAISSANCE",
|
||||
"Name": "Siege Tactics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_INDUSTRIALIZATION",
|
||||
"Cost": 930,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Industrialization"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SCIENTIFIC_THEORY",
|
||||
"Cost": 930,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Scientific Theory"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_BALLISTICS",
|
||||
"Cost": 930,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Ballistics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_MILITARY_SCIENCE",
|
||||
"Cost": 930,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Military Science"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_STEAM_POWER",
|
||||
"Cost": 1070,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Steam Power"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SANITATION",
|
||||
"Cost": 1070,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Sanitation"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ECONOMICS",
|
||||
"Cost": 1070,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Economics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_RIFLING",
|
||||
"Cost": 1070,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_INDUSTRIAL",
|
||||
"Name": "Rifling"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_FLIGHT",
|
||||
"Cost": 1250,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Flight"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_REPLACEABLE_PARTS",
|
||||
"Cost": 1250,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Replaceable Parts"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_STEEL",
|
||||
"Cost": 1250,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Steel"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ELECTRICITY",
|
||||
"Cost": 1370,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Electricity"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_RADIO",
|
||||
"Cost": 1370,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Radio"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_CHEMISTRY",
|
||||
"Cost": 1370,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Chemistry"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_COMBUSTION",
|
||||
"Cost": 1370,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Combustion"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ADVANCED_FLIGHT",
|
||||
"Cost": 1480,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Advanced Flight"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ROCKETRY",
|
||||
"Cost": 1480,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Rocketry"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ADVANCED_BALLISTICS",
|
||||
"Cost": 1480,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Advanced Ballistics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_COMBINED_ARMS",
|
||||
"Cost": 1480,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Combined Arms"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_PLASTICS",
|
||||
"Cost": 1480,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Plastics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_COMPUTERS",
|
||||
"Cost": 1660,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Computers"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_NUCLEAR_FISSION",
|
||||
"Cost": 1660,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Nuclear Fission"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SYNTHETIC_MATERIALS",
|
||||
"Cost": 1660,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_ATOMIC",
|
||||
"Name": "Synthetic Materials"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_TELECOMMUNICATIONS",
|
||||
"Cost": 1850,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Telecommunications"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SATELLITES",
|
||||
"Cost": 1850,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Satellites"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_GUIDANCE_SYSTEMS",
|
||||
"Cost": 1850,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Guidance Systems"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_LASERS",
|
||||
"Cost": 1850,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Lasers"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_COMPOSITES",
|
||||
"Cost": 1850,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Composites"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_STEALTH_TECHNOLOGY",
|
||||
"Cost": 1850,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Stealth Technology"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ROBOTICS",
|
||||
"Cost": 2155,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Robotics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_NANOTECHNOLOGY",
|
||||
"Cost": 2155,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Nanotechnology"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_NUCLEAR_FUSION",
|
||||
"Cost": 2155,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_INFORMATION",
|
||||
"Name": "Nuclear Fusion"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_BUTTRESS",
|
||||
"Cost": 300,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_MEDIEVAL",
|
||||
"Name": "Buttress"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_REFINING",
|
||||
"Cost": 1250,
|
||||
"UITreeRow": 3,
|
||||
"EraType": "ERA_MODERN",
|
||||
"Name": "Refining"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SEASTEADS",
|
||||
"Cost": 2200,
|
||||
"UITreeRow": -3,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Seasteads"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ADVANCED_AI",
|
||||
"Cost": 2200,
|
||||
"UITreeRow": -2,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Advanced AI"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_ADVANCED_POWER_CELLS",
|
||||
"Cost": 2200,
|
||||
"UITreeRow": -1,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Advanced Power Cells"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_CYBERNETICS",
|
||||
"Cost": 2200,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Cybernetics"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_SMART_MATERIALS",
|
||||
"Cost": 2200,
|
||||
"UITreeRow": 1,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Smart Materials"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_PREDICTIVE_SYSTEMS",
|
||||
"Cost": 2200,
|
||||
"UITreeRow": 2,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Predictive Systems"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_OFFWORLD_MISSION",
|
||||
"Cost": 2500,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Offworld Mission"
|
||||
},
|
||||
{
|
||||
"Type": "TECH_FUTURE_TECH",
|
||||
"Cost": 2600,
|
||||
"UITreeRow": 0,
|
||||
"EraType": "ERA_FUTURE",
|
||||
"Name": "Future Tech"
|
||||
}
|
||||
]
|
||||
77
worlds/civ_6/data/goody_hut_rewards.json
Normal file
77
worlds/civ_6/data/goody_hut_rewards.json
Normal file
@@ -0,0 +1,77 @@
|
||||
[
|
||||
{
|
||||
"Type": "GOODY_GOLD_SMALL_MODIFIER",
|
||||
"Rarity": "COMMON",
|
||||
"Name": "Gold: Small"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_GOLD_MEDIUM_MODIFIER",
|
||||
"Rarity": "COMMON",
|
||||
"Name": "Gold: Medium"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_GOLD_LARGE_MODIFIER",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Gold: Large"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_FAITH_SMALL_MODIFIER",
|
||||
"Rarity": "COMMON",
|
||||
"Name": "Faith: Small"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_FAITH_MEDIUM_MODIFIER",
|
||||
"Rarity": "COMMON",
|
||||
"Name": "Faith: Medium"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_FAITH_LARGE_MODIFIER",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Faith: Large"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_DIPLOMACY_GRANT_FAVOR",
|
||||
"Rarity": "COMMON",
|
||||
"Name": "Diplomatic Favor"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_DIPLOMACY_GRANT_GOVERNOR_TITLE",
|
||||
"Rarity": "RARE",
|
||||
"Name": "Governor Title"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_DIPLOMACY_GRANT_ENVOY",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Envoy"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_CULTURE_GRANT_ONE_RELIC",
|
||||
"Rarity": "RARE",
|
||||
"Name": "Relic"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_MILITARY_GRANT_SCOUT",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Scout"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_SURVIVORS_ADD_POPULATION",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Additional Population"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_SURVIVORS_GRANT_BUILDER",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Builder"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_SURVIVORS_GRANT_TRADER",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Trader"
|
||||
},
|
||||
{
|
||||
"Type": "GOODY_SURVIVORS_GRANT_SETTLER",
|
||||
"Rarity": "UNCOMMON",
|
||||
"Name": "Settler"
|
||||
}
|
||||
]
|
||||
87
worlds/civ_6/data/new_civic_prereqs.json
Normal file
87
worlds/civ_6/data/new_civic_prereqs.json
Normal file
@@ -0,0 +1,87 @@
|
||||
[
|
||||
{ "Civic": "CIVIC_AP_ANCIENT_01", "PrereqCivic": "CIVIC_AP_ANCIENT_00" },
|
||||
{ "Civic": "CIVIC_AP_ANCIENT_02", "PrereqCivic": "CIVIC_AP_ANCIENT_00" },
|
||||
{ "Civic": "CIVIC_AP_ANCIENT_03", "PrereqCivic": "CIVIC_AP_ANCIENT_01" },
|
||||
{ "Civic": "CIVIC_AP_ANCIENT_04", "PrereqCivic": "CIVIC_AP_ANCIENT_01" },
|
||||
{ "Civic": "CIVIC_AP_ANCIENT_05", "PrereqCivic": "CIVIC_AP_ANCIENT_02" },
|
||||
{ "Civic": "CIVIC_AP_ANCIENT_06", "PrereqCivic": "CIVIC_AP_ANCIENT_02" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_07", "PrereqCivic": "CIVIC_AP_ANCIENT_04" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_08", "PrereqCivic": "CIVIC_AP_ANCIENT_04" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_08", "PrereqCivic": "CIVIC_AP_ANCIENT_05" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_09", "PrereqCivic": "CIVIC_AP_ANCIENT_05" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_10", "PrereqCivic": "CIVIC_AP_ANCIENT_03" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_10", "PrereqCivic": "CIVIC_AP_CLASSICAL_07" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_11", "PrereqCivic": "CIVIC_AP_CLASSICAL_07" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_11", "PrereqCivic": "CIVIC_AP_CLASSICAL_08" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_12", "PrereqCivic": "CIVIC_AP_CLASSICAL_08" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_12", "PrereqCivic": "CIVIC_AP_CLASSICAL_09" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_13", "PrereqCivic": "CIVIC_AP_CLASSICAL_09" },
|
||||
{ "Civic": "CIVIC_AP_CLASSICAL_13", "PrereqCivic": "CIVIC_AP_ANCIENT_06" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_14", "PrereqCivic": "CIVIC_AP_CLASSICAL_11" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_15", "PrereqCivic": "CIVIC_AP_CLASSICAL_11" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_16", "PrereqCivic": "CIVIC_AP_CLASSICAL_11" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_16", "PrereqCivic": "CIVIC_AP_CLASSICAL_12" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_17", "PrereqCivic": "CIVIC_AP_CLASSICAL_10" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_17", "PrereqCivic": "CIVIC_AP_MEDIEVAL_15" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_18", "PrereqCivic": "CIVIC_AP_MEDIEVAL_15" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_19", "PrereqCivic": "CIVIC_AP_MEDIEVAL_15" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_19", "PrereqCivic": "CIVIC_AP_MEDIEVAL_16" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_20", "PrereqCivic": "CIVIC_AP_MEDIEVAL_16" },
|
||||
{ "Civic": "CIVIC_AP_MEDIEVAL_20", "PrereqCivic": "CIVIC_AP_CLASSICAL_13" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_21", "PrereqCivic": "CIVIC_AP_MEDIEVAL_17" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_21", "PrereqCivic": "CIVIC_AP_MEDIEVAL_18" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_22", "PrereqCivic": "CIVIC_AP_MEDIEVAL_18" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_22", "PrereqCivic": "CIVIC_AP_MEDIEVAL_19" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_23", "PrereqCivic": "CIVIC_AP_MEDIEVAL_19" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_24", "PrereqCivic": "CIVIC_AP_MEDIEVAL_19" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_24", "PrereqCivic": "CIVIC_AP_MEDIEVAL_20" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_25", "PrereqCivic": "CIVIC_AP_RENAISSANCE_22" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_26", "PrereqCivic": "CIVIC_AP_RENAISSANCE_22" },
|
||||
{ "Civic": "CIVIC_AP_RENAISSANCE_26", "PrereqCivic": "CIVIC_AP_RENAISSANCE_23" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_27", "PrereqCivic": "CIVIC_AP_RENAISSANCE_25" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_28", "PrereqCivic": "CIVIC_AP_RENAISSANCE_25" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_29", "PrereqCivic": "CIVIC_AP_RENAISSANCE_26" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_30", "PrereqCivic": "CIVIC_AP_RENAISSANCE_26" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_31", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_27" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_32", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_29" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_33", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_28" },
|
||||
{ "Civic": "CIVIC_AP_INDUSTRIAL_33", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_29" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_34", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_31" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_37", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_31" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_37", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_33" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_35", "PrereqCivic": "CIVIC_AP_MODERN_37" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_38", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_33" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_39", "PrereqCivic": "CIVIC_AP_MODERN_37" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_39", "PrereqCivic": "CIVIC_AP_MODERN_38" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_36", "PrereqCivic": "CIVIC_AP_MODERN_39" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_40", "PrereqCivic": "CIVIC_AP_MODERN_39" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_41", "PrereqCivic": "CIVIC_AP_MODERN_39" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_42", "PrereqCivic": "CIVIC_AP_MODERN_39" },
|
||||
{ "Civic": "CIVIC_AP_ATOMIC_43", "PrereqCivic": "CIVIC_AP_MODERN_39" },
|
||||
{ "Civic": "CIVIC_AP_ATOMIC_44", "PrereqCivic": "CIVIC_AP_MODERN_39" },
|
||||
{ "Civic": "CIVIC_AP_ATOMIC_45", "PrereqCivic": "CIVIC_AP_MODERN_34" },
|
||||
{ "Civic": "CIVIC_AP_ATOMIC_46", "PrereqCivic": "CIVIC_AP_ATOMIC_43" },
|
||||
{ "Civic": "CIVIC_AP_ATOMIC_47", "PrereqCivic": "CIVIC_AP_ATOMIC_43" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_48", "PrereqCivic": "CIVIC_AP_ATOMIC_46" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_48", "PrereqCivic": "CIVIC_AP_ATOMIC_47" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_49", "PrereqCivic": "CIVIC_AP_ATOMIC_47" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_49", "PrereqCivic": "CIVIC_AP_ATOMIC_44" },
|
||||
{ "Civic": "CIVIC_AP_FUTURE_50", "PrereqCivic": "CIVIC_AP_INFORMATION_48" },
|
||||
{ "Civic": "CIVIC_AP_FUTURE_50", "PrereqCivic": "CIVIC_AP_INFORMATION_49" },
|
||||
{ "Civic": "CIVIC_AP_MODERN_38", "PrereqCivic": "CIVIC_AP_INDUSTRIAL_32" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_51", "PrereqCivic": "CIVIC_AP_ATOMIC_45" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_51", "PrereqCivic": "CIVIC_AP_ATOMIC_46" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_52", "PrereqCivic": "CIVIC_AP_INFORMATION_48" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_52", "PrereqCivic": "CIVIC_AP_INFORMATION_49" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_53", "PrereqCivic": "CIVIC_AP_INFORMATION_48" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_53", "PrereqCivic": "CIVIC_AP_INFORMATION_49" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_54", "PrereqCivic": "CIVIC_AP_INFORMATION_48" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_54", "PrereqCivic": "CIVIC_AP_INFORMATION_49" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_55", "PrereqCivic": "CIVIC_AP_INFORMATION_51" },
|
||||
{ "Civic": "CIVIC_AP_INFORMATION_55", "PrereqCivic": "CIVIC_AP_INFORMATION_48" },
|
||||
{"Civic": "CIVIC_AP_FUTURE_56", "PrereqCivic": "CIVIC_AP_FUTURE_50"},
|
||||
{"Civic": "CIVIC_AP_FUTURE_57", "PrereqCivic": "CIVIC_AP_FUTURE_50"},
|
||||
{"Civic": "CIVIC_AP_FUTURE_58", "PrereqCivic": "CIVIC_AP_FUTURE_50"},
|
||||
{"Civic": "CIVIC_AP_FUTURE_59", "PrereqCivic": "CIVIC_AP_FUTURE_50"},
|
||||
{"Civic": "CIVIC_AP_FUTURE_60", "PrereqCivic": "CIVIC_AP_FUTURE_50"}
|
||||
]
|
||||
63
worlds/civ_6/data/new_civics.json
Normal file
63
worlds/civ_6/data/new_civics.json
Normal file
@@ -0,0 +1,63 @@
|
||||
[
|
||||
{"Type": "CIVIC_AP_ANCIENT_00", "Cost": 20, "UITreeRow": 0, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "CIVIC_AP_ANCIENT_01", "Cost": 40, "UITreeRow": -2, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "CIVIC_AP_ANCIENT_02", "Cost": 40, "UITreeRow": 2, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "CIVIC_AP_ANCIENT_03", "Cost": 50, "UITreeRow": -3, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "CIVIC_AP_ANCIENT_04", "Cost": 70, "UITreeRow": 0, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "CIVIC_AP_ANCIENT_05", "Cost": 70, "UITreeRow": 1, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "CIVIC_AP_ANCIENT_06", "Cost": 50, "UITreeRow": 3, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "CIVIC_AP_CLASSICAL_07", "Cost": 110, "UITreeRow": -2, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "CIVIC_AP_CLASSICAL_08", "Cost": 110, "UITreeRow": 0, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "CIVIC_AP_CLASSICAL_09", "Cost": 110, "UITreeRow": 2, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "CIVIC_AP_CLASSICAL_10", "Cost": 120, "UITreeRow": -3, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "CIVIC_AP_CLASSICAL_11", "Cost": 175, "UITreeRow": -1, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "CIVIC_AP_CLASSICAL_12", "Cost": 175, "UITreeRow": 1, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "CIVIC_AP_CLASSICAL_13", "Cost": 120, "UITreeRow": 3, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "CIVIC_AP_MEDIEVAL_14", "Cost": 220, "UITreeRow": -2, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "CIVIC_AP_MEDIEVAL_15", "Cost": 300, "UITreeRow": -1, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "CIVIC_AP_MEDIEVAL_16", "Cost": 300, "UITreeRow": 1, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "CIVIC_AP_MEDIEVAL_17", "Cost": 340, "UITreeRow": -3, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "CIVIC_AP_MEDIEVAL_18", "Cost": 420, "UITreeRow": -1, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "CIVIC_AP_MEDIEVAL_19", "Cost": 420, "UITreeRow": 1, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "CIVIC_AP_MEDIEVAL_20", "Cost": 340, "UITreeRow": 3, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "CIVIC_AP_RENAISSANCE_21", "Cost": 440, "UITreeRow": -3, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "CIVIC_AP_RENAISSANCE_22", "Cost": 600, "UITreeRow": -1, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "CIVIC_AP_RENAISSANCE_23", "Cost": 600, "UITreeRow": 1, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "CIVIC_AP_RENAISSANCE_24", "Cost": 440, "UITreeRow": 3, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "CIVIC_AP_RENAISSANCE_25", "Cost": 720, "UITreeRow": -1, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "CIVIC_AP_RENAISSANCE_26", "Cost": 720, "UITreeRow": 1, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "CIVIC_AP_INDUSTRIAL_27", "Cost": 800, "UITreeRow": -3, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "CIVIC_AP_INDUSTRIAL_28", "Cost": 1010, "UITreeRow": -1, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "CIVIC_AP_INDUSTRIAL_29", "Cost": 1010, "UITreeRow": 0, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "CIVIC_AP_INDUSTRIAL_30", "Cost": 800, "UITreeRow": 2, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "CIVIC_AP_INDUSTRIAL_31", "Cost": 1050, "UITreeRow": -3, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "CIVIC_AP_INDUSTRIAL_32", "Cost": 1210, "UITreeRow": 2, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "CIVIC_AP_INDUSTRIAL_33", "Cost": 1210, "UITreeRow": -1, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "CIVIC_AP_MODERN_34", "Cost": 1540, "UITreeRow": -3, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_35", "Cost": 1580, "UITreeRow": -2, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_36", "Cost": 1715, "UITreeRow": -2, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_37", "Cost": 1540, "UITreeRow": -1, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_38", "Cost": 1540, "UITreeRow": 1, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_39", "Cost": 1640, "UITreeRow": -1, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_40", "Cost": 1640, "UITreeRow": 0, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_41", "Cost": 1640, "UITreeRow": 2, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_MODERN_42", "Cost": 1640, "UITreeRow": 3, "EraType": "ERA_MODERN"},
|
||||
{"Type": "CIVIC_AP_ATOMIC_43", "Cost": 2185, "UITreeRow": -1, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "CIVIC_AP_ATOMIC_44", "Cost": 2185, "UITreeRow": 2, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "CIVIC_AP_ATOMIC_45", "Cost": 1955, "UITreeRow": -3, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "CIVIC_AP_ATOMIC_46", "Cost": 2415, "UITreeRow": -1, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "CIVIC_AP_ATOMIC_47", "Cost": 2415, "UITreeRow": 1, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "CIVIC_AP_INFORMATION_48", "Cost": 2880, "UITreeRow": 0, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "CIVIC_AP_INFORMATION_49", "Cost": 2880, "UITreeRow": 2, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "CIVIC_AP_FUTURE_50", "Cost": 3200, "UITreeRow": 3, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "CIVIC_AP_INFORMATION_51", "Cost": 2880, "UITreeRow": -2, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "CIVIC_AP_INFORMATION_52", "Cost": 3000, "UITreeRow": 0, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "CIVIC_AP_INFORMATION_53", "Cost": 3000, "UITreeRow": 1, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "CIVIC_AP_INFORMATION_54", "Cost": 3000, "UITreeRow": 2, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "CIVIC_AP_INFORMATION_55", "Cost": 3100, "UITreeRow": -1, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "CIVIC_AP_FUTURE_56", "Cost": 3200, "UITreeRow": -2, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "CIVIC_AP_FUTURE_57", "Cost": 3200, "UITreeRow": -1, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "CIVIC_AP_FUTURE_58", "Cost": 3200, "UITreeRow": 0, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "CIVIC_AP_FUTURE_59", "Cost": 3200, "UITreeRow": 1, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "CIVIC_AP_FUTURE_60", "Cost": 3200, "UITreeRow": 2, "EraType": "ERA_FUTURE"}
|
||||
]
|
||||
79
worlds/civ_6/data/new_tech.json
Normal file
79
worlds/civ_6/data/new_tech.json
Normal file
@@ -0,0 +1,79 @@
|
||||
[
|
||||
{"Type": "TECH_AP_ANCIENT_00", "Cost": 25, "UITreeRow": 0, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_01", "Cost": 25, "UITreeRow": 1, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_02", "Cost": 25, "UITreeRow": 3, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_03", "Cost": 50, "UITreeRow": -3, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_04", "Cost": 50, "UITreeRow": -2, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_05", "Cost": 50, "UITreeRow": -1, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_06", "Cost": 50, "UITreeRow": 1, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_07", "Cost": 50, "UITreeRow": 0, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_08", "Cost": 80, "UITreeRow": 2, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_09", "Cost": 80, "UITreeRow": 3, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_ANCIENT_10", "Cost": 80, "UITreeRow": 4, "EraType": "ERA_ANCIENT"},
|
||||
{"Type": "TECH_AP_CLASSICAL_11", "Cost": 120, "UITreeRow": -2, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_CLASSICAL_12", "Cost": 120, "UITreeRow": 0, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_CLASSICAL_13", "Cost": 120, "UITreeRow": 1, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_CLASSICAL_14", "Cost": 120, "UITreeRow": 3, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_CLASSICAL_15", "Cost": 200, "UITreeRow": -3, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_CLASSICAL_16", "Cost": 200, "UITreeRow": -1, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_CLASSICAL_17", "Cost": 200, "UITreeRow": 2, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_CLASSICAL_18", "Cost": 200, "UITreeRow": 4, "EraType": "ERA_CLASSICAL"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_19", "Cost": 300, "UITreeRow": -2, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_20", "Cost": 300, "UITreeRow": 0, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_21", "Cost": 300, "UITreeRow": 4, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_22", "Cost": 390, "UITreeRow": -1, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_23", "Cost": 390, "UITreeRow": 1, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_24", "Cost": 390, "UITreeRow": 2, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_25", "Cost": 390, "UITreeRow": 3, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_26", "Cost": 600, "UITreeRow": -3, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_27", "Cost": 600, "UITreeRow": -2, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_28", "Cost": 600, "UITreeRow": 0, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_29", "Cost": 600, "UITreeRow": 1, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_30", "Cost": 600, "UITreeRow": 4, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_31", "Cost": 730, "UITreeRow": -3, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_32", "Cost": 730, "UITreeRow": -1, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_33", "Cost": 730, "UITreeRow": 1, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_RENAISSANCE_34", "Cost": 730, "UITreeRow": 3, "EraType": "ERA_RENAISSANCE"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_35", "Cost": 930, "UITreeRow": -2, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_36", "Cost": 930, "UITreeRow": -1, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_37", "Cost": 930, "UITreeRow": 1, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_38", "Cost": 930, "UITreeRow": 3, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_39", "Cost": 1070, "UITreeRow": -3, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_40", "Cost": 1070, "UITreeRow": -1, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_41", "Cost": 1070, "UITreeRow": 0, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_INDUSTRIAL_42", "Cost": 1070, "UITreeRow": 2, "EraType": "ERA_INDUSTRIAL"},
|
||||
{"Type": "TECH_AP_MODERN_43", "Cost": 1250, "UITreeRow": -2, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_MODERN_44", "Cost": 1250, "UITreeRow": 0, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_MODERN_45", "Cost": 1250, "UITreeRow": 1, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_MODERN_46", "Cost": 1370, "UITreeRow": -3, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_MODERN_47", "Cost": 1370, "UITreeRow": -2, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_MODERN_48", "Cost": 1370, "UITreeRow": -1, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_MODERN_49", "Cost": 1370, "UITreeRow": 2, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_ATOMIC_50", "Cost": 1480, "UITreeRow": -2, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_ATOMIC_51", "Cost": 1480, "UITreeRow": -1, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_ATOMIC_52", "Cost": 1480, "UITreeRow": 0, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_ATOMIC_53", "Cost": 1480, "UITreeRow": 1, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_ATOMIC_54", "Cost": 1480, "UITreeRow": 2, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_ATOMIC_55", "Cost": 1660, "UITreeRow": -3, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_ATOMIC_56", "Cost": 1660, "UITreeRow": 1, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_ATOMIC_57", "Cost": 1660, "UITreeRow": 2, "EraType": "ERA_ATOMIC"},
|
||||
{"Type": "TECH_AP_INFORMATION_58", "Cost": 1850, "UITreeRow": -3, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_59", "Cost": 1850, "UITreeRow": -1, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_60", "Cost": 1850, "UITreeRow": 0, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_61", "Cost": 1850, "UITreeRow": 1, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_62", "Cost": 1850, "UITreeRow": 2, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_63", "Cost": 1850, "UITreeRow": 3, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_64", "Cost": 2155, "UITreeRow": -2, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_65", "Cost": 2155, "UITreeRow": 2, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_INFORMATION_66", "Cost": 2155, "UITreeRow": 1, "EraType": "ERA_INFORMATION"},
|
||||
{"Type": "TECH_AP_MEDIEVAL_67", "Cost": 300, "UITreeRow": -3, "EraType": "ERA_MEDIEVAL"},
|
||||
{"Type": "TECH_AP_MODERN_68", "Cost": 1250, "UITreeRow": 3, "EraType": "ERA_MODERN"},
|
||||
{"Type": "TECH_AP_FUTURE_69", "Cost": 2200, "UITreeRow": -3, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "TECH_AP_FUTURE_70", "Cost": 2200, "UITreeRow": -2, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "TECH_AP_FUTURE_71", "Cost": 2200, "UITreeRow": -1, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "TECH_AP_FUTURE_72", "Cost": 2200, "UITreeRow": 0, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "TECH_AP_FUTURE_73", "Cost": 2200, "UITreeRow": 1, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "TECH_AP_FUTURE_74", "Cost": 2200, "UITreeRow": 2, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "TECH_AP_FUTURE_75", "Cost": 2500, "UITreeRow": 0, "EraType": "ERA_FUTURE"},
|
||||
{"Type": "TECH_AP_FUTURE_76", "Cost": 2600, "UITreeRow": 0, "EraType": "ERA_FUTURE"}
|
||||
]
|
||||
104
worlds/civ_6/data/new_tech_prereqs.json
Normal file
104
worlds/civ_6/data/new_tech_prereqs.json
Normal file
@@ -0,0 +1,104 @@
|
||||
[
|
||||
{"Technology": "TECH_AP_ANCIENT_06", "PrereqTech": "TECH_AP_ANCIENT_01"},
|
||||
{"Technology": "TECH_AP_ANCIENT_07", "PrereqTech": "TECH_AP_ANCIENT_00"},
|
||||
{"Technology": "TECH_AP_ANCIENT_05", "PrereqTech": "TECH_AP_ANCIENT_00"},
|
||||
{"Technology": "TECH_AP_ANCIENT_08", "PrereqTech": "TECH_AP_ANCIENT_02"},
|
||||
{"Technology": "TECH_AP_ANCIENT_09", "PrereqTech": "TECH_AP_ANCIENT_02"},
|
||||
{"Technology": "TECH_AP_ANCIENT_10", "PrereqTech": "TECH_AP_ANCIENT_02"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_15", "PrereqTech": "TECH_AP_ANCIENT_03"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_11", "PrereqTech": "TECH_AP_ANCIENT_03"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_11", "PrereqTech": "TECH_AP_ANCIENT_04"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_12", "PrereqTech": "TECH_AP_ANCIENT_07"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_13", "PrereqTech": "TECH_AP_ANCIENT_06"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_14", "PrereqTech": "TECH_AP_ANCIENT_09"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_16", "PrereqTech": "TECH_AP_CLASSICAL_12"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_17", "PrereqTech": "TECH_AP_ANCIENT_08"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_17", "PrereqTech": "TECH_AP_CLASSICAL_13"},
|
||||
{"Technology": "TECH_AP_CLASSICAL_18", "PrereqTech": "TECH_AP_ANCIENT_10"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_19", "PrereqTech": "TECH_AP_CLASSICAL_16"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_20", "PrereqTech": "TECH_AP_CLASSICAL_12"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_20", "PrereqTech": "TECH_AP_CLASSICAL_13"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_23", "PrereqTech": "TECH_AP_CLASSICAL_13"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_21", "PrereqTech": "TECH_AP_CLASSICAL_14"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_21", "PrereqTech": "TECH_AP_CLASSICAL_18"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_22", "PrereqTech": "TECH_AP_CLASSICAL_16"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_22", "PrereqTech": "TECH_AP_MEDIEVAL_20"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_25", "PrereqTech": "TECH_AP_CLASSICAL_17"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_24", "PrereqTech": "TECH_AP_CLASSICAL_17"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_27", "PrereqTech": "TECH_AP_MEDIEVAL_22"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_28", "PrereqTech": "TECH_AP_MEDIEVAL_22"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_28", "PrereqTech": "TECH_AP_MEDIEVAL_23"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_29", "PrereqTech": "TECH_AP_MEDIEVAL_20"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_29", "PrereqTech": "TECH_AP_MEDIEVAL_23"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_29", "PrereqTech": "TECH_AP_MEDIEVAL_24"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_30", "PrereqTech": "TECH_AP_MEDIEVAL_21"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_31", "PrereqTech": "TECH_AP_RENAISSANCE_26"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_32", "PrereqTech": "TECH_AP_MEDIEVAL_22"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_33", "PrereqTech": "TECH_AP_RENAISSANCE_29"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_34", "PrereqTech": "TECH_AP_MEDIEVAL_25"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_35", "PrereqTech": "TECH_AP_RENAISSANCE_31"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_35", "PrereqTech": "TECH_AP_RENAISSANCE_27"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_36", "PrereqTech": "TECH_AP_RENAISSANCE_32"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_36", "PrereqTech": "TECH_AP_RENAISSANCE_28"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_41", "PrereqTech": "TECH_AP_INDUSTRIAL_36"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_41", "PrereqTech": "TECH_AP_RENAISSANCE_33"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_38", "PrereqTech": "TECH_AP_RENAISSANCE_34"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_38", "PrereqTech": "TECH_AP_RENAISSANCE_30"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_39", "PrereqTech": "TECH_AP_INDUSTRIAL_35"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_40", "PrereqTech": "TECH_AP_INDUSTRIAL_36"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_37", "PrereqTech": "TECH_AP_RENAISSANCE_33"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_42", "PrereqTech": "TECH_AP_INDUSTRIAL_37"},
|
||||
{"Technology": "TECH_AP_INDUSTRIAL_42", "PrereqTech": "TECH_AP_INDUSTRIAL_38"},
|
||||
{"Technology": "TECH_AP_MODERN_43", "PrereqTech": "TECH_AP_INDUSTRIAL_35"},
|
||||
{"Technology": "TECH_AP_MODERN_43", "PrereqTech": "TECH_AP_INDUSTRIAL_36"},
|
||||
{"Technology": "TECH_AP_MODERN_44", "PrereqTech": "TECH_AP_INDUSTRIAL_41"},
|
||||
{"Technology": "TECH_AP_MODERN_45", "PrereqTech": "TECH_AP_INDUSTRIAL_42"},
|
||||
{"Technology": "TECH_AP_MODERN_46", "PrereqTech": "TECH_AP_INDUSTRIAL_39"},
|
||||
{"Technology": "TECH_AP_MODERN_47", "PrereqTech": "TECH_AP_INDUSTRIAL_39"},
|
||||
{"Technology": "TECH_AP_MODERN_47", "PrereqTech": "TECH_AP_MODERN_43"},
|
||||
{"Technology": "TECH_AP_MODERN_48", "PrereqTech": "TECH_AP_INDUSTRIAL_40"},
|
||||
{"Technology": "TECH_AP_MODERN_49", "PrereqTech": "TECH_AP_MODERN_45"},
|
||||
{"Technology": "TECH_AP_ATOMIC_55", "PrereqTech": "TECH_AP_MODERN_46"},
|
||||
{"Technology": "TECH_AP_ATOMIC_55", "PrereqTech": "TECH_AP_MODERN_47"},
|
||||
{"Technology": "TECH_AP_ATOMIC_50", "PrereqTech": "TECH_AP_MODERN_47"},
|
||||
{"Technology": "TECH_AP_ATOMIC_51", "PrereqTech": "TECH_AP_MODERN_47"},
|
||||
{"Technology": "TECH_AP_ATOMIC_51", "PrereqTech": "TECH_AP_MODERN_48"},
|
||||
{"Technology": "TECH_AP_ATOMIC_52", "PrereqTech": "TECH_AP_MODERN_44"},
|
||||
{"Technology": "TECH_AP_ATOMIC_52", "PrereqTech": "TECH_AP_MODERN_45"},
|
||||
{"Technology": "TECH_AP_ATOMIC_53", "PrereqTech": "TECH_AP_MODERN_45"},
|
||||
{"Technology": "TECH_AP_ATOMIC_53", "PrereqTech": "TECH_AP_MODERN_49"},
|
||||
{"Technology": "TECH_AP_ATOMIC_56", "PrereqTech": "TECH_AP_ATOMIC_52"},
|
||||
{"Technology": "TECH_AP_ATOMIC_56", "PrereqTech": "TECH_AP_ATOMIC_53"},
|
||||
{"Technology": "TECH_AP_ATOMIC_54", "PrereqTech": "TECH_AP_MODERN_49"},
|
||||
{"Technology": "TECH_AP_ATOMIC_57", "PrereqTech": "TECH_AP_ATOMIC_54"},
|
||||
{"Technology": "TECH_AP_INFORMATION_58", "PrereqTech": "TECH_AP_ATOMIC_55"},
|
||||
{"Technology": "TECH_AP_INFORMATION_64", "PrereqTech": "TECH_AP_ATOMIC_55"},
|
||||
{"Technology": "TECH_AP_INFORMATION_59", "PrereqTech": "TECH_AP_ATOMIC_50"},
|
||||
{"Technology": "TECH_AP_INFORMATION_59", "PrereqTech": "TECH_AP_ATOMIC_51"},
|
||||
{"Technology": "TECH_AP_INFORMATION_60", "PrereqTech": "TECH_AP_ATOMIC_51"},
|
||||
{"Technology": "TECH_AP_INFORMATION_60", "PrereqTech": "TECH_AP_ATOMIC_52"},
|
||||
{"Technology": "TECH_AP_INFORMATION_61", "PrereqTech": "TECH_AP_ATOMIC_56"},
|
||||
{"Technology": "TECH_AP_INFORMATION_62", "PrereqTech": "TECH_AP_ATOMIC_57"},
|
||||
{"Technology": "TECH_AP_INFORMATION_63", "PrereqTech": "TECH_AP_ATOMIC_57"},
|
||||
{"Technology": "TECH_AP_INFORMATION_65", "PrereqTech": "TECH_AP_INFORMATION_62"},
|
||||
{"Technology": "TECH_AP_INFORMATION_66", "PrereqTech": "TECH_AP_INFORMATION_61"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_67", "PrereqTech": "TECH_AP_CLASSICAL_15"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_67", "PrereqTech": "TECH_AP_CLASSICAL_16"},
|
||||
{"Technology": "TECH_AP_MEDIEVAL_23", "PrereqTech": "TECH_AP_MEDIEVAL_20"},
|
||||
{"Technology": "TECH_AP_MODERN_68", "PrereqTech": "TECH_AP_INDUSTRIAL_42"},
|
||||
{"Technology": "TECH_AP_MODERN_49", "PrereqTech": "TECH_AP_MODERN_68"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_26", "PrereqTech": "TECH_AP_MEDIEVAL_67"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_27", "PrereqTech": "TECH_AP_MEDIEVAL_67"},
|
||||
{"Technology": "TECH_AP_RENAISSANCE_27", "PrereqTech": "TECH_AP_MEDIEVAL_19"},
|
||||
{"Technology": "TECH_AP_MODERN_48", "PrereqTech": "TECH_AP_MODERN_44"},
|
||||
{"Technology": "TECH_AP_INFORMATION_64", "PrereqTech": "TECH_AP_INFORMATION_59"},
|
||||
{"Technology": "TECH_AP_INFORMATION_64", "PrereqTech": "TECH_AP_INFORMATION_60"},
|
||||
{"Technology": "TECH_AP_INFORMATION_64", "PrereqTech": "TECH_AP_INFORMATION_61"},
|
||||
{"Technology": "TECH_AP_FUTURE_69", "PrereqTech": "TECH_AP_AP60"},
|
||||
{"Technology": "TECH_AP_FUTURE_70", "PrereqTech": "TECH_AP_AP60"},
|
||||
{"Technology": "TECH_AP_FUTURE_71", "PrereqTech": "TECH_AP_AP60"},
|
||||
{"Technology": "TECH_AP_FUTURE_72", "PrereqTech": "TECH_AP_AP60"},
|
||||
{"Technology": "TECH_AP_FUTURE_73", "PrereqTech": "TECH_AP_AP60"},
|
||||
{"Technology": "TECH_AP_FUTURE_74", "PrereqTech": "TECH_AP_AP60"},
|
||||
{"Technology": "TECH_AP_FUTURE_75", "PrereqTech": "TECH_AP_AP60"},
|
||||
{"Technology": "TECH_AP_FUTURE_76", "PrereqTech": "TECH_AP_AP60"}]
|
||||
64
worlds/civ_6/data/progressive_districts.json
Normal file
64
worlds/civ_6/data/progressive_districts.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"PROGRESSIVE_CAMPUS": ["TECH_WRITING", "TECH_EDUCATION", "TECH_CHEMISTRY"],
|
||||
|
||||
"PROGRESSIVE_THEATER": [
|
||||
"CIVIC_DRAMA_POETRY",
|
||||
"CIVIC_HUMANISM",
|
||||
"TECH_RADIO"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_HOLY_SITE": ["TECH_ASTROLOGY", "CIVIC_THEOLOGY"],
|
||||
|
||||
"PROGRESSIVE_ENCAMPMENT": [
|
||||
"TECH_BRONZE_WORKING",
|
||||
"TECH_MILITARY_ENGINEERING",
|
||||
"TECH_MILITARY_SCIENCE"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_COMMERCIAL_HUB": [
|
||||
"TECH_CURRENCY",
|
||||
"TECH_BANKING",
|
||||
"TECH_ECONOMICS"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_HARBOR": [
|
||||
"TECH_CELESTIAL_NAVIGATION",
|
||||
"TECH_MASS_PRODUCTION"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_INDUSTRIAL_ZONE": [
|
||||
"TECH_APPRENTICESHIP",
|
||||
"TECH_INDUSTRIALIZATION",
|
||||
"TECH_ELECTRICITY",
|
||||
"TECH_NUCLEAR_FISSION"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_PRESERVE": ["CIVIC_MYSTICISM", "CIVIC_CONSERVATION"],
|
||||
|
||||
"PROGRESSIVE_ENTERTAINMENT_COMPLEX": [
|
||||
"CIVIC_GAMES_RECREATION",
|
||||
"CIVIC_NATURAL_HISTORY",
|
||||
"CIVIC_PROFESSIONAL_SPORTS"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_NEIGHBORHOOD": [
|
||||
"CIVIC_URBANIZATION",
|
||||
"TECH_REPLACEABLE_PARTS",
|
||||
"CIVIC_CAPITALISM"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_AERODROME": ["TECH_FLIGHT", "TECH_ADVANCED_FLIGHT"],
|
||||
|
||||
"PROGRESSIVE_DIPLOMATIC_QUARTER": [
|
||||
"TECH_MATHEMATICS",
|
||||
"CIVIC_DIPLOMATIC_SERVICE"
|
||||
],
|
||||
|
||||
"PROGRESSIVE_SPACE_PORT": [
|
||||
"TECH_ROCKETRY",
|
||||
"TECH_SATELLITES",
|
||||
"TECH_NANOTECHNOLOGY",
|
||||
"TECH_SMART_MATERIALS",
|
||||
"TECH_OFFWORLD_MISSION"
|
||||
]
|
||||
}
|
||||
15
worlds/civ_6/docs/boostsanity.md
Normal file
15
worlds/civ_6/docs/boostsanity.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## Boostsanity
|
||||
Boostsanity takes all of the Eureka & Inspiration events and makes them location checks. This feature is the one to changeup the way Civilization is played in an AP multiworld/randomizer to date. What normally are mundane tasks that are passively collected now become a novel and interesting bucket list that you need to pay attention to in order to unlock items for yourself and others!
|
||||
Boosts have logic associated with them in order to verify you can always reach the ones you need to, when you need to. One side effect of this is that when boostsanity is enabled, previously some "Useful" items are now flagged as "Progression" (Urbanization, Pottery, The Wheel, to name a few).
|
||||
|
||||
### FAQs
|
||||
- Someone sent me a tech/civic and I'm worried I won't be able to boost it anymore!
|
||||
- Fear not! The mod has been updated, and through a lot of wizardry 🧙♂️ you will be able to boost civics/techs that have already been received. Additionally the UI has been updated to show you whether they have been boosted or not after receiving them still.
|
||||
- I need to kill a unit with a slinger/archer/musketman or some other obsolete unit I can't build anymore, how can I do this??
|
||||
- Don't forget you can go into the Tech Tree and click on a Vanilla tech you've received in order to toggle it on/off. This is necessary in order to pursue some of the boosts if you receive techs in certain orders.
|
||||
- Something happened and I'm not able to unlock the boost due to game rules!
|
||||
- A few scenarios you may worry about: "Found a religion", "Make an alliance with another player", "Develop an alliance to level 2", "Build a wonder from X Era", to name a few. Any boost that is "miss-able" has been flagged as an "Excluded" location and will not ever receive a progression item. For a list of how each boost is flagged, take a look [here](../data/boosts.json).
|
||||
- I'm worried that my `PROGRESSIVE_ERA` item is going to be stuck in a boost I won't have time to complete before my maximum unlocked era ends!
|
||||
- I, too, have shared this fear. Due to the unpredictable timing of boosts and unlocking them, this could lead to a hard lock in certain scenarios. As a result, `PROGRESSIVE_ERA` items will never be located at a boost check.
|
||||
- There's too many boosts, how will I know which one's I should focus on?!
|
||||
- In order to give a little more focus to all the boosts rather than just arbitrarily picking them at random, items in both of the vanilla trees will now have an advisor icon on them if it's associated boost contains a progression item.
|
||||
53
worlds/civ_6/docs/en_Civilization VI.md
Normal file
53
worlds/civ_6/docs/en_Civilization VI.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Civlization 6 Archipelago
|
||||
|
||||
## Setup Guide
|
||||
For setup instructions go [here](./docs/setup_en.md).
|
||||
|
||||
## What does randomization do to this game?
|
||||
|
||||
In Civilization VI, the tech and civic trees are both shuffled. This presents some interesting ways to play the game in a non-standard way. If you are feeling adventurous, you can enable the `boostsanity` option in order to really change up the way you normally would play a Civ game. Details on the option can be found [here](./docs/boostsanity.md)
|
||||
|
||||
There are a few changes that the Archipelago mod introduces in order to make this playable/fun. These are detailed in the __FAQ__ section below.
|
||||
|
||||
## What is the goal of Civilization VI when randomized?
|
||||
The goal of randomized Civlization VI remains the same. Pursue any victory type you have enabled in your game settings, the one you normally go for may or may not be feasible based on how things have been changed up!
|
||||
|
||||
## Which items can be in another player's world?
|
||||
All technologies and civics can be found in another player's world.
|
||||
|
||||
## What does another world's item look like in Civilization VI?
|
||||
Each item from another world is represented as a researchable tech/civic in your normal tech/civic trees.
|
||||
|
||||
## When the player receives an item, what happens?
|
||||
A short period after receiving an item, you will get a notification indicating you have discovered the relevant tech/civic. You will also get the regular popup that details what the given item has unlocked for you.
|
||||
|
||||
## FAQs
|
||||
- Do I need the DLC to play this?
|
||||
- Yes, you need both Rise & Fall and Gathering Storm. If there is enough interest then I can eventually add support for Archipellago runs that don't require both expansions.
|
||||
|
||||
- Does this work with Multiplayer?
|
||||
- It does not and, despite my best efforts, probably won't until there's a new way for external programs to be able to interact with the game.
|
||||
|
||||
- Does my mod that reskins Barbarians as various Pro Wrestlers work with this??
|
||||
- Only one way to find out! Any mods that modify techs/civics will most likely cause issues, though.
|
||||
|
||||
- "Help! I can't see any of the items that have been sent to me!"
|
||||
- Both trees by default will show you the researchable Archipelago locations. To view the normal tree, you can click "Toggle Archipelago Tree" on the top left corner of the tree view.
|
||||
|
||||
- "Oh no! I received the Machinery tech and now instead of getting an Archer next turn, I have to wait an additional 10 turns to get a Crossbowman!"
|
||||
- Vanilla prevents you from building units of the same class from an earlier tech level after you have researched a later variant. For example, this could be problematic if someone unlocks Crossbowmen for you right out the gate since you won't be able to make Archers (which have a much lower production cost).
|
||||
|
||||
- Solution: You can now go in to the tech tree, click "Toggle Archipelago Tree" to view your unlocked techs, and then can click any tech you have unlocked to toggle whether it is currently active or not. __NOTE__: This is an experimental feature and may yield some unexpected behaviors. Please DM `@Hesto2` on Discord if you run into any issues.
|
||||
|
||||
- I enabled `progressive districts` but I have no idea techs/civics what items are locked behind progression now!
|
||||
- Any technology or civic that grants you a new building in a district (or grants you the district itself) is now locked behind a progressive item. For example, `PROGRESSIVE_CAMPUS` would give you these items in the following order:
|
||||
1. `TECH_WRITING`
|
||||
2. `TECH_EDUCATION`
|
||||
3. `TECH_CHEMISTRY`
|
||||
- If you want to see the details around each item, you can review [this file](./data/progressive_districts.json)
|
||||
|
||||
- "How does DeathLink work? Am I going to have to start a new game every time one of my friends dies??"
|
||||
- Heavens no, my fellow Archipelago appreciator. When configuring your Archipelago options for Civilization on the options page, there are several choices available for you to fine tune the way you'd like to be punished for the follies of your friends. These include: Having a random unit destroyed, losing a percentage of gold or faith, or even losing a point on your era score. If you can't make up your mind, you can elect to have any of them be selected every time a death link is sent your way.
|
||||
|
||||
- In the event you lose one of your units in combat (this means captured units don't count), then you will send a death link event to the rest of your friends.
|
||||
|
||||
111
worlds/civ_6/docs/setup_en.md
Normal file
111
worlds/civ_6/docs/setup_en.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Setup Guide for Civilization VI Archipelago
|
||||
|
||||
This guide is meant to help you get up and running with Civlization VI in your Archipelago run. Note that this requires you to have both Rise & Fall as well as Gathering Storm installed. This will not work unless both of those DLCs are enabled.
|
||||
|
||||
## Requirements
|
||||
|
||||
The following are required in order to play Civ VI in Archipelago
|
||||
|
||||
- Windows OS (Firaxis does not support the necessary tooling for Mac, Linux is yet to bet verified)
|
||||
|
||||
- Installed [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases) v0.4.5 or higher.\
|
||||
**Make sure to install the Generator if you intend to generate multiworlds.**
|
||||
- The latest version of the [Civ VI apworld](https://github.com/hesto2/civilization_vi_apworld/releases/latest).
|
||||
|
||||
- The latest version of the [Civ VI AP Mod](https://github.com/hesto2/civilization_archipelago_mod).
|
||||
|
||||
- Tuner setting enabled so the archipelago client can communicate with the game
|
||||
|
||||
## Enabling the tuner
|
||||
Depending on how you installed Civ 6 you will have to navigate to one of the following:
|
||||
- `YOUR_USER/Documents/My Games/Sid Meier's Civilization VI/AppOptions.txt`
|
||||
- `YOUR_USER/AppData/Local/Firaxis Games/Sid Meier's Civilization VI/AppOptions.txt`
|
||||
|
||||
Once you have located your `AppOptions.txt`, do a search for `Enable FireTuner`. Set `EnableTuner` to `1` instead of `0`. __NOTE__: While this is active, achievments will be disabled.
|
||||
|
||||
## Mod Installation
|
||||
|
||||
1. Download and unzip the latest release of the mod from [github](https://github.com/hesto2/civilization_archipelago_mod/releases).
|
||||
|
||||
2. Copy the folder containing the mod files to your Civ VI mods folder. On Windows, this is usually located at `C:\Users\YOUR_USER\Documents\My Games\Sid Meier's Civilization VI\Mods`
|
||||
|
||||
3. After the Archipelago host generates a game, you should be given another zip file titled `AP-{playername}....zip`. Unzip this and copy all of its contents into your mod folder.
|
||||
|
||||
4. Your finished mod folder should look something like this:
|
||||
- Civ VI Mods Directory
|
||||
- civilization_archipelago_mod
|
||||
- NewItems.xml
|
||||
- InitOptions.lua
|
||||
- Archipelago.modinfo
|
||||
- All the other mod files, etc.
|
||||
|
||||
## AP World Installation
|
||||
|
||||
1. Unzip the downloaded Civ VI apworld zip file
|
||||
2. Place the `civ6.apworld` file in your Archipelago installation's `lib/worlds` folder (Windows default to:
|
||||
`%programdata%/Archipelago`).
|
||||
|
||||
- If you have a `civ6.apworld` file from a previous version of the apworld, you **must** delete it, as it is no longer
|
||||
supported. Additionally, if there is a `civ6` folder in that folder, you **must** also delete it. Keeping
|
||||
these around will cause issues, even if multiworlds are successfully generated.
|
||||
|
||||
## Setting Up a YAML
|
||||
|
||||
All players playing Civ VI must provide the room host with a YAML file containing the settings for their world.
|
||||
A sample YAML file for Civ VI is supplied in the Civ VI apworld download. Refer to the comments in that file for
|
||||
details about what each setting does.
|
||||
|
||||
Once complete, provide the room host with your YAML file.
|
||||
|
||||
## Generating a Multiworld
|
||||
|
||||
If you're generating a multiworld game that includes Civ VI, you'll need to run it locally since the online
|
||||
generator does not yet support it. Follow these steps to generate a multiworld:
|
||||
|
||||
1. Gather all player's YAMLs. Place these YAMLs into the `Players` folder of your Archipelago installation. If the
|
||||
folder does not exist, then it must be created manually. The files here should not be compressed.
|
||||
2. Modify any local host settings for generation, as desired.
|
||||
3. Run `ArchipelagoGenerate.exe` (without `.exe` on Linux) or click `Generate` in the launcher. The generation output
|
||||
is placed in the `output` folder (usually named something like `AP_XXXXX.zip`). \* Please note that if any player in the game you want to generate plays a game that needs a ROM file to generate,
|
||||
you will need the corresponding ROM files.
|
||||
4. Unzip the `AP_XXXXX.zip` file. It should include a zip file for each player in the room playing Civ VI. Distribute each file to the appropriate player.
|
||||
5. **Delete the distributed zip files and re-zip the remaining files**. In the next section, use this archive file to
|
||||
host a room or provide it to the room host. \* If you plan to host the room on a local machine, skip this step and use the original zip file (`AP_XXXX.zip`) instead.
|
||||
|
||||
## Hosting a Room
|
||||
|
||||
If you're generating the multiworld, follow the instructions in the previous section. Once you have the zip file
|
||||
corresponding to your multiworld, follow
|
||||
[these steps](https://archipelago.gg/tutorial/Archipelago/setup/en#hosting-an-archipelago-server) to host a room. Follow
|
||||
the instructions for hosting on the website from a locally generated game or on a local machine.
|
||||
|
||||
## Connecting to a Room
|
||||
|
||||
You should have the zip file provided to you by the multiworld generator. You should also have the room's server
|
||||
name and port number from the room's host.
|
||||
|
||||
Once you do, follow these steps to connect to the room:
|
||||
|
||||
1. Unzip the folder given to you and copy its contents (should include `NewItems.xml` an `archipelago.json`, and more) into the installed mod folder.
|
||||
2. Start `ArchipelagoLauncher.exe` and choose `Civ6 Client`, which will open the text client.
|
||||
3. Connect to the room by entering the server name and port number at the top and pressing `Connect`. For rooms hosted
|
||||
on the website, this will be `archipelago.gg:<port>`, where `<port>` is the port number. If a game is hosted from the
|
||||
`ArchipelagoServer.exe` (without `.exe` on Linux), this will default to `38281` but may be changed in the `host.yaml`.
|
||||
4. Once you successfully configure and launch a game, the client should let you know it is connected and you will be ready to play!
|
||||
|
||||
## Configuring your game
|
||||
|
||||
When configuring your game, make sure to start the game in the Ancient Era and leave all settings related to starting technologies and civics as the defaults. Other than that, configure difficulty, AI, etc. as you normally would.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- If you do not see the client in the launcher, ensure you have placed the `civ6.apworld` in the correct folder (the
|
||||
`lib/worlds` folder of your Archipelago installation).
|
||||
|
||||
- If you are getting an error: `The remote computer refused the network connection`, or something else related to the client (or tuner) not being able to connect, it likely indicates the tuner is not actually enabled. One simple way to verify that it is enabled is, after completing the setup steps, to go Main Menu -> Options -> Look for an option named "Tuner" and verify it is set to "Enabled"
|
||||
|
||||
- If your game gets in a state where someone has sent you items or you have sent locations but these are not correctly replicated to the multiworld, you can run `/resync` from the Civ 6 client. This may take up to a minute depending on how many items there are.
|
||||
|
||||
|
||||
## Feedback
|
||||
In the offical [Archipelago Discord](https://discord.com/invite/8Z65BR2) under the `future-game-design` channel there is a `civilization-vi` [thread](https://discord.com/channels/731205301247803413/1235473969487024189/1235473969487024189). Feel free to ping `@hesto2` with any bugs/thoughts/complaints/wishes/jokes you may have!
|
||||
0
worlds/civ_6/requirements.txt
Normal file
0
worlds/civ_6/requirements.txt
Normal file
50
worlds/civ_6/test/TestBoostsanity.py
Normal file
50
worlds/civ_6/test/TestBoostsanity.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from Fill import distribute_items_restrictive
|
||||
from ..Data import get_boosts_data
|
||||
from . import CivVITestBase
|
||||
|
||||
|
||||
class TestBoostsanityIncluded(CivVITestBase):
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"boostsanity": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"shuffle_goody_hut_rewards": "false",
|
||||
"pre_hint_items": "all",
|
||||
}
|
||||
|
||||
def test_boosts_get_included(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive(self.multiworld)
|
||||
locations = self.multiworld.get_locations(self.player)
|
||||
found_locations = 0
|
||||
for location in locations:
|
||||
if "BOOST" in location.name != -1:
|
||||
found_locations += 1
|
||||
num_boost_locations = len(get_boosts_data())
|
||||
self.assertEqual(found_locations, num_boost_locations)
|
||||
|
||||
|
||||
class TestBoostsanityExcluded(CivVITestBase):
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"boostsanity": "false",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"shuffle_goody_hut_rewards": "false",
|
||||
"pre_hint_items": "all",
|
||||
}
|
||||
|
||||
def test_boosts_are_not_included(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive(self.multiworld)
|
||||
locations = self.multiworld.get_locations(self.player)
|
||||
found_locations = 0
|
||||
for location in locations:
|
||||
if "BOOST" in location.name != -1:
|
||||
found_locations += 1
|
||||
self.assertEqual(found_locations, 0)
|
||||
125
worlds/civ_6/test/TestGoodyHuts.py
Normal file
125
worlds/civ_6/test/TestGoodyHuts.py
Normal file
@@ -0,0 +1,125 @@
|
||||
from typing import Dict
|
||||
from BaseClasses import ItemClassification
|
||||
from Fill import distribute_items_restrictive
|
||||
from ..Items import FILLER_DISTRIBUTION, FillerItemRarity, get_filler_item_data
|
||||
from . import CivVITestBase
|
||||
|
||||
|
||||
class TestGoodyHutsIncluded(CivVITestBase):
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"shuffle_goody_hut_rewards": "true",
|
||||
"pre_hint_items": "all",
|
||||
}
|
||||
|
||||
def test_goody_huts_get_included(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive
|
||||
distribute_items_restrictive(self.multiworld)
|
||||
expected_goody_huts = 10
|
||||
found = 0
|
||||
for i in range(expected_goody_huts):
|
||||
location = self.multiworld.get_location(f"GOODY_HUT_{i + 1}", self.player)
|
||||
self.assertEqual(location.item.classification, ItemClassification.filler)
|
||||
found += 1
|
||||
self.assertEqual(found, expected_goody_huts)
|
||||
|
||||
|
||||
class TestGoodyHutsExcluded(CivVITestBase):
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"shuffle_goody_hut_rewards": "false",
|
||||
"pre_hint_items": "all",
|
||||
}
|
||||
|
||||
def test_goody_huts_are_not_included(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive
|
||||
found_goody_huts = 0
|
||||
for location in self.multiworld.get_locations(self.player):
|
||||
if location.name.startswith("GOODY_HUT_"):
|
||||
found_goody_huts += 1
|
||||
self.assertEqual(found_goody_huts, 0)
|
||||
|
||||
|
||||
class TestFillerItemsIncludedByRarity(CivVITestBase):
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"shuffle_goody_hut_rewards": "true",
|
||||
"pre_hint_items": "all",
|
||||
"boostsanity": "true"
|
||||
}
|
||||
|
||||
def test_filler_items_are_included_by_rarity(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive
|
||||
rarity_counts: Dict[FillerItemRarity, int] = {
|
||||
FillerItemRarity.COMMON: 0,
|
||||
FillerItemRarity.UNCOMMON: 0,
|
||||
FillerItemRarity.RARE: 0,
|
||||
}
|
||||
total_filler_items = 0
|
||||
for item in self.multiworld.itempool:
|
||||
if item.classification == ItemClassification.filler:
|
||||
rarity = get_filler_item_data()[item.name].rarity
|
||||
rarity_counts[rarity] += 1
|
||||
total_filler_items += 1
|
||||
|
||||
expected_counts = {
|
||||
FillerItemRarity.COMMON: 102,
|
||||
FillerItemRarity.UNCOMMON: 26,
|
||||
FillerItemRarity.RARE: 3,
|
||||
}
|
||||
|
||||
for rarity, expected in expected_counts.items():
|
||||
self.assertEqual(rarity_counts[rarity], expected, f"Expected {expected} {rarity} items, found {rarity_counts[rarity]}")
|
||||
|
||||
|
||||
|
||||
class TestFillerItemsIncludedByRarityWithoutBoostsanity(CivVITestBase):
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"shuffle_goody_hut_rewards": "true",
|
||||
"pre_hint_items": "all",
|
||||
"boostsanity": "false"
|
||||
}
|
||||
|
||||
def test_filler_items_are_included_by_rarity_without_boostsanity(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive
|
||||
rarity_counts: Dict[FillerItemRarity, int] = {
|
||||
FillerItemRarity.COMMON: 0,
|
||||
FillerItemRarity.UNCOMMON: 0,
|
||||
FillerItemRarity.RARE: 0,
|
||||
}
|
||||
total_filler_items = 0
|
||||
for item in self.multiworld.itempool:
|
||||
if item.classification == ItemClassification.filler:
|
||||
rarity = get_filler_item_data()[item.name].rarity
|
||||
rarity_counts[rarity] += 1
|
||||
total_filler_items += 1
|
||||
|
||||
expected_counts = {
|
||||
FillerItemRarity.COMMON: 7,
|
||||
FillerItemRarity.UNCOMMON: 2,
|
||||
FillerItemRarity.RARE: 1,
|
||||
}
|
||||
|
||||
for rarity, expected in expected_counts.items():
|
||||
self.assertEqual(rarity_counts[rarity], expected, f"Expected {expected} {rarity} items, found {rarity_counts[rarity]}")
|
||||
238
worlds/civ_6/test/TestRegionRequirements.py
Normal file
238
worlds/civ_6/test/TestRegionRequirements.py
Normal file
@@ -0,0 +1,238 @@
|
||||
from typing import List
|
||||
|
||||
from BaseClasses import CollectionState
|
||||
from ..Data import get_era_required_items_data
|
||||
from ..Enum import EraType
|
||||
from ..ProgressiveDistricts import convert_items_to_have_progression
|
||||
from ..Items import get_item_by_civ_name
|
||||
from . import CivVITestBase
|
||||
|
||||
|
||||
def collect_items_for_era(test: CivVITestBase, era: EraType) -> None:
|
||||
era_required_items = get_era_required_items_data()
|
||||
items = [get_item_by_civ_name(item, test.world.item_table).name for item in era_required_items[era.value]]
|
||||
test.collect_by_name(items)
|
||||
|
||||
|
||||
def collect_items_for_era_progressive(test: CivVITestBase, era: EraType) -> None:
|
||||
era_progression_items = get_era_required_items_data()
|
||||
progressive_items = convert_items_to_have_progression(
|
||||
era_progression_items[era.value])
|
||||
items = [get_item_by_civ_name(item, test.world.item_table).name for item in progressive_items]
|
||||
test.collect_by_name(items)
|
||||
|
||||
|
||||
def verify_eras_accessible(test: CivVITestBase, state: CollectionState, collect_func):
|
||||
for era in EraType:
|
||||
if era == EraType.ERA_ANCIENT:
|
||||
test.assertTrue(state.can_reach(
|
||||
era.value, "Region", test.player))
|
||||
else:
|
||||
test.assertFalse(state.can_reach(
|
||||
era.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_ANCIENT)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_CLASSICAL.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_CLASSICAL)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_MEDIEVAL.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_MEDIEVAL)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_RENAISSANCE.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_RENAISSANCE)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_INDUSTRIAL.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_INDUSTRIAL)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_MODERN.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_MODERN)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_ATOMIC.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_ATOMIC)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_INFORMATION.value, "Region", test.player))
|
||||
|
||||
collect_func(test, EraType.ERA_INFORMATION)
|
||||
test.assertTrue(state.can_reach(
|
||||
EraType.ERA_FUTURE.value, "Region", test.player))
|
||||
|
||||
|
||||
class TestNonProgressiveRegionRequirements(CivVITestBase):
|
||||
options = {
|
||||
"pre_hint_items": "all",
|
||||
"progression_style": "none",
|
||||
"death_link": "false",
|
||||
"death_link_effect": "unit_killed",
|
||||
"boostsanity": "false",
|
||||
}
|
||||
|
||||
def test_eras_are_accessible_without_progressive_districts(self) -> None:
|
||||
state = self.multiworld.state
|
||||
verify_eras_accessible(self, state, collect_items_for_era)
|
||||
|
||||
|
||||
class TestNonProgressiveRegionRequirementsWithBoostsanity(CivVITestBase):
|
||||
options = {
|
||||
"pre_hint_items": "all",
|
||||
"progression_style": "none",
|
||||
"death_link": "false",
|
||||
"death_link_effect": "unit_killed",
|
||||
"boostsanity": "true",
|
||||
}
|
||||
|
||||
def test_eras_are_accessible_without_progressive_districts(self) -> None:
|
||||
state = self.multiworld.state
|
||||
verify_eras_accessible(self, state, collect_items_for_era)
|
||||
|
||||
|
||||
class TestProgressiveDistrictRequirementsWithBoostsanity(CivVITestBase):
|
||||
options = {
|
||||
"pre_hint_items": "all",
|
||||
"progression_style": "districts_only",
|
||||
"death_link": "false",
|
||||
"death_link_effect": "unit_killed",
|
||||
"boostsanity": "true",
|
||||
}
|
||||
|
||||
def test_eras_are_accessible_with_progressive_districts(self) -> None:
|
||||
state = self.multiworld.state
|
||||
verify_eras_accessible(self, state, collect_items_for_era_progressive)
|
||||
|
||||
|
||||
class TestProgressiveDistrictRequirements(CivVITestBase):
|
||||
options = {
|
||||
"pre_hint_items": "all",
|
||||
"progression_style": "districts_only",
|
||||
"death_link": "false",
|
||||
"death_link_effect": "unit_killed",
|
||||
"boostsanity": "false",
|
||||
}
|
||||
|
||||
def test_eras_are_accessible_with_progressive_districts(self) -> None:
|
||||
state = self.multiworld.state
|
||||
verify_eras_accessible(self, state, collect_items_for_era_progressive)
|
||||
|
||||
|
||||
class TestProgressiveEraRequirements(CivVITestBase):
|
||||
options = {
|
||||
"pre_hint_items": "all",
|
||||
"progression_style": "eras_and_districts",
|
||||
"death_link": "false",
|
||||
"death_link_effect": "unit_killed"
|
||||
}
|
||||
|
||||
def test_eras_are_accessible_with_progressive_eras(self) -> None:
|
||||
state = self.multiworld.state
|
||||
self.collect_all_but(["Progressive Era"])
|
||||
|
||||
def check_eras_accessible(eras: List[EraType]):
|
||||
for era in EraType:
|
||||
if era in eras:
|
||||
self.assertTrue(state.can_reach(
|
||||
era.value, "Region", self.player))
|
||||
else:
|
||||
self.assertFalse(state.can_reach(
|
||||
era.value, "Region", self.player))
|
||||
|
||||
progresive_era_item = self.get_item_by_name("Progressive Era")
|
||||
accessible_eras = [EraType.ERA_ANCIENT]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
# Classical era requires 2 progressive era items
|
||||
self.collect(progresive_era_item)
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_CLASSICAL]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_MEDIEVAL]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_RENAISSANCE]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_INDUSTRIAL]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_MODERN]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_ATOMIC]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
# Since we collect 2 in the ancient era, information and future era have same logic requirement
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_INFORMATION]
|
||||
accessible_eras += [EraType.ERA_FUTURE]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
|
||||
class TestProgressiveEraRequirementsWithBoostsanity(CivVITestBase):
|
||||
options = {
|
||||
"pre_hint_items": "all",
|
||||
"progression_style": "eras_and_districts",
|
||||
"death_link": "false",
|
||||
"death_link_effect": "unit_killed",
|
||||
"boostsanity": "true",
|
||||
}
|
||||
|
||||
def test_eras_are_accessible_with_progressive_eras(self) -> None:
|
||||
state = self.multiworld.state
|
||||
self.collect_all_but(["Progressive Era"])
|
||||
|
||||
def check_eras_accessible(eras: List[EraType]):
|
||||
for era in EraType:
|
||||
if era in eras:
|
||||
self.assertTrue(state.can_reach(
|
||||
era.value, "Region", self.player))
|
||||
else:
|
||||
self.assertFalse(state.can_reach(
|
||||
era.value, "Region", self.player))
|
||||
|
||||
progresive_era_item = self.get_item_by_name("Progressive Era")
|
||||
accessible_eras = [EraType.ERA_ANCIENT]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
# Classical era requires 2 progressive era items
|
||||
self.collect(progresive_era_item)
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_CLASSICAL]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_MEDIEVAL]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_RENAISSANCE]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_INDUSTRIAL]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_MODERN]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_ATOMIC]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
# Since we collect 2 in the ancient era, information and future era have same logic requirement
|
||||
self.collect(progresive_era_item)
|
||||
accessible_eras += [EraType.ERA_INFORMATION]
|
||||
accessible_eras += [EraType.ERA_FUTURE]
|
||||
check_eras_accessible(accessible_eras)
|
||||
|
||||
90
worlds/civ_6/test/TestStartingHints.py
Normal file
90
worlds/civ_6/test/TestStartingHints.py
Normal file
@@ -0,0 +1,90 @@
|
||||
from BaseClasses import ItemClassification
|
||||
from Fill import distribute_items_restrictive
|
||||
from ..Enum import CivVICheckType
|
||||
from . import CivVITestBase
|
||||
|
||||
|
||||
class TestStartingHints(CivVITestBase):
|
||||
run_default_tests = False
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"pre_hint_items": "all",
|
||||
}
|
||||
|
||||
def test_all_tech_civic_items_are_hinted_default(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive(self.multiworld)
|
||||
self.world.post_fill()
|
||||
start_location_hints = self.world.options.start_location_hints.value
|
||||
for location_name, location_data in self.world.location_table.items():
|
||||
if location_data.location_type == CivVICheckType.CIVIC or location_data.location_type == CivVICheckType.TECH:
|
||||
self.assertIn(location_name, start_location_hints)
|
||||
else:
|
||||
self.assertNotIn(location_name, start_location_hints)
|
||||
|
||||
|
||||
class TestOnlyProgressionItemsHinted(CivVITestBase):
|
||||
run_default_tests = False
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"pre_hint_items": "progression_items",
|
||||
}
|
||||
|
||||
def test_only_progression_items_are_hinted(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive(self.multiworld)
|
||||
self.world.post_fill()
|
||||
start_location_hints = self.world.options.start_location_hints.value
|
||||
self.assertTrue(len(start_location_hints) > 0)
|
||||
for hint in start_location_hints:
|
||||
location_data = self.world.get_location(hint)
|
||||
self.assertTrue(location_data.item.classification == ItemClassification.progression)
|
||||
|
||||
|
||||
class TestNoJunkItemsHinted(CivVITestBase):
|
||||
run_default_tests = False
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"pre_hint_items": "no_junk",
|
||||
}
|
||||
|
||||
def test_no_junk_items_are_hinted(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive(self.multiworld)
|
||||
self.world.post_fill()
|
||||
start_location_hints = self.world.options.start_location_hints.value
|
||||
self.assertTrue(len(start_location_hints) > 0)
|
||||
for hint in start_location_hints:
|
||||
location_data = self.world.get_location(hint)
|
||||
self.assertTrue(location_data.item.classification == ItemClassification.progression or location_data.item.classification == ItemClassification.useful)
|
||||
|
||||
|
||||
class TestNoItemsHinted(CivVITestBase):
|
||||
run_default_tests = False
|
||||
auto_construct = False
|
||||
options = {
|
||||
"progressive_eras": "true",
|
||||
"death_link": "true",
|
||||
"death_link_effect": "unit_killed",
|
||||
"progressive_districts": "true",
|
||||
"pre_hint_items": "none",
|
||||
}
|
||||
|
||||
def test_no_items_are_hinted(self) -> None:
|
||||
self.world_setup()
|
||||
distribute_items_restrictive(self.multiworld)
|
||||
self.world.post_fill()
|
||||
start_location_hints = self.world.options.start_location_hints.value
|
||||
self.assertEqual(len(start_location_hints), 0)
|
||||
8
worlds/civ_6/test/__init__.py
Normal file
8
worlds/civ_6/test/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from typing import ClassVar
|
||||
|
||||
from test.bases import WorldTestBase
|
||||
|
||||
|
||||
class CivVITestBase(WorldTestBase):
|
||||
game = "Civilization VI"
|
||||
player: ClassVar[int] = 1
|
||||
Reference in New Issue
Block a user