Blasphemous: Randomizer 2.0 (#1883)

Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
This commit is contained in:
Trevor L 2023-07-05 22:39:26 -06:00 committed by GitHub
parent f2117be7d9
commit 1338d7a968
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 10277 additions and 2650 deletions

View File

@ -67,7 +67,6 @@ non_apworlds: set = {
"Adventure",
"ArchipIDLE",
"Archipelago",
"Blasphemous",
"ChecksFinder",
"Clique",
"DLCQuest",

View File

@ -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"
}

View File

@ -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

View File

@ -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
}

5405
worlds/blasphemous/Rooms.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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 generate_early(self):
world = self.multiworld
player = self.player
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 (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 world.difficulty[player].value < 2:
locations.remove(6)
if world.dash_shuffle[player]:
locations.remove(0)
if 6 in locations:
locations.remove(6)
if world.wall_climb_shuffle[player]:
locations.remove(3)
if world.starting_location[player].value == 6 and world.difficulty[player].value < 2:
invalid = True
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 invalid:
world.starting_location[player].value = world.random.choice(locations)
if not world.dash_shuffle[player]:
world.push_precollected(self.create_item("Dash Ability"))
if not world.wall_climb_shuffle[player]:
world.push_precollected(self.create_item("Wall Climb Ability"))
if world.skip_long_quests[player]:
for loc in junk_locations:
world.exclude_locations[player].value.add(loc)
start_rooms: Dict[int, str] = {
0: "D17Z01S01",
1: "D01Z02S01",
2: "D02Z03S09",
3: "D03Z03S11",
4: "D04Z03S01",
5: "D06Z01S09",
6: "D20Z02S09"
}
self.start_room = start_rooms[world.starting_location[player].value]
def create_items(self):
placed_items = []
world = self.multiworld
player = self.player
placed_items.extend(Vanilla.unrandomized_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.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)")
skipped_items = []
junk: int = 0
if not self.multiworld.cherub_shuffle[self.player]:
for i in range(38):
placed_items.append("Child of Moonlight")
for item, count in world.start_inventory[player].value.items():
for _ in range(count):
skipped_items.append(item)
junk += 1
if not self.multiworld.life_shuffle[self.player]:
for i in range(6):
placed_items.append("Life Upgrade")
skipped_items.extend(unrandomized_dict.values())
if not self.multiworld.fervour_shuffle[self.player]:
for i in range(6):
placed_items.append("Fervour Upgrade")
if not self.multiworld.sword_shuffle[self.player]:
for i in range(7):
placed_items.append("Mea Culpa Upgrade")
if not self.multiworld.blessing_shuffle[self.player]:
placed_items.extend(Vanilla.blessing_dict.values())
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 not self.multiworld.altasgracias_shuffle[self.player]:
placed_items.extend(Vanilla.altasgracias_dict.values())
if not self.multiworld.tentudia_shuffle[self.player]:
placed_items.extend(Vanilla.tentudia_dict.values())
if not self.multiworld.gemino_shuffle[self.player]:
placed_items.extend(Vanilla.gemino_dict.values())
if not self.multiworld.guilt_shuffle[self.player]:
placed_items.append("Weight of True Guilt")
if not self.multiworld.ossuary_shuffle[self.player]:
placed_items.extend(Vanilla.ossuary_dict.values())
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())
if not self.multiworld.mask_shuffle[self.player]:
placed_items.extend(Vanilla.mask_dict.values())
if not self.multiworld.eye_shuffle[self.player]:
placed_items.extend(Vanilla.eye_dict.values())
if not self.multiworld.herb_shuffle[self.player]:
placed_items.extend(Vanilla.herb_dict.values())
if not self.multiworld.church_shuffle[self.player]:
placed_items.extend(Vanilla.church_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)
}
menu_region = Region("Menu", player, world)
misc_region = Region("Misc", player, world)
world.regions += [menu_region, misc_region]
for rname, reg in region_table.items():
world.regions.append(reg)
for room in room_table:
region = Region(room, player, world)
world.regions.append(region)
for ename, exits in region_exit_table.items():
if ename == rname:
for i in exits:
ent = Entrance(player, i, reg)
reg.exits.append(ent)
menu_region.add_exits({self.start_room: "New Game"})
world.get_region(self.start_room, player).add_exits({"Misc": "Misc"})
for e, r in exit_lookup_table.items():
if i == e:
ent.connect(region_table[r])
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"]
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"]]))
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
})
victory = Location(self.player, "His Holiness Escribar", None, self.multiworld.get_region("Deambulatory of His Holiness", self.player))
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"))
self.multiworld.get_region("Deambulatory of His Holiness", self.player).locations.append(victory)
world.get_region("D07Z01S03", player).locations.append(victory)
if self.multiworld.ending[self.player].value == 1:
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

View File

@ -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.**