Skip to content

Commit

Permalink
FO4: Implement DOBJ, DOOR and DUAL
Browse files Browse the repository at this point in the history
At least DOBJ doesn't have the stupid MelExtra stuff from Skyrim
anymore.

DUAL doesn't actually exist in Fallout4.esm or any of the DLCs, but
the CK can create it. Format is identical to Skyrim.

And with that, all D* records are done.
  • Loading branch information
Infernio committed Aug 22, 2022
1 parent 9cbf308 commit 47d601b
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 65 deletions.
43 changes: 41 additions & 2 deletions Mopy/bash/brec/common_subrecords.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
MelFloat, MelReadOnly, MelFids, MelUInt32Flags, MelUInt8Flags, MelSInt32, \
MelStrings, MelUInt8, MelUInt16Flags
from .utils_constants import int_unpacker, FID, null1, ZERO_FID
from ..bolt import Flags, encode, struct_pack, struct_unpack, unpack_byte, \
dict_sort, TrimmedFlags, structs_cache
from ..bolt import Flags, encode, struct_pack, dict_sort, TrimmedFlags, \
structs_cache
from ..exception import ModError, ModSizeError

#------------------------------------------------------------------------------
Expand Down Expand Up @@ -433,6 +433,33 @@ class MelDescription(MelLString):
def __init__(self):
super().__init__(b'DESC', 'description')

#------------------------------------------------------------------------------
class MelDoorFlags(MelUInt8Flags):
_door_flags = Flags.from_names(
'oblivion_gate' # Oblivion only
'automatic',
'hidden',
'minimal_use',
'sliding_door', # since FO3
'do_not_open_in_combat_search', # since Skyrim
'no_to_text', # since FO4
)

def __init__(self):
super().__init__(b'FNAM', 'door_flags', self._door_flags)

#------------------------------------------------------------------------------
class MelDualData(MelStruct):
"""Handles the DUAL subrecord DATA (Data)."""
_inherit_scale_flags = Flags.from_names('hit_effect_art_scale',
'projectile_scale', 'explosion_scale')

def __init__(self):
super().__init__(b'DATA', ['6I'], (FID, 'projectile'),
(FID, 'explosion'), (FID, 'effect_shader'),
(FID, 'hit_effect_art'), (FID, 'impact_data_set'),
(self._inherit_scale_flags, 'inherit_scale_flags')),

#------------------------------------------------------------------------------
class MelEdid(MelString):
"""Handles an Editor ID (EDID) subrecord."""
Expand Down Expand Up @@ -806,6 +833,12 @@ def pack_subrecord_data(self, record, *, __zero_fid=ZERO_FID):
return super(MelRaceVoices, self).pack_subrecord_data(record)
return None

#------------------------------------------------------------------------------
class MelRandomTeleports(MelSorted):
"""Handles the DOOR subrecord TNAM (Random Teleport Destinations)."""
def __init__(self):
super().__init__(MelFids('random_teleports', MelFid(b'TNAM')))

#------------------------------------------------------------------------------
class MelRef3D(MelOptStruct):
"""3D position and rotation for a reference record (REFR, ACHR, etc.)."""
Expand Down Expand Up @@ -927,6 +960,12 @@ class MelSoundClose(MelFid):
def __init__(self, sc_sig=b'QNAM'):
super().__init__(sc_sig, 'sound_close')

#------------------------------------------------------------------------------
class MelSoundLooping(MelFid):
"""Handles the DOOR subrecord BNAM (Sound - Looping)."""
def __init__(self):
super().__init__(b'BNAM', 'sound_looping')

#------------------------------------------------------------------------------
class MelSoundPickupDrop(MelSequential):
"""Handles the common YNAM (Pickup Sound) and ZNAM (Drop Sound) subrecords.
Expand Down
2 changes: 1 addition & 1 deletion Mopy/bash/game/fallout3/patcher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@
b'COBJ': (u'pickupSound', u'dropSound'),
b'CONT': ('sound', 'sound_close'),
b'CREA': (u'footWeight', u'inheritsSoundsFrom', u'sounds'),
b'DOOR': ('sound', 'sound_close', 'soundLoop'),
b'DOOR': ('sound', 'sound_close', 'sound_looping'),
b'EXPL': (u'soundLevel', u'sound1', u'sound2'),
b'IPCT': ('soundLevel', 'sound', 'sound2'),
b'LIGH': (u'sound',),
Expand Down
16 changes: 5 additions & 11 deletions Mopy/bash/game/fallout3/records.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@
MelRefScale, MelMapMarker, MelActionFlags, MelEnchantment, MelScript, \
MelDecalData, MelDescription, MelLists, MelSoundPickupDrop, MelBookText, \
MelActivateParents, BipedFlags, MelSpells, MelUInt8Flags, MelUInt16Flags, \
MelUInt32Flags, MelOwnership, MelDebrData, MelRaceData, MelRegions, \
MelUInt32Flags, MelOwnership, MelRaceData, MelRegions, MelDoorFlags, \
MelClmtWeatherTypes, MelFactionRanks, perk_effect_key, MelLscrLocations, \
MelReflectedRefractedBy, MelValueWeight, SpellFlags, MelBaseR, MelExtra, \
MelSound, MelSoundActivation, MelWaterType, MelConditionsFo3, \
MelNodeIndex, MelAddnDnam, MelEffectsFo3, MelShortName, PerkEpdfDecider, \
MelPerkParamsGroups, MelUnorderedGroups, MelImageSpaceMod, MelAspcRdat, \
MelSoundClose, AMelItems, AMelLLItems, MelContData, MelCpthShared
MelSoundClose, AMelItems, AMelLLItems, MelContData, MelCpthShared, \
MelSoundLooping
from ...exception import ModSizeError

_is_fnv = bush.game.fsName == u'FalloutNV'
Expand Down Expand Up @@ -1040,13 +1041,6 @@ class MreDoor(MelRecord):
"""Door."""
rec_sig = b'DOOR'

_flags = Flags.from_names(
(1, 'automatic'),
(2, 'hidden'),
(3, 'minimalUse'),
(4, 'slidingDoor'),
)

melSet = MelSet(
MelEdid(),
MelBounds(),
Expand All @@ -1056,8 +1050,8 @@ class MreDoor(MelRecord):
MelDestructible(),
MelSound(),
MelSoundClose(b'ANAM'),
MelFid(b'BNAM','soundLoop'),
MelUInt8Flags(b'FNAM', u'flags', _flags),
MelSoundLooping(),
MelDoorFlags(),
)
__slots__ = melSet.getSlotsUsed()

Expand Down
23 changes: 12 additions & 11 deletions Mopy/bash/game/fallout4/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,25 +223,26 @@ def init(cls):
MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \
MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \
MreCmpo, MreCobj, MreCont, MreCpth, MreCsty, MreDfob, MreDmgt, \
MreDobj, MreDoor, MreDual, \
MreGmst, MreLvli, MreLvln, MrePerk, MreTes4
cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (
MreAact, MreActi, MreAddn, MreAech, MreAmdl, MreAnio, MreAoru,
MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook,
MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj,
MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreDfob, MreDlbr,
MreDlvw, MreDmgt,
MreDlvw, MreDmgt, MreDobj, MreDoor, MreDual,
MreGmst, MreLvli, MreLvln, MrePerk,
)}
# Setting RecordHeader class variables --------------------------------
from ... import brec
header_type = brec.RecordHeader
header_type.top_grup_sigs = [
b'GMST', b'KYWD', b'LCRT', b'AACT', b'TRNS', b'CMPO', b'TXST',
b'GLOB', b'DMGT', b'CLAS', b'FACT', b'HDPT', b'RACE', b'SOUN',
b'ASPC', b'MGEF', b'LTEX', b'ENCH', b'SPEL', b'ACTI', b'TACT',
b'ARMO', b'BOOK', b'CONT', b'DOOR', b'INGR', b'LIGH', b'MISC',
b'STAT', b'SCOL', b'MSTT', b'GRAS', b'TREE', b'FLOR', b'FURN',
b'WEAP', b'AMMO', b'NPC_', b'PLYR', b'LVLN', b'KEYM', b'ALCH',
b'GLOB', b'DMGT', b'CLAS', b'FACT', b'HDPT', b'EYES', b'RACE',
b'SOUN', b'ASPC', b'MGEF', b'LTEX', b'ENCH', b'SPEL', b'ACTI',
b'TACT', b'ARMO', b'BOOK', b'CONT', b'DOOR', b'INGR', b'LIGH',
b'MISC', b'STAT', b'SCOL', b'MSTT', b'GRAS', b'TREE', b'FLOR',
b'FURN', b'WEAP', b'AMMO', b'NPC_', b'LVLN', b'KEYM', b'ALCH',
b'IDLM', b'NOTE', b'PROJ', b'HAZD', b'BNDS', b'TERM', b'LVLI',
b'WTHR', b'CLMT', b'SPGD', b'RFCT', b'REGN', b'NAVI', b'CELL',
b'WRLD', b'QUST', b'IDLE', b'PACK', b'CSTY', b'LSCR', b'LVSP',
Expand All @@ -251,10 +252,10 @@ def init(cls):
b'MESG', b'DOBJ', b'DFOB', b'LGTM', b'MUSC', b'FSTP', b'FSTS',
b'SMBN', b'SMQN', b'SMEN', b'DLBR', b'MUST', b'DLVW', b'EQUP',
b'RELA', b'SCEN', b'ASTP', b'OTFT', b'ARTO', b'MATO', b'MOVT',
b'SNDR', b'SNCT', b'SOPM', b'COLL', b'CLFM', b'REVB', b'PKIN',
b'RFGP', b'AMDL', b'LAYR', b'COBJ', b'OMOD', b'MSWP', b'ZOOM',
b'INNR', b'KSSM', b'AECH', b'SCCO', b'AORU', b'SCSN', b'STAG',
b'NOCM', b'LENS', b'GDRY', b'OVIS',
b'SNDR', b'DUAL', b'SNCT', b'SOPM', b'COLL', b'CLFM', b'REVB',
b'PKIN', b'RFGP', b'AMDL', b'LAYR', b'COBJ', b'OMOD', b'MSWP',
b'ZOOM', b'INNR', b'KSSM', b'AECH', b'SCCO', b'AORU', b'SCSN',
b'STAG', b'NOCM', b'LENS', b'GDRY', b'OVIS',
]
header_type.valid_header_sigs = (set(header_type.top_grup_sigs) |
{b'GRUP', b'TES4', b'REFR', b'ACHR', b'PMIS', b'PARW', b'PGRE',
Expand All @@ -270,7 +271,7 @@ def init(cls):
MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook,
MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj,
MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreDfob, MreDlbr,
MreDlvw, MreDmgt,
MreDlvw, MreDmgt, MreDobj, MreDoor, MreDual,
MreGmst, MreLvli, MreLvln, MrePerk, MreTes4,
)}
brec.MreRecord.simpleTypes = (
Expand Down
55 changes: 54 additions & 1 deletion Mopy/bash/game/fallout4/records.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
MelBookText, MelBookDescription, MelInventoryArt, MelUnorderedGroups, \
MelImageSpaceMod, MelClmtWeatherTypes, MelClmtTiming, MelClmtTextures, \
MelCobjOutput, AMreWithItems, AMelItems, MelContData, MelSoundClose, \
MelCpthShared, FormVersionDecider
MelCpthShared, FormVersionDecider, MelSoundLooping, MelDoorFlags, \
MelRandomTeleports, MelDualData

##: What about texture hashes? I carried discarding them forward from Skyrim,
# but that was due to the 43-44 problems. See also #620.
Expand Down Expand Up @@ -919,6 +920,58 @@ class MreDmgt(MelRecord):
)
__slots__ = melSet.getSlotsUsed()

#------------------------------------------------------------------------------
class MreDobj(MelRecord):
"""Default Object Manager."""
rec_sig = b'DOBJ'

melSet = MelSet(
MelEdid(),
MelSorted(MelArray('default_objects',
MelStruct(b'DNAM', ['2I'], 'default_object_use',
(FID, 'default_object_fid')),
), sort_by_attrs='default_object_use'),
)
__slots__ = melSet.getSlotsUsed()

#------------------------------------------------------------------------------
class MreDoor(MelRecord):
"""Door."""
rec_sig = b'DOOR'

melSet = MelSet(
MelEdid(),
MelVmad(),
MelBounds(),
MelPreviewTransform(),
MelFull(),
MelModel(),
MelDestructible(),
MelKeywords(),
MelNativeTerminal(),
MelSound(),
MelSoundClose(b'ANAM'),
MelSoundLooping(),
MelDoorFlags(),
MelLString(b'ONAM', 'alternate_text_open'),
MelLString(b'CNAM', 'alternate_text_close'),
MelRandomTeleports(),
)
__slots__ = melSet.getSlotsUsed()

#------------------------------------------------------------------------------
# Not present in Fallout4.esm, but can be created in CK
class MreDual(MelRecord):
"""Dual Cast Data."""
rec_sig = b'DUAL'

melSet = MelSet(
MelEdid(),
MelBounds(),
MelDualData(),
)
__slots__ = melSet.getSlotsUsed()

#------------------------------------------------------------------------------
class MreGmst(AMreGmst):
"""Game Setting."""
Expand Down
18 changes: 9 additions & 9 deletions Mopy/bash/game/fallout4vr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ def init(cls):
header_type = brec.RecordHeader
header_type.top_grup_sigs = [
b'GMST', b'KYWD', b'LCRT', b'AACT', b'TRNS', b'CMPO', b'TXST',
b'GLOB', b'DMGT', b'CLAS', b'FACT', b'HDPT', b'RACE', b'SOUN',
b'ASPC', b'MGEF', b'LTEX', b'ENCH', b'SPEL', b'ACTI', b'TACT',
b'ARMO', b'BOOK', b'CONT', b'DOOR', b'INGR', b'LIGH', b'MISC',
b'STAT', b'SCOL', b'MSTT', b'GRAS', b'TREE', b'FLOR', b'FURN',
b'WEAP', b'AMMO', b'NPC_', b'PLYR', b'LVLN', b'KEYM', b'ALCH',
b'GLOB', b'DMGT', b'CLAS', b'FACT', b'HDPT', b'EYES', b'RACE',
b'SOUN', b'ASPC', b'MGEF', b'LTEX', b'ENCH', b'SPEL', b'ACTI',
b'TACT', b'ARMO', b'BOOK', b'CONT', b'DOOR', b'INGR', b'LIGH',
b'MISC', b'STAT', b'SCOL', b'MSTT', b'GRAS', b'TREE', b'FLOR',
b'FURN', b'WEAP', b'AMMO', b'NPC_', b'LVLN', b'KEYM', b'ALCH',
b'IDLM', b'NOTE', b'PROJ', b'HAZD', b'BNDS', b'TERM', b'LVLI',
b'WTHR', b'CLMT', b'SPGD', b'RFCT', b'REGN', b'NAVI', b'CELL',
b'WRLD', b'QUST', b'IDLE', b'PACK', b'CSTY', b'LSCR', b'LVSP',
Expand All @@ -112,10 +112,10 @@ def init(cls):
b'MESG', b'DOBJ', b'DFOB', b'LGTM', b'MUSC', b'FSTP', b'FSTS',
b'SMBN', b'SMQN', b'SMEN', b'DLBR', b'MUST', b'DLVW', b'EQUP',
b'RELA', b'SCEN', b'ASTP', b'OTFT', b'ARTO', b'MATO', b'MOVT',
b'SNDR', b'SNCT', b'SOPM', b'COLL', b'CLFM', b'REVB', b'PKIN',
b'RFGP', b'AMDL', b'LAYR', b'COBJ', b'OMOD', b'MSWP', b'ZOOM',
b'INNR', b'KSSM', b'AECH', b'SCCO', b'AORU', b'SCSN', b'STAG',
b'NOCM', b'LENS', b'GDRY', b'OVIS',
b'SNDR', b'DUAL', b'SNCT', b'SOPM', b'COLL', b'CLFM', b'REVB',
b'PKIN', b'RFGP', b'AMDL', b'LAYR', b'COBJ', b'OMOD', b'MSWP',
b'ZOOM', b'INNR', b'KSSM', b'AECH', b'SCCO', b'AORU', b'SCSN',
b'STAG', b'NOCM', b'LENS', b'GDRY', b'OVIS',
]
header_type.valid_header_sigs = (set(header_type.top_grup_sigs) |
{b'GRUP', b'TES4', b'REFR', b'ACHR', b'PMIS', b'PARW', b'PGRE',
Expand Down
2 changes: 1 addition & 1 deletion Mopy/bash/game/oblivion/patcher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@
b'ACTI': ('sound',),
b'CONT': ('sound', 'sound_close'),
b'CREA': (u'footWeight', u'inheritsSoundsFrom', u'sounds'),
b'DOOR': ('sound', 'sound_close', 'soundLoop'),
b'DOOR': ('sound', 'sound_close', 'sound_looping'),
b'LIGH': (u'sound',),
b'MGEF': (u'castingSound', u'boltSound', u'hitSound', u'areaSound'),
# b'REGN': ('entries.sounds',),
Expand Down
12 changes: 5 additions & 7 deletions Mopy/bash/game/oblivion/records.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
MelClmtWeatherTypes, MelFactionRanks, MelLscrLocations, attr_csv_struct, \
MelEnchantment, MelValueWeight, null4, SpellFlags, MelOwnership, \
MelSound, MelWeight, MelEffectsTes4ObmeFull, MelBookText, MelClmtTiming, \
MelClmtTextures, MelSoundClose, AMelItems, AMelLLItems, MelContData
MelClmtTextures, MelSoundClose, AMelItems, AMelLLItems, MelContData, \
MelDoorFlags, MelSoundLooping, MelRandomTeleports

#------------------------------------------------------------------------------
# Record Elements -------------------------------------------------------------
Expand Down Expand Up @@ -907,19 +908,16 @@ class MreDoor(MelRecord):
"""Door."""
rec_sig = b'DOOR'

_flags = Flags.from_names('oblivionGate', 'automatic', 'hidden',
'minimalUse')

melSet = MelSet(
MelEdid(),
MelFull(),
MelModel(),
MelScript(),
MelSound(),
MelSoundClose(b'ANAM'),
MelFid(b'BNAM','soundLoop'),
MelUInt8Flags(b'FNAM', u'flags', _flags),
MelSorted(MelFids('destinations', MelFid(b'TNAM'))),
MelSoundLooping(),
MelDoorFlags(),
MelRandomTeleports(),
)
__slots__ = melSet.getSlotsUsed()

Expand Down
2 changes: 1 addition & 1 deletion Mopy/bash/game/skyrim/patcher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@
b'ASPC': ('sound', 'use_sound_from_region', 'aspc_reverb'),
b'BOOK': (u'pickupSound', u'dropSound'),
b'CONT': ('sound', 'sound_close'),
b'DOOR': ('sound', 'sound_close', 'soundLoop'),
b'DOOR': ('sound', 'sound_close', 'sound_looping'),
b'EFSH': (u'ambientSound',), ##: This is also in graphicsTypes!
b'EXPL': (u'sound1', u'sound2'),
b'FLOR': ('sound',),
Expand Down

0 comments on commit 47d601b

Please sign in to comment.