forked from ArchipelagoMW/Archipelago
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OSRS: Implement New Game (ArchipelagoMW#1976)
* MMBN3: Press program now has proper color index when received remotely * Initial commit of OSRS untangled from MMBN3 branch * Fixes some broken region connections * Removes some locations * Rearranges locations to fill in slots left by removed locations * Adds starting area rando * Moves Oak and Willow trees to resource regions * Fixes various PEP8 violations * Refactor of regions * Fixes variable capture issue with region rules * Partial completion of brutal grind logic * Finishes can_reach_skill function * Adds skill requirements to location rules, fixes regions rules * Adds documentation for OSRS * Removes match statement * Updates Data Version to test mode to prevent item name caching * Fixes starting spawn logic for east varrock * Fixes river lum crossing logic to not assume you can phase across water * Prevents equipping items when you haven't unlocked them * Changes canoe logic to not require huge levels * Skeletoning out some data I'll need for variable task system * Adds csvs and parser for logic * Adds Items parsing * Fixes the spawning logic to not default to Chunksanity when you didn't pick it * Begins adding generation rules for data-driven logic * Moves region handling and location creating to different methods * Adds logic limits to Options * Begun the location generation has * Randomly generates tasks for each skill until populated * Mopping up improper names, adding custom logic, and fixes location rolling * Drastically cleans up the location rolling loop * Modifies generation to properly use local variables and pass unit tests * Game is now generating, but rules don't seem to work * Lambda capture, my old nemesis. We meet again * Fixes issue with Corsair Cove item requirement causing logic loop * Okay one more fix, another variable capture * On second thought lets not have skull sceptre tasks. 'Tis a silly place * Removes QP from item pool (they're events not items) * Removes Stronghold floor tasks, no varbit to track them * Loads CSV with pkutil so it can be used in apworld * Fixes logic of skill tasks and adds QP requirements to long grinds * Fixes pathing in pkgutil call * Better handling for empty task categories, no longer throws errors * Fixes order for progressive tasks, removes un-checkable spider task * Fixes logic issues related to stew and the Blurite caves * Fixes issues generating causing tests to sporadically fail * Adds missing task that caused off-by-one error * Updates to new Options API * Updates generation to function properly with the Universal Tracker (Thanks Faris) * Replaces runtime CSV parsing with pre-made python files generated from CSVs * Switches to self.random and uses random.choice instead of doing it manually * Fixes to typing, variable names, iterators, and continue conditions * Replaces Name classes with Enums * Fixes parse error on region special rules * Skill requirements check now returns an accessrule instead of being one that checks options * Updates documentation and setup guide * Adjusts maximum numbers for combat and general tasks * Fixes region names so dictionary lookup works for chunksanity * Update worlds/osrs/docs/en_Old School Runescape.md Co-authored-by: Nicholas Saylor <[email protected]> * Update worlds/osrs/docs/en_Old School Runescape.md Co-authored-by: Nicholas Saylor <[email protected]> * Updates readme.md and codeowners doc * Removes erroneous East Varrock -> Al Kharid connection * Changes to canoe logic to account for woodcutting level options * Fixes embarassing typo on 'Edgeville' * Moves Logic CSVs to separate repository, addresses suggested changes on PR * Fixes logic error in east/west lumbridge regions. Fixes incorrect List typing in main * Removes task types with weight 0 from the list of rollable tasks * Missed another place that the task type had to be removed if 0 weight * Prevents adding an empty task weight if levels are too restrictive for tasks to be added * Removes giant blank space in error message * Adds player name to error for not having enough available tasks --------- Co-authored-by: Nicholas Saylor <[email protected]>
- Loading branch information
1 parent
90446ad
commit 8ddb49f
Showing
15 changed files
with
2,052 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import typing | ||
|
||
from BaseClasses import Item, ItemClassification | ||
from .Names import ItemNames | ||
|
||
|
||
class ItemRow(typing.NamedTuple): | ||
name: str | ||
amount: int | ||
progression: ItemClassification | ||
|
||
|
||
class OSRSItem(Item): | ||
game: str = "Old School Runescape" | ||
|
||
|
||
QP_Items: typing.List[str] = [ | ||
ItemNames.QP_Cooks_Assistant, | ||
ItemNames.QP_Demon_Slayer, | ||
ItemNames.QP_Restless_Ghost, | ||
ItemNames.QP_Romeo_Juliet, | ||
ItemNames.QP_Sheep_Shearer, | ||
ItemNames.QP_Shield_of_Arrav, | ||
ItemNames.QP_Ernest_the_Chicken, | ||
ItemNames.QP_Vampyre_Slayer, | ||
ItemNames.QP_Imp_Catcher, | ||
ItemNames.QP_Prince_Ali_Rescue, | ||
ItemNames.QP_Dorics_Quest, | ||
ItemNames.QP_Black_Knights_Fortress, | ||
ItemNames.QP_Witchs_Potion, | ||
ItemNames.QP_Knights_Sword, | ||
ItemNames.QP_Goblin_Diplomacy, | ||
ItemNames.QP_Pirates_Treasure, | ||
ItemNames.QP_Rune_Mysteries, | ||
ItemNames.QP_Misthalin_Mystery, | ||
ItemNames.QP_Corsair_Curse, | ||
ItemNames.QP_X_Marks_the_Spot, | ||
ItemNames.QP_Below_Ice_Mountain | ||
] | ||
|
||
starting_area_dict: typing.Dict[int, str] = { | ||
0: ItemNames.Lumbridge, | ||
1: ItemNames.Al_Kharid, | ||
2: ItemNames.Central_Varrock, | ||
3: ItemNames.West_Varrock, | ||
4: ItemNames.Edgeville, | ||
5: ItemNames.Falador, | ||
6: ItemNames.Draynor_Village, | ||
7: ItemNames.Wilderness, | ||
} | ||
|
||
chunksanity_starting_chunks: typing.List[str] = [ | ||
ItemNames.Lumbridge, | ||
ItemNames.Lumbridge_Swamp, | ||
ItemNames.Lumbridge_Farms, | ||
ItemNames.HAM_Hideout, | ||
ItemNames.Draynor_Village, | ||
ItemNames.Draynor_Manor, | ||
ItemNames.Wizards_Tower, | ||
ItemNames.Al_Kharid, | ||
ItemNames.Citharede_Abbey, | ||
ItemNames.South_Of_Varrock, | ||
ItemNames.Central_Varrock, | ||
ItemNames.Varrock_Palace, | ||
ItemNames.East_Of_Varrock, | ||
ItemNames.West_Varrock, | ||
ItemNames.Edgeville, | ||
ItemNames.Barbarian_Village, | ||
ItemNames.Monastery, | ||
ItemNames.Ice_Mountain, | ||
ItemNames.Dwarven_Mines, | ||
ItemNames.Falador, | ||
ItemNames.Falador_Farm, | ||
ItemNames.Crafting_Guild, | ||
ItemNames.Rimmington, | ||
ItemNames.Port_Sarim, | ||
ItemNames.Mudskipper_Point, | ||
ItemNames.Wilderness | ||
] | ||
|
||
# Some starting areas contain multiple regions, so if that area is rolled for Chunksanity, we need to map it to one | ||
chunksanity_special_region_names: typing.Dict[str, str] = { | ||
ItemNames.Lumbridge_Farms: 'Lumbridge Farms East', | ||
ItemNames.Crafting_Guild: 'Crafting Guild Outskirts', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import typing | ||
|
||
from BaseClasses import Location | ||
|
||
|
||
class SkillRequirement(typing.NamedTuple): | ||
skill: str | ||
level: int | ||
|
||
|
||
class LocationRow(typing.NamedTuple): | ||
name: str | ||
category: str | ||
regions: typing.List[str] | ||
skills: typing.List[SkillRequirement] | ||
items: typing.List[str] | ||
qp: int | ||
|
||
|
||
class OSRSLocation(Location): | ||
game: str = "Old School Runescape" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
""" | ||
This is a utility file that converts logic in the form of CSV files into Python files that can be imported and used | ||
directly by the world implementation. Whenever the logic files are updated, this script should be run to re-generate | ||
the python files containing the data. | ||
""" | ||
import requests | ||
|
||
# The CSVs are updated at this repository to be shared between generator and client. | ||
data_repository_address = "https://raw.githubusercontent.com/digiholic/osrs-archipelago-logic/" | ||
# The Github tag of the CSVs this was generated with | ||
data_csv_tag = "v1.5" | ||
|
||
if __name__ == "__main__": | ||
import sys | ||
import os | ||
import csv | ||
import typing | ||
|
||
# makes this module runnable from its world folder. Shamelessly stolen from Subnautica | ||
sys.path.remove(os.path.dirname(__file__)) | ||
new_home = os.path.normpath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) | ||
os.chdir(new_home) | ||
sys.path.append(new_home) | ||
|
||
|
||
def load_location_csv(): | ||
this_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
with open(os.path.join(this_dir, "locations_generated.py"), 'w+') as locPyFile: | ||
locPyFile.write('"""\nThis file was auto generated by LogicCSVToPython.py\n"""\n') | ||
locPyFile.write("from ..Locations import LocationRow, SkillRequirement\n") | ||
locPyFile.write("\n") | ||
locPyFile.write("location_rows = [\n") | ||
|
||
with requests.get(data_repository_address + "/" + data_csv_tag + "/locations.csv") as req: | ||
locations_reader = csv.reader(req.text.splitlines()) | ||
for row in locations_reader: | ||
row_line = "LocationRow(" | ||
row_line += str_format(row[0]) | ||
row_line += str_format(row[1].lower()) | ||
|
||
region_strings = row[2].split(", ") if row[2] else [] | ||
row_line += f"{str_list_to_py(region_strings)}, " | ||
|
||
skill_strings = row[3].split(", ") | ||
row_line += "[" | ||
if skill_strings: | ||
split_skills = [skill.split(" ") for skill in skill_strings if skill != ""] | ||
if split_skills: | ||
for split in split_skills: | ||
row_line += f"SkillRequirement('{split[0]}', {split[1]}), " | ||
row_line += "], " | ||
|
||
item_strings = row[4].split(", ") if row[4] else [] | ||
row_line += f"{str_list_to_py(item_strings)}, " | ||
row_line += f"{row[5]})" if row[5] != "" else "0)" | ||
locPyFile.write(f"\t{row_line},\n") | ||
locPyFile.write("]\n") | ||
|
||
def load_region_csv(): | ||
this_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
with open(os.path.join(this_dir, "regions_generated.py"), 'w+') as regPyFile: | ||
regPyFile.write('"""\nThis file was auto generated by LogicCSVToPython.py\n"""\n') | ||
regPyFile.write("from ..Regions import RegionRow\n") | ||
regPyFile.write("\n") | ||
regPyFile.write("region_rows = [\n") | ||
|
||
with requests.get(data_repository_address + "/" + data_csv_tag + "/regions.csv") as req: | ||
regions_reader = csv.reader(req.text.splitlines()) | ||
for row in regions_reader: | ||
row_line = "RegionRow(" | ||
row_line += str_format(row[0]) | ||
row_line += str_format(row[1]) | ||
connections = row[2].replace("'", "\\'") | ||
row_line += f"{str_list_to_py(connections.split(', '))}, " | ||
resources = row[3].replace("'", "\\'") | ||
row_line += f"{str_list_to_py(resources.split(', '))})" | ||
regPyFile.write(f"\t{row_line},\n") | ||
regPyFile.write("]\n") | ||
|
||
def load_resource_csv(): | ||
this_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
with open(os.path.join(this_dir, "resources_generated.py"), 'w+') as resPyFile: | ||
resPyFile.write('"""\nThis file was auto generated by LogicCSVToPython.py\n"""\n') | ||
resPyFile.write("from ..Regions import ResourceRow\n") | ||
resPyFile.write("\n") | ||
resPyFile.write("resource_rows = [\n") | ||
|
||
with requests.get(data_repository_address + "/" + data_csv_tag + "/resources.csv") as req: | ||
resource_reader = csv.reader(req.text.splitlines()) | ||
for row in resource_reader: | ||
name = row[0].replace("'", "\\'") | ||
row_line = f"ResourceRow('{name}')" | ||
resPyFile.write(f"\t{row_line},\n") | ||
resPyFile.write("]\n") | ||
|
||
|
||
def load_item_csv(): | ||
this_dir = os.path.dirname(os.path.abspath(__file__)) | ||
|
||
with open(os.path.join(this_dir, "items_generated.py"), 'w+') as itemPyfile: | ||
itemPyfile.write('"""\nThis file was auto generated by LogicCSVToPython.py\n"""\n') | ||
itemPyfile.write("from BaseClasses import ItemClassification\n") | ||
itemPyfile.write("from ..Items import ItemRow\n") | ||
itemPyfile.write("\n") | ||
itemPyfile.write("item_rows = [\n") | ||
|
||
with requests.get(data_repository_address + "/" + data_csv_tag + "/items.csv") as req: | ||
item_reader = csv.reader(req.text.splitlines()) | ||
for row in item_reader: | ||
row_line = "ItemRow(" | ||
row_line += str_format(row[0]) | ||
row_line += f"{row[1]}, " | ||
|
||
row_line += f"ItemClassification.{row[2]})" | ||
|
||
itemPyfile.write(f"\t{row_line},\n") | ||
itemPyfile.write("]\n") | ||
|
||
|
||
def str_format(s) -> str: | ||
ret_str = s.replace("'", "\\'") | ||
return f"'{ret_str}', " | ||
|
||
|
||
def str_list_to_py(str_list) -> str: | ||
ret_str = "[" | ||
for s in str_list: | ||
ret_str += f"'{s}', " | ||
ret_str += "]" | ||
return ret_str | ||
|
||
|
||
|
||
load_location_csv() | ||
print("Generated locations py") | ||
load_region_csv() | ||
print("Generated regions py") | ||
load_resource_csv() | ||
print("Generated resource py") | ||
load_item_csv() | ||
print("Generated item py") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
""" | ||
This file was auto generated by LogicCSVToPython.py | ||
""" | ||
from BaseClasses import ItemClassification | ||
from ..Items import ItemRow | ||
|
||
item_rows = [ | ||
ItemRow('Area: Lumbridge', 1, ItemClassification.progression), | ||
ItemRow('Area: Lumbridge Swamp', 1, ItemClassification.progression), | ||
ItemRow('Area: HAM Hideout', 1, ItemClassification.progression), | ||
ItemRow('Area: Lumbridge Farms', 1, ItemClassification.progression), | ||
ItemRow('Area: South of Varrock', 1, ItemClassification.progression), | ||
ItemRow('Area: East Varrock', 1, ItemClassification.progression), | ||
ItemRow('Area: Central Varrock', 1, ItemClassification.progression), | ||
ItemRow('Area: Varrock Palace', 1, ItemClassification.progression), | ||
ItemRow('Area: West Varrock', 1, ItemClassification.progression), | ||
ItemRow('Area: Edgeville', 1, ItemClassification.progression), | ||
ItemRow('Area: Barbarian Village', 1, ItemClassification.progression), | ||
ItemRow('Area: Draynor Manor', 1, ItemClassification.progression), | ||
ItemRow('Area: Falador', 1, ItemClassification.progression), | ||
ItemRow('Area: Dwarven Mines', 1, ItemClassification.progression), | ||
ItemRow('Area: Ice Mountain', 1, ItemClassification.progression), | ||
ItemRow('Area: Monastery', 1, ItemClassification.progression), | ||
ItemRow('Area: Falador Farms', 1, ItemClassification.progression), | ||
ItemRow('Area: Port Sarim', 1, ItemClassification.progression), | ||
ItemRow('Area: Mudskipper Point', 1, ItemClassification.progression), | ||
ItemRow('Area: Karamja', 1, ItemClassification.progression), | ||
ItemRow('Area: Crandor', 1, ItemClassification.progression), | ||
ItemRow('Area: Rimmington', 1, ItemClassification.progression), | ||
ItemRow('Area: Crafting Guild', 1, ItemClassification.progression), | ||
ItemRow('Area: Draynor Village', 1, ItemClassification.progression), | ||
ItemRow('Area: Wizard Tower', 1, ItemClassification.progression), | ||
ItemRow('Area: Corsair Cove', 1, ItemClassification.progression), | ||
ItemRow('Area: Al Kharid', 1, ItemClassification.progression), | ||
ItemRow('Area: Citharede Abbey', 1, ItemClassification.progression), | ||
ItemRow('Area: Wilderness', 1, ItemClassification.progression), | ||
ItemRow('Progressive Armor', 6, ItemClassification.progression), | ||
ItemRow('Progressive Weapons', 6, ItemClassification.progression), | ||
ItemRow('Progressive Tools', 6, ItemClassification.useful), | ||
ItemRow('Progressive Ranged Weapons', 3, ItemClassification.useful), | ||
ItemRow('Progressive Ranged Armor', 3, ItemClassification.useful), | ||
ItemRow('Progressive Magic', 2, ItemClassification.useful), | ||
] |
Oops, something went wrong.