 8541c87c97
			
		
	
	8541c87c97
	
	
	
		
			
			* Paint: Implement New Game * Add docstring * Remove unnecessary self.multiworld references * Implement start_inventory_from_pool * Convert logic to use LogicMixin * Add location_exists_with_options function to deduplicate code * Simplify starting tool creation * Add Paint to supported games list * Increment version to 0.4.1 * Update docs to include color selection features * Fix world attribute definitions * Fix linting errors * De-duplicate lists of traps * Move LogicMixin to __init__.py * 0.5.0 features - adjustable canvas size increment, updated similarity metric * Fix OptionError formatting * Create OptionError when generating single-player game with error-prone settings * Increment version to 0.5.1 * Update CODEOWNERS * Update documentation for 0.5.2 client changes * Simplify region creation * Add comments describing logic * Remove unnecessary f-strings * Remove unused import * Refactor rules to location class * Remove unnecessary self.multiworld references * Update logic to correctly match client-side item caps --------- Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
		
			
				
	
	
		
			129 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from typing import Dict, Any
 | |
| 
 | |
| from BaseClasses import CollectionState, Item, MultiWorld, Tutorial, Region
 | |
| from Options import OptionError
 | |
| from worlds.AutoWorld import LogicMixin, World, WebWorld
 | |
| from .items import item_table, PaintItem, item_data_table, traps, deathlink_traps
 | |
| from .locations import location_table, PaintLocation, location_data_table
 | |
| from .options import PaintOptions
 | |
| 
 | |
| 
 | |
| class PaintWebWorld(WebWorld):
 | |
|     theme = "partyTime"
 | |
| 
 | |
|     setup_en = Tutorial(
 | |
|         tutorial_name="Start Guide",
 | |
|         description="A guide to playing Paint in Archipelago.",
 | |
|         language="English",
 | |
|         file_name="guide_en.md",
 | |
|         link="guide/en",
 | |
|         authors=["MarioManTAW"]
 | |
|     )
 | |
| 
 | |
|     tutorials = [setup_en]
 | |
| 
 | |
| 
 | |
| class PaintWorld(World):
 | |
|     """
 | |
|     The classic Microsoft app, reimagined as an Archipelago game! Find your tools, expand your canvas, and paint the
 | |
|     greatest image the world has ever seen.
 | |
|     """
 | |
|     game = "Paint"
 | |
|     options_dataclass = PaintOptions
 | |
|     options: PaintOptions
 | |
|     web = PaintWebWorld()
 | |
|     location_name_to_id = location_table
 | |
|     item_name_to_id = item_table
 | |
|     origin_region_name = "Canvas"
 | |
| 
 | |
|     def generate_early(self) -> None:
 | |
|         if self.options.canvas_size_increment < 50 and self.options.logic_percent <= 55:
 | |
|             if self.multiworld.players == 1:
 | |
|                 raise OptionError("Logic Percent must be greater than 55 when generating a single-player world with "
 | |
|                                   "Canvas Size Increment below 50.")
 | |
| 
 | |
|     def get_filler_item_name(self) -> str:
 | |
|         if self.random.randint(0, 99) >= self.options.trap_count:
 | |
|             return "Additional Palette Color"
 | |
|         elif self.options.death_link:
 | |
|             return self.random.choice(deathlink_traps)
 | |
|         else:
 | |
|             return self.random.choice(traps)
 | |
| 
 | |
|     def create_item(self, name: str) -> PaintItem:
 | |
|         item = PaintItem(name, item_data_table[name].type, item_data_table[name].code, self.player)
 | |
|         return item
 | |
| 
 | |
|     def create_items(self) -> None:
 | |
|         starting_tools = ["Brush", "Pencil", "Eraser/Color Eraser", "Airbrush", "Line", "Rectangle", "Ellipse",
 | |
|                           "Rounded Rectangle"]
 | |
|         self.push_precollected(self.create_item("Magnifier"))
 | |
|         self.push_precollected(self.create_item(starting_tools.pop(self.options.starting_tool)))
 | |
|         items_to_create = ["Free-Form Select", "Select", "Fill With Color", "Pick Color", "Text", "Curve", "Polygon"]
 | |
|         items_to_create += starting_tools
 | |
|         items_to_create += ["Progressive Canvas Width"] * (400 // self.options.canvas_size_increment)
 | |
|         items_to_create += ["Progressive Canvas Height"] * (300 // self.options.canvas_size_increment)
 | |
|         depth_items = ["Progressive Color Depth (Red)", "Progressive Color Depth (Green)",
 | |
|                        "Progressive Color Depth (Blue)"]
 | |
|         for item in depth_items:
 | |
|             self.push_precollected(self.create_item(item))
 | |
|         items_to_create += depth_items * 6
 | |
|         pre_filled = len(items_to_create)
 | |
|         to_fill = len(self.get_region("Canvas").locations)
 | |
|         if pre_filled > to_fill:
 | |
|             raise OptionError(f"{self.player_name}'s Paint world has too few locations for its required items. "
 | |
|                               "Consider adding more locations by raising logic percent or adding fractional checks. "
 | |
|                               "Alternatively, increasing the canvas size increment will require fewer items.")
 | |
|         while len(items_to_create) < (to_fill - pre_filled) * (self.options.trap_count / 100) + pre_filled:
 | |
|             if self.options.death_link:
 | |
|                 items_to_create += [self.random.choice(deathlink_traps)]
 | |
|             else:
 | |
|                 items_to_create += [self.random.choice(traps)]
 | |
|         while len(items_to_create) < to_fill:
 | |
|             items_to_create += ["Additional Palette Color"]
 | |
|         self.multiworld.itempool += [self.create_item(item) for item in items_to_create]
 | |
| 
 | |
|     def create_regions(self) -> None:
 | |
|         canvas = Region("Canvas", self.player, self.multiworld)
 | |
|         canvas.locations += [PaintLocation(self.player, loc_name, loc_data.address, canvas)
 | |
|                              for loc_name, loc_data in location_data_table.items()
 | |
|                              if location_exists_with_options(self, loc_data.address)]
 | |
| 
 | |
|         self.multiworld.regions += [canvas]
 | |
| 
 | |
|     def set_rules(self) -> None:
 | |
|         from .rules import set_completion_rules
 | |
|         set_completion_rules(self, self.player)
 | |
| 
 | |
|     def fill_slot_data(self) -> Dict[str, Any]:
 | |
|         return dict(self.options.as_dict("logic_percent", "goal_percent", "goal_image", "death_link",
 | |
|                                          "canvas_size_increment"), version="0.5.2")
 | |
| 
 | |
|     def collect(self, state: CollectionState, item: Item) -> bool:
 | |
|         change = super().collect(state, item)
 | |
|         if change:
 | |
|             state.paint_percent_stale[self.player] = True
 | |
|         return change
 | |
| 
 | |
|     def remove(self, state: CollectionState, item: Item) -> bool:
 | |
|         change = super().remove(state, item)
 | |
|         if change:
 | |
|             state.paint_percent_stale[self.player] = True
 | |
|         return change
 | |
| 
 | |
| 
 | |
| def location_exists_with_options(world: PaintWorld, location: int):
 | |
|     l = location % 198600
 | |
|     return l <= world.options.logic_percent * 4 and (l % 4 == 0 or
 | |
|                                                     (l > world.options.half_percent_checks * 4 and l % 2 == 0) or
 | |
|                                                     l > world.options.quarter_percent_checks * 4)
 | |
| 
 | |
| 
 | |
| class PaintState(LogicMixin):
 | |
|     paint_percent_available: dict[int, float]  # per player
 | |
|     paint_percent_stale: dict[int, bool]
 | |
| 
 | |
|     def init_mixin(self, multiworld: MultiWorld) -> None:
 | |
|         self.paint_percent_available = {player: 0 for player in multiworld.get_game_players("Paint")}
 | |
|         self.paint_percent_stale = {player: True for player in multiworld.get_game_players("Paint")}
 |