forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
242 lines
12 KiB
Python
242 lines
12 KiB
Python
"""All code associated with temporary holiday-based cosmetic effects."""
|
|
|
|
import gzip
|
|
from PIL import Image, ImageEnhance
|
|
from randomizer.Patching.Patcher import ROM
|
|
from randomizer.Patching.Library.Generic import Holidays, getHoliday
|
|
from randomizer.Patching.Library.Image import (
|
|
getImageFile,
|
|
getBonusSkinOffset,
|
|
ExtraTextures,
|
|
TextureFormat,
|
|
maskImageWithColor,
|
|
writeColorImageToROM,
|
|
hueShift,
|
|
hueShiftImageContainer,
|
|
)
|
|
from randomizer.Patching.Library.Assets import getPointerLocation, TableNames
|
|
from randomizer.Settings import CharacterColors, KongModels
|
|
|
|
|
|
def changeBarrelColor(settings, ROM_COPY: ROM, barrel_color: tuple = None, metal_color: tuple = None, brighten_barrel: bool = False):
|
|
"""Change the colors of the various barrels."""
|
|
if settings.archipelago: # Something weird going on with AP
|
|
return
|
|
wood_img = getImageFile(ROM_COPY, 25, getBonusSkinOffset(ExtraTextures.ShellWood), True, 32, 64, TextureFormat.RGBA5551)
|
|
metal_img = getImageFile(ROM_COPY, 25, getBonusSkinOffset(ExtraTextures.ShellMetal), True, 32, 64, TextureFormat.RGBA5551)
|
|
qmark_img = getImageFile(ROM_COPY, 25, getBonusSkinOffset(ExtraTextures.ShellQMark), True, 32, 64, TextureFormat.RGBA5551)
|
|
if barrel_color is not None:
|
|
if brighten_barrel:
|
|
enhancer = ImageEnhance.Brightness(wood_img)
|
|
wood_img = enhancer.enhance(2)
|
|
wood_img = maskImageWithColor(wood_img, barrel_color)
|
|
if metal_color is not None:
|
|
metal_img = maskImageWithColor(metal_img, metal_color)
|
|
wood_img.paste(metal_img, (0, 0), metal_img)
|
|
writeColorImageToROM(wood_img, 25, getBonusSkinOffset(ExtraTextures.BonusShell), 32, 64, False, TextureFormat.RGBA5551, ROM_COPY) # Bonus Barrel
|
|
tag_img = Image.new(mode="RGBA", size=(32, 64))
|
|
tag_img.paste(wood_img, (0, 0), wood_img)
|
|
tag_img.paste(qmark_img, (0, 0), qmark_img)
|
|
writeColorImageToROM(tag_img, 25, 4938, 32, 64, False, TextureFormat.RGBA5551, ROM_COPY) # Tag Barrel
|
|
# Compose Transform Barrels
|
|
kongs = [
|
|
{"face_left": 0x27C, "face_right": 0x27B, "barrel_tex_start": 4817, "targ_width": 24}, # DK
|
|
{"face_left": 0x279, "face_right": 0x27A, "barrel_tex_start": 4815, "targ_width": 24}, # Diddy
|
|
{"face_left": 0x277, "face_right": 0x278, "barrel_tex_start": 4819, "targ_width": 24}, # Lanky
|
|
{"face_left": 0x276, "face_right": 0x275, "barrel_tex_start": 4769, "targ_width": 24}, # Tiny
|
|
{"face_left": 0x273, "face_right": 0x274, "barrel_tex_start": 4747, "targ_width": 24}, # Chunky
|
|
]
|
|
for kong in kongs:
|
|
bar_left = Image.new(mode="RGBA", size=(32, 64))
|
|
bar_right = Image.new(mode="RGBA", size=(32, 64))
|
|
face_left = getImageFile(ROM_COPY, 25, kong["face_left"], True, 32, 64, TextureFormat.RGBA5551)
|
|
face_right = getImageFile(ROM_COPY, 25, kong["face_right"], True, 32, 64, TextureFormat.RGBA5551)
|
|
width = kong["targ_width"]
|
|
height = width * 2
|
|
face_left = face_left.resize((width, height))
|
|
face_right = face_right.resize((width, height))
|
|
right_w_offset = 32 - width
|
|
top_h_offset = (64 - height) >> 1
|
|
bar_left.paste(wood_img, (0, 0), wood_img)
|
|
bar_right.paste(wood_img, (0, 0), wood_img)
|
|
bar_left.paste(face_left, (right_w_offset, top_h_offset), face_left)
|
|
bar_right.paste(face_right, (0, top_h_offset), face_right)
|
|
writeColorImageToROM(bar_left, 25, kong["barrel_tex_start"], 32, 64, False, TextureFormat.RGBA5551, ROM_COPY)
|
|
writeColorImageToROM(bar_right, 25, kong["barrel_tex_start"] + 1, 32, 64, False, TextureFormat.RGBA5551, ROM_COPY)
|
|
# Cannons
|
|
barrel_left = Image.new(mode="RGBA", size=(32, 64))
|
|
barrel_right = Image.new(mode="RGBA", size=(32, 64))
|
|
barrel_left.paste(wood_img, (0, 0), wood_img)
|
|
barrel_right.paste(wood_img, (0, 0), wood_img)
|
|
barrel_left = barrel_left.crop((0, 0, 16, 64))
|
|
barrel_right = barrel_right.crop((16, 0, 32, 64))
|
|
writeColorImageToROM(barrel_left, 25, 0x12B3, 16, 64, False, TextureFormat.RGBA5551, ROM_COPY)
|
|
writeColorImageToROM(barrel_right, 25, 0x12B4, 16, 64, False, TextureFormat.RGBA5551, ROM_COPY)
|
|
if barrel_color is not None:
|
|
tex_data = {
|
|
getBonusSkinOffset(ExtraTextures.RocketTop): (1, 1372),
|
|
0x12B5: (48, 32),
|
|
0x12B8: (44, 44),
|
|
}
|
|
for img in tex_data:
|
|
dim_x = tex_data[img][0]
|
|
dim_y = tex_data[img][1]
|
|
img_output = getImageFile(ROM_COPY, 25, img, True, dim_x, dim_y, TextureFormat.RGBA5551)
|
|
img_output = maskImageWithColor(img_output, barrel_color)
|
|
writeColorImageToROM(img_output, 25, img, dim_x, dim_y, False, TextureFormat.RGBA5551, ROM_COPY)
|
|
|
|
|
|
def applyCelebrationRims(ROM_COPY: ROM, hue_shift: int, enabled_bananas: list[bool] = [False, False, False, False, False]):
|
|
"""Retexture the warp pad rims to have a more celebratory tone."""
|
|
banana_textures = []
|
|
vanilla_banana_textures = [0xA8, 0x98, 0xE8, 0xD0, 0xF0]
|
|
for kong_index, ban in enumerate(enabled_bananas):
|
|
if ban:
|
|
banana_textures.append(vanilla_banana_textures[kong_index])
|
|
place_bananas = False
|
|
if len(banana_textures) > 0:
|
|
place_bananas = True
|
|
if len(banana_textures) < 4:
|
|
banana_textures = (banana_textures * 4)[:4]
|
|
if place_bananas:
|
|
bananas = [getImageFile(ROM_COPY, 7, x, False, 44, 44, TextureFormat.RGBA5551).resize((14, 14)) for x in banana_textures]
|
|
banana_placement = [
|
|
# File, x, y
|
|
[0xBB3, 15, 1], # 3
|
|
[0xBB2, 2, 1], # 2
|
|
[0xBB3, 0, 1], # 4
|
|
[0xBB2, 17, 1], # 1
|
|
]
|
|
for img in (0xBB2, 0xBB3):
|
|
side_im = getImageFile(ROM_COPY, 25, img, True, 32, 16, TextureFormat.RGBA5551)
|
|
hueShift(side_im, hue_shift)
|
|
if place_bananas:
|
|
for bi, banana in enumerate(bananas):
|
|
if banana_placement[bi][0] == img:
|
|
b_x = banana_placement[bi][1]
|
|
b_y = banana_placement[bi][2]
|
|
side_im.paste(banana, (b_x, b_y), banana)
|
|
side_by = []
|
|
side_px = side_im.load()
|
|
for y in range(16):
|
|
for x in range(32):
|
|
red_short = (side_px[x, y][0] >> 3) & 31
|
|
green_short = (side_px[x, y][1] >> 3) & 31
|
|
blue_short = (side_px[x, y][2] >> 3) & 31
|
|
alpha_short = 1 if side_px[x, y][3] > 128 else 0
|
|
value = (red_short << 11) | (green_short << 6) | (blue_short << 1) | alpha_short
|
|
side_by.extend([(value >> 8) & 0xFF, value & 0xFF])
|
|
px_data = bytearray(side_by)
|
|
px_data = gzip.compress(px_data, compresslevel=9)
|
|
ROM_COPY.seek(getPointerLocation(TableNames.TexturesGeometry, img))
|
|
ROM_COPY.writeBytes(px_data)
|
|
|
|
|
|
def applyHolidayMode(settings, ROM_COPY: ROM):
|
|
"""Change grass texture to snow."""
|
|
HOLIDAY = getHoliday(settings)
|
|
if HOLIDAY == Holidays.no_holiday:
|
|
changeBarrelColor(settings, ROM_COPY) # Fixes some Krusha stuff
|
|
return
|
|
if HOLIDAY == Holidays.Christmas:
|
|
# Set season to Christmas
|
|
ROM_COPY.seek(settings.rom_data + 0xDB)
|
|
ROM_COPY.writeMultipleBytes(2, 1)
|
|
# Grab Snow texture, transplant it
|
|
ROM_COPY.seek(0x1FF8000)
|
|
snow_im = Image.new(mode="RGBA", size=((32, 32)))
|
|
snow_px = snow_im.load()
|
|
snow_by = []
|
|
for y in range(32):
|
|
for x in range(32):
|
|
rgba_px = int.from_bytes(ROM_COPY.readBytes(2), "big")
|
|
red = ((rgba_px >> 11) & 31) << 3
|
|
green = ((rgba_px >> 6) & 31) << 3
|
|
blue = ((rgba_px >> 1) & 31) << 3
|
|
alpha = (rgba_px & 1) * 255
|
|
snow_px[x, y] = (red, green, blue, alpha)
|
|
for dim in (32, 16, 8, 4):
|
|
snow_im = snow_im.resize((dim, dim))
|
|
px = snow_im.load()
|
|
for y in range(dim):
|
|
for x in range(dim):
|
|
rgba_data = list(px[x, y])
|
|
data = 0
|
|
for c in range(3):
|
|
data |= (rgba_data[c] >> 3) << (1 + (5 * c))
|
|
if rgba_data[3] != 0:
|
|
data |= 1
|
|
snow_by.extend([(data >> 8), (data & 0xFF)])
|
|
byte_data = gzip.compress(bytearray(snow_by), compresslevel=9)
|
|
for img in (0x4DD, 0x4E4, 0x6B, 0xF0, 0x8B2, 0x5C2, 0x66E, 0x66F, 0x685, 0x6A1, 0xF8, 0x136):
|
|
start = getPointerLocation(TableNames.TexturesGeometry, img)
|
|
ROM_COPY.seek(start)
|
|
ROM_COPY.writeBytes(byte_data)
|
|
# Alter CI4 Palettes
|
|
start = getPointerLocation(TableNames.TexturesGeometry, 2007)
|
|
mags = [140, 181, 156, 181, 222, 206, 173, 230, 255, 255, 255, 189, 206, 255, 181, 255]
|
|
new_ci4_palette = []
|
|
for mag in mags:
|
|
comp_mag = mag >> 3
|
|
data = (comp_mag << 11) | (comp_mag << 6) | (comp_mag << 1) | 1
|
|
new_ci4_palette.extend([(data >> 8), (data & 0xFF)])
|
|
byte_data = gzip.compress(bytearray(new_ci4_palette), compresslevel=9)
|
|
ROM_COPY.seek(start)
|
|
ROM_COPY.writeBytes(byte_data)
|
|
# Alter rims
|
|
applyCelebrationRims(ROM_COPY, 50, [True, True, True, True, False])
|
|
# Change DK's Tie and Tiny's Hair
|
|
if settings.dk_tie_colors != CharacterColors.custom and settings.kong_model_dk == KongModels.default:
|
|
tie_hang = [0xFF] * 0xAB8
|
|
tie_hang_data = gzip.compress(bytearray(tie_hang), compresslevel=9)
|
|
ROM_COPY.seek(getPointerLocation(TableNames.TexturesGeometry, 0xE8D))
|
|
ROM_COPY.writeBytes(tie_hang_data)
|
|
tie_loop = [0xFF] * (32 * 32 * 2)
|
|
tie_loop_data = gzip.compress(bytearray(tie_loop), compresslevel=9)
|
|
ROM_COPY.seek(getPointerLocation(TableNames.TexturesGeometry, 0x177D))
|
|
ROM_COPY.writeBytes(tie_loop_data)
|
|
if settings.tiny_hair_colors != CharacterColors.custom and settings.kong_model_tiny == KongModels.default:
|
|
tiny_hair = []
|
|
for x in range(32 * 32):
|
|
tiny_hair.extend([0xF8, 0x01])
|
|
tiny_hair_data = gzip.compress(bytearray(tiny_hair), compresslevel=9)
|
|
ROM_COPY.seek(getPointerLocation(TableNames.TexturesGeometry, 0xE68))
|
|
ROM_COPY.writeBytes(tiny_hair_data)
|
|
# Tag Barrel, Bonus Barrel & Transform Barrels
|
|
changeBarrelColor(settings, ROM_COPY, None, (0x00, 0xC0, 0x00))
|
|
elif HOLIDAY == Holidays.Halloween:
|
|
ROM_COPY.seek(settings.rom_data + 0xDB)
|
|
ROM_COPY.writeMultipleBytes(1, 1)
|
|
# Pad Rim
|
|
applyCelebrationRims(ROM_COPY, -12)
|
|
# Tag Barrel, Bonus Barrel & Transform Barrels
|
|
changeBarrelColor(settings, ROM_COPY, (0x00, 0xC0, 0x00))
|
|
# Turn Ice Tomato Orange
|
|
sizes = {
|
|
0x1237: 700,
|
|
0x1238: 1404,
|
|
0x1239: 1372,
|
|
0x123A: 1372,
|
|
0x123B: 692,
|
|
0x123C: 1372,
|
|
0x123D: 1372,
|
|
0x123E: 1372,
|
|
0x123F: 1372,
|
|
0x1240: 1372,
|
|
0x1241: 1404,
|
|
}
|
|
for img in range(0x1237, 0x1241 + 1):
|
|
hueShiftImageContainer(25, img, 1, sizes[img], TextureFormat.RGBA5551, 240)
|
|
elif HOLIDAY == Holidays.Anniv25:
|
|
changeBarrelColor(settings, ROM_COPY, (0xFF, 0xFF, 0x00), None, True)
|
|
sticker_im = getImageFile(ROM_COPY, 25, getBonusSkinOffset(ExtraTextures.Anniv25Sticker), True, 1, 1372, TextureFormat.RGBA5551)
|
|
vanilla_sticker_im = getImageFile(ROM_COPY, 25, 0xB7D, True, 1, 1372, TextureFormat.RGBA5551)
|
|
sticker_im_snipped = sticker_im.crop((0, 0, 1, 1360))
|
|
writeColorImageToROM(sticker_im_snipped, 25, 0xB7D, 1, 1360, False, TextureFormat.RGBA5551, ROM_COPY)
|
|
vanilla_sticker_portion = vanilla_sticker_im.crop((0, 1360, 1, 1372))
|
|
new_im = Image.new(mode="RGBA", size=(1, 1372))
|
|
new_im.paste(sticker_im_snipped, (0, 0), sticker_im_snipped)
|
|
new_im.paste(vanilla_sticker_portion, (0, 1360), vanilla_sticker_portion)
|
|
writeColorImageToROM(new_im, 25, 0x1266, 1, 1372, False, TextureFormat.RGBA5551, ROM_COPY)
|
|
applyCelebrationRims(ROM_COPY, 0, [False, True, True, True, True])
|