 db7c0c9db9
			
		
	
	db7c0c9db9
	
	
	
		
			
			* Cleaned up Undertale documentation Standardized file names * Outlined Terraria installation more clearly Other minor edits to setup guide * Minor edits to DOOM 1993 set-up guide * Update worlds/terraria/docs/setup_en.md Co-authored-by: kindasneaki <ryandj67@hotmail.com> * Suggested changes from @Seldom-SE Co-authored-by: Seldom <38388947+seldom-se@users.noreply.github.com> * Code block to quotation change from code review Co-authored-by: Seldom <38388947+seldom-se@users.noreply.github.com> Co-authored-by: Chris Wilson <chris@legendserver.info> * Code review from @LegendaryLinux Co-authored-by: Chris Wilson <chris@legendserver.info> --------- Co-authored-by: kindasneaki <ryandj67@hotmail.com> Co-authored-by: Seldom <38388947+seldom-se@users.noreply.github.com> Co-authored-by: Chris Wilson <chris@legendserver.info>
		
			
				
	
	
		
			231 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from .Items import UndertaleItem, item_table, required_armor, required_weapons, non_key_items, key_items, \
 | |
|     junk_weights_all, plot_items, junk_weights_neutral, junk_weights_pacifist, junk_weights_genocide
 | |
| from .Locations import UndertaleAdvancement, advancement_table, exclusion_table
 | |
| from .Regions import undertale_regions, link_undertale_areas
 | |
| from .Rules import set_rules, set_completion_rules
 | |
| from worlds.generic.Rules import exclusion_rules
 | |
| from BaseClasses import Region, Entrance, Tutorial, Item
 | |
| from .Options import undertale_options
 | |
| from worlds.AutoWorld import World, WebWorld
 | |
| from worlds.LauncherComponents import Component, components, Type
 | |
| from multiprocessing import Process
 | |
| 
 | |
| 
 | |
| def run_client():
 | |
|     print('running undertale client')
 | |
|     from .UndertaleClient import main  # lazy import
 | |
|     p = Process(target=main)
 | |
|     p.start()
 | |
| 
 | |
| 
 | |
| components.append(Component("Undertale Client", "UndertaleClient"))
 | |
| # components.append(Component("Undertale Client", func=run_client))
 | |
| 
 | |
| 
 | |
| def data_path(file_name: str):
 | |
|     import pkgutil
 | |
|     return pkgutil.get_data(__name__, "data/" + file_name)
 | |
| 
 | |
| 
 | |
| class UndertaleWeb(WebWorld):
 | |
|     tutorials = [Tutorial(
 | |
|         "Multiworld Setup Tutorial",
 | |
|         "A guide to setting up the Archipelago Undertale software on your computer. This guide covers "
 | |
|         "single-player, multiworld, and related software.",
 | |
|         "English",
 | |
|         "setup_en.md",
 | |
|         "setup/en",
 | |
|         ["Mewlif"]
 | |
|     )]
 | |
| 
 | |
| 
 | |
| class UndertaleWorld(World):
 | |
|     """
 | |
|     Undertale is an RPG where every choice you make matters. You could choose to hurt all the enemies, eventually
 | |
|     causing genocide of the monster species. Or you can spare all the enemies, befriending them and freeing them
 | |
|     from their underground prison.
 | |
|     """
 | |
|     game = "Undertale"
 | |
|     option_definitions = undertale_options
 | |
|     web = UndertaleWeb()
 | |
| 
 | |
|     item_name_to_id = {name: data.code for name, data in item_table.items()}
 | |
|     location_name_to_id = {name: data.id for name, data in advancement_table.items()}
 | |
| 
 | |
|     data_version = 7
 | |
| 
 | |
|     def _get_undertale_data(self):
 | |
|         return {
 | |
|             "world_seed": self.multiworld.per_slot_randoms[self.player].getrandbits(32),
 | |
|             "seed_name": self.multiworld.seed_name,
 | |
|             "player_name": self.multiworld.get_player_name(self.player),
 | |
|             "player_id": self.player,
 | |
|             "client_version": self.required_client_version,
 | |
|             "race": self.multiworld.is_race,
 | |
|             "route": self.multiworld.route_required[self.player].current_key,
 | |
|             "starting_area": self.multiworld.starting_area[self.player].current_key,
 | |
|             "temy_armor_include": bool(self.multiworld.temy_include[self.player].value),
 | |
|             "only_flakes": bool(self.multiworld.only_flakes[self.player].value),
 | |
|             "no_equips": bool(self.multiworld.no_equips[self.player].value),
 | |
|             "key_hunt": bool(self.multiworld.key_hunt[self.player].value),
 | |
|             "key_pieces": self.multiworld.key_pieces[self.player].value,
 | |
|             "rando_love": bool(self.multiworld.rando_love[self.player].value),
 | |
|             "rando_stats": bool(self.multiworld.rando_stats[self.player].value),
 | |
|             "prog_armor": bool(self.multiworld.prog_armor[self.player].value),
 | |
|             "prog_weapons": bool(self.multiworld.prog_weapons[self.player].value),
 | |
|             "rando_item_button": bool(self.multiworld.rando_item_button[self.player].value)
 | |
|         }
 | |
| 
 | |
|     def create_items(self):
 | |
|         self.multiworld.get_location("Undyne Date", self.player).place_locked_item(self.create_item("Undyne Date"))
 | |
|         self.multiworld.get_location("Alphys Date", self.player).place_locked_item(self.create_item("Alphys Date"))
 | |
|         self.multiworld.get_location("Papyrus Date", self.player).place_locked_item(self.create_item("Papyrus Date"))
 | |
|         # Generate item pool
 | |
|         itempool = []
 | |
|         if self.multiworld.route_required[self.player] == "all_routes":
 | |
|             junk_pool = junk_weights_all.copy()
 | |
|         elif self.multiworld.route_required[self.player] == "genocide":
 | |
|             junk_pool = junk_weights_genocide.copy()
 | |
|         elif self.multiworld.route_required[self.player] == "neutral":
 | |
|             junk_pool = junk_weights_neutral.copy()
 | |
|         elif self.multiworld.route_required[self.player] == "pacifist":
 | |
|             junk_pool = junk_weights_pacifist.copy()
 | |
|         else:
 | |
|             junk_pool = junk_weights_all.copy()
 | |
|         # Add all required progression items
 | |
|         for name, num in key_items.items():
 | |
|             itempool += [name] * num
 | |
|         for name, num in required_armor.items():
 | |
|             itempool += [name] * num
 | |
|         for name, num in required_weapons.items():
 | |
|             itempool += [name] * num
 | |
|         for name, num in non_key_items.items():
 | |
|             itempool += [name] * num
 | |
|         if self.multiworld.rando_item_button[self.player]:
 | |
|             itempool += ["ITEM"]
 | |
|         else:
 | |
|             self.multiworld.push_precollected(self.create_item("ITEM"))
 | |
|         self.multiworld.push_precollected(self.create_item("FIGHT"))
 | |
|         self.multiworld.push_precollected(self.create_item("ACT"))
 | |
|         self.multiworld.push_precollected(self.create_item("MERCY"))
 | |
|         if self.multiworld.route_required[self.player] == "genocide":
 | |
|             itempool = [item for item in itempool if item != "Popato Chisps" and item != "Stained Apron" and
 | |
|                         item != "Nice Cream" and item != "Hot Cat" and item != "Hot Dog...?" and item != "Punch Card"]
 | |
|         elif self.multiworld.route_required[self.player] == "neutral":
 | |
|             itempool = [item for item in itempool if item != "Popato Chisps" and item != "Hot Cat" and
 | |
|                         item != "Hot Dog...?"]
 | |
|         if self.multiworld.route_required[self.player] == "pacifist" or \
 | |
|                 self.multiworld.route_required[self.player] == "all_routes":
 | |
|             itempool += ["Undyne Letter EX"]
 | |
|         else:
 | |
|             itempool.remove("Complete Skeleton")
 | |
|             itempool.remove("Fish")
 | |
|             itempool.remove("DT Extractor")
 | |
|             itempool.remove("Hush Puppy")
 | |
|         if self.multiworld.key_hunt[self.player]:
 | |
|             itempool += ["Key Piece"] * self.multiworld.key_pieces[self.player].value
 | |
|         else:
 | |
|             itempool += ["Left Home Key"]
 | |
|             itempool += ["Right Home Key"]
 | |
|         if not self.multiworld.rando_love[self.player] or \
 | |
|                 (self.multiworld.route_required[self.player] != "genocide" and
 | |
|                  self.multiworld.route_required[self.player] != "all_routes"):
 | |
|             itempool = [item for item in itempool if not item == "LOVE"]
 | |
|         if not self.multiworld.rando_stats[self.player] or \
 | |
|                 (self.multiworld.route_required[self.player] != "genocide" and
 | |
|                  self.multiworld.route_required[self.player] != "all_routes"):
 | |
|             itempool = [item for item in itempool if not (item == "ATK Up" or item == "DEF Up" or item == "HP Up")]
 | |
|         if self.multiworld.temy_include[self.player]:
 | |
|             itempool += ["temy armor"]
 | |
|         if self.multiworld.no_equips[self.player]:
 | |
|             itempool = [item for item in itempool if item not in required_armor and item not in required_weapons]
 | |
|         else:
 | |
|             if self.multiworld.prog_armor[self.player]:
 | |
|                 itempool = [item if (item not in required_armor and not item == "temy armor") else
 | |
|                             "Progressive Armor" for item in itempool]
 | |
|             if self.multiworld.prog_weapons[self.player]:
 | |
|                 itempool = [item if item not in required_weapons else "Progressive Weapons" for item in itempool]
 | |
|         if self.multiworld.route_required[self.player] == "genocide" or \
 | |
|                 self.multiworld.route_required[self.player] == "all_routes":
 | |
|             if not self.multiworld.only_flakes[self.player]:
 | |
|                 itempool += ["Snowman Piece"] * 2
 | |
|             if not self.multiworld.no_equips[self.player]:
 | |
|                 itempool = ["Real Knife" if item == "Worn Dagger" else "The Locket"
 | |
|                             if item == "Heart Locket" else item for item in itempool]
 | |
|         if self.multiworld.only_flakes[self.player]:
 | |
|             itempool = [item for item in itempool if item not in non_key_items]
 | |
| 
 | |
|         starting_key = self.multiworld.starting_area[self.player].current_key.title() + " Key"
 | |
|         itempool.remove(starting_key)
 | |
|         self.multiworld.push_precollected(self.create_item(starting_key))
 | |
|         # Choose locations to automatically exclude based on settings
 | |
|         exclusion_pool = set()
 | |
|         exclusion_pool.update(exclusion_table[self.multiworld.route_required[self.player].current_key])
 | |
|         if not self.multiworld.rando_love[self.player] or \
 | |
|                 (self.multiworld.route_required[self.player] != "genocide" and
 | |
|                  self.multiworld.route_required[self.player] != "all_routes"):
 | |
|             exclusion_pool.update(exclusion_table["NoLove"])
 | |
|         if not self.multiworld.rando_stats[self.player] or \
 | |
|                 (self.multiworld.route_required[self.player] != "genocide" and
 | |
|                  self.multiworld.route_required[self.player] != "all_routes"):
 | |
|             exclusion_pool.update(exclusion_table["NoStats"])
 | |
| 
 | |
|         # Choose locations to automatically exclude based on settings
 | |
|         exclusion_checks = set()
 | |
|         exclusion_checks.update(["Nicecream Punch Card", "Hush Trade"])
 | |
|         exclusion_rules(self.multiworld, self.player, exclusion_checks)
 | |
| 
 | |
|         # Fill remaining items with randomly generated junk or Temmie Flakes
 | |
|         if not self.multiworld.only_flakes[self.player]:
 | |
|             itempool += self.multiworld.random.choices(list(junk_pool.keys()), weights=list(junk_pool.values()),
 | |
|                                                        k=len(self.location_names)-len(itempool)-len(exclusion_pool))
 | |
|         else:
 | |
|             itempool += ["Temmie Flakes"] * (len(self.location_names) - len(itempool) - len(exclusion_pool))
 | |
|         # Convert itempool into real items
 | |
|         itempool = [item for item in map(lambda name: self.create_item(name), itempool)]
 | |
| 
 | |
|         self.multiworld.itempool += itempool
 | |
| 
 | |
|     def set_rules(self):
 | |
|         set_rules(self.multiworld, self.player)
 | |
|         set_completion_rules(self.multiworld, self.player)
 | |
| 
 | |
|     def create_regions(self):
 | |
|         def UndertaleRegion(region_name: str, exits=[]):
 | |
|             ret = Region(region_name, self.player, self.multiworld)
 | |
|             ret.locations = [UndertaleAdvancement(self.player, loc_name, loc_data.id, ret)
 | |
|                              for loc_name, loc_data in advancement_table.items()
 | |
|                              if loc_data.region == region_name and
 | |
|                              (loc_name not in exclusion_table["NoStats"] or
 | |
|                               (self.multiworld.rando_stats[self.player] and
 | |
|                                (self.multiworld.route_required[self.player] == "genocide" or
 | |
|                                 self.multiworld.route_required[self.player] == "all_routes"))) and
 | |
|                              (loc_name not in exclusion_table["NoLove"] or
 | |
|                               (self.multiworld.rando_love[self.player] and
 | |
|                                (self.multiworld.route_required[self.player] == "genocide" or
 | |
|                                 self.multiworld.route_required[self.player] == "all_routes"))) and
 | |
|                              loc_name not in exclusion_table[self.multiworld.route_required[self.player].current_key]]
 | |
|             for exit in exits:
 | |
|                 ret.exits.append(Entrance(self.player, exit, ret))
 | |
|             return ret
 | |
| 
 | |
|         self.multiworld.regions += [UndertaleRegion(*r) for r in undertale_regions]
 | |
|         link_undertale_areas(self.multiworld, self.player)
 | |
| 
 | |
|     def fill_slot_data(self):
 | |
|         slot_data = self._get_undertale_data()
 | |
|         for option_name in undertale_options:
 | |
|             option = getattr(self.multiworld, option_name)[self.player]
 | |
|             if (option_name == "rando_love" or option_name == "rando_stats") and \
 | |
|                     self.multiworld.route_required[self.player] != "genocide" and \
 | |
|                     self.multiworld.route_required[self.player] != "all_routes":
 | |
|                 option.value = False
 | |
|             if slot_data.get(option_name, None) is None and type(option.value) in {str, int}:
 | |
|                 slot_data[option_name] = int(option.value)
 | |
|         return slot_data
 | |
| 
 | |
|     def create_item(self, name: str) -> Item:
 | |
|         item_data = item_table[name]
 | |
|         item = UndertaleItem(name, item_data.classification, item_data.code, self.player)
 | |
|         return item
 |