Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Halo 1 MCC def handler #46

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions mozzarilla/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
# ##############
__author__ = "Sigmmma"
# YYYY.MM.DD
__date__ = "2021.03.12"
__version__ = (1, 10, 0)
__date__ = "2024.03.16"
__version__ = (1, 15, 1)
__website__ = "https://github.com/Sigmmma/mozzarilla"
16 changes: 11 additions & 5 deletions mozzarilla/app_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from reclaimer.h3.handler import Halo3Handler
from reclaimer.os_v3_hek.handler import OsV3HaloHandler
from reclaimer.os_v4_hek.handler import OsV4HaloHandler
from reclaimer.mcc_hek.handler import MCCHaloHandler
from reclaimer.misc.handler import MiscHaloLoader
from reclaimer.stubbs.handler import StubbsHandler
from supyr_struct.util import tagpath_to_fullpath, path_split,\
Expand Down Expand Up @@ -100,13 +101,16 @@ class Mozzarilla(Binilla):
guerilla_workspace_def = None
config_version = 3

# NOTE: halo 3 stuff has been disabled since it was always experimental,
# and people shouldn't think it works with official h3 mod tools.
handler_classes = (
HaloHandler,
OsV3HaloHandler,
OsV4HaloHandler,
MCCHaloHandler,
MiscHaloLoader,
StubbsHandler,
Halo3Handler,
#Halo3Handler,
)

handlers = ()
Expand All @@ -115,18 +119,20 @@ class Mozzarilla(Binilla):
"Halo 1",
"Halo 1 OS v3",
"Halo 1 OS v4",
"Halo 1 MCC",
"Halo 1 Misc",
"Stubbs the Zombie",
"Halo 3"
#"Halo 3"
)

# names of the handlers that MUST load tags from within their tags_dir
tags_dir_relative = frozenset((
"Halo 1",
"Halo 1 OS v3",
"Halo 1 OS v4",
"Halo 1 MCC",
"Stubbs the Zombie",
"Halo 3"
#"Halo 3"
))

about_module_names = (
Expand Down Expand Up @@ -310,7 +316,7 @@ def __init__(self, *args, **kwargs):
label="Bitmap(s) from bitmap source", command=self.bitmap_from_bitmap_source)
self.compile_menu.add_separator()
self.compile_menu.add_command(
label="Sound from wav", command=self.show_sound_compiler_window)
label="Sound from source files", command=self.show_sound_compiler_window)
self.compile_menu.add_separator()
self.compile_menu.add_command(
label="Model_animations from jma", command=self.show_animations_compiler_window)
Expand Down Expand Up @@ -820,7 +826,7 @@ def load_tags(self, filepaths=None, def_id=None):
return ()
elif isinstance(filepaths, str) and filepaths.startswith('{'):
# account for a stupid bug with certain versions of windows
filepaths = re.split("\}\W\{", filepaths[1:-1])
filepaths = re.split(r"\}\W\{", filepaths[1:-1])

if isinstance(filepaths, (str, PurePath)):
filepaths = (filepaths, )
Expand Down
2 changes: 1 addition & 1 deletion mozzarilla/defs/config_def.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@
"halo_1",
"halo_1_os_v3",
"halo_1_os_v4",
"halo_1_mcc",
"halo_1_misc",
"stubbs",
"halo_3",
EDITABLE=False, VISIBLE=VISIBILITY_METADATA
),
UInt16("last_tags_dir", VISIBLE=VISIBILITY_METADATA, EDITABLE=False),
Expand Down
3 changes: 2 additions & 1 deletion mozzarilla/widgets/field_widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@
"Halo3BitmapDisplayButton", "Halo3BitmapTagFrame", "HaloColorEntry",
"HaloUInt32ColorPickerFrame", "MeterImageDisplayFrame", "MeterImageFrame",
"HaloRawdataFrame", "HaloScriptSourceFrame", "SoundSampleFrame",
"ReflexiveFrame",
"ReflexiveFrame", "SoundPlayerFrame",
) + tuple(field_widgets.__all__)

from binilla.widgets.field_widgets import *

from mozzarilla.widgets.field_widgets.computed_text_frames import \
HaloScriptTextFrame, HaloHudMessageTextFrame
from mozzarilla.widgets.field_widgets.dependency_frame import DependencyFrame
from mozzarilla.widgets.field_widgets.sound_player_frame import SoundPlayerFrame
from mozzarilla.widgets.field_widgets.font_display_frame import \
FontCharacterDisplayFrame, FontCharacterFrame
from mozzarilla.widgets.field_widgets.halo_1_bitmap_display import \
Expand Down
21 changes: 14 additions & 7 deletions mozzarilla/widgets/field_widgets/computed_text_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,30 @@ def get_text(self):
if None in (self.strings, self.syntax):
return

typ = "script"
if "global" in self.f_widget_parent.node.NAME:
typ = "global"
# figure out the engine so we can decompile the script data correctly.
# NOTE: refinery sets the tag window engine when it displays it.
# we default to what the tag itself says though.
tag = getattr(self.tag_window, "tag", None)
engine = (getattr(tag, "engine", None) or
getattr(self.tag_window, "engine", None))
kw = dict(engine=engine) if engine else dict()

typ = "global" if "global" in self.f_widget_parent.node.NAME else "script"

tag_data = self.parent.parent.parent.parent
script_strings_by_type = ()
try:
if self.tag_window.use_scenario_names_for_script_names:
script_strings_by_type = reclaimer.halo_script.hsc.\
get_h1_scenario_script_object_type_strings(tag_data)
get_scenario_script_object_type_strings(tag_data, **kw)
except Exception:
pass

new_text = reclaimer.halo_script.hsc.hsc_bytecode_to_string(
self.syntax, self.strings, self.f_widget_parent.attr_index,
tag_data.scripts.STEPTREE, tag_data.globals.STEPTREE, typ,
hsc_node_strings_by_type=script_strings_by_type)
self.syntax, self.strings, self.f_widget_parent.attr_index,
tag_data.scripts.STEPTREE, tag_data.globals.STEPTREE, typ,
hsc_node_strings_by_type=script_strings_by_type,
)
return new_text


Expand Down
2 changes: 1 addition & 1 deletion mozzarilla/widgets/field_widgets/dependency_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def get_dependency_tag(self):
print(format_exc())

try:
tag = handler.get_tag(filepath + ext)
tag = handler.get_tag(filepath)
except Exception:
try:
tag = handler.build_tag(filepath=filepath)
Expand Down
11 changes: 4 additions & 7 deletions mozzarilla/widgets/field_widgets/halo_color_picker_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,6 @@ def __init__(self, *args, **kwargs):
if self.f_widget_parent is None:
self.pack_padx = self.pack_pady = 0

if 'a' in self.desc['COLOR_CHANNELS']:
self.has_alpha = True
else:
self.has_alpha = False

tk.Frame.__init__(self, *args, **e_c.fix_kwargs(**kwargs))

self._initialized = True
Expand Down Expand Up @@ -260,12 +255,14 @@ def reload(self):
for wid in self.f_widget_ids:
self.f_widgets[wid].reload()

apply_style = FieldWidget.apply_style

def pose_fields(self):
ContainerFrame.pose_fields(self)
self.color_btn.pack(side='left')

@property
def has_alpha(self):
return 'a' in self.desc.get('COLOR_CHANNELS', '')

@property
def alpha(self):
if self.node is None: return 0.0
Expand Down
74 changes: 70 additions & 4 deletions mozzarilla/widgets/field_widgets/rawdata_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@
from pathlib import Path
import copy
import tkinter as tk
import tkinter.ttk as ttk

from traceback import format_exc

from supyr_struct.buffer import get_rawdata
from supyr_struct.defs.audio.wav import wav_def
from supyr_struct.tag import Tag as SupyrTag

from binilla.widgets.field_widgets import FieldWidget, RawdataFrame
from binilla.windows.filedialog import askopenfilename, asksaveasfilename

from mozzarilla.widgets.field_widgets.sound_player_frame import SoundPlayerMixin
from reclaimer.meta.wrappers.byteswapping import byteswap_pcm16_samples
from reclaimer.sounds import playback


class HaloRawdataFrame(RawdataFrame):
Expand Down Expand Up @@ -71,7 +74,40 @@ class HaloScriptSourceFrame(HaloRawdataFrame):
def field_ext(self): return '.hsc'


class SoundSampleFrame(HaloRawdataFrame):
class SoundSampleFrame(HaloRawdataFrame, SoundPlayerMixin):

def __init__(self, *args, **kwargs):
SoundPlayerMixin.__init__(self)
HaloRawdataFrame.__init__(self, *args, **kwargs)
self.sound_player.concatenate_perm_chain = False

@property
def big_endian_pcm(self):
# metadata pcm audio is little endian. we can detect
# this based on whether or not the engine property
# exists that Refinery's MetaWindow should have.
return not hasattr(getattr(self, "tag_window", None), "engine")

def destroy(self):
try:
self.playback_action("stop_all")
except Exception:
pass
super().destroy()

def update_player(self):
try:
perm = self.parent.parent
perms = perm.parent
pr = perms.parent.parent
prs = pr.parent
self.permutation_index = perms.index_by_id(perm)
self.pitch_range_index = prs.index_by_id(pr)
except (ValueError, AttributeError):
self.permutation_index = -1
self.pitch_range_index = -1

super().update_player()

@property
def field_ext(self):
Expand All @@ -83,6 +119,28 @@ def field_ext(self):
pass
return '.wav'

def populate(self):
self.play_sound_btn = ttk.Button(
self, width=6, text='Play',
command=(lambda e=None: self.playback_action("play"))
)
self.stop_sound_btn = ttk.Button(
self, width=6, text='Stop',
command=(lambda e=None: self.playback_action("stop"))
)
self.stop_all_sounds_btn = ttk.Button(
self, width=8, text='Stop all',
command=(lambda e=None: self.playback_action("stop_all"))
)
super().populate()

def pose_fields(self):
super().pose_fields()
padx, pady = self.horizontal_padx, self.horizontal_pady
self.play_sound_btn.pack(side='left', fill="x", padx=padx, pady=pady)
self.stop_sound_btn.pack(side='left', fill="x", padx=padx, pady=pady)
self.stop_all_sounds_btn.pack(side='left', fill="x", padx=padx, pady=pady)

def import_node(self):
'''Prompts the user for an exported node file.
Imports data into the node from the file.'''
Expand All @@ -95,7 +153,11 @@ def import_node(self):

filepath = askopenfilename(
initialdir=initialdir, defaultextension=ext,
filetypes=[(self.name, "*" + ext), ('All', '*')],
filetypes=[
(ext.lstrip(".").capitalize() + " file", "*" + ext),
("Rawdata", "*.bin"),
('All', '*')
],
title="Import sound data from...", parent=self)

if not filepath:
Expand Down Expand Up @@ -201,7 +263,11 @@ def export_node(self):

filepath = asksaveasfilename(
initialdir=initialdir, title="Export sound data to...",
parent=self, filetypes=[(self.name, '*' + def_ext), ('All', '*')])
parent=self, filetypes=[
(def_ext.lstrip(".").capitalize() + " file", "*" + def_ext),
("Rawdata", "*.bin"),
('All', '*')
])

if not filepath:
return
Expand Down
Loading