Files
Jonathan Tinney 7971961166
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
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

176 lines
7.1 KiB
Python

"""All code associated with Krusha."""
import js
import zlib
import gzip
from typing import TYPE_CHECKING
from randomizer.Settings import Settings
from randomizer.Enums.Settings import ColorblindMode
from randomizer.Patching.Library.Generic import getObjectAddress
from randomizer.Patching.Library.DataTypes import float_to_hex, intf_to_float, int_to_list
from randomizer.Patching.Patcher import LocalROM
from randomizer.Patching.Library.Image import (
writeColorImageToROM,
getImageFile,
getBonusSkinOffset,
ExtraTextures,
TextureFormat,
)
from randomizer.Patching.Library.Assets import TableNames, getRawFile, writeRawFile
from randomizer.Enums.Kongs import Kongs
from PIL import Image
DK_SCALE = 0.75
GENERIC_SCALE = 0.49
krusha_scaling = [
# [x, y, z, xz, y]
# DK
[
lambda x: x * DK_SCALE,
lambda x: x * DK_SCALE,
lambda x: x * GENERIC_SCALE,
lambda x: x * DK_SCALE,
lambda x: x * DK_SCALE,
],
# Diddy
[
lambda x: (x * 1.043) - 41.146,
lambda x: (x * 9.893) - 8.0,
lambda x: x * GENERIC_SCALE,
lambda x: (x * 1.103) - 14.759,
lambda x: (x * 0.823) + 35.220,
],
# Lanky
[
lambda x: (x * 0.841) - 17.231,
lambda x: (x * 6.925) - 2.0,
lambda x: x * GENERIC_SCALE,
lambda x: (x * 0.680) - 18.412,
lambda x: (x * 0.789) + 42.138,
],
# Tiny
[
lambda x: (x * 0.632) + 7.590,
lambda x: (x * 6.925) + 0.0,
lambda x: x * GENERIC_SCALE,
lambda x: (x * 1.567) - 21.676,
lambda x: (x * 0.792) + 41.509,
],
# Chunky
[lambda x: x, lambda x: x, lambda x: x, lambda x: x, lambda x: x],
]
def readListAsInt(arr: list, start: int, size: int) -> int:
"""Read list and convert to int."""
val = 0
for i in range(size):
val = (val * 256) + arr[start + i]
return val
kong_index_mapping = {
# Regular model, instrument model
Kongs.donkey: (3, None),
Kongs.diddy: (0, 1),
Kongs.lanky: (5, 6),
Kongs.tiny: (8, 9),
Kongs.chunky: (11, 12),
}
def fixModelSmallKongCollision(kong_index: int, ROM_COPY: LocalROM):
"""Modify Krusha Model to be smaller to enable him to fit through smaller gaps."""
for x in range(2):
file = kong_index_mapping[kong_index][x]
if file is None:
continue
data = getRawFile(ROM_COPY, TableNames.ActorGeometry, file, True)
num_data = [] # data, but represented as nums rather than b strings
for d in data:
num_data.append(d)
head = readListAsInt(num_data, 0, 4)
ptr = readListAsInt(num_data, 0xC, 4)
base = (ptr - head) + 0x28 + 8
count_0 = readListAsInt(num_data, base, 4)
changes = krusha_scaling[kong_index][:3]
changes_0 = [
krusha_scaling[kong_index][3],
krusha_scaling[kong_index][4],
krusha_scaling[kong_index][3],
]
for i in range(count_0):
i_start = base + 4 + (i * 0x14)
for coord_index, change in enumerate(changes):
val_i = readListAsInt(num_data, i_start + (4 * coord_index) + 4, 4)
val_f = change(intf_to_float(val_i))
val_i = int(float_to_hex(val_f), 16)
for di, d in enumerate(int_to_list(val_i, 4)):
num_data[i_start + (4 * coord_index) + 4 + di] = d
section_2_start = base + 4 + (count_0 * 0x14)
count_1 = readListAsInt(num_data, section_2_start, 4)
for i in range(count_1):
i_start = section_2_start + 4 + (i * 0x10)
for coord_index, change in enumerate(changes_0):
val_i = readListAsInt(num_data, i_start + (4 * coord_index), 4)
val_f = change(intf_to_float(val_i))
val_i = int(float_to_hex(val_f), 16)
for di, d in enumerate(int_to_list(val_i, 4)):
num_data[i_start + (4 * coord_index) + di] = d
data = bytearray(num_data) # convert num_data back to binary string
writeRawFile(TableNames.ActorGeometry, file, True, data, ROM_COPY)
def fixBaboonBlasts(ROM_COPY: LocalROM):
"""Fix various baboon blasts to work for Krusha."""
# Fungi Baboon Blast
for id in (2, 5):
item_start = getObjectAddress(ROM_COPY, 0xBC, id, "actor")
if item_start is not None:
ROM_COPY.seek(item_start + 0x14)
ROM_COPY.writeMultipleBytes(0xFFFFFFEC, 4)
ROM_COPY.seek(item_start + 0x1B)
ROM_COPY.writeMultipleBytes(0, 1)
# Caves Baboon Blast
item_start = getObjectAddress(ROM_COPY, 0xBA, 4, "actor")
if item_start is not None:
ROM_COPY.seek(item_start + 0x4)
ROM_COPY.writeMultipleBytes(int(float_to_hex(510), 16), 4)
item_start = getObjectAddress(ROM_COPY, 0xBA, 12, "actor")
if item_start is not None:
ROM_COPY.seek(item_start + 0x4)
ROM_COPY.writeMultipleBytes(int(float_to_hex(333), 16), 4)
# Castle Baboon Blast
item_start = getObjectAddress(ROM_COPY, 0xBB, 4, "actor")
if item_start is not None:
ROM_COPY.seek(item_start + 0x0)
ROM_COPY.writeMultipleBytes(int(float_to_hex(2472), 16), 4)
ROM_COPY.seek(item_start + 0x8)
ROM_COPY.writeMultipleBytes(int(float_to_hex(1980), 16), 4)
def placeKrushaHead(ROM_COPY: LocalROM, settings: Settings, slot):
"""Replace a kong's face with the Krusha face."""
if settings.colorblind_mode != ColorblindMode.off:
return
kong_face_textures = [[0x27C, 0x27B], [0x279, 0x27A], [0x277, 0x278], [0x276, 0x275], [0x273, 0x274]]
unc_face_textures = [[579, 586], [580, 587], [581, 588], [582, 589], [577, 578]]
krushaFace64 = getImageFile(ROM_COPY, TableNames.TexturesGeometry, getBonusSkinOffset(ExtraTextures.KrushaFace1 + slot), True, 64, 64, TextureFormat.RGBA5551)
krushaFace64Left = krushaFace64.crop([0, 0, 32, 64])
krushaFace64Right = krushaFace64.crop([32, 0, 64, 64])
# Used in File Select, Pause Menu, Tag Barrels, Switches, Transformation Barrels
writeColorImageToROM(krushaFace64Left, 25, kong_face_textures[slot][0], 32, 64, False, TextureFormat.RGBA5551, ROM_COPY)
writeColorImageToROM(krushaFace64Right, 25, kong_face_textures[slot][1], 32, 64, False, TextureFormat.RGBA5551, ROM_COPY)
# Used in Troff and Scoff
writeColorImageToROM(krushaFace64Left, 7, unc_face_textures[slot][0], 32, 64, False, TextureFormat.RGBA5551, ROM_COPY)
writeColorImageToROM(krushaFace64Right, 7, unc_face_textures[slot][1], 32, 64, False, TextureFormat.RGBA5551, ROM_COPY)
krushaFace32 = krushaFace64.resize((32, 32))
krushaFace32 = krushaFace32.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
krushaFace32RBGA32 = getImageFile(ROM_COPY, TableNames.TexturesGeometry, getBonusSkinOffset(ExtraTextures.KrushaFace321 + slot), True, 32, 32, TextureFormat.RGBA32)
# Used in the DPad Selection Menu
writeColorImageToROM(krushaFace32, 14, 190 + slot, 32, 32, False, TextureFormat.RGBA5551, ROM_COPY)
# Used in Shops Previews
writeColorImageToROM(krushaFace32RBGA32, 14, 197 + slot, 32, 32, False, TextureFormat.RGBA32, ROM_COPY)