@@ -219,7 +219,11 @@ def unpack(self, output_dir: Path, section_index: int, **kwargs) -> None:
219219 if isinstance (file , (Sprite , FramedSprite )):
220220 for section in self .__sections :
221221 if isinstance (section , Palette ):
222- file .add_palette (section )
222+ if self .__game == Game .MG2 :
223+ palette_bytes = self .__build_mg2_palette (section_index , section )
224+ file .add_palette (palette_bytes )
225+ else :
226+ file .add_palette (section )
223227 break
224228
225229 file_type = file_type_map .get (section_index , FileType .UNKNOWN )
@@ -243,6 +247,79 @@ def __get_file_type_map(self) -> dict:
243247 return MG2_FILE_TYPE_MAP
244248 raise ValueError (f"Unsupported game: { self .__game } " )
245249
250+ def __build_mg2_palette (self , section_index : int , palette : Palette ) -> bytes :
251+ """Build a 256-color palette for a specific MG2 sprite section.
252+
253+ Section 24 uses a combined palette from two large blocks covering
254+ indices 0-90 and 96-206. Sections 25-45 each use a single block
255+ whose colors start at index 192.
256+ """
257+ from mgtools .mg2 .mappings import (
258+ MG2_PALETTE_SECTION_24_BLOCKS ,
259+ MG2_PALETTE_SPRITE_OFFSET ,
260+ )
261+
262+ if section_index == 24 :
263+ return palette .build_palette_bytes (MG2_PALETTE_SECTION_24_BLOCKS )
264+
265+ # Sections 25-45: find a palette block whose size matches the
266+ # number of contiguous colour indices this section uses at 192+.
267+ file_type_map = self .__get_file_type_map ()
268+ sprite_sections = sorted (
269+ idx
270+ for idx , ft in file_type_map .items ()
271+ if ft == FileType .SPRITE and idx != 24
272+ )
273+
274+ # Determine how many colours this section needs
275+ section_file = self .__sections [section_index ]
276+ needed = 0
277+ if hasattr (section_file , "_Sprite__variants" ):
278+ all_unique : set [int ] = set ()
279+ for v in section_file ._Sprite__variants : # type: ignore[attr-defined]
280+ all_unique .update (v .tobytes ())
281+ needed = len ([x for x in all_unique if x >= MG2_PALETTE_SPRITE_OFFSET ])
282+
283+ # Reserve large blocks (section-24 group)
284+ used : set [int ] = set ()
285+ for bi , _ in MG2_PALETTE_SECTION_24_BLOCKS :
286+ used .add (bi )
287+ # Also reserve all blocks whose first colour is magenta (255,0,255)
288+ # — these are section-24 palette components.
289+ for bi in range (palette .block_count ):
290+ block_colors = palette ._Palette__color_blocks [bi ] # type: ignore[attr-defined]
291+ if block_colors and block_colors [0 ] == (255 , 0 , 255 ):
292+ used .add (bi )
293+
294+ # Greedy first-fit: iterate over sprite sections in order (25-45).
295+ # For each section, consume the first unused block with matching size.
296+ assigned : dict [int , int ] = {}
297+ for sec in sprite_sections :
298+ sec_file = self .__sections [sec ]
299+ sec_needed = 0
300+ if hasattr (sec_file , "_Sprite__variants" ):
301+ sec_unique : set [int ] = set ()
302+ for v in sec_file ._Sprite__variants : # type: ignore[attr-defined]
303+ sec_unique .update (v .tobytes ())
304+ sec_needed = len (
305+ [x for x in sec_unique if x >= MG2_PALETTE_SPRITE_OFFSET ]
306+ )
307+ for bi in range (palette .block_count ):
308+ if bi in used :
309+ continue
310+ if palette .get_block_size (bi ) == sec_needed :
311+ assigned [sec ] = bi
312+ used .add (bi )
313+ break
314+
315+ if section_index in assigned :
316+ return palette .build_palette_bytes (
317+ [(assigned [section_index ], MG2_PALETTE_SPRITE_OFFSET )]
318+ )
319+
320+ # Fallback: use the flat palette
321+ return palette .palette_bytes
322+
246323 def add_from_folder (self , input_dir : Path , section_index : int , ** kwargs ) -> None :
247324 if self .__game == Game .MG1 :
248325 default_data_type = DataType .MG1_SECTION
0 commit comments