Blasphemous: Randomizer 2.0 (#1883)
Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
This commit is contained in:
parent
f2117be7d9
commit
1338d7a968
1
setup.py
1
setup.py
|
@ -67,7 +67,6 @@ non_apworlds: set = {
|
|||
"Adventure",
|
||||
"ArchipIDLE",
|
||||
"Archipelago",
|
||||
"Blasphemous",
|
||||
"ChecksFinder",
|
||||
"Clique",
|
||||
"DLCQuest",
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
from typing import List, Dict
|
||||
|
||||
|
||||
region_exit_table: Dict[str, List[str]] = {
|
||||
"menu" : ["New Game"],
|
||||
|
||||
"albero" : ["To The Holy Line",
|
||||
"To Desecrated Cistern",
|
||||
"To Wasteland of the Buried Churches",
|
||||
"To Dungeons"],
|
||||
|
||||
"attots" : ["To Mother of Mothers"],
|
||||
|
||||
"ar" : ["To Mother of Mothers",
|
||||
"To Wall of the Holy Prohibitions",
|
||||
"To Deambulatory of His Holiness"],
|
||||
|
||||
"bottc" : ["To Wasteland of the Buried Churches",
|
||||
"To Ferrous Tree"],
|
||||
|
||||
"botss" : ["To The Holy Line",
|
||||
"To Mountains of the Endless Dusk"],
|
||||
|
||||
"coolotcv" : ["To Graveyard of the Peaks",
|
||||
"To Wall of the Holy Prohibitions"],
|
||||
|
||||
"dohh" : ["To Archcathedral Rooftops"],
|
||||
|
||||
"dc" : ["To Albero",
|
||||
"To Mercy Dreams",
|
||||
"To Mountains of the Endless Dusk",
|
||||
"To Echoes of Salt",
|
||||
"To Grievance Ascends"],
|
||||
|
||||
"eos" : ["To Jondo",
|
||||
"To Mountains of the Endless Dusk",
|
||||
"To Desecrated Cistern",
|
||||
"To The Resting Place of the Sister",
|
||||
"To Mourning and Havoc"],
|
||||
|
||||
"ft" : ["To Bridge of the Three Cavalries",
|
||||
"To Hall of the Dawning",
|
||||
"To Patio of the Silent Steps"],
|
||||
|
||||
"gotp" : ["To Where Olive Trees Wither",
|
||||
"To Convent of Our Lady of the Charred Visage"],
|
||||
|
||||
"ga" : ["To Jondo",
|
||||
"To Desecrated Cistern"],
|
||||
|
||||
"hotd" : ["To Ferrous Tree"],
|
||||
|
||||
"jondo" : ["To Mountains of the Endless Dusk",
|
||||
"To Grievance Ascends"],
|
||||
|
||||
"kottw" : ["To Mother of Mothers"],
|
||||
|
||||
"lotnw" : ["To Mother of Mothers",
|
||||
"To The Sleeping Canvases"],
|
||||
|
||||
"md" : ["To Wasteland of the Buried Churches",
|
||||
"To Desecrated Cistern",
|
||||
"To The Sleeping Canvases"],
|
||||
|
||||
"mom" : ["To Patio of the Silent Steps",
|
||||
"To Archcathedral Rooftops",
|
||||
"To Knot of the Three Words",
|
||||
"To Library of the Negated Words",
|
||||
"To All the Tears of the Sea"],
|
||||
|
||||
"moted" : ["To Brotherhood of the Silent Sorrow",
|
||||
"To Jondo",
|
||||
"To Desecrated Cistern"],
|
||||
|
||||
"mah" : ["To Echoes of Salt",
|
||||
"To Mother of Mothers"],
|
||||
|
||||
"potss" : ["To Ferrous Tree",
|
||||
"To Mother of Mothers",
|
||||
"To Wall of the Holy Prohibitions"],
|
||||
|
||||
"petrous" : ["To The Holy Line"],
|
||||
|
||||
"thl" : ["To Brotherhood of the Silent Sorrow",
|
||||
"To Petrous",
|
||||
"To Albero"],
|
||||
|
||||
"trpots" : ["To Echoes of Salt"],
|
||||
|
||||
"tsc" : ["To Library of the Negated Words",
|
||||
"To Mercy Dreams"],
|
||||
|
||||
"wothp" : ["To Archcathedral Rooftops",
|
||||
"To Convent of Our Lady of the Charred Visage"],
|
||||
|
||||
"wotbc" : ["To Albero",
|
||||
"To Where Olive Trees Wither",
|
||||
"To Mercy Dreams"],
|
||||
|
||||
"wotw" : ["To Wasteland of the Buried Churches",
|
||||
"To Graveyard of the Peaks"]
|
||||
}
|
||||
|
||||
exit_lookup_table: Dict[str, str] = {
|
||||
"New Game": "botss",
|
||||
"To Albero": "albero",
|
||||
"To All the Tears of the Sea": "attots",
|
||||
"To Archcathedral Rooftops": "ar",
|
||||
"To Bridge of the Three Cavalries": "bottc",
|
||||
"To Brotherhood of the Silent Sorrow": "botss",
|
||||
"To Convent of Our Lady of the Charred Visage": "coolotcv",
|
||||
"To Deambulatory of His Holiness": "dohh",
|
||||
"To Desecrated Cistern": "dc",
|
||||
"To Echoes of Salt": "eos",
|
||||
"To Ferrous Tree": "ft",
|
||||
"To Graveyard of the Peaks": "gotp",
|
||||
"To Grievance Ascends": "ga",
|
||||
"To Hall of the Dawning": "hotd",
|
||||
"To Jondo": "jondo",
|
||||
"To Knot of the Three Words": "kottw",
|
||||
"To Library of the Negated Words": "lotnw",
|
||||
"To Mercy Dreams": "md",
|
||||
"To Mother of Mothers": "mom",
|
||||
"To Mountains of the Endless Dusk": "moted",
|
||||
"To Mourning and Havoc": "mah",
|
||||
"To Patio of the Silent Steps": "potss",
|
||||
"To Petrous": "petrous",
|
||||
"To The Holy Line": "thl",
|
||||
"To The Resting Place of the Sister": "trpots",
|
||||
"To The Sleeping Canvases": "tsc",
|
||||
"To Wall of the Holy Prohibitions": "wothp",
|
||||
"To Wasteland of the Buried Churches": "wotbc",
|
||||
"To Where Olive Trees Wither": "wotw",
|
||||
"To Dungeons": "dungeon"
|
||||
}
|
|
@ -219,6 +219,12 @@ item_table: List[ItemDict] = [
|
|||
{'name': "Three Gnarled Tongues",
|
||||
'count': 1,
|
||||
'classification': ItemClassification.progression},
|
||||
{'name': "Boots of Pleading",
|
||||
'count': 1,
|
||||
'classification': ItemClassification.progression},
|
||||
{'name': "Purified Hand of the Nun",
|
||||
'count': 1,
|
||||
'classification': ItemClassification.progression},
|
||||
|
||||
# Mea Culpa Hearts
|
||||
{'name': "Smoking Heart of Incense",
|
||||
|
@ -372,7 +378,7 @@ item_table: List[ItemDict] = [
|
|||
'classification': ItemClassification.progression},
|
||||
{'name': "Quicksilver",
|
||||
'count': 5,
|
||||
'classification': ItemClassification.useful},
|
||||
'classification': ItemClassification.progression},
|
||||
{'name': "Petrified Bell",
|
||||
'count': 1,
|
||||
'classification': ItemClassification.progression},
|
||||
|
@ -398,7 +404,7 @@ item_table: List[ItemDict] = [
|
|||
# Skills
|
||||
{'name': "Combo Skill",
|
||||
'count': 3,
|
||||
'classification': ItemClassification.useful},
|
||||
'classification': ItemClassification.progression},
|
||||
{'name': "Charged Skill",
|
||||
'count': 3,
|
||||
'classification': ItemClassification.progression},
|
||||
|
@ -410,7 +416,13 @@ item_table: List[ItemDict] = [
|
|||
'classification': ItemClassification.progression},
|
||||
{'name': "Lunge Skill",
|
||||
'count': 3,
|
||||
'classification': ItemClassification.useful},
|
||||
'classification': ItemClassification.progression},
|
||||
{'name': "Dash Ability",
|
||||
'count': 1,
|
||||
'classification': ItemClassification.progression},
|
||||
{'name': "Wall Climb Ability",
|
||||
'count': 1,
|
||||
'classification': ItemClassification.progression},
|
||||
|
||||
# Other
|
||||
{'name': "Parietal bone of Lasser, the Inquisitor",
|
||||
|
@ -625,6 +637,23 @@ item_table: List[ItemDict] = [
|
|||
'classification': ItemClassification.filler}
|
||||
]
|
||||
|
||||
event_table: Dict[str, str] = {
|
||||
"OpenedDCGateW": "D01Z05S24",
|
||||
"OpenedDCGateE": "D01Z05S12",
|
||||
"OpenedDCLadder": "D01Z05S20",
|
||||
"OpenedWOTWCave": "D02Z01S06",
|
||||
"RodeGOTPElevator": "D02Z02S11",
|
||||
"OpenedConventLadder": "D02Z03S11",
|
||||
"BrokeJondoBellW": "D03Z02S09",
|
||||
"BrokeJondoBellE": "D03Z02S05",
|
||||
"OpenedMOMLadder": "D04Z02S06",
|
||||
"OpenedTSCGate": "D05Z02S11",
|
||||
"OpenedARLadder": "D06Z01S23",
|
||||
"BrokeBOTTCStatue": "D08Z01S02",
|
||||
"OpenedWOTHPGate": "D09Z01S05",
|
||||
"OpenedBOTSSLadder": "D17Z01S04"
|
||||
}
|
||||
|
||||
group_table: Dict[str, Set[str]] = {
|
||||
"wounds" : ["Holy Wound of Attrition",
|
||||
"Holy Wound of Contrition",
|
||||
|
@ -634,6 +663,10 @@ group_table: Dict[str, Set[str]] = {
|
|||
"Mirrored Mask of Dolphos",
|
||||
"Embossed Mask of Crescente"],
|
||||
|
||||
"marks" : ["Mark of the First Refuge",
|
||||
"Mark of the Second Refuge",
|
||||
"Mark of the Third Refuge"],
|
||||
|
||||
"tirso" : ["Bouquet of Rosemary",
|
||||
"Incense Garlic",
|
||||
"Olive Seeds",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,22 @@
|
|||
from Options import Choice, Toggle, DefaultOnToggle, DeathLink
|
||||
from Options import Choice, Toggle, DefaultOnToggle, DeathLink, StartInventoryPool
|
||||
import random
|
||||
|
||||
|
||||
class ChoiceIsRandom(Choice):
|
||||
randomized: bool = False
|
||||
|
||||
@classmethod
|
||||
def from_text(cls, text: str) -> Choice:
|
||||
text = text.lower()
|
||||
if text == "random":
|
||||
cls.randomized = True
|
||||
return cls(random.choice(list(cls.name_lookup)))
|
||||
for option_name, value in cls.options.items():
|
||||
if option_name == text:
|
||||
return cls(value)
|
||||
raise KeyError(
|
||||
f'Could not find option "{text}" for "{cls.__name__}", '
|
||||
f'known options are {", ".join(f"{option}" for option in cls.name_lookup.values())}')
|
||||
|
||||
|
||||
class PrieDieuWarp(DefaultOnToggle):
|
||||
|
@ -17,13 +35,12 @@ class CorpseHints(DefaultOnToggle):
|
|||
|
||||
|
||||
class Difficulty(Choice):
|
||||
"""Adjusts the logic required to defeat bosses.
|
||||
Impossible: Removes all logic requirements for bosses. Good luck."""
|
||||
"""Adjusts the overall difficulty of the randomizer, including upgrades required to defeat bosses
|
||||
and advanced movement tricks or glitches."""
|
||||
display_name = "Difficulty"
|
||||
option_easy = 0
|
||||
option_normal = 1
|
||||
option_hard = 2
|
||||
option_impossible = 3
|
||||
default = 1
|
||||
|
||||
|
||||
|
@ -32,9 +49,20 @@ class Penitence(Toggle):
|
|||
display_name = "Penitence"
|
||||
|
||||
|
||||
class ExpertLogic(Toggle):
|
||||
"""Expands the logic used by the randomizer to allow for some difficult and/or lesser known tricks."""
|
||||
display_name = "Expert Logic"
|
||||
class StartingLocation(ChoiceIsRandom):
|
||||
"""Choose where to start the randomizer. Note that some starting locations cannot be chosen with certain
|
||||
other options.
|
||||
Specifically, Brotherhood and Mourning And Havoc cannot be chosen if Shuffle Dash is enabled, and Grievance Ascends
|
||||
cannot be chosen if Shuffle Wall Climb is enabled."""
|
||||
display_name = "Starting Location"
|
||||
option_brotherhood = 0
|
||||
option_albero = 1
|
||||
option_convent = 2
|
||||
option_grievance = 3
|
||||
option_knot_of_words = 4
|
||||
option_rooftops = 5
|
||||
option_mourning_havoc = 6
|
||||
default = 0
|
||||
|
||||
|
||||
class Ending(Choice):
|
||||
|
@ -48,6 +76,13 @@ class Ending(Choice):
|
|||
default = 0
|
||||
|
||||
|
||||
class SkipLongQuests(Toggle):
|
||||
"""Ensures that the rewards for long quests will be filler items.
|
||||
Affected locations: \"Albero: Donate 50000 Tears\", \"Ossuary: 11th reward\", \"AtTotS: Miriam's gift\",
|
||||
\"TSC: Jocinero's final reward\""""
|
||||
display_name = "Skip Long Quests"
|
||||
|
||||
|
||||
class ThornShuffle(Choice):
|
||||
"""Shuffles the Thorn given by Deogracias and all Thorn upgrades into the item pool."""
|
||||
display_name = "Shuffle Thorn"
|
||||
|
@ -57,124 +92,33 @@ class ThornShuffle(Choice):
|
|||
default = 0
|
||||
|
||||
|
||||
class DashShuffle(Toggle):
|
||||
"""Turns the ability to dash into an item that must be found in the multiworld."""
|
||||
display_name = "Shuffle Dash"
|
||||
|
||||
|
||||
class WallClimbShuffle(Toggle):
|
||||
"""Turns the ability to climb walls with your sword into an item that must be found in the multiworld."""
|
||||
display_name = "Shuffle Wall Climb"
|
||||
|
||||
|
||||
class ReliquaryShuffle(DefaultOnToggle):
|
||||
"""Adds the True Torment exclusive Reliquary rosary beads into the item pool."""
|
||||
display_name = "Shuffle Penitence Rewards"
|
||||
|
||||
|
||||
class CherubShuffle(DefaultOnToggle):
|
||||
"""Shuffles Children of Moonlight into the item pool."""
|
||||
display_name = "Shuffle Children of Moonlight"
|
||||
class CustomItem1(Toggle):
|
||||
"""Adds the custom relic Boots of Pleading into the item pool, which grants the ability to fall onto spikes
|
||||
and survive.
|
||||
Must have the \"Blasphemous-Boots-of-Pleading\" mod installed to connect to a multiworld."""
|
||||
display_name = "Boots of Pleading"
|
||||
|
||||
|
||||
class LifeShuffle(DefaultOnToggle):
|
||||
"""Shuffles life upgrades from the Lady of the Six Sorrows into the item pool."""
|
||||
display_name = "Shuffle Life Upgrades"
|
||||
|
||||
|
||||
class FervourShuffle(DefaultOnToggle):
|
||||
"""Shuffles fervour upgrades from the Oil of the Pilgrims into the item pool."""
|
||||
display_name = "Shuffle Fervour Upgrades"
|
||||
|
||||
|
||||
class SwordShuffle(DefaultOnToggle):
|
||||
"""Shuffles Mea Culpa upgrades from the Mea Culpa Altars into the item pool."""
|
||||
display_name = "Shuffle Mea Culpa Upgrades"
|
||||
|
||||
|
||||
class BlessingShuffle(DefaultOnToggle):
|
||||
"""Shuffles blessings from the Lake of Silent Pilgrims into the item pool."""
|
||||
display_name = "Shuffle Blessings"
|
||||
|
||||
|
||||
class DungeonShuffle(DefaultOnToggle):
|
||||
"""Shuffles rewards from completing Confessor Dungeons into the item pool."""
|
||||
display_name = "Shuffle Dungeon Rewards"
|
||||
|
||||
|
||||
class TirsoShuffle(DefaultOnToggle):
|
||||
"""Shuffles rewards from delivering herbs to Tirso into the item pool."""
|
||||
display_name = "Shuffle Tirso's Rewards"
|
||||
|
||||
|
||||
class MiriamShuffle(DefaultOnToggle):
|
||||
"""Shuffles the prayer given by Miriam into the item pool."""
|
||||
display_name = "Shuffle Miriram's Reward"
|
||||
|
||||
|
||||
class RedentoShuffle(DefaultOnToggle):
|
||||
"""Shuffles rewards from assisting Redento into the item pool."""
|
||||
display_name = "Shuffle Redento's Rewards"
|
||||
|
||||
|
||||
class JocineroShuffle(DefaultOnToggle):
|
||||
"""Shuffles rewards from rescuing 20 and 38 Children of Moonlight into the item pool."""
|
||||
display_name = "Shuffle Jocinero's Rewards"
|
||||
|
||||
|
||||
class AltasgraciasShuffle(DefaultOnToggle):
|
||||
"""Shuffles the reward given by Altasgracias and the item left behind by them into the item pool."""
|
||||
display_name = "Shuffle Altasgracias' Rewards"
|
||||
|
||||
|
||||
class TentudiaShuffle(DefaultOnToggle):
|
||||
"""Shuffles the rewards from delivering Tentudia's remains to Lvdovico into the item pool."""
|
||||
display_name = "Shuffle Lvdovico's Rewards"
|
||||
|
||||
|
||||
class GeminoShuffle(DefaultOnToggle):
|
||||
"""Shuffles the rewards from Gemino's quest and the hidden tomb into the item pool."""
|
||||
display_name = "Shuffle Gemino's Rewards"
|
||||
|
||||
|
||||
class GuiltShuffle(DefaultOnToggle):
|
||||
"""Shuffles the Weight of True Guilt into the item pool."""
|
||||
display_name = "Shuffle Immaculate Bead"
|
||||
|
||||
|
||||
class OssuaryShuffle(DefaultOnToggle):
|
||||
"""Shuffles the rewards from delivering bones to the Ossuary into the item pool."""
|
||||
display_name = "Shuffle Ossuary Rewards"
|
||||
|
||||
|
||||
class BossShuffle(DefaultOnToggle):
|
||||
"""Shuffles the Tears of Atonement from defeating bosses into the item pool."""
|
||||
display_name = "Shuffle Boss Tears"
|
||||
|
||||
|
||||
class WoundShuffle(DefaultOnToggle):
|
||||
"""Shuffles the Holy Wounds required to pass the Bridge of the Three Cavalries into the item pool."""
|
||||
display_name = "Shuffle Holy Wounds"
|
||||
|
||||
|
||||
class MaskShuffle(DefaultOnToggle):
|
||||
"""Shuffles the masks required to use the elevator in Archcathedral Rooftops into the item pool."""
|
||||
display_name = "Shuffle Masks"
|
||||
|
||||
|
||||
class EyeShuffle(DefaultOnToggle):
|
||||
"""Shuffles the Eyes of the Traitor from defeating Isidora and Sierpes into the item pool."""
|
||||
display_name = "Shuffle Traitor's Eyes"
|
||||
|
||||
|
||||
class HerbShuffle(DefaultOnToggle):
|
||||
"""Shuffles the herbs required for Tirso's quest into the item pool."""
|
||||
display_name = "Shuffle Herbs"
|
||||
|
||||
|
||||
class ChurchShuffle(DefaultOnToggle):
|
||||
"""Shuffles the rewards from donating 5,000 and 50,000 Tears of Atonement to the Church in Albero into the item pool."""
|
||||
display_name = "Shuffle Donation Rewards"
|
||||
|
||||
|
||||
class ShopShuffle(DefaultOnToggle):
|
||||
"""Shuffles the items sold in Candelaria's shops into the item pool."""
|
||||
display_name = "Shuffle Shop Items"
|
||||
|
||||
|
||||
class CandleShuffle(DefaultOnToggle):
|
||||
"""Shuffles the Beads of Wax and their upgrades into the item pool."""
|
||||
display_name = "Shuffle Candles"
|
||||
class CustomItem2(Toggle):
|
||||
"""Adds the custom relic Purified Hand of the Nun into the item pool, which grants the ability to jump
|
||||
a second time in mid-air.
|
||||
Must have the \"Blasphemous-Double-Jump\" mod installed to connect to a multiworld."""
|
||||
display_name = "Purified Hand of the Nun"
|
||||
|
||||
|
||||
class StartWheel(Toggle):
|
||||
|
@ -189,7 +133,8 @@ class SkillRando(Toggle):
|
|||
|
||||
class EnemyRando(Choice):
|
||||
"""Randomizes the enemies that appear in each room.
|
||||
Shuffled: Enemies will be shuffled amongst each other, but can only appear as many times as they do in a standard game.
|
||||
Shuffled: Enemies will be shuffled amongst each other, but can only appear as many times as they do in
|
||||
a standard game.
|
||||
Randomized: Every enemy is completely random, and can appear any number of times.
|
||||
Some enemies will never be randomized."""
|
||||
display_name = "Enemy Randomizer"
|
||||
|
@ -223,37 +168,20 @@ blasphemous_options = {
|
|||
"corpse_hints": CorpseHints,
|
||||
"difficulty": Difficulty,
|
||||
"penitence": Penitence,
|
||||
"expert_logic": ExpertLogic,
|
||||
"starting_location": StartingLocation,
|
||||
"ending": Ending,
|
||||
"skip_long_quests": SkipLongQuests,
|
||||
"thorn_shuffle" : ThornShuffle,
|
||||
"dash_shuffle": DashShuffle,
|
||||
"wall_climb_shuffle": WallClimbShuffle,
|
||||
"reliquary_shuffle": ReliquaryShuffle,
|
||||
"cherub_shuffle" : CherubShuffle,
|
||||
"life_shuffle" : LifeShuffle,
|
||||
"fervour_shuffle" : FervourShuffle,
|
||||
"sword_shuffle" : SwordShuffle,
|
||||
"blessing_shuffle" : BlessingShuffle,
|
||||
"dungeon_shuffle" : DungeonShuffle,
|
||||
"tirso_shuffle" : TirsoShuffle,
|
||||
"miriam_shuffle" : MiriamShuffle,
|
||||
"redento_shuffle" : RedentoShuffle,
|
||||
"jocinero_shuffle" : JocineroShuffle,
|
||||
"altasgracias_shuffle" : AltasgraciasShuffle,
|
||||
"tentudia_shuffle" : TentudiaShuffle,
|
||||
"gemino_shuffle" : GeminoShuffle,
|
||||
"guilt_shuffle" : GuiltShuffle,
|
||||
"ossuary_shuffle" : OssuaryShuffle,
|
||||
"boss_shuffle" : BossShuffle,
|
||||
"wound_shuffle" : WoundShuffle,
|
||||
"mask_shuffle" : MaskShuffle,
|
||||
"eye_shuffle": EyeShuffle,
|
||||
"herb_shuffle" : HerbShuffle,
|
||||
"church_shuffle" : ChurchShuffle,
|
||||
"shop_shuffle" : ShopShuffle,
|
||||
"candle_shuffle" : CandleShuffle,
|
||||
"boots_of_pleading": CustomItem1,
|
||||
"purified_hand": CustomItem2,
|
||||
"start_wheel": StartWheel,
|
||||
"skill_randomizer": SkillRando,
|
||||
"enemy_randomizer": EnemyRando,
|
||||
"enemy_groups": EnemyGroups,
|
||||
"enemy_scaling": EnemyScaling,
|
||||
"death_link": BlasphemousDeathLink
|
||||
"death_link": BlasphemousDeathLink,
|
||||
"start_inventory": StartInventoryPool
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -7,205 +7,14 @@ unrandomized_dict: Dict[str, str] = {
|
|||
"DC: Chalice room": "Chalice of Inverted Verses"
|
||||
}
|
||||
|
||||
cherub_set: Set[str] = [
|
||||
"Albero: Child of Moonlight",
|
||||
"AR: Upper west shaft Child of Moonlight",
|
||||
"BotSS: Starting room Child of Moonlight",
|
||||
"DC: Child of Moonlight, above water",
|
||||
"DC: Upper east Child of Moonlight",
|
||||
"DC: Child of Moonlight, miasma room",
|
||||
"DC: Child of Moonlight, behind pillar",
|
||||
"DC: Top of elevator Child of Moonlight",
|
||||
"DC: Elevator shaft Child of Moonlight",
|
||||
"GotP: Shop cave Child of Moonlight",
|
||||
"GotP: Elevator shaft Child of Moonlight",
|
||||
"GotP: West shaft Child of Moonlight",
|
||||
"GotP: Center shaft Child of Moonlight",
|
||||
"GA: Miasma room Child of Moonlight",
|
||||
"GA: Blood bridge Child of Moonlight",
|
||||
"GA: Lower east Child of Moonlight",
|
||||
"Jondo: Upper east Child of Moonlight",
|
||||
"Jondo: Spike tunnel Child of Moonlight",
|
||||
"Jondo: Upper west Child of Moonlight",
|
||||
"LotNW: Platform room Child of Moonlight",
|
||||
"LotNW: Lowest west Child of Moonlight",
|
||||
"LotNW: Elevator Child of Moonlight",
|
||||
"MD: Second area Child of Moonlight",
|
||||
"MD: Cave Child of Moonlight",
|
||||
"MoM: Lower west Child of Moonlight",
|
||||
"MoM: Upper center Child of Moonlight",
|
||||
"MotED: Child of Moonlight, above chasm",
|
||||
"PotSS: First area Child of Moonlight",
|
||||
"PotSS: Third area Child of Moonlight",
|
||||
"THL: Child of Moonlight",
|
||||
"WotHP: Upper east room, top bronze cell",
|
||||
"WotHP: Upper west room, top silver cell",
|
||||
"WotHP: Lower east room, bottom silver cell",
|
||||
"WotHP: Outside Child of Moonlight",
|
||||
"WotBC: Outside Child of Moonlight",
|
||||
"WotBC: Cliffside Child of Moonlight",
|
||||
"WOTW: Underground Child of Moonlight",
|
||||
"WOTW: Upper east Child of Moonlight",
|
||||
|
||||
junk_locations: Set[str] = [
|
||||
"Albero: Donate 50000 Tears",
|
||||
"Ossuary: 11th reward",
|
||||
"AtTotS: Miriam's gift",
|
||||
"TSC: Jocinero's final reward"
|
||||
]
|
||||
|
||||
life_set: Set[str] = [
|
||||
"AR: Lady of the Six Sorrows",
|
||||
"CoOLotCV: Lady of the Six Sorrows",
|
||||
"DC: Lady of the Six Sorrows, from MD",
|
||||
"DC: Lady of the Six Sorrows, elevator shaft",
|
||||
"GotP: Lady of the Six Sorrows",
|
||||
"LotNW: Lady of the Six Sorrows"
|
||||
]
|
||||
|
||||
fervour_set: Set[str] = [
|
||||
"DC: Oil of the Pilgrims",
|
||||
"GotP: Oil of the Pilgrims",
|
||||
"GA: Oil of the Pilgrims",
|
||||
"LotNW: Oil of the Pilgrims",
|
||||
"MoM: Oil of the Pilgrims",
|
||||
"WotHP: Oil of the Pilgrims"
|
||||
]
|
||||
|
||||
sword_set: Set[str] = [
|
||||
"Albero: Mea Culpa altar",
|
||||
"AR: Mea Culpa altar",
|
||||
"BotSS: Mea Culpa altar",
|
||||
"CoOLotCV: Mea Culpa altar",
|
||||
"DC: Mea Culpa altar",
|
||||
"LotNW: Mea Culpa altar",
|
||||
"MoM: Mea Culpa altar"
|
||||
]
|
||||
|
||||
blessing_dict: Dict[str, str] = {
|
||||
"Albero: Bless Severed Hand": "Incorrupt Hand of the Fraternal Master",
|
||||
"Albero: Bless Linen Cloth": "Shroud of Dreamt Sins",
|
||||
"Albero: Bless Hatched Egg": "Three Gnarled Tongues"
|
||||
}
|
||||
|
||||
dungeon_dict: Dict[str, str] = {
|
||||
"Confessor Dungeon 1 extra": "Tears of Atonement (1000)",
|
||||
"Confessor Dungeon 2 extra": "Heart of the Single Tone",
|
||||
"Confessor Dungeon 3 extra": "Tears of Atonement (3000)",
|
||||
"Confessor Dungeon 4 extra": "Embers of a Broken Star",
|
||||
"Confessor Dungeon 5 extra": "Tears of Atonement (5000)",
|
||||
"Confessor Dungeon 6 extra": "Scaly Coin",
|
||||
"Confessor Dungeon 7 extra": "Seashell of the Inverted Spiral"
|
||||
}
|
||||
|
||||
tirso_dict: Dict[str, str] = {
|
||||
"Albero: Tirso's 1st reward": "Linen Cloth",
|
||||
"Albero: Tirso's 2nd reward": "Tears of Atonement (500)",
|
||||
"Albero: Tirso's 3rd reward": "Tears of Atonement (1000)",
|
||||
"Albero: Tirso's 4th reward": "Tears of Atonement (2000)",
|
||||
"Albero: Tirso's 5th reward": "Tears of Atonement (5000)",
|
||||
"Albero: Tirso's 6th reward": "Tears of Atonement (10000)",
|
||||
"Albero: Tirso's final reward": "Knot of Rosary Rope"
|
||||
}
|
||||
|
||||
redento_dict: Dict[str, str] = {
|
||||
"MoM: Redento's treasure": "Nail Uprooted from Dirt",
|
||||
"MoM: Final meeting with Redento": "Knot of Rosary Rope",
|
||||
"MotED: 1st meeting with Redento": "Fourth Toe made of Limestone",
|
||||
"PotSS: 4th meeting with Redento": "Big Toe made of Limestone",
|
||||
"WotBC: 3rd meeting with Redento": "Little Toe made of Limestone"
|
||||
}
|
||||
|
||||
jocinero_dict: Dict[str, str] = {
|
||||
"TSC: Jocinero's 1st reward": "Linen of Golden Thread",
|
||||
"TSC: Jocinero's final reward": "Campanillero to the Sons of the Aurora"
|
||||
}
|
||||
|
||||
altasgracias_dict: Dict[str, str] = {
|
||||
"GA: Altasgracias' gift": "Egg of Deformity",
|
||||
"GA: Empty giant egg": "Knot of Hair"
|
||||
}
|
||||
|
||||
tentudia_dict: Dict[str, str] = {
|
||||
"Albero: Lvdovico's 1st reward": "Tears of Atonement (500)",
|
||||
"Albero: Lvdovico's 2nd reward": "Tears of Atonement (1000)",
|
||||
"Albero: Lvdovico's 3rd reward": "Debla of the Lights"
|
||||
}
|
||||
|
||||
gemino_dict: Dict[str, str] = {
|
||||
"WOTW: Gift for the tomb": "Dried Flowers bathed in Tears",
|
||||
"WOTW: Underground tomb": "Saeta Dolorosa",
|
||||
"WOTW: Gemino's gift": "Empty Golden Thimble",
|
||||
"WOTW: Gemino's reward": "Frozen Olive"
|
||||
}
|
||||
|
||||
ossuary_dict: Dict[str, str] = {
|
||||
"Ossuary: 1st reward": "Tears of Atonement (250)",
|
||||
"Ossuary: 2nd reward": "Tears of Atonement (500)",
|
||||
"Ossuary: 3rd reward": "Tears of Atonement (750)",
|
||||
"Ossuary: 4th reward": "Tears of Atonement (1000)",
|
||||
"Ossuary: 5th reward": "Tears of Atonement (1250)",
|
||||
"Ossuary: 6th reward": "Tears of Atonement (1500)",
|
||||
"Ossuary: 7th reward": "Tears of Atonement (1750)",
|
||||
"Ossuary: 8th reward": "Tears of Atonement (2000)",
|
||||
"Ossuary: 9th reward": "Tears of Atonement (2500)",
|
||||
"Ossuary: 10th reward": "Tears of Atonement (3000)",
|
||||
"Ossuary: 11th reward": "Tears of Atonement (5000)",
|
||||
}
|
||||
|
||||
boss_dict: Dict[str, str] = {
|
||||
"BotTC: Esdras, of the Anointed Legion": "Tears of Atonement (4300)",
|
||||
"BotSS: Warden of the Silent Sorrow": "Tears of Atonement (300)",
|
||||
"CoOLotCV: Our Lady of the Charred Visage": "Tears of Atonement (2600)",
|
||||
"HotD: Laudes, the First of the Amanecidas": "Tears of Atonement (30000)",
|
||||
"GotP: Amanecida of the Bejeweled Arrow": "Tears of Atonement (18000)",
|
||||
"GA: Tres Angustias": "Tears of Atonement (2100)",
|
||||
"MD: Ten Piedad": "Tears of Atonement (625)",
|
||||
"MoM: Melquiades, The Exhumed Archbishop": "Tears of Atonement (5500)",
|
||||
"MotED: Amanecida of the Golden Blades": "Tears of Atonement (18000)",
|
||||
"MaH: Sierpes": "Tears of Atonement (5000)",
|
||||
"PotSS: Amanecida of the Chiselled Steel": "Tears of Atonement (18000)",
|
||||
"TSC: Exposito, Scion of Abjuration": "Tears of Atonement (9000)",
|
||||
"WotHP: Quirce, Returned By The Flames": "Tears of Atonement (11250)",
|
||||
"WotHP: Amanecida of the Molten Thorn": "Tears of Atonement (18000)"
|
||||
}
|
||||
|
||||
wound_dict: Dict[str, str] = {
|
||||
"CoOLotCV: Visage of Compunction": "Holy Wound of Compunction",
|
||||
"GA: Visage of Contrition": "Holy Wound of Contrition",
|
||||
"MD: Visage of Attrition": "Holy Wound of Attrition"
|
||||
}
|
||||
|
||||
mask_dict: Dict[str, str] = {
|
||||
"CoOLotCV: Mask room": "Mirrored Mask of Dolphos",
|
||||
"LotNW: Mask room": "Embossed Mask of Crescente",
|
||||
"MoM: Mask room": "Deformed Mask of Orestes"
|
||||
}
|
||||
|
||||
eye_dict: Dict[str, str] = {
|
||||
"Ossuary: Isidora, Voice of the Dead": "Severed Right Eye of the Traitor",
|
||||
"MaH: Sierpes' eye": "Broken Left Eye of the Traitor"
|
||||
}
|
||||
|
||||
herb_dict: Dict[str, str] = {
|
||||
"Albero: Gate of Travel room": "Bouquet of Thyme",
|
||||
"Jondo: Lower east bell trap": "Bouquet of Rosemary",
|
||||
"MotED: Blood platform alcove": "Dried Clove",
|
||||
"PotSS: Third area lower ledge": "Olive Seeds",
|
||||
"TSC: Painting ladder ledge": "Sooty Garlic",
|
||||
"WOTW: Entrance to tomb": "Incense Garlic"
|
||||
}
|
||||
|
||||
church_dict: Dict[str, str] = {
|
||||
"Albero: Donate 5000 Tears": "Token of Appreciation",
|
||||
"Albero: Donate 50000 Tears": "Cloistered Ruby"
|
||||
}
|
||||
|
||||
shop_dict: Dict[str, str] = {
|
||||
"GotP: Shop item 1": "Torn Bridal Ribbon",
|
||||
"GotP: Shop item 2": "Calcified Eye of Erudition",
|
||||
"GotP: Shop item 3": "Ember of the Holy Cremation",
|
||||
"MD: Shop item 1": "Key to the Chamber of the Eldest Brother",
|
||||
"MD: Shop item 2": "Hollow Pearl",
|
||||
"MD: Shop item 3": "Moss Preserved in Glass",
|
||||
"TSC: Shop item 1": "Wicker Knot",
|
||||
"TSC: Shop item 2": "Empty Bile Vessel",
|
||||
"TSC: Shop item 3": "Key of the Inquisitor"
|
||||
}
|
||||
|
||||
thorn_set: Set[str] = {
|
||||
"THL: Deogracias' gift",
|
||||
|
@ -218,14 +27,6 @@ thorn_set: Set[str] = {
|
|||
"Confessor Dungeon 7 main",
|
||||
}
|
||||
|
||||
candle_dict: Dict[str, str] = {
|
||||
"CoOLotCV: Red candle": "Bead of Red Wax",
|
||||
"LotNW: Red candle": "Bead of Red Wax",
|
||||
"MD: Red candle": "Bead of Red Wax",
|
||||
"BotSS: Blue candle": "Bead of Blue Wax",
|
||||
"CoOLotCV: Blue candle": "Bead of Blue Wax",
|
||||
"MD: Blue candle": "Bead of Blue Wax"
|
||||
}
|
||||
|
||||
skill_dict: Dict[str, str] = {
|
||||
"Skill 1, Tier 1": "Combo Skill",
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
from typing import Dict, Set, List, Any
|
||||
from typing import Dict, List, Set, Any
|
||||
from collections import Counter
|
||||
from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification
|
||||
from ..AutoWorld import World, WebWorld
|
||||
from .Items import base_id, item_table, group_table, tears_set, reliquary_set, skill_set
|
||||
from .Locations import location_table, shop_set
|
||||
from .Exits import region_exit_table, exit_lookup_table
|
||||
from worlds.AutoWorld import World, WebWorld
|
||||
from .Items import base_id, item_table, group_table, tears_set, reliquary_set, event_table
|
||||
from .Locations import location_table
|
||||
from .Rooms import room_table, door_table
|
||||
from .Rules import rules
|
||||
from worlds.generic.Rules import set_rule
|
||||
from worlds.generic.Rules import set_rule, add_rule
|
||||
from .Options import blasphemous_options
|
||||
from . import Vanilla
|
||||
from .Vanilla import unrandomized_dict, junk_locations, thorn_set, skill_dict
|
||||
|
||||
|
||||
class BlasphemousWeb(WebWorld):
|
||||
|
@ -32,7 +32,7 @@ class BlasphemousWorld(World):
|
|||
|
||||
game: str = "Blasphemous"
|
||||
web = BlasphemousWeb()
|
||||
data_version = 1
|
||||
data_version = 2
|
||||
|
||||
item_name_to_id = {item["name"]: (base_id + index) for index, item in enumerate(item_table)}
|
||||
location_name_to_id = {loc["name"]: (base_id + index) for index, loc in enumerate(location_table)}
|
||||
|
@ -41,6 +41,14 @@ class BlasphemousWorld(World):
|
|||
item_name_groups = group_table
|
||||
option_definitions = blasphemous_options
|
||||
|
||||
required_client_version = (0, 4, 2)
|
||||
|
||||
|
||||
def __init__(self, multiworld, player):
|
||||
super(BlasphemousWorld, self).__init__(multiworld, player)
|
||||
self.start_room: str = "D17Z01S01"
|
||||
self.door_connections: Dict[str, str] = {}
|
||||
|
||||
|
||||
def set_rules(self):
|
||||
rules(self)
|
||||
|
@ -61,102 +69,134 @@ class BlasphemousWorld(World):
|
|||
return self.multiworld.random.choice(tears_set)
|
||||
|
||||
|
||||
def create_items(self):
|
||||
placed_items = []
|
||||
def generate_early(self):
|
||||
world = self.multiworld
|
||||
player = self.player
|
||||
|
||||
placed_items.extend(Vanilla.unrandomized_dict.values())
|
||||
if not world.starting_location[player].randomized:
|
||||
if world.starting_location[player].value == 6 and world.difficulty[player].value < 2:
|
||||
raise Exception(f"[Blasphemous - '{world.get_player_name(player)}'] {world.starting_location[player]}"
|
||||
" cannot be chosen if Difficulty is lower than Hard.")
|
||||
|
||||
if not self.multiworld.reliquary_shuffle[self.player]:
|
||||
placed_items.extend(reliquary_set)
|
||||
elif self.multiworld.reliquary_shuffle[self.player]:
|
||||
placed_items.append("Tears of Atonement (250)")
|
||||
placed_items.append("Tears of Atonement (300)")
|
||||
placed_items.append("Tears of Atonement (500)")
|
||||
if (world.starting_location[player].value == 0 or world.starting_location[player].value == 6) \
|
||||
and world.dash_shuffle[player]:
|
||||
raise Exception(f"[Blasphemous - '{world.get_player_name(player)}'] {world.starting_location[player]}"
|
||||
" cannot be chosen if Shuffle Dash is enabled.")
|
||||
|
||||
if world.starting_location[player].value == 3 and world.wall_climb_shuffle[player]:
|
||||
raise Exception(f"[Blasphemous - '{world.get_player_name(player)}'] {world.starting_location[player]}"
|
||||
" cannot be chosen if Shuffle Wall Climb is enabled.")
|
||||
else:
|
||||
locations: List[int] = [ 0, 1, 2, 3, 4, 5, 6 ]
|
||||
invalid: bool = False
|
||||
|
||||
if not self.multiworld.cherub_shuffle[self.player]:
|
||||
for i in range(38):
|
||||
placed_items.append("Child of Moonlight")
|
||||
if world.difficulty[player].value < 2:
|
||||
locations.remove(6)
|
||||
|
||||
if not self.multiworld.life_shuffle[self.player]:
|
||||
for i in range(6):
|
||||
placed_items.append("Life Upgrade")
|
||||
if world.dash_shuffle[player]:
|
||||
locations.remove(0)
|
||||
if 6 in locations:
|
||||
locations.remove(6)
|
||||
|
||||
if not self.multiworld.fervour_shuffle[self.player]:
|
||||
for i in range(6):
|
||||
placed_items.append("Fervour Upgrade")
|
||||
if world.wall_climb_shuffle[player]:
|
||||
locations.remove(3)
|
||||
|
||||
if not self.multiworld.sword_shuffle[self.player]:
|
||||
for i in range(7):
|
||||
placed_items.append("Mea Culpa Upgrade")
|
||||
if world.starting_location[player].value == 6 and world.difficulty[player].value < 2:
|
||||
invalid = True
|
||||
|
||||
if not self.multiworld.blessing_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.blessing_dict.values())
|
||||
if (world.starting_location[player].value == 0 or world.starting_location[player].value == 6) \
|
||||
and world.dash_shuffle[player]:
|
||||
invalid = True
|
||||
|
||||
if world.starting_location[player].value == 3 and world.wall_climb_shuffle[player]:
|
||||
invalid = True
|
||||
|
||||
if not self.multiworld.dungeon_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.dungeon_dict.values())
|
||||
|
||||
if not self.multiworld.tirso_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.tirso_dict.values())
|
||||
|
||||
if not self.multiworld.miriam_shuffle[self.player]:
|
||||
placed_items.append("Cantina of the Blue Rose")
|
||||
|
||||
if not self.multiworld.redento_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.redento_dict.values())
|
||||
|
||||
if not self.multiworld.jocinero_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.jocinero_dict.values())
|
||||
if invalid:
|
||||
world.starting_location[player].value = world.random.choice(locations)
|
||||
|
||||
|
||||
if not self.multiworld.altasgracias_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.altasgracias_dict.values())
|
||||
if not world.dash_shuffle[player]:
|
||||
world.push_precollected(self.create_item("Dash Ability"))
|
||||
|
||||
if not self.multiworld.tentudia_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.tentudia_dict.values())
|
||||
if not world.wall_climb_shuffle[player]:
|
||||
world.push_precollected(self.create_item("Wall Climb Ability"))
|
||||
|
||||
if not self.multiworld.gemino_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.gemino_dict.values())
|
||||
if world.skip_long_quests[player]:
|
||||
for loc in junk_locations:
|
||||
world.exclude_locations[player].value.add(loc)
|
||||
|
||||
if not self.multiworld.guilt_shuffle[self.player]:
|
||||
placed_items.append("Weight of True Guilt")
|
||||
start_rooms: Dict[int, str] = {
|
||||
0: "D17Z01S01",
|
||||
1: "D01Z02S01",
|
||||
2: "D02Z03S09",
|
||||
3: "D03Z03S11",
|
||||
4: "D04Z03S01",
|
||||
5: "D06Z01S09",
|
||||
6: "D20Z02S09"
|
||||
}
|
||||
|
||||
if not self.multiworld.ossuary_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.ossuary_dict.values())
|
||||
self.start_room = start_rooms[world.starting_location[player].value]
|
||||
|
||||
if not self.multiworld.boss_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.boss_dict.values())
|
||||
|
||||
if not self.multiworld.wound_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.wound_dict.values())
|
||||
def create_items(self):
|
||||
world = self.multiworld
|
||||
player = self.player
|
||||
|
||||
if not self.multiworld.mask_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.mask_dict.values())
|
||||
removed: int = 0
|
||||
to_remove: List[str] = [
|
||||
"Tears of Atonement (250)",
|
||||
"Tears of Atonement (300)",
|
||||
"Tears of Atonement (500)",
|
||||
"Tears of Atonement (500)",
|
||||
"Tears of Atonement (500)"
|
||||
]
|
||||
|
||||
if not self.multiworld.eye_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.eye_dict.values())
|
||||
skipped_items = []
|
||||
junk: int = 0
|
||||
|
||||
if not self.multiworld.herb_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.herb_dict.values())
|
||||
for item, count in world.start_inventory[player].value.items():
|
||||
for _ in range(count):
|
||||
skipped_items.append(item)
|
||||
junk += 1
|
||||
|
||||
if not self.multiworld.church_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.church_dict.values())
|
||||
skipped_items.extend(unrandomized_dict.values())
|
||||
|
||||
if not self.multiworld.shop_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.shop_dict.values())
|
||||
|
||||
if self.multiworld.thorn_shuffle[self.player] == 2:
|
||||
if world.thorn_shuffle[player] == 2:
|
||||
for i in range(8):
|
||||
placed_items.append("Thorn Upgrade")
|
||||
skipped_items.append("Thorn Upgrade")
|
||||
|
||||
if not self.multiworld.candle_shuffle[self.player]:
|
||||
placed_items.extend(Vanilla.candle_dict.values())
|
||||
if world.dash_shuffle[player]:
|
||||
skipped_items.append(to_remove[removed])
|
||||
removed += 1
|
||||
elif not world.dash_shuffle[player]:
|
||||
skipped_items.append("Dash Ability")
|
||||
|
||||
if self.multiworld.start_wheel[self.player]:
|
||||
placed_items.append("The Young Mason's Wheel")
|
||||
if world.wall_climb_shuffle[player]:
|
||||
skipped_items.append(to_remove[removed])
|
||||
removed += 1
|
||||
elif not world.wall_climb_shuffle[player]:
|
||||
skipped_items.append("Wall Climb Ability")
|
||||
|
||||
if not self.multiworld.skill_randomizer[self.player]:
|
||||
placed_items.extend(Vanilla.skill_dict.values())
|
||||
if not world.reliquary_shuffle[player]:
|
||||
skipped_items.extend(reliquary_set)
|
||||
elif world.reliquary_shuffle[player]:
|
||||
for i in range(3):
|
||||
skipped_items.append(to_remove[removed])
|
||||
removed += 1
|
||||
|
||||
counter = Counter(placed_items)
|
||||
if not world.boots_of_pleading[player]:
|
||||
skipped_items.append("Boots of Pleading")
|
||||
|
||||
if not world.purified_hand[player]:
|
||||
skipped_items.append("Purified Hand of the Nun")
|
||||
|
||||
if world.start_wheel[player]:
|
||||
skipped_items.append("The Young Mason's Wheel")
|
||||
|
||||
if not world.skill_randomizer[player]:
|
||||
skipped_items.extend(skill_dict.values())
|
||||
|
||||
counter = Counter(skipped_items)
|
||||
|
||||
pool = []
|
||||
|
||||
|
@ -169,95 +209,30 @@ class BlasphemousWorld(World):
|
|||
for i in range(count):
|
||||
pool.append(self.create_item(item["name"]))
|
||||
|
||||
self.multiworld.itempool += pool
|
||||
for _ in range(junk):
|
||||
pool.append(self.create_item(self.get_filler_item_name()))
|
||||
|
||||
world.itempool += pool
|
||||
|
||||
|
||||
def pre_fill(self):
|
||||
self.place_items_from_dict(Vanilla.unrandomized_dict)
|
||||
world = self.multiworld
|
||||
player = self.player
|
||||
|
||||
if not self.multiworld.cherub_shuffle[self.player]:
|
||||
self.place_items_from_set(Vanilla.cherub_set, "Child of Moonlight")
|
||||
self.place_items_from_dict(unrandomized_dict)
|
||||
|
||||
if not self.multiworld.life_shuffle[self.player]:
|
||||
self.place_items_from_set(Vanilla.life_set, "Life Upgrade")
|
||||
if world.thorn_shuffle[player] == 2:
|
||||
self.place_items_from_set(thorn_set, "Thorn Upgrade")
|
||||
|
||||
if not self.multiworld.fervour_shuffle[self.player]:
|
||||
self.place_items_from_set(Vanilla.fervour_set, "Fervour Upgrade")
|
||||
|
||||
if not self.multiworld.sword_shuffle[self.player]:
|
||||
self.place_items_from_set(Vanilla.sword_set, "Mea Culpa Upgrade")
|
||||
|
||||
if not self.multiworld.blessing_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.blessing_dict)
|
||||
|
||||
if not self.multiworld.dungeon_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.dungeon_dict)
|
||||
|
||||
if not self.multiworld.tirso_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.tirso_dict)
|
||||
|
||||
if not self.multiworld.miriam_shuffle[self.player]:
|
||||
self.multiworld.get_location("AtTotS: Miriam's gift", self.player)\
|
||||
.place_locked_item(self.create_item("Cantina of the Blue Rose"))
|
||||
|
||||
if not self.multiworld.redento_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.redento_dict)
|
||||
|
||||
if not self.multiworld.jocinero_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.jocinero_dict)
|
||||
|
||||
if not self.multiworld.altasgracias_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.altasgracias_dict)
|
||||
|
||||
if not self.multiworld.tentudia_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.tentudia_dict)
|
||||
|
||||
if not self.multiworld.gemino_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.gemino_dict)
|
||||
|
||||
if not self.multiworld.guilt_shuffle[self.player]:
|
||||
self.multiworld.get_location("GotP: Confessor Dungeon room", self.player)\
|
||||
.place_locked_item(self.create_item("Weight of True Guilt"))
|
||||
|
||||
if not self.multiworld.ossuary_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.ossuary_dict)
|
||||
|
||||
if not self.multiworld.boss_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.boss_dict)
|
||||
|
||||
if not self.multiworld.wound_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.wound_dict)
|
||||
|
||||
if not self.multiworld.mask_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.mask_dict)
|
||||
|
||||
if not self.multiworld.eye_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.eye_dict)
|
||||
|
||||
if not self.multiworld.herb_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.herb_dict)
|
||||
|
||||
if not self.multiworld.church_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.church_dict)
|
||||
|
||||
if not self.multiworld.shop_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.shop_dict)
|
||||
|
||||
if self.multiworld.thorn_shuffle[self.player] == 2:
|
||||
self.place_items_from_set(Vanilla.thorn_set, "Thorn Upgrade")
|
||||
|
||||
if not self.multiworld.candle_shuffle[self.player]:
|
||||
self.place_items_from_dict(Vanilla.candle_dict)
|
||||
|
||||
if self.multiworld.start_wheel[self.player]:
|
||||
self.multiworld.get_location("BotSS: Beginning gift", self.player)\
|
||||
if world.start_wheel[player]:
|
||||
world.get_location("Beginning gift", player)\
|
||||
.place_locked_item(self.create_item("The Young Mason's Wheel"))
|
||||
|
||||
if not self.multiworld.skill_randomizer[self.player]:
|
||||
self.place_items_from_dict(Vanilla.skill_dict)
|
||||
if not world.skill_randomizer[player]:
|
||||
self.place_items_from_dict(skill_dict)
|
||||
|
||||
if self.multiworld.thorn_shuffle[self.player] == 1:
|
||||
self.multiworld.local_items[self.player].value.add("Thorn Upgrade")
|
||||
if world.thorn_shuffle[player] == 1:
|
||||
world.local_items[player].value.add("Thorn Upgrade")
|
||||
|
||||
|
||||
def place_items_from_set(self, location_set: Set[str], name: str):
|
||||
|
@ -273,133 +248,143 @@ class BlasphemousWorld(World):
|
|||
|
||||
|
||||
def create_regions(self) -> None:
|
||||
|
||||
player = self.player
|
||||
world = self.multiworld
|
||||
|
||||
region_table: Dict[str, Region] = {
|
||||
"menu" : Region("Menu", player, world),
|
||||
"albero" : Region("Albero", player, world),
|
||||
"attots" : Region("All the Tears of the Sea", player, world),
|
||||
"ar" : Region("Archcathedral Rooftops", player, world),
|
||||
"bottc" : Region("Bridge of the Three Cavalries", player, world),
|
||||
"botss" : Region("Brotherhood of the Silent Sorrow", player, world),
|
||||
"coolotcv": Region("Convent of Our Lady of the Charred Visage", player, world),
|
||||
"dohh" : Region("Deambulatory of His Holiness", player, world),
|
||||
"dc" : Region("Desecrated Cistern", player, world),
|
||||
"eos" : Region("Echoes of Salt", player, world),
|
||||
"ft" : Region("Ferrous Tree", player, world),
|
||||
"gotp" : Region("Graveyard of the Peaks", player, world),
|
||||
"ga" : Region("Grievance Ascends", player, world),
|
||||
"hotd" : Region("Hall of the Dawning", player, world),
|
||||
"jondo" : Region("Jondo", player, world),
|
||||
"kottw" : Region("Knot of the Three Words", player, world),
|
||||
"lotnw" : Region("Library of the Negated Words", player, world),
|
||||
"md" : Region("Mercy Dreams", player, world),
|
||||
"mom" : Region("Mother of Mothers", player, world),
|
||||
"moted" : Region("Mountains of the Endless Dusk", player, world),
|
||||
"mah" : Region("Mourning and Havoc", player, world),
|
||||
"potss" : Region("Patio of the Silent Steps", player, world),
|
||||
"petrous" : Region("Petrous", player, world),
|
||||
"thl" : Region("The Holy Line", player, world),
|
||||
"trpots" : Region("The Resting Place of the Sister", player, world),
|
||||
"tsc" : Region("The Sleeping Canvases", player, world),
|
||||
"wothp" : Region("Wall of the Holy Prohibitions", player, world),
|
||||
"wotbc" : Region("Wasteland of the Buried Churches", player, world),
|
||||
"wotw" : Region("Where Olive Trees Wither", player, world),
|
||||
"dungeon" : Region("Dungeons", player, world)
|
||||
}
|
||||
|
||||
for rname, reg in region_table.items():
|
||||
world.regions.append(reg)
|
||||
|
||||
for ename, exits in region_exit_table.items():
|
||||
if ename == rname:
|
||||
for i in exits:
|
||||
ent = Entrance(player, i, reg)
|
||||
reg.exits.append(ent)
|
||||
|
||||
for e, r in exit_lookup_table.items():
|
||||
if i == e:
|
||||
ent.connect(region_table[r])
|
||||
|
||||
for loc in location_table:
|
||||
id = base_id + location_table.index(loc)
|
||||
region_table[loc["region"]].locations\
|
||||
.append(BlasphemousLocation(self.player, loc["name"], id, region_table[loc["region"]]))
|
||||
|
||||
victory = Location(self.player, "His Holiness Escribar", None, self.multiworld.get_region("Deambulatory of His Holiness", self.player))
|
||||
victory.place_locked_item(self.create_event("Victory"))
|
||||
self.multiworld.get_region("Deambulatory of His Holiness", self.player).locations.append(victory)
|
||||
menu_region = Region("Menu", player, world)
|
||||
misc_region = Region("Misc", player, world)
|
||||
world.regions += [menu_region, misc_region]
|
||||
|
||||
if self.multiworld.ending[self.player].value == 1:
|
||||
for room in room_table:
|
||||
region = Region(room, player, world)
|
||||
world.regions.append(region)
|
||||
|
||||
menu_region.add_exits({self.start_room: "New Game"})
|
||||
world.get_region(self.start_room, player).add_exits({"Misc": "Misc"})
|
||||
|
||||
for door in door_table:
|
||||
if door.get("OriginalDoor") is None:
|
||||
continue
|
||||
else:
|
||||
if not door["Id"] in self.door_connections.keys():
|
||||
self.door_connections[door["Id"]] = door["OriginalDoor"]
|
||||
self.door_connections[door["OriginalDoor"]] = door["Id"]
|
||||
|
||||
parent_region: Region = self.get_room_from_door(door["Id"])
|
||||
target_region: Region = self.get_room_from_door(door["OriginalDoor"])
|
||||
parent_region.add_exits({
|
||||
target_region.name: door["Id"]
|
||||
}, {
|
||||
target_region.name: lambda x: door.get("VisibilityFlags") != 1
|
||||
})
|
||||
|
||||
for index, loc in enumerate(location_table):
|
||||
if not world.boots_of_pleading[player] and loc["name"] == "BotSS: 2nd meeting with Redento":
|
||||
continue
|
||||
if not world.purified_hand[player] and loc["name"] == "MoM: Western room ledge":
|
||||
continue
|
||||
|
||||
region: Region = world.get_region(loc["room"], player)
|
||||
region.add_locations({loc["name"]: base_id + index})
|
||||
#id = base_id + location_table.index(loc)
|
||||
#reg.locations.append(BlasphemousLocation(player, loc["name"], id, reg))
|
||||
|
||||
for e, r in event_table.items():
|
||||
region: Region = world.get_region(r, player)
|
||||
event = BlasphemousLocation(player, e, None, region)
|
||||
event.show_in_spoiler = False
|
||||
event.place_locked_item(self.create_event(e))
|
||||
region.locations.append(event)
|
||||
|
||||
for door in door_table:
|
||||
region: Region = self.get_room_from_door(self.door_connections[door["Id"]])
|
||||
event = BlasphemousLocation(player, door["Id"], None, region)
|
||||
event.show_in_spoiler = False
|
||||
event.place_locked_item(self.create_event(door["Id"]))
|
||||
add_rule(event, lambda state: state.can_reach(self.get_connected_door(door["Id"])), player)
|
||||
region.locations.append(event)
|
||||
|
||||
victory = Location(player, "His Holiness Escribar", None, world.get_region("D07Z01S03", player))
|
||||
victory.place_locked_item(self.create_event("Victory"))
|
||||
world.get_region("D07Z01S03", player).locations.append(victory)
|
||||
|
||||
if world.ending[self.player].value == 1:
|
||||
set_rule(victory, lambda state: state.has("Thorn Upgrade", player, 8))
|
||||
elif self.multiworld.ending[self.player].value == 2:
|
||||
set_rule(victory, lambda state: state.has("Thorn Upgrade", player, 8) and \
|
||||
elif world.ending[self.player].value == 2:
|
||||
set_rule(victory, lambda state: state.has("Thorn Upgrade", player, 8) and
|
||||
state.has("Holy Wound of Abnegation", player))
|
||||
|
||||
self.multiworld.completion_condition[self.player] = lambda state: state.has("Victory", self.player)
|
||||
world.completion_condition[self.player] = lambda state: state.has("Victory", player)
|
||||
|
||||
|
||||
def get_room_from_door(self, door: str) -> Region:
|
||||
return self.multiworld.get_region(door.split("[")[0], self.player)
|
||||
|
||||
|
||||
def get_connected_door(self, door: str) -> Entrance:
|
||||
return self.multiworld.get_entrance(self.door_connections[door], self.player)
|
||||
|
||||
|
||||
def fill_slot_data(self) -> Dict[str, Any]:
|
||||
slot_data: Dict[str, Any] = {}
|
||||
locations = []
|
||||
doors: Dict[str, str] = {}
|
||||
|
||||
for loc in self.multiworld.get_filled_locations(self.player):
|
||||
if loc.name == "His Holiness Escribar":
|
||||
world = self.multiworld
|
||||
player = self.player
|
||||
thorns: bool = True
|
||||
|
||||
if world.thorn_shuffle[player].value == 2:
|
||||
thorns = False
|
||||
|
||||
for loc in world.get_filled_locations(player):
|
||||
if loc.item.code == None:
|
||||
continue
|
||||
else:
|
||||
data = {
|
||||
"id": self.location_name_to_game_id[loc.name],
|
||||
"ap_id": loc.address,
|
||||
"name": loc.item.name,
|
||||
"player_name": self.multiworld.player_name[loc.item.player]
|
||||
"player_name": world.player_name[loc.item.player],
|
||||
"type": int(loc.item.classification)
|
||||
}
|
||||
|
||||
if loc.name in shop_set:
|
||||
data["type"] = loc.item.classification.name
|
||||
|
||||
locations.append(data)
|
||||
|
||||
config = {
|
||||
"versionCreated": "AP",
|
||||
"general": {
|
||||
"teleportationAlwaysUnlocked": bool(self.multiworld.prie_dieu_warp[self.player].value),
|
||||
"skipCutscenes": bool(self.multiworld.skip_cutscenes[self.player].value),
|
||||
"enablePenitence": bool(self.multiworld.penitence[self.player].value),
|
||||
"hardMode": False,
|
||||
"customSeed": 0,
|
||||
"allowHints": bool(self.multiworld.corpse_hints[self.player].value)
|
||||
},
|
||||
"items": {
|
||||
"type": 1,
|
||||
"lungDamage": False,
|
||||
"disableNPCDeath": True,
|
||||
"startWithWheel": bool(self.multiworld.start_wheel[self.player].value),
|
||||
"shuffleReliquaries": bool(self.multiworld.reliquary_shuffle[self.player].value)
|
||||
},
|
||||
"enemies": {
|
||||
"type": self.multiworld.enemy_randomizer[self.player].value,
|
||||
"maintainClass": bool(self.multiworld.enemy_groups[self.player].value),
|
||||
"areaScaling": bool(self.multiworld.enemy_scaling[self.player].value)
|
||||
},
|
||||
"prayers": {
|
||||
"type": 0,
|
||||
"removeMirabis": False
|
||||
},
|
||||
"doors": {
|
||||
"type": 0
|
||||
},
|
||||
"debug": {
|
||||
"type": 0
|
||||
}
|
||||
"LogicDifficulty": world.difficulty[player].value,
|
||||
"StartingLocation": world.starting_location[player].value,
|
||||
"VersionCreated": "AP",
|
||||
|
||||
"UnlockTeleportation": bool(world.prie_dieu_warp[player].value),
|
||||
"AllowHints": bool(world.corpse_hints[player].value),
|
||||
"AllowPenitence": bool(world.penitence[player].value),
|
||||
|
||||
"ShuffleReliquaries": bool(world.reliquary_shuffle[player].value),
|
||||
"ShuffleBootsOfPleading": bool(world.boots_of_pleading[player].value),
|
||||
"ShufflePurifiedHand": bool(world.purified_hand[player].value),
|
||||
"ShuffleDash": bool(world.dash_shuffle[player].value),
|
||||
"ShuffleWallClimb": bool(world.wall_climb_shuffle[player].value),
|
||||
|
||||
"ShuffleSwordSkills": bool(world.skill_randomizer[player].value),
|
||||
"ShuffleThorns": thorns,
|
||||
"JunkLongQuests": bool(world.skip_long_quests[player].value),
|
||||
"StartWithWheel": bool(world.start_wheel[player].value),
|
||||
|
||||
"EnemyShuffleType": world.enemy_randomizer[player].value,
|
||||
"MaintainClass": bool(world.enemy_groups[player].value),
|
||||
"AreaScaling": bool(world.enemy_scaling[player].value),
|
||||
|
||||
"BossShuffleType": 0,
|
||||
"DoorShuffleType": 0
|
||||
}
|
||||
|
||||
slot_data = {
|
||||
"locations": locations,
|
||||
"doors": doors,
|
||||
"cfg": config,
|
||||
"ending": self.multiworld.ending[self.player].value,
|
||||
"death_link": bool(self.multiworld.death_link[self.player].value)
|
||||
"ending": world.ending[self.player].value,
|
||||
"death_link": bool(world.death_link[self.player].value)
|
||||
}
|
||||
|
||||
return slot_data
|
||||
|
|
|
@ -1,24 +1,49 @@
|
|||
# Blasphemous Multiworld Setup Guide
|
||||
|
||||
## Required Software
|
||||
## Useful Links
|
||||
|
||||
- Blasphemous from: [Steam](https://store.steampowered.com/app/774361/Blasphemous/)
|
||||
- Blasphemous Modding API from: [GitHub](https://github.com/BrandenEK/Blasphemous-Modding-API)
|
||||
- Blasphemous Randomizer from: [GitHub](https://github.com/BrandenEK/Blasphemous-Randomizer)
|
||||
- Blasphemous Multiworld from: [GitHub](https://github.com/BrandenEK/Blasphemous-Multiworld)
|
||||
- (*Optional*) PopTracker Pack from: [GitHub](https://github.com/sassyvania/Blasphemous-Randomizer-Maptracker)
|
||||
Required:
|
||||
- Blasphemous: [Steam](https://store.steampowered.com/app/774361/Blasphemous/)
|
||||
- The GOG version of Blasphemous will also work.
|
||||
- Blasphemous Mod Installer: [GitHub](https://github.com/BrandenEK/Blasphemous-Mod-Installer)
|
||||
- Blasphemous Modding API: [GitHub](https://github.com/BrandenEK/Blasphemous-Modding-API)
|
||||
- Blasphemous Randomizer: [GitHub](https://github.com/BrandenEK/Blasphemous-Randomizer)
|
||||
- Blasphemous Multiworld: [GitHub](https://github.com/BrandenEK/Blasphemous-Multiworld)
|
||||
|
||||
## Instructions (Windows)
|
||||
Optional:
|
||||
- In-game map tracker: [GitHub](https://github.com/BrandenEK/Blasphemous-Rando-Map)
|
||||
- Quick Prie Dieu warp mod: [GitHub](https://github.com/BadMagic100/Blasphemous-PrieWarp)
|
||||
- Boots of Pleading mod: [GitHub](https://github.com/BrandenEK/Blasphemous-Boots-of-Pleading)
|
||||
- Double Jump mod: [GitHub](https://github.com/BrandenEK/Blasphemous-Double-Jump)
|
||||
- PopTracker pack: [GitHub](https://github.com/sassyvania/Blasphemous-Randomizer-Maptracker)
|
||||
|
||||
1. Download the [Modding API](https://github.com/BrandenEK/Blasphemous-Modding-API/releases), and follow the [installation instructions](https://github.com/BrandenEK/Blasphemous-Modding-API#installation) on the GitHub page.
|
||||
## Mod Installer (Recommended)
|
||||
|
||||
2. After the Modding API has been installed, download the [Randomizer](https://github.com/BrandenEK/Blasphemous-Randomizer/releases) and [Multiworld](https://github.com/BrandenEK/Blasphemous-Multiworld/releases) archives, and extract the contents of both into the `Modding` folder.
|
||||
1. Download the [Mod Installer](https://github.com/BrandenEK/Blasphemous-Mod-Installer),
|
||||
and point it to your install directory for Blasphemous.
|
||||
|
||||
3. Start Blasphemous. To verfy that the mods are working, look for a version number for both the Randomizer and Multiworld on the title screen.
|
||||
2. Install the `Modding API`, `Randomizer`, and `Multiworld` mods. Optionally, you can also install the
|
||||
`Rando Map`, `PrieWarp`, `Boots of Pleading`, and `Double Jump` mods, and set up the PopTracker pack if desired.
|
||||
|
||||
4. (*Optional*) Add the Blasphemous pack to PopTracker. In game, open the console by pressing backslash `\` and type `randomizer autotracker on` to automatically connect the game to PopTracker.
|
||||
3. Start Blasphemous. To verfy that the mods are working, look for a version number for both
|
||||
the Randomizer and Multiworld on the title screen.
|
||||
|
||||
## Manual Installation
|
||||
|
||||
1. Download the [Modding API](https://github.com/BrandenEK/Blasphemous-Modding-API/releases), and follow
|
||||
the [installation instructions](https://github.com/BrandenEK/Blasphemous-Modding-API#installation) on the GitHub page.
|
||||
|
||||
2. After the Modding API has been installed, download the
|
||||
[Randomizer](https://github.com/BrandenEK/Blasphemous-Randomizer/releases) and
|
||||
[Multiworld](https://github.com/BrandenEK/Blasphemous-Multiworld/releases) archives, and extract the contents of both
|
||||
into the `Modding` folder. Then, add any desired additional mods.
|
||||
|
||||
3. Start Blasphemous. To verfy that the mods are working, look for a version number for both
|
||||
the Randomizer and Multiworld on the title screen.
|
||||
|
||||
## Connecting
|
||||
|
||||
To connect to an Archipelago server, open the in-game console by pressing backslash `\` and use the command `multiworld connect [address:port] [name] [password]`. The port and password are both optional - if no port is provided then the default port of 38281 is used.
|
||||
To connect to an Archipelago server, open the in-game console by pressing backslash `\` and use
|
||||
the command `multiworld connect [address:port] [name] [password]`.
|
||||
The port and password are both optional - if no port is provided then the default port of 38281 is used.
|
||||
**Make sure to connect to the server before attempting to start a new save file.**
|
Loading…
Reference in New Issue