forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
165 lines
8.9 KiB
Python
165 lines
8.9 KiB
Python
import logging
|
|
from typing import ClassVar, Mapping, Any
|
|
|
|
import settings
|
|
from BaseClasses import Item, ItemClassification, Region, MultiWorld, Tutorial
|
|
from worlds.AutoWorld import World, WebWorld
|
|
from . import client, options, locations
|
|
|
|
|
|
client.register_client()
|
|
|
|
|
|
class VoltorbFlipSettings(settings.Group):
|
|
|
|
class AllowExperimentalLogic(settings.Bool):
|
|
"""Allows the **experimental** choice in the **Artificial Logic** option."""
|
|
|
|
allow_experimental_logic: AllowExperimentalLogic | bool = False
|
|
|
|
class VoltorbFlipWeb(WebWorld):
|
|
theme = "ocean"
|
|
tutorials = [Tutorial(
|
|
"Multiworld Setup Guide",
|
|
"A guide to setting up the Voltorb Flip software on your computer. This guide covers single-player, "
|
|
"multiworld, and related software.",
|
|
"English",
|
|
"setup_en.md",
|
|
"setup/en",
|
|
["menudo"]
|
|
)]
|
|
|
|
class VoltorbFlipWorld(World):
|
|
game = "Voltorb Flip"
|
|
options_dataclass = options.VoltorbFlipOptions
|
|
options: options.VoltorbFlipOptions
|
|
settings_key = "voltorb_flip_settings"
|
|
settings: ClassVar[VoltorbFlipSettings]
|
|
topology_present = True
|
|
web = VoltorbFlipWeb()
|
|
item_name_to_id = {"Luck": 50000}
|
|
location_name_to_id = locations.locations
|
|
progression_list: ClassVar[list[tuple[str, int]]] = [] # Only used in set_rules, so reusable for other slots
|
|
|
|
def __init__(self, multiworld: MultiWorld, player: int):
|
|
super().__init__(multiworld, player)
|
|
self.regions: dict[str, Region] = {}
|
|
self.max_level = 0
|
|
self.last_coin = 0
|
|
|
|
def create_item(self, name: str) -> "Item":
|
|
return VoltorbFlipItem(name, ItemClassification.progression_deprioritized_skip_balancing,
|
|
self.item_name_to_id[name], self.player)
|
|
|
|
def get_filler_item_name(self) -> str:
|
|
return "Luck"
|
|
|
|
def create_regions(self) -> None:
|
|
self.regions = {
|
|
"Menu": Region("Menu", self.player, self.multiworld),
|
|
"Earlier levels": Region("Earlier levels", self.player, self.multiworld), # Always sphere 1
|
|
"Later levels": Region("Later levels", self.player, self.multiworld),
|
|
"Last level": Region("Last level", self.player, self.multiworld),
|
|
"Early coins": Region("Early coins", self.player, self.multiworld), # Always sphere 1
|
|
"Mid coins": Region("Mid coins", self.player, self.multiworld),
|
|
"Late coins": Region("Late coins", self.player, self.multiworld),
|
|
"Last coins": Region("Last coins", self.player, self.multiworld),
|
|
}
|
|
max_level = self.options.level_locations_adjustments["Maximum"]
|
|
self.max_level = max_level
|
|
for i in range(1, max_level+1):
|
|
if i == 1 or i/max_level <= 0.4:
|
|
self.regions["Earlier levels"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Win level {i}", i, self.regions["Earlier levels"]
|
|
))
|
|
elif i == max_level:
|
|
self.regions["Last level"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Win level {i}", i, self.regions["Last level"]
|
|
))
|
|
else:
|
|
self.regions["Later levels"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Win level {i}", i, self.regions["Later levels"]
|
|
))
|
|
max_coins = self.options.coin_locations_adjustments["Maximum"]
|
|
coin_steps = self.options.coin_locations_adjustments["Steps"]
|
|
last_coin = max_coins - (max_coins % coin_steps)
|
|
self.last_coin = last_coin
|
|
for i in range(coin_steps, last_coin+1, coin_steps):
|
|
if i == coin_steps:
|
|
self.regions["Early coins"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Collect {i} coins", i, self.regions["Early coins"]
|
|
))
|
|
elif i == last_coin:
|
|
self.regions["Last coins"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Collect {i} coins", i, self.regions["Last coins"]
|
|
))
|
|
elif i <= 1000:
|
|
self.regions["Early coins"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Collect {i} coins", i, self.regions["Early coins"]
|
|
))
|
|
elif i <= last_coin//2:
|
|
self.regions["Mid coins"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Collect {i} coins", i, self.regions["Mid coins"]
|
|
))
|
|
else:
|
|
self.regions["Late coins"].locations.append(locations.VoltorbFlipLocation(
|
|
self.player, f"Collect {i} coins", i, self.regions["Late coins"]
|
|
))
|
|
self.multiworld.regions.extend(self.regions.values())
|
|
|
|
def create_items(self) -> None:
|
|
for _ in range(sum(len(reg.locations) for reg in self.regions.values())):
|
|
self.multiworld.itempool.append(self.create_item("Luck"))
|
|
|
|
def set_rules(self) -> None:
|
|
self.regions["Menu"].connect(self.regions["Earlier levels"], "Earlier levels")
|
|
self.regions["Menu"].connect(self.regions["Early coins"], "Early coins")
|
|
if self.options.artificial_logic == "experimental" and not settings.get_settings()["voltorb_flip_settings"]["allow_experimental_logic"]:
|
|
import logging
|
|
logging.warning("Experimental logic was disabled in host settings, so it will be reverted to non-experimental for player "+self.player_name+".")
|
|
self.options.artificial_logic.value = 1
|
|
if self.options.artificial_logic == "experimental":
|
|
self.options.progression_balancing.value = 0 # Reduces rate of generation failures
|
|
if not VoltorbFlipWorld.progression_list:
|
|
VoltorbFlipWorld.progression_list.extend([
|
|
(item.name, item.player)
|
|
for item in self.multiworld.itempool
|
|
if ItemClassification.progression in item.classification
|
|
])
|
|
items = [self.random.choice(VoltorbFlipWorld.progression_list) for _ in range(5)]
|
|
print(items)
|
|
self.regions["Earlier levels"].connect(self.regions["Later levels"], "Later levels", lambda state: state.has(items[0][0], items[0][1]))
|
|
self.regions["Later levels"].connect(self.regions["Last level"], "Last level", lambda state: state.has(items[1][0], items[1][1]))
|
|
self.regions["Early coins"].connect(self.regions["Mid coins"], "Mid coins", lambda state: state.has(items[2][0], items[2][1]))
|
|
self.regions["Mid coins"].connect(self.regions["Late coins"], "Late coins", lambda state: state.has(items[3][0], items[3][1]))
|
|
self.regions["Late coins"].connect(self.regions["Last coins"], "Last coins", lambda state: state.has(items[4][0], items[4][1]))
|
|
elif self.options.artificial_logic == "on":
|
|
count = sum(len(reg.locations) for reg in self.regions.values())
|
|
self.regions["Earlier levels"].connect(self.regions["Later levels"], "Later levels", lambda state: state.has("Luck", self.player, 1))
|
|
self.regions["Later levels"].connect(self.regions["Last level"], "Last level", lambda state: state.has("Luck", self.player, count//2))
|
|
self.regions["Early coins"].connect(self.regions["Mid coins"], "Mid coins", lambda state: state.has("Luck", self.player, 1))
|
|
self.regions["Mid coins"].connect(self.regions["Late coins"], "Late coins", lambda state: state.has("Luck", self.player, max(1, count//5)))
|
|
self.regions["Late coins"].connect(self.regions["Last coins"], "Last coins", lambda state: state.has("Luck", self.player, count//2))
|
|
else:
|
|
self.regions["Earlier levels"].connect(self.regions["Later levels"], "Later levels")
|
|
self.regions["Later levels"].connect(self.regions["Last level"], "Last level")
|
|
self.regions["Early coins"].connect(self.regions["Mid coins"], "Mid coins")
|
|
self.regions["Mid coins"].connect(self.regions["Late coins"], "Late coins")
|
|
self.regions["Late coins"].connect(self.regions["Last coins"], "Last coins")
|
|
if self.options.goal == "levels":
|
|
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach_location(f"Win level {self.max_level}", self.player)
|
|
else:
|
|
self.multiworld.completion_condition[self.player] = lambda state: state.can_reach_location(f"Collect {self.last_coin} coins", self.player)
|
|
self.regions.clear()
|
|
|
|
def fill_slot_data(self) -> Mapping[str, Any]:
|
|
return {
|
|
"goal": self.options.goal.current_key,
|
|
"level_locations_adjustments": self.options.level_locations_adjustments.value,
|
|
"coin_locations_adjustments": self.options.coin_locations_adjustments.value,
|
|
}
|
|
|
|
|
|
class VoltorbFlipItem(Item):
|
|
game = "Voltorb Flip"
|