mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
RL: Rename Rogue Legacy Folder (#452)
* rename rogue legacy "`rogue-legacy` is not a valid python module name" * revert rename of the documentation file
This commit is contained in:
136
worlds/rogue_legacy/Items.py
Normal file
136
worlds/rogue_legacy/Items.py
Normal file
@@ -0,0 +1,136 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Item
|
||||
from .Names import ItemName
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
code: typing.Optional[int]
|
||||
progression: bool
|
||||
quantity: int = 1
|
||||
event: bool = False
|
||||
|
||||
|
||||
class LegacyItem(Item):
|
||||
game: str = "Rogue Legacy"
|
||||
|
||||
|
||||
# Separate tables for each type of item.
|
||||
vendors_table = {
|
||||
ItemName.blacksmith: ItemData(90000, True),
|
||||
ItemName.enchantress: ItemData(90001, True),
|
||||
ItemName.architect: ItemData(90002, False),
|
||||
}
|
||||
|
||||
static_classes_table = {
|
||||
ItemName.knight: ItemData(90080, False),
|
||||
ItemName.paladin: ItemData(90081, False),
|
||||
ItemName.mage: ItemData(90082, False),
|
||||
ItemName.archmage: ItemData(90083, False),
|
||||
ItemName.barbarian: ItemData(90084, False),
|
||||
ItemName.barbarian_king: ItemData(90085, False),
|
||||
ItemName.knave: ItemData(90086, False),
|
||||
ItemName.assassin: ItemData(90087, False),
|
||||
ItemName.shinobi: ItemData(90088, False),
|
||||
ItemName.hokage: ItemData(90089, False),
|
||||
ItemName.miner: ItemData(90090, False),
|
||||
ItemName.spelunker: ItemData(90091, False),
|
||||
ItemName.lich: ItemData(90092, False),
|
||||
ItemName.lich_king: ItemData(90093, False),
|
||||
ItemName.spellthief: ItemData(90094, False),
|
||||
ItemName.spellsword: ItemData(90095, False),
|
||||
ItemName.dragon: ItemData(90096, False),
|
||||
ItemName.traitor: ItemData(90097, False),
|
||||
}
|
||||
|
||||
progressive_classes_table = {
|
||||
ItemName.progressive_knight: ItemData(90003, False, 2),
|
||||
ItemName.progressive_mage: ItemData(90004, False, 2),
|
||||
ItemName.progressive_barbarian: ItemData(90005, False, 2),
|
||||
ItemName.progressive_knave: ItemData(90006, False, 2),
|
||||
ItemName.progressive_shinobi: ItemData(90007, False, 2),
|
||||
ItemName.progressive_miner: ItemData(90008, False, 2),
|
||||
ItemName.progressive_lich: ItemData(90009, False, 2),
|
||||
ItemName.progressive_spellthief: ItemData(90010, False, 2),
|
||||
}
|
||||
|
||||
configurable_skill_unlocks_table = {
|
||||
ItemName.health: ItemData(90013, True, 15),
|
||||
ItemName.mana: ItemData(90014, True, 15),
|
||||
ItemName.attack: ItemData(90015, True, 15),
|
||||
ItemName.magic_damage: ItemData(90016, True, 15),
|
||||
ItemName.armor: ItemData(90017, True, 10),
|
||||
ItemName.equip: ItemData(90018, True, 10),
|
||||
ItemName.crit_chance: ItemData(90019, False, 5),
|
||||
ItemName.crit_damage: ItemData(90020, False, 5),
|
||||
}
|
||||
|
||||
skill_unlocks_table = {
|
||||
ItemName.down_strike: ItemData(90021, False),
|
||||
ItemName.gold_gain: ItemData(90022, False),
|
||||
ItemName.potion_efficiency: ItemData(90023, False),
|
||||
ItemName.invulnerability_time: ItemData(90024, False),
|
||||
ItemName.mana_cost_down: ItemData(90025, False),
|
||||
ItemName.death_defiance: ItemData(90026, False),
|
||||
ItemName.haggling: ItemData(90027, False),
|
||||
ItemName.random_children: ItemData(90028, False),
|
||||
}
|
||||
|
||||
blueprints_table = {
|
||||
ItemName.squire_blueprints: ItemData(90040, False),
|
||||
ItemName.silver_blueprints: ItemData(90041, False),
|
||||
ItemName.guardian_blueprints: ItemData(90042, False),
|
||||
ItemName.imperial_blueprints: ItemData(90043, False),
|
||||
ItemName.royal_blueprints: ItemData(90044, False),
|
||||
ItemName.knight_blueprints: ItemData(90045, False),
|
||||
ItemName.ranger_blueprints: ItemData(90046, False),
|
||||
ItemName.sky_blueprints: ItemData(90047, False),
|
||||
ItemName.dragon_blueprints: ItemData(90048, False),
|
||||
ItemName.slayer_blueprints: ItemData(90049, False),
|
||||
ItemName.blood_blueprints: ItemData(90050, False),
|
||||
ItemName.sage_blueprints: ItemData(90051, False),
|
||||
ItemName.retribution_blueprints: ItemData(90052, False),
|
||||
ItemName.holy_blueprints: ItemData(90053, False),
|
||||
ItemName.dark_blueprints: ItemData(90054, False),
|
||||
}
|
||||
|
||||
progressive_blueprint_table = {
|
||||
ItemName.progressive_blueprints: ItemData(90055, False),
|
||||
}
|
||||
|
||||
runes_table = {
|
||||
ItemName.vault_runes: ItemData(90060, False),
|
||||
ItemName.sprint_runes: ItemData(90061, False),
|
||||
ItemName.vampire_runes: ItemData(90062, False),
|
||||
ItemName.sky_runes: ItemData(90063, False),
|
||||
ItemName.siphon_runes: ItemData(90064, False),
|
||||
ItemName.retaliation_runes: ItemData(90065, False),
|
||||
ItemName.bounty_runes: ItemData(90066, False),
|
||||
ItemName.haste_runes: ItemData(90067, False),
|
||||
ItemName.curse_runes: ItemData(90068, False),
|
||||
ItemName.grace_runes: ItemData(90069, False),
|
||||
ItemName.balance_runes: ItemData(90070, False),
|
||||
}
|
||||
|
||||
misc_items_table = {
|
||||
ItemName.trip_stat_increase: ItemData(90030, False),
|
||||
ItemName.gold_1000: ItemData(90031, False),
|
||||
ItemName.gold_3000: ItemData(90032, False),
|
||||
ItemName.gold_5000: ItemData(90033, False),
|
||||
# ItemName.rage_trap: ItemData(90034, False),
|
||||
}
|
||||
|
||||
# Complete item table.
|
||||
item_table = {
|
||||
**vendors_table,
|
||||
**static_classes_table,
|
||||
**progressive_classes_table,
|
||||
**configurable_skill_unlocks_table,
|
||||
**skill_unlocks_table,
|
||||
**blueprints_table,
|
||||
**progressive_blueprint_table,
|
||||
**runes_table,
|
||||
**misc_items_table,
|
||||
}
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
90
worlds/rogue_legacy/Locations.py
Normal file
90
worlds/rogue_legacy/Locations.py
Normal file
@@ -0,0 +1,90 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Location
|
||||
from .Names import LocationName
|
||||
|
||||
|
||||
class LegacyLocation(Location):
|
||||
game: str = "Rogue Legacy"
|
||||
|
||||
|
||||
base_location_table = {
|
||||
# Manor Renovations
|
||||
LocationName.manor_ground_base: 91000,
|
||||
LocationName.manor_main_base: 91001,
|
||||
LocationName.manor_main_bottom_window: 91002,
|
||||
LocationName.manor_main_top_window: 91003,
|
||||
LocationName.manor_main_roof: 91004,
|
||||
LocationName.manor_left_wing_base: 91005,
|
||||
LocationName.manor_left_wing_window: 91006,
|
||||
LocationName.manor_left_wing_roof: 91007,
|
||||
LocationName.manor_left_big_base: 91008,
|
||||
LocationName.manor_left_big_upper1: 91009,
|
||||
LocationName.manor_left_big_upper2: 91010,
|
||||
LocationName.manor_left_big_windows: 91011,
|
||||
LocationName.manor_left_big_roof: 91012,
|
||||
LocationName.manor_left_far_base: 91013,
|
||||
LocationName.manor_left_far_roof: 91014,
|
||||
LocationName.manor_left_extension: 91015,
|
||||
LocationName.manor_left_tree1: 91016,
|
||||
LocationName.manor_left_tree2: 91017,
|
||||
LocationName.manor_right_wing_base: 91018,
|
||||
LocationName.manor_right_wing_window: 91019,
|
||||
LocationName.manor_right_wing_roof: 91020,
|
||||
LocationName.manor_right_big_base: 91021,
|
||||
LocationName.manor_right_big_upper: 91022,
|
||||
LocationName.manor_right_big_roof: 91023,
|
||||
LocationName.manor_right_high_base: 91024,
|
||||
LocationName.manor_right_high_upper: 91025,
|
||||
LocationName.manor_right_high_tower: 91026,
|
||||
LocationName.manor_right_extension: 91027,
|
||||
LocationName.manor_right_tree: 91028,
|
||||
LocationName.manor_observatory_base: 91029,
|
||||
LocationName.manor_observatory_scope: 91030,
|
||||
|
||||
# Boss Rewards
|
||||
LocationName.boss_castle: 91100,
|
||||
LocationName.boss_forest: 91102,
|
||||
LocationName.boss_tower: 91104,
|
||||
LocationName.boss_dungeon: 91106,
|
||||
|
||||
# Special Rooms
|
||||
LocationName.special_jukebox: 91200,
|
||||
LocationName.special_painting: 91201,
|
||||
LocationName.special_cheapskate: 91202,
|
||||
LocationName.special_carnival: 91203,
|
||||
|
||||
# Special Locations
|
||||
LocationName.castle: None,
|
||||
LocationName.garden: None,
|
||||
LocationName.tower: None,
|
||||
LocationName.dungeon: None,
|
||||
LocationName.fountain: None,
|
||||
}
|
||||
|
||||
diary_location_table = {f"{LocationName.diary} {i + 1}": i + 91300 for i in range(0, 25)}
|
||||
|
||||
fairy_chest_location_table = {
|
||||
**{f"{LocationName.castle} - Fairy Chest {i + 1}": i + 91400 for i in range(0, 50)},
|
||||
**{f"{LocationName.garden} - Fairy Chest {i + 1}": i + 91450 for i in range(0, 50)},
|
||||
**{f"{LocationName.tower} - Fairy Chest {i + 1}": i + 91500 for i in range(0, 50)},
|
||||
**{f"{LocationName.dungeon} - Fairy Chest {i + 1}": i + 91550 for i in range(0, 50)},
|
||||
**{f"Fairy Chest {i + 1}": i + 92200 for i in range(0, 60)},
|
||||
}
|
||||
|
||||
chest_location_table = {
|
||||
**{f"{LocationName.castle} - Chest {i + 1}": i + 91600 for i in range(0, 100)},
|
||||
**{f"{LocationName.garden} - Chest {i + 1}": i + 91700 for i in range(0, 100)},
|
||||
**{f"{LocationName.tower} - Chest {i + 1}": i + 91800 for i in range(0, 100)},
|
||||
**{f"{LocationName.dungeon} - Chest {i + 1}": i + 91900 for i in range(0, 100)},
|
||||
**{f"Chest {i + 1}": i + 92000 for i in range(0, 120)},
|
||||
}
|
||||
|
||||
location_table = {
|
||||
**base_location_table,
|
||||
**diary_location_table,
|
||||
**fairy_chest_location_table,
|
||||
**chest_location_table,
|
||||
}
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {id: name for name, _ in location_table.items()}
|
97
worlds/rogue_legacy/Names/ItemName.py
Normal file
97
worlds/rogue_legacy/Names/ItemName.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# Vendor Definitions
|
||||
blacksmith = "Blacksmith"
|
||||
enchantress = "Enchantress"
|
||||
architect = "Architect"
|
||||
|
||||
# Progressive Class Definitions
|
||||
progressive_knight = "Progressive Knights"
|
||||
progressive_mage = "Progressive Mages"
|
||||
progressive_barbarian = "Progressive Barbarians"
|
||||
progressive_knave = "Progressive Knaves"
|
||||
progressive_shinobi = "Progressive Shinobis"
|
||||
progressive_miner = "Progressive Miners"
|
||||
progressive_lich = "Progressive Liches"
|
||||
progressive_spellthief = "Progressive Spellthieves"
|
||||
|
||||
# Static Class Definitions
|
||||
knight = "Knights"
|
||||
paladin = "Paladins"
|
||||
mage = "Mages"
|
||||
archmage = "Archmages"
|
||||
barbarian = "Barbarians"
|
||||
barbarian_king = "Barbarian Kings"
|
||||
knave = "Knaves"
|
||||
assassin = "Assassins"
|
||||
shinobi = "Shinobis"
|
||||
hokage = "Hokages"
|
||||
miner = "Miners"
|
||||
spelunker = "Spelunkers"
|
||||
lich = "Lichs"
|
||||
lich_king = "Lich Kings"
|
||||
spellthief = "Spellthieves"
|
||||
spellsword = "Spellswords"
|
||||
dragon = "Dragons"
|
||||
traitor = "Traitors"
|
||||
|
||||
# Skill Unlock Definitions
|
||||
health = "Health Up"
|
||||
mana = "Mana Up"
|
||||
attack = "Attack Up"
|
||||
magic_damage = "Magic Damage Up"
|
||||
armor = "Armor Up"
|
||||
equip = "Equip Up"
|
||||
crit_chance = "Crit Chance Up"
|
||||
crit_damage = "Crit Damage Up"
|
||||
down_strike = "Down Strike Up"
|
||||
gold_gain = "Gold Gain Up"
|
||||
potion_efficiency = "Potion Efficiency Up"
|
||||
invulnerability_time = "Invulnerability Time Up"
|
||||
mana_cost_down = "Mana Cost Down"
|
||||
death_defiance = "Death Defiance"
|
||||
haggling = "Haggling"
|
||||
random_children = "Randomize Children"
|
||||
|
||||
# Misc. Definitions
|
||||
trip_stat_increase = "Triple Stat Increase"
|
||||
gold_1000 = "1000 Gold"
|
||||
gold_3000 = "3000 Gold"
|
||||
gold_5000 = "5000 Gold"
|
||||
rage_trap = "Rage Trap"
|
||||
|
||||
# Blueprint Definitions
|
||||
progressive_blueprints = "Progressive Blueprints"
|
||||
squire_blueprints = "Squire Blueprints"
|
||||
silver_blueprints = "Silver Blueprints"
|
||||
guardian_blueprints = "Guardian Blueprints"
|
||||
imperial_blueprints = "Imperial Blueprints"
|
||||
royal_blueprints = "Royal Blueprints"
|
||||
knight_blueprints = "Knight Blueprints"
|
||||
ranger_blueprints = "Ranger Blueprints"
|
||||
sky_blueprints = "Sky Blueprints"
|
||||
dragon_blueprints = "Dragon Blueprints"
|
||||
slayer_blueprints = "Slayer Blueprints"
|
||||
blood_blueprints = "Blood Blueprints"
|
||||
sage_blueprints = "Sage Blueprints"
|
||||
retribution_blueprints = "Retribution Blueprints"
|
||||
holy_blueprints = "Holy Blueprints"
|
||||
dark_blueprints = "Dark Blueprints"
|
||||
|
||||
# Rune Definitions
|
||||
vault_runes = "Vault Runes"
|
||||
sprint_runes = "Sprint Runes"
|
||||
vampire_runes = "Vampire Runes"
|
||||
sky_runes = "Sky Runes"
|
||||
siphon_runes = "Siphon Runes"
|
||||
retaliation_runes = "Retaliation Runes"
|
||||
bounty_runes = "Bounty Runes"
|
||||
haste_runes = "Haste Runes"
|
||||
curse_runes = "Curse Runes"
|
||||
grace_runes = "Grace Runes"
|
||||
balance_runes = "Balance Runes"
|
||||
|
||||
# Event Definitions
|
||||
boss_castle = "Defeat Castle Hamson Boss"
|
||||
boss_forest = "Defeat Forest Abkhazia Boss"
|
||||
boss_tower = "Defeat The Maya Boss"
|
||||
boss_dungeon = "Defeat The Land of Darkness Boss"
|
||||
boss_fountain = "Defeat The Fountain"
|
55
worlds/rogue_legacy/Names/LocationName.py
Normal file
55
worlds/rogue_legacy/Names/LocationName.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Manor Piece Definitions
|
||||
manor_ground_base = "Manor Renovation - Ground Road"
|
||||
manor_main_base = "Manor Renovation - Main Base"
|
||||
manor_main_bottom_window = "Manor Renovation - Main Bottom Window"
|
||||
manor_main_top_window = "Manor Renovation - Main Top Window"
|
||||
manor_main_roof = "Manor Renovation - Main Rooftop"
|
||||
manor_left_wing_base = "Manor Renovation - Left Wing Base"
|
||||
manor_left_wing_window = "Manor Renovation - Left Wing Window"
|
||||
manor_left_wing_roof = "Manor Renovation - Left Wing Rooftop"
|
||||
manor_left_big_base = "Manor Renovation - Left Big Base"
|
||||
manor_left_big_upper1 = "Manor Renovation - Left Big Upper 1"
|
||||
manor_left_big_upper2 = "Manor Renovation - Left Big Upper 2"
|
||||
manor_left_big_windows = "Manor Renovation - Left Big Windows"
|
||||
manor_left_big_roof = "Manor Renovation - Left Big Rooftop"
|
||||
manor_left_far_base = "Manor Renovation - Left Far Base"
|
||||
manor_left_far_roof = "Manor Renovation - Left Far Roof"
|
||||
manor_left_extension = "Manor Renovation - Left Extension"
|
||||
manor_left_tree1 = "Manor Renovation - Left Tree 1"
|
||||
manor_left_tree2 = "Manor Renovation - Left Tree 2"
|
||||
manor_right_wing_base = "Manor Renovation - Right Wing Base"
|
||||
manor_right_wing_window = "Manor Renovation - Right Wing Window"
|
||||
manor_right_wing_roof = "Manor Renovation - Right Wing Rooftop"
|
||||
manor_right_big_base = "Manor Renovation - Right Big Base"
|
||||
manor_right_big_upper = "Manor Renovation - Right Big Upper"
|
||||
manor_right_big_roof = "Manor Renovation - Right Big Rooftop"
|
||||
manor_right_high_base = "Manor Renovation - Right High Base"
|
||||
manor_right_high_upper = "Manor Renovation - Right High Upper"
|
||||
manor_right_high_tower = "Manor Renovation - Right High Tower"
|
||||
manor_right_extension = "Manor Renovation - Right Extension"
|
||||
manor_right_tree = "Manor Renovation - Right Tree"
|
||||
manor_observatory_base = "Manor Renovation - Observatory Base"
|
||||
manor_observatory_scope = "Manor Renovation - Observatory Telescope"
|
||||
|
||||
# Boss Chest Definitions
|
||||
boss_castle = "Castle Hamson Boss"
|
||||
boss_forest = "Forest Abkhazia Boss"
|
||||
boss_tower = "The Maya Boss"
|
||||
boss_dungeon = "The Land of Darkness Boss"
|
||||
|
||||
# Special Room Definitions
|
||||
special_jukebox = "Jukebox"
|
||||
special_painting = "Painting"
|
||||
special_cheapskate = "Cheapskate Elf's Game"
|
||||
special_carnival = "Carnival"
|
||||
|
||||
# Shorthand Definitions
|
||||
diary = "Diary"
|
||||
|
||||
# Region Definitions
|
||||
outside = "Outside Castle Hamson"
|
||||
castle = "Castle Hamson"
|
||||
garden = "Forest Abkhazia"
|
||||
tower = "The Maya"
|
||||
dungeon = "The Land of Darkness"
|
||||
fountain = "Fountain Room"
|
374
worlds/rogue_legacy/Options.py
Normal file
374
worlds/rogue_legacy/Options.py
Normal file
@@ -0,0 +1,374 @@
|
||||
import typing
|
||||
|
||||
from Options import Choice, Range, Option, Toggle, DeathLink, DefaultOnToggle, OptionList, OptionSet
|
||||
|
||||
|
||||
class StartingGender(Choice):
|
||||
"""
|
||||
Determines the gender of your initial 'Sir Lee' character.
|
||||
"""
|
||||
display_name = "Starting Gender"
|
||||
option_sir = 0
|
||||
option_lady = 1
|
||||
alias_male = 0
|
||||
alias_female = 1
|
||||
default = "random"
|
||||
|
||||
|
||||
class StartingClass(Choice):
|
||||
"""
|
||||
Determines the starting class of your initial 'Sir Lee' character.
|
||||
"""
|
||||
display_name = "Starting Class"
|
||||
option_knight = 0
|
||||
option_mage = 1
|
||||
option_barbarian = 2
|
||||
option_knave = 3
|
||||
option_shinobi = 4
|
||||
option_miner = 5
|
||||
option_spellthief = 6
|
||||
option_lich = 7
|
||||
default = 0
|
||||
|
||||
|
||||
class NewGamePlus(Choice):
|
||||
"""
|
||||
Puts the castle in new game plus mode which vastly increases enemy level, but increases gold gain by 50%. Not
|
||||
recommended for those inexperienced to Rogue Legacy!
|
||||
"""
|
||||
display_name = "New Game Plus"
|
||||
option_normal = 0
|
||||
option_new_game_plus = 1
|
||||
option_new_game_plus_2 = 2
|
||||
alias_hard = 1
|
||||
alias_brutal = 2
|
||||
default = 0
|
||||
|
||||
|
||||
class LevelScaling(Range):
|
||||
"""
|
||||
A percentage modifier for scaling enemy level as you continue throughout the castle. 100 means enemies will have
|
||||
100% level scaling (normal). Setting this too high will result in enemies with absurdly high levels, you have been
|
||||
warned.
|
||||
"""
|
||||
display_name = "Enemy Level Scaling Percentage"
|
||||
range_start = 1
|
||||
range_end = 300
|
||||
default = 100
|
||||
|
||||
|
||||
class FairyChestsPerZone(Range):
|
||||
"""
|
||||
Determines the number of Fairy Chests in a given zone that contain items. After these have been checked, only stat
|
||||
bonuses can be found in Fairy Chests.
|
||||
"""
|
||||
display_name = "Fairy Chests Per Zone"
|
||||
range_start = 5
|
||||
range_end = 15
|
||||
default = 5
|
||||
|
||||
|
||||
class ChestsPerZone(Range):
|
||||
"""
|
||||
Determines the number of Non-Fairy Chests in a given zone that contain items. After these have been checked, only
|
||||
gold or stat bonuses can be found in Chests.
|
||||
"""
|
||||
display_name = "Chests Per Zone"
|
||||
range_start = 15
|
||||
range_end = 30
|
||||
default = 15
|
||||
|
||||
|
||||
class UniversalFairyChests(Toggle):
|
||||
"""
|
||||
Determines if fairy chests should be combined into one pool instead of per zone, similar to Risk of Rain 2.
|
||||
"""
|
||||
display_name = "Universal Fairy Chests"
|
||||
|
||||
|
||||
class UniversalChests(Toggle):
|
||||
"""
|
||||
Determines if non-fairy chests should be combined into one pool instead of per zone, similar to Risk of Rain 2.
|
||||
"""
|
||||
display_name = "Universal Non-Fairy Chests"
|
||||
|
||||
|
||||
class Vendors(Choice):
|
||||
"""
|
||||
Determines where to place the Blacksmith and Enchantress unlocks in logic (or start with them unlocked).
|
||||
"""
|
||||
display_name = "Vendors"
|
||||
option_start_unlocked = 0
|
||||
option_early = 1
|
||||
option_normal = 2
|
||||
option_anywhere = 3
|
||||
default = 1
|
||||
|
||||
|
||||
class Architect(Choice):
|
||||
"""
|
||||
Determines where the Architect sits in the item pool.
|
||||
"""
|
||||
display_name = "Architect"
|
||||
option_start_unlocked = 0
|
||||
option_normal = 2
|
||||
option_disabled = 3
|
||||
default = 2
|
||||
|
||||
|
||||
class ArchitectFee(Range):
|
||||
"""
|
||||
Determines how large of a percentage the architect takes from the player when utilizing his services. 100 means he
|
||||
takes all your gold. 0 means his services are free.
|
||||
"""
|
||||
display_name = "Architect Fee Percentage"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 40
|
||||
|
||||
|
||||
class DisableCharon(Toggle):
|
||||
"""
|
||||
Prevents Charon from taking your money when you re-enter the castle. Also removes Haggling from the Item Pool.
|
||||
"""
|
||||
display_name = "Disable Charon"
|
||||
|
||||
|
||||
class RequirePurchasing(DefaultOnToggle):
|
||||
"""
|
||||
Determines where you will be required to purchase equipment and runes from the Blacksmith and Enchantress before
|
||||
equipping them. If you disable require purchasing, Manor Renovations are scaled to take this into account.
|
||||
"""
|
||||
display_name = "Require Purchasing"
|
||||
|
||||
|
||||
class ProgressiveBlueprints(Toggle):
|
||||
"""
|
||||
Instead of shuffling blueprints randomly into the pool, blueprint unlocks are progressively unlocked. You would get
|
||||
Squire first, then Knight, etc., until finally Dark.
|
||||
"""
|
||||
display_name = "Progressive Blueprints"
|
||||
|
||||
|
||||
class GoldGainMultiplier(Choice):
|
||||
"""
|
||||
Adjusts the multiplier for gaining gold from all sources.
|
||||
"""
|
||||
display_name = "Gold Gain Multiplier"
|
||||
option_normal = 0
|
||||
option_quarter = 1
|
||||
option_half = 2
|
||||
option_double = 3
|
||||
option_quadruple = 4
|
||||
default = 0
|
||||
|
||||
|
||||
class NumberOfChildren(Range):
|
||||
"""
|
||||
Determines the number of offspring you can choose from on the lineage screen after a death.
|
||||
"""
|
||||
display_name = "Number of Children"
|
||||
range_start = 1
|
||||
range_end = 5
|
||||
default = 3
|
||||
|
||||
|
||||
class AdditionalNames(OptionList):
|
||||
"""
|
||||
Set of additional names your potential offspring can have. If Allow Default Names is disabled, this is the only list
|
||||
of names your children can have. The first value will also be your initial character's name depending on Starting
|
||||
Gender.
|
||||
"""
|
||||
display_name = "Additional Names"
|
||||
|
||||
|
||||
class AllowDefaultNames(DefaultOnToggle):
|
||||
"""
|
||||
Determines if the default names defined in the vanilla game are allowed to be used. Warning: Your world will not
|
||||
generate if the number of Additional Names defined is less than the Number of Children value.
|
||||
"""
|
||||
display_name = "Allow Default Names"
|
||||
|
||||
|
||||
class CastleScaling(Range):
|
||||
"""
|
||||
Adjusts the scaling factor for how big a castle can be. Larger castles scale enemies quicker and also take longer
|
||||
to generate. 100 means normal castle size.
|
||||
"""
|
||||
display_name = "Castle Size Scaling Percentage"
|
||||
range_start = 50
|
||||
range_end = 300
|
||||
default = 100
|
||||
|
||||
|
||||
class ChallengeBossKhidr(Choice):
|
||||
"""
|
||||
Determines if Neo Khidr replaces Khidr in their boss room.
|
||||
"""
|
||||
display_name = "Khidr"
|
||||
option_vanilla = 0
|
||||
option_challenge = 1
|
||||
default = 0
|
||||
|
||||
|
||||
class ChallengeBossAlexander(Choice):
|
||||
"""
|
||||
Determines if Alexander the IV replaces Alexander in their boss room.
|
||||
"""
|
||||
display_name = "Alexander"
|
||||
option_vanilla = 0
|
||||
option_challenge = 1
|
||||
default = 0
|
||||
|
||||
|
||||
class ChallengeBossLeon(Choice):
|
||||
"""
|
||||
Determines if Ponce de Freon replaces Ponce de Leon in their boss room.
|
||||
"""
|
||||
display_name = "Ponce de Leon"
|
||||
option_vanilla = 0
|
||||
option_challenge = 1
|
||||
default = 0
|
||||
|
||||
|
||||
class ChallengeBossHerodotus(Choice):
|
||||
"""
|
||||
Determines if Astrodotus replaces Herodotus in their boss room.
|
||||
"""
|
||||
display_name = "Herodotus"
|
||||
option_vanilla = 0
|
||||
option_challenge = 1
|
||||
default = 0
|
||||
|
||||
|
||||
class HealthUpPool(Range):
|
||||
"""
|
||||
Determines the number of Health Ups in the item pool.
|
||||
"""
|
||||
display_name = "Health Up Pool"
|
||||
range_start = 0
|
||||
range_end = 15
|
||||
default = 15
|
||||
|
||||
|
||||
class ManaUpPool(Range):
|
||||
"""
|
||||
Determines the number of Mana Ups in the item pool.
|
||||
"""
|
||||
display_name = "Mana Up Pool"
|
||||
range_start = 0
|
||||
range_end = 15
|
||||
default = 15
|
||||
|
||||
|
||||
class AttackUpPool(Range):
|
||||
"""
|
||||
Determines the number of Attack Ups in the item pool.
|
||||
"""
|
||||
display_name = "Attack Up Pool"
|
||||
range_start = 0
|
||||
range_end = 15
|
||||
default = 15
|
||||
|
||||
|
||||
class MagicDamageUpPool(Range):
|
||||
"""
|
||||
Determines the number of Magic Damage Ups in the item pool.
|
||||
"""
|
||||
display_name = "Magic Damage Up Pool"
|
||||
range_start = 0
|
||||
range_end = 15
|
||||
default = 15
|
||||
|
||||
|
||||
class ArmorUpPool(Range):
|
||||
"""
|
||||
Determines the number of Armor Ups in the item pool.
|
||||
"""
|
||||
display_name = "Armor Up Pool"
|
||||
range_start = 0
|
||||
range_end = 10
|
||||
default = 10
|
||||
|
||||
|
||||
class EquipUpPool(Range):
|
||||
"""
|
||||
Determines the number of Equip Ups in the item pool.
|
||||
"""
|
||||
display_name = "Equip Up Pool"
|
||||
range_start = 0
|
||||
range_end = 10
|
||||
default = 10
|
||||
|
||||
|
||||
class CritChanceUpPool(Range):
|
||||
"""
|
||||
Determines the number of Crit Chance Ups in the item pool.
|
||||
"""
|
||||
display_name = "Crit Chance Up Pool"
|
||||
range_start = 0
|
||||
range_end = 5
|
||||
default = 5
|
||||
|
||||
|
||||
class CritDamageUpPool(Range):
|
||||
"""
|
||||
Determines the number of Crit Damage Ups in the item pool.
|
||||
"""
|
||||
display_name = "Crit Damage Up Pool"
|
||||
range_start = 0
|
||||
range_end = 5
|
||||
default = 5
|
||||
|
||||
|
||||
class FreeDiaryOnGeneration(DefaultOnToggle):
|
||||
"""
|
||||
Allows the player to get a free diary check every time they regenerate the castle in the starting room.
|
||||
"""
|
||||
display_name = "Free Diary On Generation"
|
||||
|
||||
|
||||
class AvailableClasses(OptionSet):
|
||||
"""
|
||||
List of classes that will be in the item pool to find. The upgraded form of the class will be added with it.
|
||||
The upgraded form of your starting class will be available regardless.
|
||||
"""
|
||||
display_name = "Available Classes"
|
||||
default = {"Knight", "Mage", "Barbarian", "Knave", "Shinobi", "Miner", "Spellthief", "Lich", "Dragon", "Traitor"}
|
||||
valid_keys = {"Knight", "Mage", "Barbarian", "Knave", "Shinobi", "Miner", "Spellthief", "Lich", "Dragon", "Traitor"}
|
||||
|
||||
legacy_options: typing.Dict[str, type(Option)] = {
|
||||
"starting_gender": StartingGender,
|
||||
"starting_class": StartingClass,
|
||||
"available_classes": AvailableClasses,
|
||||
"new_game_plus": NewGamePlus,
|
||||
"fairy_chests_per_zone": FairyChestsPerZone,
|
||||
"chests_per_zone": ChestsPerZone,
|
||||
"universal_fairy_chests": UniversalFairyChests,
|
||||
"universal_chests": UniversalChests,
|
||||
"vendors": Vendors,
|
||||
"architect": Architect,
|
||||
"architect_fee": ArchitectFee,
|
||||
"disable_charon": DisableCharon,
|
||||
"require_purchasing": RequirePurchasing,
|
||||
"progressive_blueprints": ProgressiveBlueprints,
|
||||
"gold_gain_multiplier": GoldGainMultiplier,
|
||||
"number_of_children": NumberOfChildren,
|
||||
"free_diary_on_generation": FreeDiaryOnGeneration,
|
||||
"khidr": ChallengeBossKhidr,
|
||||
"alexander": ChallengeBossAlexander,
|
||||
"leon": ChallengeBossLeon,
|
||||
"herodotus": ChallengeBossHerodotus,
|
||||
"health_pool": HealthUpPool,
|
||||
"mana_pool": ManaUpPool,
|
||||
"attack_pool": AttackUpPool,
|
||||
"magic_damage_pool": MagicDamageUpPool,
|
||||
"armor_pool": ArmorUpPool,
|
||||
"equip_pool": EquipUpPool,
|
||||
"crit_chance_pool": CritChanceUpPool,
|
||||
"crit_damage_pool": CritDamageUpPool,
|
||||
"allow_default_names": AllowDefaultNames,
|
||||
"additional_lady_names": AdditionalNames,
|
||||
"additional_sir_names": AdditionalNames,
|
||||
"death_link": DeathLink,
|
||||
}
|
72
worlds/rogue_legacy/Regions.py
Normal file
72
worlds/rogue_legacy/Regions.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import MultiWorld, Region, RegionType, Entrance, ItemClassification
|
||||
from .Items import LegacyItem
|
||||
from .Locations import LegacyLocation, diary_location_table, location_table, base_location_table
|
||||
from .Names import LocationName, ItemName
|
||||
|
||||
prog = ItemClassification.progression
|
||||
|
||||
|
||||
def create_regions(world, player: int):
|
||||
|
||||
locations: typing.List[str] = []
|
||||
|
||||
# Add required locations.
|
||||
locations += [location for location in base_location_table]
|
||||
locations += [location for location in diary_location_table]
|
||||
|
||||
# Add chests per settings.
|
||||
if world.universal_fairy_chests[player]:
|
||||
fairies = int(world.fairy_chests_per_zone[player]) * 4
|
||||
for i in range(0, fairies):
|
||||
locations += [f"Fairy Chest {i + 1}"]
|
||||
else:
|
||||
fairies = int(world.fairy_chests_per_zone[player])
|
||||
for i in range(0, fairies):
|
||||
locations += [f"{LocationName.castle} - Fairy Chest {i + 1}"]
|
||||
locations += [f"{LocationName.garden} - Fairy Chest {i + 1}"]
|
||||
locations += [f"{LocationName.tower} - Fairy Chest {i + 1}"]
|
||||
locations += [f"{LocationName.dungeon} - Fairy Chest {i + 1}"]
|
||||
|
||||
if world.universal_chests[player]:
|
||||
chests = int(world.chests_per_zone[player]) * 4
|
||||
for i in range(0, chests):
|
||||
locations += [f"Chest {i + 1}"]
|
||||
else:
|
||||
chests = int(world.chests_per_zone[player])
|
||||
for i in range(0, chests):
|
||||
locations += [f"{LocationName.castle} - Chest {i + 1}"]
|
||||
locations += [f"{LocationName.garden} - Chest {i + 1}"]
|
||||
locations += [f"{LocationName.tower} - Chest {i + 1}"]
|
||||
locations += [f"{LocationName.dungeon} - Chest {i + 1}"]
|
||||
|
||||
# Set up the regions correctly.
|
||||
world.regions += [
|
||||
create_region(world, player, "Menu", None, [LocationName.outside]),
|
||||
create_region(world, player, LocationName.castle, locations),
|
||||
]
|
||||
|
||||
# Connect entrances and set up events.
|
||||
world.get_entrance(LocationName.outside, player).connect(world.get_region(LocationName.castle, player))
|
||||
world.get_location(LocationName.castle, player).place_locked_item(LegacyItem(ItemName.boss_castle, prog, None, player))
|
||||
world.get_location(LocationName.garden, player).place_locked_item(LegacyItem(ItemName.boss_forest, prog, None, player))
|
||||
world.get_location(LocationName.tower, player).place_locked_item(LegacyItem(ItemName.boss_tower, prog, None, player))
|
||||
world.get_location(LocationName.dungeon, player).place_locked_item(LegacyItem(ItemName.boss_dungeon, prog, None, player))
|
||||
world.get_location(LocationName.fountain, player).place_locked_item(LegacyItem(ItemName.boss_fountain, prog, None, player))
|
||||
|
||||
|
||||
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
|
||||
# Shamelessly stolen from the ROR2 definition, lol
|
||||
ret = Region(name, RegionType.Generic, name, player)
|
||||
ret.world = world
|
||||
if locations:
|
||||
for location in locations:
|
||||
loc_id = location_table.get(location, 0)
|
||||
location = LegacyLocation(player, location, loc_id, ret)
|
||||
ret.locations.append(location)
|
||||
if exits:
|
||||
for exit in exits:
|
||||
ret.exits.append(Entrance(player, exit, ret))
|
||||
|
||||
return ret
|
177
worlds/rogue_legacy/Rules.py
Normal file
177
worlds/rogue_legacy/Rules.py
Normal file
@@ -0,0 +1,177 @@
|
||||
from BaseClasses import MultiWorld
|
||||
from .Names import LocationName, ItemName
|
||||
from ..AutoWorld import LogicMixin
|
||||
from ..generic.Rules import set_rule
|
||||
|
||||
|
||||
class LegacyLogic(LogicMixin):
|
||||
def _legacy_has_any_vendors(self, player: int) -> bool:
|
||||
return self.has_any({ItemName.blacksmith, ItemName.enchantress}, player)
|
||||
|
||||
def _legacy_has_all_vendors(self, player: int) -> bool:
|
||||
return self.has_all({ItemName.blacksmith, ItemName.enchantress}, player)
|
||||
|
||||
def _legacy_has_stat_upgrades(self, player: int, amount: int) -> bool:
|
||||
return self._legacy_stat_upgrade_count(player) >= amount
|
||||
|
||||
def _legacy_total_stat_upgrades_count(self, player: int) -> int:
|
||||
return int(self.world.health_pool[player]) + \
|
||||
int(self.world.mana_pool[player]) + \
|
||||
int(self.world.attack_pool[player]) + \
|
||||
int(self.world.magic_damage_pool[player]) + \
|
||||
int(self.world.armor_pool[player]) + \
|
||||
int(self.world.equip_pool[player])
|
||||
|
||||
def _legacy_stat_upgrade_count(self, player: int) -> int:
|
||||
return self.item_count(ItemName.health, player) + self.item_count(ItemName.mana, player) + \
|
||||
self.item_count(ItemName.attack, player) + self.item_count(ItemName.magic_damage, player) + \
|
||||
self.item_count(ItemName.armor, player) + self.item_count(ItemName.equip, player)
|
||||
|
||||
|
||||
def set_rules(world: MultiWorld, player: int):
|
||||
# Check for duplicate names.
|
||||
if len(set(world.additional_lady_names[player].value)) != len(world.additional_lady_names[player].value):
|
||||
raise Exception(f"Duplicate values are not allowed in additional_lady_names.")
|
||||
if len(set(world.additional_sir_names[player].value)) != len(world.additional_sir_names[player].value):
|
||||
raise Exception(f"Duplicate values are not allowed in additional_sir_names.")
|
||||
|
||||
if not world.allow_default_names[player]:
|
||||
# Check for quantity.
|
||||
name_count = len(world.additional_lady_names[player].value)
|
||||
if name_count < int(world.number_of_children[player]):
|
||||
raise Exception(f"allow_default_names is off, but not enough names are defined in additional_lady_names. Expected {int(world.number_of_children[player])}, Got {name_count}")
|
||||
|
||||
name_count = len(world.additional_sir_names[player].value)
|
||||
if name_count < int(world.number_of_children[player]):
|
||||
raise Exception(f"allow_default_names is off, but not enough names are defined in additional_sir_names. Expected {int(world.number_of_children[player])}, Got {name_count}")
|
||||
|
||||
# Chests
|
||||
if world.universal_chests[player]:
|
||||
for i in range(0, world.chests_per_zone[player]):
|
||||
set_rule(world.get_location(f"Chest {i + 1 + (world.chests_per_zone[player] * 1)}", player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(f"Chest {i + 1 + (world.chests_per_zone[player] * 2)}", player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(f"Chest {i + 1 + (world.chests_per_zone[player] * 3)}", player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
else:
|
||||
for i in range(0, world.chests_per_zone[player]):
|
||||
set_rule(world.get_location(f"{LocationName.garden} - Chest {i + 1}", player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(f"{LocationName.tower} - Chest {i + 1}", player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(f"{LocationName.dungeon} - Chest {i + 1}", player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
|
||||
# Fairy Chests
|
||||
if world.universal_fairy_chests[player]:
|
||||
for i in range(0, world.fairy_chests_per_zone[player]):
|
||||
set_rule(world.get_location(f"Fairy Chest {i + 1 + (world.fairy_chests_per_zone[player] * 1)}", player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(f"Fairy Chest {i + 1 + (world.fairy_chests_per_zone[player] * 2)}", player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(f"Fairy Chest {i + 1 + (world.fairy_chests_per_zone[player] * 3)}", player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
else:
|
||||
for i in range(0, world.fairy_chests_per_zone[player]):
|
||||
set_rule(world.get_location(f"{LocationName.garden} - Fairy Chest {i + 1}", player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(f"{LocationName.tower} - Fairy Chest {i + 1}", player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(f"{LocationName.dungeon} - Fairy Chest {i + 1}", player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
|
||||
# Vendors
|
||||
if world.vendors[player] == "early":
|
||||
set_rule(world.get_location(LocationName.boss_castle, player),
|
||||
lambda state: state._legacy_has_all_vendors(player))
|
||||
elif world.vendors[player] == "normal":
|
||||
set_rule(world.get_location(LocationName.garden, player),
|
||||
lambda state: state._legacy_has_any_vendors(player))
|
||||
|
||||
# Diaries
|
||||
for i in range(0, 5):
|
||||
set_rule(world.get_location(f"Diary {i + 6}", player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(f"Diary {i + 11}", player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(f"Diary {i + 16}", player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
set_rule(world.get_location(f"Diary {i + 21}", player),
|
||||
lambda state: state.has(ItemName.boss_dungeon, player))
|
||||
|
||||
# Scale each manor location.
|
||||
set_rule(world.get_location(LocationName.manor_left_wing_window, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_wing_roof, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_wing_window, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_wing_roof, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_big_base, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_big_base, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_tree1, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_tree2, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_tree, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_big_upper1, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_big_upper2, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_big_windows, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_big_roof, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_far_base, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_far_roof, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_left_extension, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_big_upper, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_big_roof, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_extension, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_high_base, player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_high_upper, player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
set_rule(world.get_location(LocationName.manor_right_high_tower, player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
set_rule(world.get_location(LocationName.manor_observatory_base, player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
set_rule(world.get_location(LocationName.manor_observatory_scope, player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
|
||||
# Standard Zone Progression
|
||||
set_rule(world.get_location(LocationName.garden, player),
|
||||
lambda state: state._legacy_has_stat_upgrades(player, 0.125 * state._legacy_total_stat_upgrades_count(player)) and state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.tower, player),
|
||||
lambda state: state._legacy_has_stat_upgrades(player, 0.3125 * state._legacy_total_stat_upgrades_count(player)) and state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.dungeon, player),
|
||||
lambda state: state._legacy_has_stat_upgrades(player, 0.5 * state._legacy_total_stat_upgrades_count(player)) and state.has(ItemName.boss_tower, player))
|
||||
|
||||
# Bosses
|
||||
set_rule(world.get_location(LocationName.boss_castle, player),
|
||||
lambda state: state.has(ItemName.boss_castle, player))
|
||||
set_rule(world.get_location(LocationName.boss_forest, player),
|
||||
lambda state: state.has(ItemName.boss_forest, player))
|
||||
set_rule(world.get_location(LocationName.boss_tower, player),
|
||||
lambda state: state.has(ItemName.boss_tower, player))
|
||||
set_rule(world.get_location(LocationName.boss_dungeon, player),
|
||||
lambda state: state.has(ItemName.boss_dungeon, player))
|
||||
set_rule(world.get_location(LocationName.fountain, player),
|
||||
lambda state: state._legacy_has_stat_upgrades(player, 0.625 * state._legacy_total_stat_upgrades_count(player))
|
||||
and state.has(ItemName.boss_castle, player)
|
||||
and state.has(ItemName.boss_forest, player)
|
||||
and state.has(ItemName.boss_tower, player)
|
||||
and state.has(ItemName.boss_dungeon, player))
|
||||
|
||||
world.completion_condition[player] = lambda state: state.has(ItemName.boss_fountain, player)
|
39
worlds/rogue_legacy/Traits.py
Normal file
39
worlds/rogue_legacy/Traits.py
Normal file
@@ -0,0 +1,39 @@
|
||||
traits = [
|
||||
"Color Blind",
|
||||
"Gay",
|
||||
"Near-Sighted",
|
||||
"Far-Sighted",
|
||||
"Dyslexia",
|
||||
"Gigantism",
|
||||
"Dwarfism",
|
||||
"Baldness",
|
||||
"Endomorph",
|
||||
"Ectomorph",
|
||||
"Alzheimers",
|
||||
"Dextrocardia",
|
||||
"Coprolalia",
|
||||
"ADHD",
|
||||
"O.C.D.",
|
||||
"Hypergonadism",
|
||||
"Muscle Wk.",
|
||||
"Stereo Blind",
|
||||
"I.B.S.",
|
||||
"Vertigo",
|
||||
"Tunnel Vision",
|
||||
"Ambilevous",
|
||||
"P.A.D.",
|
||||
"Alektorophobia",
|
||||
"Hypochondriac",
|
||||
"Dementia",
|
||||
"Flexible",
|
||||
"Eid. Mem.",
|
||||
"Nostalgic",
|
||||
"C.I.P.",
|
||||
"Savant",
|
||||
"The One",
|
||||
"Clumsy",
|
||||
"EHS",
|
||||
"Glaucoma",
|
||||
"Adopted",
|
||||
]
|
||||
|
176
worlds/rogue_legacy/__init__.py
Normal file
176
worlds/rogue_legacy/__init__.py
Normal file
@@ -0,0 +1,176 @@
|
||||
import typing
|
||||
|
||||
from BaseClasses import Item, ItemClassification, Tutorial
|
||||
from .Items import LegacyItem, ItemData, item_table, vendors_table, static_classes_table, progressive_classes_table, \
|
||||
skill_unlocks_table, blueprints_table, runes_table, misc_items_table
|
||||
from .Locations import LegacyLocation, location_table, base_location_table
|
||||
from .Options import legacy_options
|
||||
from .Regions import create_regions
|
||||
from .Rules import set_rules
|
||||
from .Names import ItemName
|
||||
from ..AutoWorld import World, WebWorld
|
||||
|
||||
|
||||
class LegacyWeb(WebWorld):
|
||||
theme = "stone"
|
||||
tutorials = [Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
"A guide to setting up the Rogue Legacy Randomizer software on your computer. This guide covers single-player, multiworld, and related software.",
|
||||
"English",
|
||||
"rogue-legacy_en.md",
|
||||
"rogue-legacy/en",
|
||||
["Phar"]
|
||||
)]
|
||||
|
||||
|
||||
class LegacyWorld(World):
|
||||
"""
|
||||
Rogue Legacy is a genealogical rogue-"LITE" where anyone can be a hero. Each time you die, your child will succeed
|
||||
you. Every child is unique. One child might be colorblind, another might have vertigo-- they could even be a dwarf.
|
||||
But that's OK, because no one is perfect, and you don't have to be to succeed.
|
||||
"""
|
||||
game: str = "Rogue Legacy"
|
||||
options = legacy_options
|
||||
topology_present = False
|
||||
data_version = 3
|
||||
required_client_version = (0, 2, 3)
|
||||
web = LegacyWeb()
|
||||
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = location_table
|
||||
|
||||
def _get_slot_data(self):
|
||||
return {
|
||||
"starting_gender": self.world.starting_gender[self.player],
|
||||
"starting_class": self.world.starting_class[self.player],
|
||||
"new_game_plus": self.world.new_game_plus[self.player],
|
||||
"fairy_chests_per_zone": self.world.fairy_chests_per_zone[self.player],
|
||||
"chests_per_zone": self.world.chests_per_zone[self.player],
|
||||
"universal_fairy_chests": self.world.universal_fairy_chests[self.player],
|
||||
"universal_chests": self.world.universal_chests[self.player],
|
||||
"vendors": self.world.vendors[self.player],
|
||||
"architect_fee": self.world.architect_fee[self.player],
|
||||
"disable_charon": self.world.disable_charon[self.player],
|
||||
"require_purchasing": self.world.require_purchasing[self.player],
|
||||
"gold_gain_multiplier": self.world.gold_gain_multiplier[self.player],
|
||||
"number_of_children": self.world.number_of_children[self.player],
|
||||
"khidr": self.world.khidr[self.player],
|
||||
"alexander": self.world.alexander[self.player],
|
||||
"leon": self.world.leon[self.player],
|
||||
"herodotus": self.world.herodotus[self.player],
|
||||
"allow_default_names": self.world.allow_default_names[self.player],
|
||||
"additional_sir_names": self.world.additional_sir_names[self.player],
|
||||
"additional_lady_names": self.world.additional_lady_names[self.player],
|
||||
"death_link": self.world.death_link[self.player],
|
||||
}
|
||||
|
||||
def _create_items(self, name: str):
|
||||
data = item_table[name]
|
||||
return [self.create_item(name)] * data.quantity
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
slot_data = self._get_slot_data()
|
||||
for option_name in legacy_options:
|
||||
option = getattr(self.world, option_name)[self.player]
|
||||
slot_data[option_name] = option.value
|
||||
|
||||
return slot_data
|
||||
|
||||
def generate_basic(self):
|
||||
itempool: typing.List[LegacyItem] = []
|
||||
total_required_locations = 64 + (self.world.chests_per_zone[self.player] * 4) + (self.world.fairy_chests_per_zone[self.player] * 4)
|
||||
|
||||
# Fill item pool with all required items
|
||||
for item in {**skill_unlocks_table, **runes_table}:
|
||||
# if Haggling, do not add if Disable Charon.
|
||||
if item == ItemName.haggling and self.world.disable_charon[self.player] == 1:
|
||||
continue
|
||||
itempool += self._create_items(item)
|
||||
|
||||
# Blueprints
|
||||
if self.world.progressive_blueprints[self.player]:
|
||||
itempool += [self.create_item(ItemName.progressive_blueprints)] * 15
|
||||
else:
|
||||
for item in blueprints_table:
|
||||
itempool += self._create_items(item)
|
||||
|
||||
# Check Pool settings to add a certain amount of these items.
|
||||
itempool += [self.create_item(ItemName.health)] * int(self.world.health_pool[self.player])
|
||||
itempool += [self.create_item(ItemName.mana)] * int(self.world.mana_pool[self.player])
|
||||
itempool += [self.create_item(ItemName.attack)] * int(self.world.attack_pool[self.player])
|
||||
itempool += [self.create_item(ItemName.magic_damage)] * int(self.world.magic_damage_pool[self.player])
|
||||
itempool += [self.create_item(ItemName.armor)] * int(self.world.armor_pool[self.player])
|
||||
itempool += [self.create_item(ItemName.equip)] * int(self.world.equip_pool[self.player])
|
||||
itempool += [self.create_item(ItemName.crit_chance)] * int(self.world.crit_chance_pool[self.player])
|
||||
itempool += [self.create_item(ItemName.crit_damage)] * int(self.world.crit_damage_pool[self.player])
|
||||
|
||||
classes = self.world.available_classes[self.player]
|
||||
if "Dragon" in classes:
|
||||
itempool.append(self.create_item(ItemName.dragon))
|
||||
if "Traitor" in classes:
|
||||
itempool.append(self.create_item(ItemName.traitor))
|
||||
if self.world.starting_class[self.player] == "knight":
|
||||
itempool.append(self.create_item(ItemName.progressive_knight))
|
||||
elif "Knight" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_knight))
|
||||
if self.world.starting_class[self.player] == "mage":
|
||||
itempool.append(self.create_item(ItemName.progressive_mage))
|
||||
elif "Mage" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_mage))
|
||||
if self.world.starting_class[self.player] == "barbarian":
|
||||
itempool.append(self.create_item(ItemName.progressive_barbarian))
|
||||
elif "Barbarian" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_barbarian))
|
||||
if self.world.starting_class[self.player] == "knave":
|
||||
itempool.append(self.create_item(ItemName.progressive_knave))
|
||||
elif "Knave" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_knave))
|
||||
if self.world.starting_class[self.player] == "shinobi":
|
||||
itempool.append(self.create_item(ItemName.progressive_shinobi))
|
||||
elif "Shinobi" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_shinobi))
|
||||
if self.world.starting_class[self.player] == "miner":
|
||||
itempool.append(self.create_item(ItemName.progressive_miner))
|
||||
elif "Miner" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_miner))
|
||||
if self.world.starting_class[self.player] == "lich":
|
||||
itempool.append(self.create_item(ItemName.progressive_lich))
|
||||
elif "Lich" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_lich))
|
||||
if self.world.starting_class[self.player] == "spellthief":
|
||||
itempool.append(self.create_item(ItemName.progressive_spellthief))
|
||||
elif "Spellthief" in classes:
|
||||
itempool.extend(self._create_items(ItemName.progressive_spellthief))
|
||||
|
||||
# Check if we need to start with these vendors or put them in the pool.
|
||||
if self.world.vendors[self.player] == "start_unlocked":
|
||||
self.world.push_precollected(self.world.create_item(ItemName.blacksmith, self.player))
|
||||
self.world.push_precollected(self.world.create_item(ItemName.enchantress, self.player))
|
||||
else:
|
||||
itempool += [self.create_item(ItemName.blacksmith), self.create_item(ItemName.enchantress)]
|
||||
|
||||
# Add Architect.
|
||||
if self.world.architect[self.player] == "start_unlocked":
|
||||
self.world.push_precollected(self.world.create_item(ItemName.architect, self.player))
|
||||
elif self.world.architect[self.player] != "disabled":
|
||||
itempool += [self.create_item(ItemName.architect)]
|
||||
|
||||
# Fill item pool with the remaining
|
||||
for _ in range(len(itempool), total_required_locations):
|
||||
item = self.world.random.choice(list(misc_items_table.keys()))
|
||||
itempool += [self.create_item(item)]
|
||||
|
||||
self.world.itempool += itempool
|
||||
|
||||
def get_filler_item_name(self) -> str:
|
||||
return self.world.random.choice(list(misc_items_table.keys()))
|
||||
|
||||
def create_regions(self):
|
||||
create_regions(self.world, self.player)
|
||||
|
||||
def create_item(self, name: str) -> Item:
|
||||
data = item_table[name]
|
||||
return LegacyItem(name, ItemClassification.progression if data.progression else ItemClassification.filler, data.code, self.player)
|
||||
|
||||
def set_rules(self):
|
||||
set_rules(self.world, self.player)
|
27
worlds/rogue_legacy/docs/en_Rogue Legacy.md
Normal file
27
worlds/rogue_legacy/docs/en_Rogue Legacy.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Rogue Legacy (PC)
|
||||
|
||||
## Where is the settings page?
|
||||
|
||||
The [player settings page for this game](../player-settings) is located contains all the options you need to configure
|
||||
and export a config file.
|
||||
|
||||
## What does randomization do to this game?
|
||||
|
||||
You are not able to buy skill upgrades in the manor upgrade screen, and instead, need to find them in order to level up
|
||||
your character to make fighting the 5 bosses easier.
|
||||
|
||||
## What items and locations get shuffled?
|
||||
|
||||
All the skill upgrades, class upgrades, runes packs, and equipment packs are shuffled in the manor upgrade screen, diary
|
||||
checks, chests and fairy chests, and boss rewards. Skill upgrades are also grouped in packs of 5 to make the finding of
|
||||
stats less of a chore. Runes and Equipment are also grouped together.
|
||||
|
||||
## Which items can be in another player's world?
|
||||
|
||||
Any of the items which can be shuffled may also be placed into another player's world. It is possible to choose to limit
|
||||
certain items to your own world.
|
||||
|
||||
## When the player receives an item, what happens?
|
||||
|
||||
When the player receives an item, your character will hold the item above their head and display it to the world. It's
|
||||
good for business!
|
52
worlds/rogue_legacy/docs/rogue-legacy_en.md
Normal file
52
worlds/rogue_legacy/docs/rogue-legacy_en.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Rogue Legacy Randomizer Setup Guide
|
||||
|
||||
## Required Software
|
||||
|
||||
- Rogue Legacy Randomizer from
|
||||
the [Rogue Legacy Randomizer Releases Page](https://github.com/ThePhar/RogueLegacyRandomizer/releases)
|
||||
|
||||
## Configuring your YAML file
|
||||
|
||||
### What is a YAML file and why do I need one?
|
||||
|
||||
Your YAML file contains a set of configuration options which provide the generator with information about how it should
|
||||
generate your game. Each player of a multiworld will provide their own YAML file. This setup allows each player to enjoy
|
||||
an experience customized for their taste, and different players in the same multiworld can all have different options.
|
||||
|
||||
### Where do I get a YAML file?
|
||||
|
||||
you can customize your settings by visiting the [Rogue Legacy Settings Page](/games/Rogue%20Legacy/player-settings).
|
||||
|
||||
### Connect to the MultiServer
|
||||
|
||||
Once in game, press the start button and the AP connection screen should appear. You will fill out the hostname, port,
|
||||
slot name, and password (if applicable). You should only need to fill out hostname, port, and password if the server
|
||||
provides an alternative one to the default values.
|
||||
|
||||
### Play the game
|
||||
|
||||
Once you have entered the required values, you go to Connect and then select Confirm on the "Ready to Start" screen. Now
|
||||
you're off to start your legacy!
|
||||
|
||||
## Manual Installation
|
||||
|
||||
In order to run Rogue Legacy Randomizer you will need to have Rogue Legacy installed on your local machine. Extract the
|
||||
Randomizer release into a desired folder **outside** of your Rogue Legacy install. Copy the following files from your
|
||||
Rogue Legacy install into the main directory of your Rogue Legacy Randomizer install:
|
||||
|
||||
- DS2DEngine.dll
|
||||
- InputSystem.dll
|
||||
- Nuclex.Input.dll
|
||||
- SpriteSystem.dll
|
||||
- Tweener.dll
|
||||
|
||||
And copy the directory from your Rogue Legacy install as well into the main directory of your Rogue Legacy Randomizer
|
||||
install:
|
||||
|
||||
- Content/
|
||||
|
||||
Then copy the contents of the CustomContent directory in your Rogue Legacy Randomizer into the newly copied Content
|
||||
directory and overwrite all files.
|
||||
|
||||
**BE SURE YOU ARE REPLACING THE COPIED FILES IN YOUR ROGUE LEGACY RANDOMIZER DIRECTORY AND NOT REPLACING YOUR ROGUE
|
||||
LEGACY FILES!**
|
Reference in New Issue
Block a user