SC2: UI update, Relegate No Build Option, and Filler Item Update (#606)
This commit is contained in:
parent
f5dc39ddf0
commit
0dd67f40ba
|
@ -36,7 +36,7 @@ nest_asyncio.apply()
|
||||||
|
|
||||||
|
|
||||||
class StarcraftClientProcessor(ClientCommandProcessor):
|
class StarcraftClientProcessor(ClientCommandProcessor):
|
||||||
ctx: Context
|
ctx: SC2Context
|
||||||
|
|
||||||
def _cmd_disable_mission_check(self) -> bool:
|
def _cmd_disable_mission_check(self) -> bool:
|
||||||
"""Disables the check to see if a mission is available to play. Meant for co-op runs where one player can play
|
"""Disables the check to see if a mission is available to play. Meant for co-op runs where one player can play
|
||||||
|
@ -74,7 +74,7 @@ class StarcraftClientProcessor(ClientCommandProcessor):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Context(CommonContext):
|
class SC2Context(CommonContext):
|
||||||
command_processor = StarcraftClientProcessor
|
command_processor = StarcraftClientProcessor
|
||||||
game = "Starcraft 2 Wings of Liberty"
|
game = "Starcraft 2 Wings of Liberty"
|
||||||
items_handling = 0b111
|
items_handling = 0b111
|
||||||
|
@ -89,10 +89,12 @@ class Context(CommonContext):
|
||||||
announcement_pos = 0
|
announcement_pos = 0
|
||||||
sc2_run_task: typing.Optional[asyncio.Task] = None
|
sc2_run_task: typing.Optional[asyncio.Task] = None
|
||||||
missions_unlocked = False
|
missions_unlocked = False
|
||||||
|
current_tooltip = None
|
||||||
|
last_loc_list = None
|
||||||
|
|
||||||
async def server_auth(self, password_requested: bool = False):
|
async def server_auth(self, password_requested: bool = False):
|
||||||
if password_requested and not self.password:
|
if password_requested and not self.password:
|
||||||
await super(Context, self).server_auth(password_requested)
|
await super(SC2Context, self).server_auth(password_requested)
|
||||||
if not self.auth:
|
if not self.auth:
|
||||||
logger.info('Enter slot name:')
|
logger.info('Enter slot name:')
|
||||||
self.auth = await self.console_input()
|
self.auth = await self.console_input()
|
||||||
|
@ -105,6 +107,10 @@ class Context(CommonContext):
|
||||||
self.all_in_choice = args["slot_data"]["all_in_map"]
|
self.all_in_choice = args["slot_data"]["all_in_map"]
|
||||||
slot_req_table = args["slot_data"]["mission_req"]
|
slot_req_table = args["slot_data"]["mission_req"]
|
||||||
self.mission_req_table = {}
|
self.mission_req_table = {}
|
||||||
|
# Compatibility for 0.3.2 server data.
|
||||||
|
if "category" not in next(iter(slot_req_table)):
|
||||||
|
for i, mission_data in enumerate(slot_req_table.values()):
|
||||||
|
mission_data["category"] = wol_default_categories[i]
|
||||||
for mission in slot_req_table:
|
for mission in slot_req_table:
|
||||||
self.mission_req_table[mission] = MissionInfo(**slot_req_table[mission])
|
self.mission_req_table[mission] = MissionInfo(**slot_req_table[mission])
|
||||||
|
|
||||||
|
@ -119,19 +125,53 @@ class Context(CommonContext):
|
||||||
self.announcements.append(args["data"])
|
self.announcements.append(args["data"])
|
||||||
|
|
||||||
def run_gui(self):
|
def run_gui(self):
|
||||||
from kvui import GameManager
|
from kvui import GameManager, HoverBehavior, ServerToolTip, fade_in_animation
|
||||||
|
from kivy.app import App
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.uix.tabbedpanel import TabbedPanelItem
|
from kivy.uix.tabbedpanel import TabbedPanelItem
|
||||||
from kivy.uix.gridlayout import GridLayout
|
from kivy.uix.gridlayout import GridLayout
|
||||||
from kivy.lang import Builder
|
from kivy.lang import Builder
|
||||||
from kivy.uix.label import Label
|
from kivy.uix.label import Label
|
||||||
from kivy.uix.button import Button
|
from kivy.uix.button import Button
|
||||||
|
from kivy.uix.floatlayout import FloatLayout
|
||||||
|
from kivy.properties import StringProperty
|
||||||
|
|
||||||
import Utils
|
import Utils
|
||||||
|
|
||||||
class MissionButton(Button):
|
class HoverableButton(HoverBehavior, Button):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class MissionButton(HoverableButton):
|
||||||
|
tooltip_text = StringProperty("Test")
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(HoverableButton, self).__init__(*args, **kwargs)
|
||||||
|
self.layout = FloatLayout()
|
||||||
|
self.popuplabel = ServerToolTip(text=self.text)
|
||||||
|
self.layout.add_widget(self.popuplabel)
|
||||||
|
|
||||||
|
def on_enter(self):
|
||||||
|
self.popuplabel.text = self.tooltip_text
|
||||||
|
|
||||||
|
if self.ctx.current_tooltip:
|
||||||
|
App.get_running_app().root.remove_widget(self.ctx.current_tooltip)
|
||||||
|
|
||||||
|
if self.tooltip_text == "":
|
||||||
|
self.ctx.current_tooltip = None
|
||||||
|
else:
|
||||||
|
App.get_running_app().root.add_widget(self.layout)
|
||||||
|
self.ctx.current_tooltip = self.layout
|
||||||
|
|
||||||
|
def on_leave(self):
|
||||||
|
if self.ctx.current_tooltip:
|
||||||
|
App.get_running_app().root.remove_widget(self.ctx.current_tooltip)
|
||||||
|
|
||||||
|
self.ctx.current_tooltip = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ctx(self) -> CommonContext:
|
||||||
|
return App.get_running_app().ctx
|
||||||
|
|
||||||
class MissionLayout(GridLayout):
|
class MissionLayout(GridLayout):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -148,6 +188,9 @@ class Context(CommonContext):
|
||||||
mission_panel = None
|
mission_panel = None
|
||||||
last_checked_locations = {}
|
last_checked_locations = {}
|
||||||
mission_id_to_button = {}
|
mission_id_to_button = {}
|
||||||
|
launching = False
|
||||||
|
refresh_from_launching = True
|
||||||
|
first_check = True
|
||||||
|
|
||||||
def __init__(self, ctx):
|
def __init__(self, ctx):
|
||||||
super().__init__(ctx)
|
super().__init__(ctx)
|
||||||
|
@ -165,49 +208,87 @@ class Context(CommonContext):
|
||||||
return container
|
return container
|
||||||
|
|
||||||
def build_mission_table(self, dt):
|
def build_mission_table(self, dt):
|
||||||
self.mission_panel.clear_widgets()
|
if (not self.launching and (not self.last_checked_locations == self.ctx.checked_locations or
|
||||||
|
not self.refresh_from_launching)) or self.first_check:
|
||||||
|
self.refresh_from_launching = True
|
||||||
|
|
||||||
if self.ctx.mission_req_table:
|
self.mission_panel.clear_widgets()
|
||||||
self.mission_id_to_button = {}
|
|
||||||
categories = {}
|
|
||||||
available_missions = []
|
|
||||||
unfinished_missions = calc_unfinished_missions(self.ctx.checked_locations, self.ctx.mission_req_table,
|
|
||||||
self.ctx, available_missions=available_missions)
|
|
||||||
|
|
||||||
self.last_checked_locations = self.ctx.checked_locations
|
if self.ctx.mission_req_table:
|
||||||
|
self.last_checked_locations = self.ctx.checked_locations.copy()
|
||||||
|
self.first_check = False
|
||||||
|
|
||||||
# separate missions into categories
|
self.mission_id_to_button = {}
|
||||||
for mission in self.ctx.mission_req_table:
|
categories = {}
|
||||||
if not self.ctx.mission_req_table[mission].category in categories:
|
available_missions = []
|
||||||
categories[self.ctx.mission_req_table[mission].category] = []
|
unfinished_locations = initialize_blank_mission_dict(self.ctx.mission_req_table)
|
||||||
|
unfinished_missions = calc_unfinished_missions(self.ctx.checked_locations,
|
||||||
|
self.ctx.mission_req_table,
|
||||||
|
self.ctx, available_missions=available_missions,
|
||||||
|
unfinished_locations=unfinished_locations)
|
||||||
|
|
||||||
categories[self.ctx.mission_req_table[mission].category].append(mission)
|
# separate missions into categories
|
||||||
|
for mission in self.ctx.mission_req_table:
|
||||||
|
if not self.ctx.mission_req_table[mission].category in categories:
|
||||||
|
categories[self.ctx.mission_req_table[mission].category] = []
|
||||||
|
|
||||||
for category in categories:
|
categories[self.ctx.mission_req_table[mission].category].append(mission)
|
||||||
category_panel = MissionCategory()
|
|
||||||
category_panel.add_widget(Label(text=category, size_hint_y=None, height=50, outline_width=1))
|
|
||||||
|
|
||||||
for mission in categories[category]:
|
for category in categories:
|
||||||
text = mission
|
category_panel = MissionCategory()
|
||||||
|
category_panel.add_widget(Label(text=category, size_hint_y=None, height=50, outline_width=1))
|
||||||
|
|
||||||
if mission in unfinished_missions:
|
# Map is completed
|
||||||
text = f"[color=6495ED]{text}[/color]"
|
for mission in categories[category]:
|
||||||
elif mission in available_missions:
|
text = mission
|
||||||
text = f"[color=FFFFFF]{text}[/color]"
|
tooltip = ""
|
||||||
else:
|
|
||||||
text = f"[color=a9a9a9]{text}[/color]"
|
|
||||||
|
|
||||||
mission_button = MissionButton(text=text, size_hint_y=None, height=50)
|
# Map has uncollected locations
|
||||||
mission_button.bind(on_press=self.mission_callback)
|
if mission in unfinished_missions:
|
||||||
self.mission_id_to_button[self.ctx.mission_req_table[mission].id] = mission_button
|
text = f"[color=6495ED]{text}[/color]"
|
||||||
category_panel.add_widget(mission_button)
|
|
||||||
|
|
||||||
category_panel.add_widget(Label(text=""))
|
tooltip = f"Uncollected locations:\n"
|
||||||
self.mission_panel.add_widget(category_panel)
|
tooltip += "\n".join(location for location in unfinished_locations[mission])
|
||||||
|
elif mission in available_missions:
|
||||||
|
text = f"[color=FFFFFF]{text}[/color]"
|
||||||
|
# Map requirements not met
|
||||||
|
else:
|
||||||
|
text = f"[color=a9a9a9]{text}[/color]"
|
||||||
|
tooltip = f"Requires: "
|
||||||
|
if len(self.ctx.mission_req_table[mission].required_world) > 0:
|
||||||
|
tooltip += ", ".join(list(self.ctx.mission_req_table)[req_mission-1] for
|
||||||
|
req_mission in
|
||||||
|
self.ctx.mission_req_table[mission].required_world)
|
||||||
|
|
||||||
|
if self.ctx.mission_req_table[mission].number > 0:
|
||||||
|
tooltip += " and "
|
||||||
|
if self.ctx.mission_req_table[mission].number > 0:
|
||||||
|
tooltip += f"{self.ctx.mission_req_table[mission].number} missions completed"
|
||||||
|
|
||||||
|
mission_button = MissionButton(text=text, size_hint_y=None, height=50)
|
||||||
|
mission_button.tooltip_text = tooltip
|
||||||
|
mission_button.bind(on_press=self.mission_callback)
|
||||||
|
self.mission_id_to_button[self.ctx.mission_req_table[mission].id] = mission_button
|
||||||
|
category_panel.add_widget(mission_button)
|
||||||
|
|
||||||
|
category_panel.add_widget(Label(text=""))
|
||||||
|
self.mission_panel.add_widget(category_panel)
|
||||||
|
|
||||||
|
elif self.launching:
|
||||||
|
self.refresh_from_launching = False
|
||||||
|
|
||||||
|
self.mission_panel.clear_widgets()
|
||||||
|
self.mission_panel.add_widget(Label(text="Launching Mission"))
|
||||||
|
|
||||||
def mission_callback(self, button):
|
def mission_callback(self, button):
|
||||||
self.ctx.play_mission(list(self.mission_id_to_button.keys())
|
if not self.launching:
|
||||||
[list(self.mission_id_to_button.values()).index(button)])
|
self.ctx.play_mission(list(self.mission_id_to_button.keys())
|
||||||
|
[list(self.mission_id_to_button.values()).index(button)])
|
||||||
|
self.launching = True
|
||||||
|
Clock.schedule_once(self.finish_launching, 10)
|
||||||
|
|
||||||
|
def finish_launching(self, dt):
|
||||||
|
self.launching = False
|
||||||
|
|
||||||
self.ui = SC2Manager(self)
|
self.ui = SC2Manager(self)
|
||||||
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI")
|
||||||
|
@ -215,7 +296,7 @@ class Context(CommonContext):
|
||||||
Builder.load_file(Utils.local_path(os.path.dirname(SC2WoLWorld.__file__), "Starcraft2.kv"))
|
Builder.load_file(Utils.local_path(os.path.dirname(SC2WoLWorld.__file__), "Starcraft2.kv"))
|
||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
await super(Context, self).shutdown()
|
await super(SC2Context, self).shutdown()
|
||||||
if self.sc2_run_task:
|
if self.sc2_run_task:
|
||||||
self.sc2_run_task.cancel()
|
self.sc2_run_task.cancel()
|
||||||
|
|
||||||
|
@ -243,7 +324,7 @@ async def main():
|
||||||
parser.add_argument('--name', default=None, help="Slot Name to connect as.")
|
parser.add_argument('--name', default=None, help="Slot Name to connect as.")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
ctx = Context(args.connect, args.password)
|
ctx = SC2Context(args.connect, args.password)
|
||||||
ctx.auth = args.name
|
ctx.auth = args.name
|
||||||
if ctx.server_task is None:
|
if ctx.server_task is None:
|
||||||
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop")
|
||||||
|
@ -267,6 +348,13 @@ maps_table = [
|
||||||
"ap_tvalerian01", "ap_tvalerian02a", "ap_tvalerian02b", "ap_tvalerian03"
|
"ap_tvalerian01", "ap_tvalerian02a", "ap_tvalerian02b", "ap_tvalerian03"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
wol_default_categories = [
|
||||||
|
"Mar Sara", "Mar Sara", "Mar Sara", "Colonist", "Colonist", "Colonist", "Colonist",
|
||||||
|
"Artifact", "Artifact", "Artifact", "Artifact", "Artifact", "Covert", "Covert", "Covert", "Covert",
|
||||||
|
"Rebellion", "Rebellion", "Rebellion", "Rebellion", "Rebellion", "Prophecy", "Prophecy", "Prophecy", "Prophecy",
|
||||||
|
"Char", "Char", "Char", "Char"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def calculate_items(items):
|
def calculate_items(items):
|
||||||
unit_unlocks = 0
|
unit_unlocks = 0
|
||||||
|
@ -279,6 +367,7 @@ def calculate_items(items):
|
||||||
protoss_unlock = 0
|
protoss_unlock = 0
|
||||||
minerals = 0
|
minerals = 0
|
||||||
vespene = 0
|
vespene = 0
|
||||||
|
supply = 0
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
data = lookup_id_to_name[item.item]
|
data = lookup_id_to_name[item.item]
|
||||||
|
@ -303,9 +392,11 @@ def calculate_items(items):
|
||||||
minerals += item_table[data].number
|
minerals += item_table[data].number
|
||||||
elif item_table[data].type == "Vespene":
|
elif item_table[data].type == "Vespene":
|
||||||
vespene += item_table[data].number
|
vespene += item_table[data].number
|
||||||
|
elif item_table[data].type == "Supply":
|
||||||
|
supply += item_table[data].number
|
||||||
|
|
||||||
return [unit_unlocks, upgrade_unlocks, armory1_unlocks, armory2_unlocks, building_unlocks, merc_unlocks,
|
return [unit_unlocks, upgrade_unlocks, armory1_unlocks, armory2_unlocks, building_unlocks, merc_unlocks,
|
||||||
lab_unlocks, protoss_unlock, minerals, vespene]
|
lab_unlocks, protoss_unlock, minerals, vespene, supply]
|
||||||
|
|
||||||
|
|
||||||
def calc_difficulty(difficulty):
|
def calc_difficulty(difficulty):
|
||||||
|
@ -321,7 +412,7 @@ def calc_difficulty(difficulty):
|
||||||
return 'X'
|
return 'X'
|
||||||
|
|
||||||
|
|
||||||
async def starcraft_launch(ctx: Context, mission_id):
|
async def starcraft_launch(ctx: SC2Context, mission_id):
|
||||||
ctx.rec_announce_pos = len(ctx.items_rec_to_announce)
|
ctx.rec_announce_pos = len(ctx.items_rec_to_announce)
|
||||||
ctx.sent_announce_pos = len(ctx.items_sent_to_announce)
|
ctx.sent_announce_pos = len(ctx.items_sent_to_announce)
|
||||||
ctx.announcements_pos = len(ctx.announcements)
|
ctx.announcements_pos = len(ctx.announcements)
|
||||||
|
@ -343,14 +434,14 @@ class ArchipelagoBot(sc2.bot_ai.BotAI):
|
||||||
sixth_bonus = False
|
sixth_bonus = False
|
||||||
seventh_bonus = False
|
seventh_bonus = False
|
||||||
eight_bonus = False
|
eight_bonus = False
|
||||||
ctx: Context = None
|
ctx: SC2Context = None
|
||||||
mission_id = 0
|
mission_id = 0
|
||||||
|
|
||||||
can_read_game = False
|
can_read_game = False
|
||||||
|
|
||||||
last_received_update = 0
|
last_received_update = 0
|
||||||
|
|
||||||
def __init__(self, ctx: Context, mission_id):
|
def __init__(self, ctx: SC2Context, mission_id):
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
self.mission_id = mission_id
|
self.mission_id = mission_id
|
||||||
|
|
||||||
|
@ -361,11 +452,11 @@ class ArchipelagoBot(sc2.bot_ai.BotAI):
|
||||||
if iteration == 0:
|
if iteration == 0:
|
||||||
start_items = calculate_items(self.ctx.items_received)
|
start_items = calculate_items(self.ctx.items_received)
|
||||||
difficulty = calc_difficulty(self.ctx.difficulty)
|
difficulty = calc_difficulty(self.ctx.difficulty)
|
||||||
await self.chat_send("ArchipelagoLoad {} {} {} {} {} {} {} {} {} {} {} {}".format(
|
await self.chat_send("ArchipelagoLoad {} {} {} {} {} {} {} {} {} {} {} {} {}".format(
|
||||||
difficulty,
|
difficulty,
|
||||||
start_items[0], start_items[1], start_items[2], start_items[3], start_items[4],
|
start_items[0], start_items[1], start_items[2], start_items[3], start_items[4],
|
||||||
start_items[5], start_items[6], start_items[7], start_items[8], start_items[9],
|
start_items[5], start_items[6], start_items[7], start_items[8], start_items[9],
|
||||||
self.ctx.all_in_choice))
|
self.ctx.all_in_choice, start_items[10]))
|
||||||
self.last_received_update = len(self.ctx.items_received)
|
self.last_received_update = len(self.ctx.items_received)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -141,8 +141,9 @@ item_table = {
|
||||||
"Void Ray": ItemData(707 + SC2WOL_ITEM_ID_OFFSET, "Protoss", 7, progression=True),
|
"Void Ray": ItemData(707 + SC2WOL_ITEM_ID_OFFSET, "Protoss", 7, progression=True),
|
||||||
"Carrier": ItemData(708 + SC2WOL_ITEM_ID_OFFSET, "Protoss", 8, progression=True),
|
"Carrier": ItemData(708 + SC2WOL_ITEM_ID_OFFSET, "Protoss", 8, progression=True),
|
||||||
|
|
||||||
"+5 Starting Minerals": ItemData(800+SC2WOL_ITEM_ID_OFFSET, "Minerals", 5, quantity=0, never_exclude=False),
|
"+15 Starting Minerals": ItemData(800+SC2WOL_ITEM_ID_OFFSET, "Minerals", 15, quantity=0, never_exclude=False),
|
||||||
"+5 Starting Vespene": ItemData(801+SC2WOL_ITEM_ID_OFFSET, "Vespene", 5, quantity=0, never_exclude=False)
|
"+15 Starting Vespene": ItemData(801+SC2WOL_ITEM_ID_OFFSET, "Vespene", 15, quantity=0, never_exclude=False),
|
||||||
|
"+2 Starting Supply": ItemData(802+SC2WOL_ITEM_ID_OFFSET, "Supply", 2, quantity=0, never_exclude=False),
|
||||||
}
|
}
|
||||||
|
|
||||||
basic_unit: typing.Tuple[str, ...] = (
|
basic_unit: typing.Tuple[str, ...] = (
|
||||||
|
@ -165,8 +166,8 @@ item_name_groups["Missions"] = ["Beat Liberation Day", "Beat The Outlaws", "Beat
|
||||||
"Beat Media Blitz", "Beat Piercing the Shroud"]
|
"Beat Media Blitz", "Beat Piercing the Shroud"]
|
||||||
|
|
||||||
filler_items: typing.Tuple[str, ...] = (
|
filler_items: typing.Tuple[str, ...] = (
|
||||||
'+5 Starting Minerals',
|
'+15 Starting Minerals',
|
||||||
'+5 Starting Vespene'
|
'+15 Starting Vespene'
|
||||||
)
|
)
|
||||||
|
|
||||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in get_full_item_list().items() if data.code}
|
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in get_full_item_list().items() if data.code}
|
|
@ -24,10 +24,10 @@ class FillMission(NamedTuple):
|
||||||
type: str
|
type: str
|
||||||
connect_to: List[int] # -1 connects to Menu
|
connect_to: List[int] # -1 connects to Menu
|
||||||
category: str
|
category: str
|
||||||
number: int = 0 # number of worlds need beaten
|
number: int = 0 # number of worlds need beaten
|
||||||
completion_critical: bool = False # missions needed to beat game
|
completion_critical: bool = False # missions needed to beat game
|
||||||
or_requirements: bool = False # true if the requirements should be or-ed instead of and-ed
|
or_requirements: bool = False # true if the requirements should be or-ed instead of and-ed
|
||||||
|
relegate: bool = False # true if this is a slot no build missions should be relegated to.
|
||||||
|
|
||||||
|
|
||||||
vanilla_shuffle_order = [
|
vanilla_shuffle_order = [
|
||||||
|
@ -37,7 +37,7 @@ vanilla_shuffle_order = [
|
||||||
FillMission("easy", [2], "Colonist"),
|
FillMission("easy", [2], "Colonist"),
|
||||||
FillMission("medium", [3], "Colonist"),
|
FillMission("medium", [3], "Colonist"),
|
||||||
FillMission("hard", [4], "Colonist", number=7),
|
FillMission("hard", [4], "Colonist", number=7),
|
||||||
FillMission("hard", [4], "Colonist", number=7),
|
FillMission("hard", [4], "Colonist", number=7, relegate=True),
|
||||||
FillMission("easy", [2], "Artifact", completion_critical=True),
|
FillMission("easy", [2], "Artifact", completion_critical=True),
|
||||||
FillMission("medium", [7], "Artifact", number=8, completion_critical=True),
|
FillMission("medium", [7], "Artifact", number=8, completion_critical=True),
|
||||||
FillMission("hard", [8], "Artifact", number=11, completion_critical=True),
|
FillMission("hard", [8], "Artifact", number=11, completion_critical=True),
|
||||||
|
@ -45,17 +45,17 @@ vanilla_shuffle_order = [
|
||||||
FillMission("hard", [10], "Artifact", completion_critical=True),
|
FillMission("hard", [10], "Artifact", completion_critical=True),
|
||||||
FillMission("medium", [2], "Covert", number=4),
|
FillMission("medium", [2], "Covert", number=4),
|
||||||
FillMission("medium", [12], "Covert"),
|
FillMission("medium", [12], "Covert"),
|
||||||
FillMission("hard", [13], "Covert", number=8),
|
FillMission("hard", [13], "Covert", number=8, relegate=True),
|
||||||
FillMission("hard", [13], "Covert", number=8),
|
FillMission("hard", [13], "Covert", number=8, relegate=True),
|
||||||
FillMission("medium", [2], "Rebellion", number=6),
|
FillMission("medium", [2], "Rebellion", number=6),
|
||||||
FillMission("hard", [16], "Rebellion"),
|
FillMission("hard", [16], "Rebellion"),
|
||||||
FillMission("hard", [17], "Rebellion"),
|
FillMission("hard", [17], "Rebellion"),
|
||||||
FillMission("hard", [18], "Rebellion"),
|
FillMission("hard", [18], "Rebellion"),
|
||||||
FillMission("hard", [19], "Rebellion"),
|
FillMission("hard", [19], "Rebellion", relegate=True),
|
||||||
FillMission("medium", [8], "Prophecy"),
|
FillMission("medium", [8], "Prophecy"),
|
||||||
FillMission("hard", [21], "Prophecy"),
|
FillMission("hard", [21], "Prophecy"),
|
||||||
FillMission("hard", [22], "Prophecy"),
|
FillMission("hard", [22], "Prophecy"),
|
||||||
FillMission("hard", [23], "Prophecy"),
|
FillMission("hard", [23], "Prophecy", relegate=True),
|
||||||
FillMission("hard", [11], "Char", completion_critical=True),
|
FillMission("hard", [11], "Char", completion_critical=True),
|
||||||
FillMission("hard", [25], "Char", completion_critical=True),
|
FillMission("hard", [25], "Char", completion_critical=True),
|
||||||
FillMission("hard", [25], "Char", completion_critical=True),
|
FillMission("hard", [25], "Char", completion_critical=True),
|
||||||
|
|
|
@ -38,17 +38,25 @@ class AllInMap(Choice):
|
||||||
class MissionOrder(Choice):
|
class MissionOrder(Choice):
|
||||||
"""Determines the order the missions are played in.
|
"""Determines the order the missions are played in.
|
||||||
Vanilla: Keeps the standard mission order and branching from the WoL Campaign.
|
Vanilla: Keeps the standard mission order and branching from the WoL Campaign.
|
||||||
Vanilla Shuffled: Keeps same branching paths from the WoL Campaign but randomizes the order of missions within"""
|
Vanilla Shuffled: Keeps same branching paths from the WoL Campaign but randomizes the order of missions within."""
|
||||||
display_name = "Mission Order"
|
display_name = "Mission Order"
|
||||||
option_vanilla = 0
|
option_vanilla = 0
|
||||||
option_vanilla_shuffled = 1
|
option_vanilla_shuffled = 1
|
||||||
|
|
||||||
|
|
||||||
class ShuffleProtoss(DefaultOnToggle):
|
class ShuffleProtoss(DefaultOnToggle):
|
||||||
"""Determines if the 3 protoss missions are included in the shuffle if Vanilla Shuffled is enabled. If this is
|
"""Determines if the 3 protoss missions are included in the shuffle if Vanilla Shuffled is enabled. If this is
|
||||||
not the 3 protoss missions will stay in their vanilla order in the mission order making them optional to complete
|
not the 3 protoss missions will stay in their vanilla order in the mission order making them optional to complete
|
||||||
the game."""
|
the game."""
|
||||||
display_name = "Shuffle Protoss Missions"
|
display_name = "Shuffle Protoss Missions"
|
||||||
|
|
||||||
|
|
||||||
|
class RelegateNoBuildMissions(DefaultOnToggle):
|
||||||
|
"""If enabled, all no build missions besides the needed first one will be placed at the end of optional routes so
|
||||||
|
that none of them become required to complete the game. Only takes effect if mission order is not set to vanilla."""
|
||||||
|
display_name = "Relegate No-Build Missions"
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
sc2wol_options: Dict[str, Option] = {
|
sc2wol_options: Dict[str, Option] = {
|
||||||
"game_difficulty": GameDifficulty,
|
"game_difficulty": GameDifficulty,
|
||||||
|
@ -56,7 +64,8 @@ sc2wol_options: Dict[str, Option] = {
|
||||||
"bunker_upgrade": BunkerUpgrade,
|
"bunker_upgrade": BunkerUpgrade,
|
||||||
"all_in_map": AllInMap,
|
"all_in_map": AllInMap,
|
||||||
"mission_order": MissionOrder,
|
"mission_order": MissionOrder,
|
||||||
"shuffle_protoss": ShuffleProtoss
|
"shuffle_protoss": ShuffleProtoss,
|
||||||
|
"relegate_no_build": RelegateNoBuildMissions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,8 @@ def create_regions(world: MultiWorld, player: int, locations: Tuple[LocationData
|
||||||
for mission in vanilla_shuffle_order:
|
for mission in vanilla_shuffle_order:
|
||||||
if mission.type == "all_in":
|
if mission.type == "all_in":
|
||||||
missions.append("All-In")
|
missions.append("All-In")
|
||||||
|
elif get_option_value(world, player, "relegate_no_build") and mission.relegate:
|
||||||
|
missions.append("no_build")
|
||||||
else:
|
else:
|
||||||
missions.append(mission.type)
|
missions.append(mission.type)
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ class SC2WoLWorld(World):
|
||||||
|
|
||||||
game = "Starcraft 2 Wings of Liberty"
|
game = "Starcraft 2 Wings of Liberty"
|
||||||
web = Starcraft2WoLWebWorld()
|
web = Starcraft2WoLWebWorld()
|
||||||
|
data_version = 2
|
||||||
|
|
||||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||||
location_name_to_id = {location.name: location.code for location in get_locations(None, None)}
|
location_name_to_id = {location.name: location.code for location in get_locations(None, None)}
|
||||||
|
|
Loading…
Reference in New Issue