Skip to content

Commit

Permalink
Merge branch 'sc2-next' of https://github.com/Ziktofel/Archipelago in…
Browse files Browse the repository at this point in the history
…to sc2-next
  • Loading branch information
Salzkorn committed Jul 27, 2024
2 parents c751999 + 34bd4ac commit af3641c
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 27 deletions.
2 changes: 2 additions & 0 deletions worlds/sc2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
get_enabled_campaigns, SpearOfAdunAutonomouslyCastAbilityPresence, Starcraft2Options,
GrantStoryTech, GenericUpgradeResearch, GenericUpgradeItems,
)
from . import settings
from .pool_filter import filter_items
from .mission_tables import (
MissionInfo, SC2Campaign, SC2Mission, SC2Race, MissionFlag
Expand Down Expand Up @@ -84,6 +85,7 @@ class SC2World(World):

game = "Starcraft 2"
web = Starcraft2WebWorld()
settings: ClassVar[settings.Starcraft2Settings]

item_name_to_id = {name: data.code for name, data in get_full_item_list().items()}
location_name_to_id = {location.name: location.code for location in get_locations(None)}
Expand Down
38 changes: 34 additions & 4 deletions worlds/sc2/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
SpearOfAdunAutonomouslyCastPresentInNoBuild, NerfUnitBaselines, LEGACY_GRID_ORDERS,
)
from .mission_tables import MissionFlag
from . import SC2World


if __name__ == "__main__":
Expand Down Expand Up @@ -420,6 +421,17 @@ def _cmd_color(self, faction: str = "", color: str = "") -> None:
self.ctx.pending_color_update = True
self.output(f"Color for {faction} set to " + player_colors[self.ctx.__dict__[var_names[faction]]])

def _cmd_windowed_mode(self, value="") -> None:
if not value:
pass
elif value.casefold() in ('t', 'true', 'yes', 'y'):
SC2World.settings.game_windowed_mode = True
force_settings_save_on_close()
else:
SC2World.settings.game_windowed_mode = False
force_settings_save_on_close()
sc2_logger.info(f"Windowed mode is: {SC2World.settings.game_windowed_mode}")

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
the next mission in a chain the other player is doing."""
Expand Down Expand Up @@ -758,11 +770,12 @@ def on_print_json(self, args: dict) -> None:
super(SC2Context, self).on_print_json(args)

def run_gui(self) -> None:
from .gui_config import apply_window_defaults
warnings = apply_window_defaults()
from .client_gui import start_gui
start_gui(self)
start_gui(self, warnings)
self.ui.json_to_kivy_parser = SC2JSONtoKivyParser(self)


async def shutdown(self) -> None:
await super(SC2Context, self).shutdown()
if self.last_bot:
Expand Down Expand Up @@ -1104,8 +1117,11 @@ async def starcraft_launch(ctx: SC2Context, mission_id: int):
sc2_logger.info(f"Launching {lookup_id_to_mission[mission_id].mission_name}. If game does not launch check log file for errors.")

with DllDirectory(None):
run_game(bot.maps.get(lookup_id_to_mission[mission_id].map_file), [Bot(Race.Terran, ArchipelagoBot(ctx, mission_id),
name="Archipelago", fullscreen=True)], realtime=True)
run_game(
bot.maps.get(lookup_id_to_mission[mission_id].map_file),
[Bot(Race.Terran, ArchipelagoBot(ctx, mission_id), name="Archipelago", fullscreen=not SC2World.settings.game_windowed_mode)],
realtime=True,
)


class ArchipelagoBot(bot.bot_ai.BotAI):
Expand Down Expand Up @@ -1756,6 +1772,20 @@ def get_location_offset(mission_id):
else (SC2HOTS_LOC_ID_OFFSET - SC2Mission.ALL_IN.id * VICTORY_MODULO)


_has_forced_save = False
def force_settings_save_on_close() -> None:
"""
Settings has an existing auto-save feature, but it only triggers if a new key was introduced.
Force it to mark things as changed by introducing a new key and then cleaning up.
"""
global _has_forced_save
if _has_forced_save:
return
SC2World.settings.update({'invalid_attribute': True})
del SC2World.settings.invalid_attribute
_has_forced_save = True


def launch():
colorama.init()
asyncio.run(main())
Expand Down
38 changes: 33 additions & 5 deletions worlds/sc2/client_gui.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import *
import asyncio
import logging

from kvui import GameManager, HoverBehavior, ServerToolTip
from kivy.app import App
Expand All @@ -13,7 +14,7 @@
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty, BooleanProperty

from worlds.sc2.client import SC2Context, calc_unfinished_missions, parse_unlock
from worlds.sc2.client import SC2Context, calc_unfinished_missions, parse_unlock, force_settings_save_on_close
from worlds.sc2.mission_tables import lookup_id_to_mission, lookup_name_to_mission, campaign_race_exceptions, \
SC2Mission, SC2Race, SC2Campaign
from worlds.sc2.locations import LocationType, lookup_location_id_to_type
Expand Down Expand Up @@ -72,6 +73,7 @@ class MissionLayout(GridLayout):
class MissionCategory(GridLayout):
pass


class SC2Manager(GameManager):
logging_pairs = [
("Client", "Archipelago"),
Expand All @@ -90,9 +92,35 @@ class SC2Manager(GameManager):
first_mission = ""
ctx: SC2Context

def __init__(self, ctx) -> None:
def __init__(self, ctx: SC2Context, startup_warnings: List[str]) -> None:
super().__init__(ctx)

self.startup_warnings = startup_warnings
self.minimized = False
from kivy.core.window import Window
Window.bind(on_maximize=self.on_maximize)
Window.bind(on_minimize=self.on_minimize)
Window.bind(on_restore=self.on_restore)

def on_start(self) -> None:
super().on_start()
for startup_warning in self.startup_warnings:
logging.getLogger("Starcraft2").warning(f"Startup WARNING: {startup_warning}")

def on_maximize(self, window) -> None:
SC2World.settings.window_maximized = True
force_settings_save_on_close()

def on_minimize(self, window) -> None:
self.minimized = True

def on_restore(self, window) -> None:
if self.minimized:
self.minimized = False
else:
# Restoring from maximized
SC2World.settings.window_maximized = False
force_settings_save_on_close()

def clear_tooltip(self) -> None:
if self.ctx.current_tooltip:
App.get_running_app().root.remove_widget(self.ctx.current_tooltip)
Expand Down Expand Up @@ -325,8 +353,8 @@ def get_location_type_title(self, location_type: LocationType) -> str:
title += ""
return title

def start_gui(context: SC2Context):
context.ui = SC2Manager(context)
def start_gui(context: SC2Context, startup_warnings: List[str]):
context.ui = SC2Manager(context, startup_warnings)
context.ui_task = asyncio.create_task(context.ui.async_run(), name="UI")
import pkgutil
data = pkgutil.get_data(SC2World.__module__, "starcraft2.kv").decode()
Expand Down
40 changes: 40 additions & 0 deletions worlds/sc2/gui_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
Import this before importing client_gui.py to set window defaults from world settings.
"""
from .settings import Starcraft2Settings
from typing import List

def apply_window_defaults() -> List[str]:
"""
Set the kivy config keys from the sc2world user settings.
Returns a list of warnings to be printed once the GUI is started.
"""
from . import SC2World
# This is necessary to prevent kivy from failing because it got invalid command-line args,
# or from spamming the logs.
# Must happen before importing kivy.config
import os
os.environ["KIVY_NO_CONSOLELOG"] = "1"
os.environ["KIVY_NO_FILELOG"] = "1"
os.environ["KIVY_NO_ARGS"] = "1"
os.environ["KIVY_LOG_ENABLE"] = "0"

# validate settings
warnings: List[str] = []
if isinstance(SC2World.settings.window_height, int) and SC2World.settings.window_height > 0:
window_height = SC2World.settings.window_height
else:
warnings.append(f"Invalid value for options.yaml key sc2_options.window_height: '{SC2World.settings.window_height}'. Expected a positive integer.")
window_height = Starcraft2Settings.window_height
if isinstance(SC2World.settings.window_width, int) and SC2World.settings.window_width > 0:
window_width = SC2World.settings.window_width
else:
warnings.append(f"Invalid value for options.yaml key sc2_options.window_width: '{SC2World.settings.window_width}'. Expected a positive integer.")
window_width = Starcraft2Settings.window_width

from kivy.config import Config
Config.set('graphics', 'width', str(window_width))
Config.set('graphics', 'height', str(window_height))
if SC2World.settings.window_maximized:
Config.set('graphics', 'window_state', 'maximized')
return warnings
13 changes: 13 additions & 0 deletions worlds/sc2/item_descriptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,8 @@ def _ability_desc(unit_name_plural: str, ability_name: str, ability_description:
item_names.SCOURGE: "Flying anti-air suicide unit. Hatches in pairs from a single larva.",
item_names.BROOD_QUEEN: "Flying support caster. Can cast the Ocular Symbiote and Spawn Broodlings abilities.",
item_names.DEFILER: "Support caster. Can use the Dark Swarm, Consume, and Plague abilities.",
item_names.INFESTED_MARINE: "General-purpose Infested infantry. Has a timed life of 90 seconds.",
item_names.INFESTED_BUNKER: "Defensive structure. Periodically spawns Infested infantry that fight from inside. Acts as a mobile ground transport while uprooted.",
item_names.PROGRESSIVE_ZERG_MELEE_ATTACK: GENERIC_UPGRADE_TEMPLATE.format("damage", ZERG, "melee ground units"),
item_names.PROGRESSIVE_ZERG_MISSILE_ATTACK: GENERIC_UPGRADE_TEMPLATE.format("damage", ZERG, "ranged ground units"),
item_names.PROGRESSIVE_ZERG_GROUND_CARAPACE: GENERIC_UPGRADE_TEMPLATE.format("armor", ZERG, "ground units"),
Expand Down Expand Up @@ -660,6 +662,12 @@ def _ability_desc(unit_name_plural: str, ability_name: str, ability_description:
item_names.CORRUPTOR_RESOURCE_EFFICIENCY: _get_resource_efficiency_desc(item_names.CORRUPTOR),
item_names.PRIMAL_IGNITER_CONCENTRATED_FIRE: "Primal Igniters deal +15 damage vs light armor.",
item_names.PRIMAL_IGNITER_PRIMAL_TENACITY: "Primal Igniters gain +100 health and +1 armor.",
item_names.INFESTED_SCV_BUILD_CHARGES: "Starting Infested SCV charges increased to 3. Maximum charges increased to 5.",
item_names.INFESTED_MARINE_PLAGUED_MUNITIONS: "Infested Marines deal an extra 50 damage over 15 seconds to targets they attack.",
item_names.INFESTED_MARINE_RETINAL_AUGMENTATION: "Infested Marines gain +1 range.",
item_names.INFESTED_BUNKER_CALCIFIED_ARMOR: "Infested Bunkers gain +3 armor.",
item_names.INFESTED_BUNKER_REGENERATIVE_PLATING: "Infested Bunkers gain increased life regeneration while rooted.",
item_names.INFESTED_BUNKER_ENGORGED_BUNKERS: "Infested Bunkers gain +2 cargo slots. Infested Trooper spawn cooldown is reduced by 20%.",
item_names.ZERGLING_RAPTOR_STRAIN: "Allows Zerglings to jump up and down cliffs and leap onto enemies. Also increases Zergling attack damage by 2.",
item_names.ZERGLING_SWARMLING_STRAIN: "Zerglings will spawn instantly and with an extra Zergling per egg at no additional cost.",
item_names.ROACH_VILE_STRAIN: "Roach attacks will slow the movement and attack speed of enemies.",
Expand Down Expand Up @@ -864,6 +872,11 @@ def _ability_desc(unit_name_plural: str, ability_name: str, ability_description:
item_names.DARK_TEMPLAR_LESSER_SHADOW_FURY: "Dark Templar War Council upgrade. Dark Templar gain two strikes of their Shadow Fury ability.",
item_names.DARK_TEMPLAR_GREATER_SHADOW_FURY: "Dark Templar War Council upgrade. Dark Templar gain three strikes of their Shadow Fury ability.",
item_names.BLOOD_HUNTER_BRUTAL_EFFICIENCY: "Blood Hunter War Council upgrade. Blood Hunters attack over twice as quickly.",
item_names.SENTRY_DOUBLE_SHIELD_RECHARGE: "Sentry War Council upgrade. Sentries can heal the shields of two targets at once.",
item_names.ENERGIZER_MOBILE_CHRONO_BEAM: "Energizer War Council upgrade. Allows Energizers to use Chrono Beam in Mobile Mode.",
item_names.HAVOC_ENDURING_SIGHT: "Havoc War Council upgrade. Havoc Squad Sight stays up indefinitely and no longer takes energy.",
item_names.HIGH_TEMPLAR_PLASMA_SURGE: "High Templar War Council upgrade. High Templar Psionic Storm will heal fiendly protoss shields under it.",
item_names.DARK_ARCHON_INDOMITABLE_WILL: "Dark Archon War Council upgrade. Casting Mind Control will no longer deplete the Dark Archon's shields.",
item_names.SOA_CHRONO_SURGE: "The Spear of Adun increases a target structure's unit warp in and research speeds by +1000% for 20 seconds.",
item_names.SOA_PROGRESSIVE_PROXY_PYLON: inspect.cleandoc("""
Level 1: The Spear of Adun quickly warps in a Pylon to a target location.
Expand Down
32 changes: 30 additions & 2 deletions worlds/sc2/item_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class ItemGroupNames:
ZERG_GENERIC_UPGRADES = "Zerg Generic Upgrades"
"""+attack/armour upgrades"""
HOTS_UNITS = "HotS Units"
HOTS_BUILDINGS = "HotS Buildings"
HOTS_STRAINS = "HotS Strains"
"""Vanilla HotS strains (the upgrades you play a mini-mission for)"""
HOTS_MUTATIONS = "HotS Mutations"
Expand All @@ -134,6 +135,10 @@ class ItemGroupNames:
ZERG_MORPHS = "Zerg Morphs"
ZERG_MERCS = "Zerg Mercenaries"
ZERG_BUILDINGS = "Zerg Buildings"
INF_TERRAN_ITEMS = "Infested Terran Items"
"""All items from Stukov co-op subfaction"""
INF_TERRAN_UNITS = "Infested Terran Units"
INF_TERRAN_UPGRADES = "Infested Terran Upgrades"

PROTOSS_ITEMS = "Protoss Items"
PROTOSS_UNITS = "Protoss Units"
Expand Down Expand Up @@ -381,7 +386,10 @@ def get_all_group_names(cls) -> typing.Set[str]:
item_name for item_name, item_data in items.item_table.items()
if item_data.race == SC2Race.ZERG
]
item_name_groups[ItemGroupNames.ZERG_BUILDINGS] = zerg_buildings = [item_names.SPINE_CRAWLER, item_names.SPORE_CRAWLER]
item_name_groups[ItemGroupNames.ZERG_BUILDINGS] = zerg_buildings = [
item_names.SPINE_CRAWLER,
item_names.SPORE_CRAWLER,
item_names.INFESTED_BUNKER]
item_name_groups[ItemGroupNames.ZERG_UNITS] = zerg_units = [
item_name for item_name, item_data in items.item_table.items()
if item_data.type in (items.ZergItemType.Unit, items.ZergItemType.Mercenary, items.ZergItemType.Morph)
Expand All @@ -401,6 +409,10 @@ def get_all_group_names(cls) -> typing.Set[str]:
item_names.MUTALISK_CORRUPTOR_VIPER_ASPECT,
item_names.MUTALISK_CORRUPTOR_BROOD_LORD_ASPECT,
]
item_name_groups[ItemGroupNames.HOTS_BUILDINGS] = hots_buildings = [
item_names.SPINE_CRAWLER,
item_names.SPORE_CRAWLER,
]
item_name_groups[ItemGroupNames.HOTS_MORPHS] = hots_morphs = [
item_names.ZERGLING_BANELING_ASPECT,
item_names.HYDRALISK_IMPALER_ASPECT,
Expand Down Expand Up @@ -474,14 +486,30 @@ def get_all_group_names(cls) -> typing.Set[str]:
]
item_name_groups[ItemGroupNames.HOTS_ITEMS] = vanilla_hots_items = (
hots_units
+ zerg_buildings
+ hots_buildings
+ kerrigan_abilities
+ hots_mutations
+ hots_strains
+ hots_global_upgrades
+ zerg_generic_upgrades
)

# Zerg - Infested Terran (Stukov Co-op)
item_name_groups[ItemGroupNames.INF_TERRAN_UNITS] = infterr_units = [
item_names.INFESTED_MARINE,
item_names.INFESTED_BUNKER]
item_name_groups[ItemGroupNames.INF_TERRAN_UPGRADES] = infterr_upgrades = [
item_names.INFESTED_SCV_BUILD_CHARGES,
item_names.INFESTED_MARINE_PLAGUED_MUNITIONS,
item_names.INFESTED_MARINE_RETINAL_AUGMENTATION,
item_names.INFESTED_BUNKER_CALCIFIED_ARMOR,
item_names.INFESTED_BUNKER_REGENERATIVE_PLATING,
item_names.INFESTED_BUNKER_ENGORGED_BUNKERS
]
item_name_groups[ItemGroupNames.INF_TERRAN_ITEMS] = (
infterr_units
+ infterr_upgrades
)

# Protoss
item_name_groups[ItemGroupNames.PROTOSS_ITEMS] = protoss_items = [
Expand Down
55 changes: 40 additions & 15 deletions worlds/sc2/item_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,23 +327,25 @@
NOVA_NUKE = "Tac Nuke Strike (Nova Ability)"

# Zerg Units
ZERGLING = "Zergling"
SWARM_QUEEN = "Swarm Queen"
ROACH = "Roach"
HYDRALISK = "Hydralisk"
ABERRATION = "Aberration"
MUTALISK = "Mutalisk"
SWARM_HOST = "Swarm Host"
INFESTOR = "Infestor"
ULTRALISK = "Ultralisk"
CORRUPTOR = "Corruptor"
SCOURGE = "Scourge"
BROOD_QUEEN = "Brood Queen"
DEFILER = "Defiler"
ZERGLING = "Zergling"
SWARM_QUEEN = "Swarm Queen"
ROACH = "Roach"
HYDRALISK = "Hydralisk"
ABERRATION = "Aberration"
MUTALISK = "Mutalisk"
SWARM_HOST = "Swarm Host"
INFESTOR = "Infestor"
ULTRALISK = "Ultralisk"
CORRUPTOR = "Corruptor"
SCOURGE = "Scourge"
BROOD_QUEEN = "Brood Queen"
DEFILER = "Defiler"
INFESTED_MARINE = "Infested Marine"

# Zerg Buildings
SPORE_CRAWLER = "Spore Crawler"
SPINE_CRAWLER = "Spine Crawler"
SPORE_CRAWLER = "Spore Crawler"
SPINE_CRAWLER = "Spine Crawler"
INFESTED_BUNKER = "Infested Bunker"

# Zerg Weapon / Armor Upgrades
ZERG_UPGRADE_PREFIX = "Progressive Zerg"
Expand Down Expand Up @@ -458,6 +460,12 @@
OVERLORD_GENERATE_CREEP = "Generate Creep (Overlord)"
OVERLORD_PNEUMATIZED_CARAPACE = "Pneumatized Carapace (Overlord)"
OVERLORD_ANTENNAE = "Antennae (Overlord)"
INFESTED_SCV_BUILD_CHARGES = "Sustained Cultivation Ventricles (InfSCV Build Charges)"
INFESTED_MARINE_PLAGUED_MUNITIONS = "Plagued Munitions (Infested Marine)"
INFESTED_MARINE_RETINAL_AUGMENTATION = "Retinal Augmentation (Infested Marine)"
INFESTED_BUNKER_CALCIFIED_ARMOR = "Calcified Armor (Infested Bunker)"
INFESTED_BUNKER_REGENERATIVE_PLATING = "Regenerative Plating (Infested Bunker)"
INFESTED_BUNKER_ENGORGED_BUNKERS = "Engorged Bunkers (Infested Bunker)"

# Zerg Strains
ZERGLING_RAPTOR_STRAIN = "Raptor Strain (Zergling)"
Expand Down Expand Up @@ -692,6 +700,23 @@
DARK_TEMPLAR_LESSER_SHADOW_FURY = "Lesser Shadow Fury (Dark Templar)"
DARK_TEMPLAR_GREATER_SHADOW_FURY = "Greater Shadow Fury (Dark Templar)"
BLOOD_HUNTER_BRUTAL_EFFICIENCY = "Brutal Efficiency (Blood Hunter)"
SENTRY_DOUBLE_SHIELD_RECHARGE = "Double Shield Recharge (Sentry)"
ENERGIZER_MOBILE_CHRONO_BEAM = "Mobile Chrono Beam (Energizer)"
HAVOC_ENDURING_SIGHT = "Enduring Sight (Havoc)"
HIGH_TEMPLAR_PLASMA_SURGE = "Plasma Surge (High Templar)"
# Signifier
# Ascendant
DARK_ARCHON_INDOMITABLE_WILL = "Indomitable Will (Dark Archon)"
# IMMORTAL_IMPROVED_BARRIER = "Improved Barrier (Immortal)"
# Annihilator
# Vanguard
# Stalwart
# Colossus
# Wrathwalker
# Reaver
# Disruptor
# Warp Prism
# Observer

# Spear Of Adun
SOA_CHRONO_SURGE = "Chrono Surge (Spear of Adun Calldown)"
Expand Down
Loading

0 comments on commit af3641c

Please sign in to comment.