From 6c71e3fb6b211d19118df073f5d9f05e64f5b19a Mon Sep 17 00:00:00 2001 From: Infernio Date: Fri, 5 Aug 2022 17:54:35 +0200 Subject: [PATCH 01/13] FO4: Implement CAMS, CLAS, CLFM and CLMT All very straightforward. --- Mopy/bash/brec/common_subrecords.py | 48 +++++++++---- Mopy/bash/game/fallout3/patcher/__init__.py | 2 +- Mopy/bash/game/fallout3/records.py | 29 ++++---- Mopy/bash/game/fallout4/__init__.py | 6 +- Mopy/bash/game/fallout4/records.py | 74 ++++++++++++++++++++- Mopy/bash/game/oblivion/records.py | 13 ++-- Mopy/bash/game/skyrim/records.py | 39 +++++------ 7 files changed, 147 insertions(+), 64 deletions(-) diff --git a/Mopy/bash/brec/common_subrecords.py b/Mopy/bash/brec/common_subrecords.py index c5bf8e8008..6eb4ecfdce 100644 --- a/Mopy/bash/brec/common_subrecords.py +++ b/Mopy/bash/brec/common_subrecords.py @@ -268,6 +268,35 @@ def __init__(self): 'boundX2', 'boundY2', 'boundZ2'), ) +#------------------------------------------------------------------------------ +class MelClmtTiming(MelStruct): + """Handles the CLMT subrecord TNAM (Timing).""" + def __init__(self): + super().__init__(b'TNAM', ['6B'], 'rise_begin', 'rise_end', + 'set_begin', 'set_end', 'volatility', 'phase_length') + +#------------------------------------------------------------------------------ +class MelClmtTextures(MelSequential): + """Handles the CLMT subrecords FNAM and GNAM.""" + def __init__(self): + super().__init__( + MelString(b'FNAM', 'sun_texture'), + MelString(b'GNAM', 'sun_glare_texture'), + ) + +#------------------------------------------------------------------------------ +class MelClmtWeatherTypes(MelSorted): + """Handles the CLMT subrecord WLST (Weather Types).""" + def __init__(self, with_global=True): + weather_fmt = ['I', 'i'] + weather_elements = [(FID, 'weather'), 'chance'] + if with_global: + weather_fmt.append('I') + weather_elements.append((FID, 'global')) + super().__init__(MelArray('weather_types', + MelStruct(b'WLST', weather_fmt, *weather_elements), + ), sort_by_attrs='weather') + #------------------------------------------------------------------------------ class MelCoed(MelOptStruct): """Handles the COED (Owner Data) subrecord used for inventory items and @@ -445,6 +474,12 @@ class MelIco2(MelIcons2): def __init__(self, ico2_attr): super().__init__(ico2_attr=ico2_attr, mic2_attr='') +#------------------------------------------------------------------------------ +class MelImageSpaceMod(MelFid): + """Handles the common MNAM (Image Space Modifer) subrecord.""" + def __init__(self): + super().__init__(b'MNAM', 'image_space_modifier') + #------------------------------------------------------------------------------ class MelInteractionKeyword(MelFid): """Handles the KNAM (Interaction Keyword) subrecord of ACTI records.""" @@ -884,19 +919,6 @@ class MelWaterType(MelFid): def __init__(self): super().__init__(b'WNAM', 'water_type') -#------------------------------------------------------------------------------ -class MelWeatherTypes(MelSorted): - """Handles the CLMT subrecord WLST (Weather Types).""" - def __init__(self, with_global=True): - weather_fmt = ['I', 'i'] - weather_elements = [(FID, 'weather'), 'chance'] - if with_global: - weather_fmt.append('I') - weather_elements.append((FID, 'global')) - super().__init__(MelArray('weather_types', - MelStruct(b'WLST', weather_fmt, *weather_elements), - ), sort_by_attrs='weather') - #------------------------------------------------------------------------------ class MelWeight(MelFloat): """Handles a common variant of the DATA subrecord that consists of a single diff --git a/Mopy/bash/game/fallout3/patcher/__init__.py b/Mopy/bash/game/fallout3/patcher/__init__.py index 8280498c4e..32fe4646fe 100644 --- a/Mopy/bash/game/fallout3/patcher/__init__.py +++ b/Mopy/bash/game/fallout3/patcher/__init__.py @@ -480,7 +480,7 @@ graphicsFidTypes = { b'CREA': ('bodyPartData',), b'EFSH': (u'addonModels',), - b'EXPL': ('imageSpaceModifier', 'light', 'impactDataset', + b'EXPL': ('image_space_modifier', 'light', 'impactDataset', 'placedImpactObject'), b'IPCT': (u'textureSet',), b'IPDS': (u'stone', u'dirt', u'grass', u'metal', u'wood', u'organic', diff --git a/Mopy/bash/game/fallout3/records.py b/Mopy/bash/game/fallout3/records.py index 53c0c1b816..8946261824 100644 --- a/Mopy/bash/game/fallout3/records.py +++ b/Mopy/bash/game/fallout3/records.py @@ -43,11 +43,11 @@ MelDecalData, MelDescription, MelLists, MelSoundPickupDrop, MelBookText, \ MelActivateParents, BipedFlags, MelSpells, MelUInt8Flags, MelUInt16Flags, \ MelUInt32Flags, MelOwnership, MelDebrData, MelRaceData, MelRegions, \ - MelWeatherTypes, MelFactionRanks, perk_effect_key, MelLscrLocations, \ + MelClmtWeatherTypes, MelFactionRanks, perk_effect_key, MelLscrLocations, \ MelReflectedRefractedBy, MelValueWeight, SpellFlags, MelBaseR, MelExtra, \ MelSound, MelSoundActivation, MelWaterType, MelConditionsFo3, \ MelNodeIndex, MelAddnDnam, MelEffectsFo3, MelShortName, PerkEpdfDecider, \ - MelPerkParamsGroups, MelAspcRdat, MelUnorderedGroups + MelPerkParamsGroups, MelAspcRdat, MelUnorderedGroups, MelImageSpaceMod from ...exception import ModSizeError _is_fnv = bush.game.fsName == u'FalloutNV' @@ -688,23 +688,18 @@ class MreCams(MelRecord): """Camera Shot.""" rec_sig = b'CAMS' - CamsFlagsFlags = Flags.from_names( - (0, 'positionFollowsLocation'), - (1, 'rotationFollowsTarget'), - (2, 'dontFollowBone'), - (3, 'firstPersonCamera'), - (4, 'noTracer'), - (5, 'startAtTimeZero'), - ) + _cams_flags = Flags.from_names('position_follows_location', + 'rotation_follows_target', 'dont_follow_bone', 'first_person_camera', + 'no_tracer', 'start_at_time_zero') melSet = MelSet( MelEdid(), MelModel(), - MelStruct(b'DATA', [u'4I', u'6f'],'action','location','target', - (CamsFlagsFlags, u'flags'),'timeMultPlayer', - 'timeMultTarget','timeMultGlobal','maxTime','minTime', - 'targetPctBetweenActors',), - MelFid(b'MNAM','imageSpaceModifier',), + MelStruct(b'DATA', ['4I', '6f'], 'cams_action', 'cams_location', + 'cams_target', (_cams_flags, 'cams_flags'), 'time_mult_player', + 'time_mult_target', 'time_mult_global', 'cams_max_time', + 'cams_min_time', 'target_pct_between_actors'), + MelImageSpaceMod(), ) __slots__ = melSet.getSlotsUsed() @@ -799,7 +794,7 @@ class MreClmt(MelRecord): melSet = MelSet( MelEdid(), - MelWeatherTypes(), + MelClmtWeatherTypes(), MelString(b'FNAM','sunPath'), MelString(b'GNAM','glarePath'), MelModel(), @@ -1190,7 +1185,7 @@ class MreExpl(MelRecord): MelFull(), MelModel(), MelEnchantment(), - MelFid(b'MNAM','imageSpaceModifier'), + MelImageSpaceMod(), MelStruct(b'DATA', [u'3f', u'3I', u'f', u'2I', u'3f', u'I'], u'force', u'damage', u'radius', (FID, u'light'), (FID, u'sound1'), (_flags, u'flags'), u'isRadius', (FID, u'impactDataset'), (FID, u'sound2'), diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index f848c4c617..14d11ba425 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -220,12 +220,12 @@ def init(cls): cls._dynamic_import_modules(__name__) from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ - MreBnds, MreBook, MreBptd, \ + MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ 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, + MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -259,7 +259,7 @@ def init(cls): brec.MreRecord.type_class = {x.rec_sig: x for x in ( MreAact, MreActi, MreAddn, MreAech, MreAmdl, MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook, - MreBptd, + MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index eea6910e00..2e48400c5d 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -38,7 +38,8 @@ MelAdditionalRaces, MelFootstepSound, MelArtObject, MelEnchantment, \ MelIcons2, MelBids, MelBamt, MelTemplateArmor, MelObjectTemplate, \ MelArtType, MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, \ - MelBookText, MelBookDescription, MelInventoryArt, MelUnorderedGroups + MelBookText, MelBookDescription, MelInventoryArt, MelUnorderedGroups, \ + MelImageSpaceMod, MelClmtWeatherTypes, MelClmtTiming, MelClmtTextures ##: What about texture hashes? I carried discarding them forward from Skyrim, # but that was due to the 43-44 problems. See also #620. @@ -674,6 +675,77 @@ class MreBptd(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreCams(MelRecord): + """Camera Shot.""" + rec_sig = b'CAMS' + + _cams_flags = Flags.from_names('position_follows_location', + 'rotation_follows_target', 'dont_follow_bone', 'first_person_camera', + 'no_tracer', 'start_at_time_zero', 'dont_reset_location_spring', + 'dont_reset_target_spring') + + melSet = MelSet( + MelEdid(), + MelModel(), + MelConditionList(), + MelTruncatedStruct(b'DATA', ['4I', '12f'], 'cams_action', + 'cams_location', 'cams_target', (_cams_flags, 'cams_flags'), + 'time_mult_player', 'time_mult_target', 'time_mult_global', + 'cams_max_time', 'cams_min_time', 'target_pct_between_actors', + 'near_target_distance', 'location_spring', 'target_spring', + 'rotation_offset_x', 'rotation_offset_y', 'rotation_offset_z', + old_versions={'4I9f', '4I7f'}), + MelImageSpaceMod(), + ) + __slots__ = melSet.getSlotsUsed() + +#------------------------------------------------------------------------------ +class MreClas(MelRecord): + """Class.""" + rec_sig = b'CLAS' + + melSet = MelSet( + MelEdid(), + MelFull(), + MelDescription(), + MelIcon(), + MelProperties(), + MelStruct(b'DATA', ['4s', 'f'], 'unknown1', 'bleedout_default'), + ) + __slots__ = melSet.getSlotsUsed() + +#------------------------------------------------------------------------------ +class MreClfm(MelRecord): + """Color.""" + rec_sig = b'CLFM' + + _clfm_flags = Flags.from_names('playable', 'remapping_index', + 'extended_lut') + + melSet = MelSet( + MelEdid(), + MelFull(), + MelUInt32(b'CNAM', 'color_or_index'), + MelUInt32Flags(b'FNAM', 'clfm_flags', _clfm_flags), + MelConditionList(), + ) + __slots__ = melSet.getSlotsUsed() + +#------------------------------------------------------------------------------ +class MreClmt(MelRecord): + """Climate.""" + rec_sig = b'CLMT' + + melSet = MelSet( + MelEdid(), + MelClmtWeatherTypes(), + MelClmtTextures(), + MelModel(), + MelClmtTiming(), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreGmst(MreGmstBase): """Game Setting.""" diff --git a/Mopy/bash/game/oblivion/records.py b/Mopy/bash/game/oblivion/records.py index 445f2b854c..de8d2456ec 100644 --- a/Mopy/bash/game/oblivion/records.py +++ b/Mopy/bash/game/oblivion/records.py @@ -40,9 +40,10 @@ MelRefScale, MelMapMarker, MelActionFlags, MelPartialCounter, MelScript, \ MelDescription, BipedFlags, MelUInt8Flags, MelUInt32Flags, MelLists, \ MelConditionsTes4, MelRaceData, MelFactions, MelActorSounds, MelBaseR, \ - MelWeatherTypes, MelFactionRanks, MelLscrLocations, attr_csv_struct, \ + MelClmtWeatherTypes, MelFactionRanks, MelLscrLocations, attr_csv_struct, \ MelEnchantment, MelValueWeight, null4, SpellFlags, MelOwnership, \ - MelSound, MelWeight, MelEffectsTes4ObmeFull, MelBookText + MelSound, MelWeight, MelEffectsTes4ObmeFull, MelBookText, MelClmtTiming, \ + MelClmtTextures #------------------------------------------------------------------------------ # Record Elements ------------------------------------------------------------- @@ -713,12 +714,10 @@ class MreClmt(MelRecord): melSet = MelSet( MelEdid(), - MelWeatherTypes(with_global=False), - MelString(b'FNAM','sunPath'), - MelString(b'GNAM','glarePath'), + MelClmtWeatherTypes(with_global=False), + MelClmtTextures(), MelModel(), - MelStruct(b'TNAM', [u'6B'], 'riseBegin', 'riseEnd', 'setBegin', 'setEnd', - 'volatility', 'phaseLength'), + MelClmtTiming(), ) __slots__ = melSet.getSlotsUsed() diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index 0be10fa0f4..c3b61089e5 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -38,7 +38,7 @@ MelEnchantment, MelDecalData, MelDescription, MelSInt16, MelSkipInterior, \ MelSoundPickupDrop, MelActivateParents, BipedFlags, MelColor, \ MelColorO, MelSpells, MelFixedString, MelUInt8Flags, MelUInt16Flags, \ - MelUInt32Flags, MelOwnership, MelDebrData, MelWeatherTypes, AMelVmad, \ + MelUInt32Flags, MelOwnership, MelDebrData, MelClmtWeatherTypes, AMelVmad, \ MelActorSounds, MelFactionRanks, MelSorted, MelReflectedRefractedBy, \ perk_effect_key, MelValueWeight, MelCoed, MelSound, MelWaterType, \ MelSoundActivation, MelInteractionKeyword, MelConditionList, MelAddnDnam, \ @@ -48,7 +48,8 @@ MelArmaDnam, MelArmaModels, MelArmaSkins, MelAdditionalRaces, MelBamt, \ MelFootstepSound, MelArtObject, MelTemplateArmor, MelArtType, \ MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, MelBookText, \ - MelBookDescription, MelInventoryArt, MelUnorderedGroups, MelExtra + MelBookDescription, MelInventoryArt, MelUnorderedGroups, MelExtra, \ + MelImageSpaceMod, MelClmtTiming, MelClmtTextures from ...exception import ModSizeError _is_sse = bush.game.fsName in ( @@ -763,24 +764,19 @@ class MreCams(MelRecord): """Camera Shot.""" rec_sig = b'CAMS' - CamsFlagsFlags = Flags.from_names( - (0, 'positionFollowsLocation'), - (1, 'rotationFollowsTarget'), - (2, 'dontFollowBone'), - (3, 'firstPersonCamera'), - (4, 'noTracer'), - (5, 'startAtTimeZero'), - ) + _cams_flags = Flags.from_names('position_follows_location', + 'rotation_follows_target', 'dont_follow_bone', 'first_person_camera', + 'no_tracer', 'start_at_time_zero') melSet = MelSet( MelEdid(), MelModel(), - MelTruncatedStruct(b'DATA', [u'4I', u'7f'], 'action', 'location', 'target', - (CamsFlagsFlags, u'flags'), 'timeMultPlayer', - 'timeMultTarget', 'timeMultGlobal', 'maxTime', - 'minTime', 'targetPctBetweenActors', - 'nearTargetDistance', old_versions={'4I6f'}), - MelFid(b'MNAM','imageSpaceModifier',), + MelTruncatedStruct(b'DATA', ['4I', '7f'], 'cams_action', + 'cams_location', 'cams_target', (_cams_flags, 'cams_flags'), + 'time_mult_player', 'time_mult_target', 'time_mult_global', + 'cams_max_time', 'cams_min_time', 'target_pct_between_actors', + 'near_target_distance', old_versions={'4I6f'}), + MelImageSpaceMod(), ) __slots__ = melSet.getSlotsUsed() @@ -921,11 +917,10 @@ class MreClmt(MelRecord): melSet = MelSet( MelEdid(), - MelWeatherTypes(), - MelString(b'FNAM','sunPath',), - MelString(b'GNAM','glarePath',), + MelClmtWeatherTypes(), + MelClmtTextures(), MelModel(), - MelStruct(b'TNAM', [u'6B'],'riseBegin','riseEnd','setBegin','setEnd','volatility','phaseLength',), + MelClmtTiming(), ) __slots__ = melSet.getSlotsUsed() @@ -1314,7 +1309,7 @@ class MreExpl(MelRecord): MelFull(), MelModel(), MelEnchantment(), - MelFid(b'MNAM','imageSpaceModifier'), + MelImageSpaceMod(), MelTruncatedStruct( b'DATA', [u'6I', u'5f', u'2I'], (FID, u'light'), (FID, u'sound1'), (FID, u'sound2'), (FID, u'impactDataset'), @@ -1561,7 +1556,7 @@ class MreHazd(MelRecord): MelBounds(), MelFull(), MelModel(), - MelFid(b'MNAM','imageSpaceModifier'), + MelImageSpaceMod(), MelStruct(b'DATA', [u'I', u'4f', u'5I'],'limit','radius','lifetime', 'imageSpaceRadius','targetInterval',(HazdTypeFlags, u'flags'), (FID,'spell'),(FID,'light'),(FID,'impactDataSet'),(FID,'sound'),), From da3c1a38e0b90294103a05c8dccbeda1d1461e36 Mon Sep 17 00:00:00 2001 From: Infernio Date: Sun, 21 Aug 2022 16:51:28 +0200 Subject: [PATCH 02/13] TES4: Add comment delimiters to records Not sure why this is the only one that lacks them, but there you go. --- Mopy/bash/game/oblivion/records.py | 61 ++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/Mopy/bash/game/oblivion/records.py b/Mopy/bash/game/oblivion/records.py index de8d2456ec..67b88e0658 100644 --- a/Mopy/bash/game/oblivion/records.py +++ b/Mopy/bash/game/oblivion/records.py @@ -482,6 +482,7 @@ class MreTes4(MreHeaderBase): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreAchr(MelRecord): """Placed NPC.""" rec_sig = b'ACHR' @@ -502,6 +503,7 @@ class MreAchr(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreAcre(MelRecord): """Placed Creature.""" rec_sig = b'ACRE' @@ -517,6 +519,7 @@ class MreAcre(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreActi(MelRecord): """Activator.""" rec_sig = b'ACTI' @@ -530,6 +533,7 @@ class MreActi(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreAlch(MreHasEffects, MelRecord): """Potion.""" rec_sig = b'ALCH' @@ -550,6 +554,7 @@ class MreAlch(MreHasEffects, MelRecord): ).with_distributor(_effects_distributor) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreAmmo(MelRecord): """Ammunition.""" rec_sig = b'AMMO' @@ -568,6 +573,7 @@ class MreAmmo(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreAnio(MelRecord): """Animation Object.""" rec_sig = b'ANIO' @@ -579,6 +585,7 @@ class MreAnio(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreAppa(MelRecord): """Alchemical Apparatus.""" rec_sig = b'APPA' @@ -594,6 +601,7 @@ class MreAppa(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreArmo(MelRecord): """Armor.""" rec_sig = b'ARMO' @@ -618,6 +626,7 @@ class MreArmo(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreBook(MelRecord): """Book.""" rec_sig = b'BOOK' @@ -638,6 +647,7 @@ class MreBook(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreBsgn(MelRecord): """Birthsign.""" rec_sig = b'BSGN' @@ -651,6 +661,7 @@ class MreBsgn(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreCell(MelRecord): """Cell.""" rec_sig = b'CELL' @@ -688,6 +699,7 @@ class MreCell(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreClas(MelRecord): """Class.""" rec_sig = b'CLAS' @@ -708,6 +720,7 @@ class MreClas(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreClmt(MelRecord): """Climate.""" rec_sig = b'CLMT' @@ -721,6 +734,7 @@ class MreClmt(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreClot(MelRecord): """Clothing.""" rec_sig = b'CLOT' @@ -745,6 +759,7 @@ class MreClot(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreCont(MreWithItems): """Container.""" rec_sig = b'CONT' @@ -763,6 +778,7 @@ class MreCont(MreWithItems): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreCrea(MreActorBase): """Creature.""" rec_sig = b'CREA' @@ -824,6 +840,7 @@ class MreCrea(MreActorBase): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreCsty(MelRecord): """Combat Style.""" rec_sig = b'CSTY' @@ -873,6 +890,7 @@ class MreCsty(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreDial(MelRecord): """Dialogue.""" rec_sig = b'DIAL' @@ -886,6 +904,7 @@ class MreDial(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreDoor(MelRecord): """Door.""" rec_sig = b'DOOR' @@ -906,6 +925,7 @@ class MreDoor(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreEfsh(MelRecord): """Effect Shader.""" rec_sig = b'EFSH' @@ -946,6 +966,7 @@ class MreEfsh(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreEnch(MreHasEffects, MelRecord): """Enchantment.""" rec_sig = b'ENCH' @@ -963,6 +984,7 @@ class MreEnch(MreHasEffects, MelRecord): ).with_distributor(_effects_distributor) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreEyes(MelRecord): """Eyes.""" rec_sig = b'EYES' @@ -977,6 +999,7 @@ class MreEyes(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreFact(MelRecord): """Faction.""" rec_sig = b'FACT' @@ -994,6 +1017,7 @@ class MreFact(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreFlor(MelRecord): """Flora.""" rec_sig = b'FLOR' @@ -1008,6 +1032,7 @@ class MreFlor(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreFurn(MelRecord): """Furniture.""" rec_sig = b'FURN' @@ -1025,10 +1050,12 @@ class MreFurn(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreGmst(MreGmstBase): """Game Setting.""" __slots__ = () +#------------------------------------------------------------------------------ class MreGras(MelRecord): """Grass.""" rec_sig = b'GRAS' @@ -1045,6 +1072,7 @@ class MreGras(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreHair(MelRecord): """Hair.""" rec_sig = b'HAIR' @@ -1060,6 +1088,7 @@ class MreHair(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreIdle(MelRecord): """Idle Animation.""" rec_sig = b'IDLE' @@ -1075,6 +1104,7 @@ class MreIdle(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreInfo(MelRecord): """Dialog Response.""" rec_sig = b'INFO' @@ -1102,6 +1132,7 @@ class MreInfo(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreIngr(MreHasEffects, MelRecord): """Ingredient.""" rec_sig = b'INGR' @@ -1122,6 +1153,7 @@ class MreIngr(MreHasEffects, MelRecord): ).with_distributor(_effects_distributor) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreKeym(MelRecord): """Key.""" rec_sig = b'KEYM' @@ -1136,6 +1168,7 @@ class MreKeym(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreLigh(MelRecord): """Light.""" rec_sig = b'LIGH' @@ -1160,6 +1193,7 @@ class MreLigh(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreLscr(MelRecord): """Load Screen.""" rec_sig = b'LSCR' @@ -1172,6 +1206,7 @@ class MreLscr(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreLtex(MelRecord): """Landscape Texture.""" rec_sig = b'LTEX' @@ -1204,21 +1239,25 @@ class MreLtex(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreLvlc(MreLeveledList): """Leveled Creature.""" rec_sig = b'LVLC' __slots__ = [] +#------------------------------------------------------------------------------ class MreLvli(MreLeveledList): """Leveled Item.""" rec_sig = b'LVLI' __slots__ = [] +#------------------------------------------------------------------------------ class MreLvsp(MreLeveledList): """Leveled Spell.""" rec_sig = b'LVSP' __slots__ = [] +#------------------------------------------------------------------------------ class MreMgef(MelRecord): """Magic Effect.""" rec_sig = b'MGEF' @@ -1511,6 +1550,7 @@ class MreMgef(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreMisc(MelRecord): """Misc. Item.""" rec_sig = b'MISC' @@ -1528,6 +1568,7 @@ class MreMisc(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreNpc(MreActorBase): """Non-Player Character.""" rec_sig = b'NPC_' @@ -1613,6 +1654,7 @@ def setRace(self,race): } self.fnam = fnams.get(race, b'\x8e5') # default to Imperial +#------------------------------------------------------------------------------ class MrePack(MelRecord): """AI Package.""" rec_sig = b'PACK' @@ -1654,6 +1696,7 @@ class MrePack(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MrePgrd(MelRecord): """Path Grid.""" rec_sig = b'PGRD' @@ -1678,6 +1721,7 @@ class MrePgrd(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreQust(MelRecord): """Quest.""" rec_sig = b'QUST' @@ -1721,6 +1765,7 @@ class MreQust(MelRecord): }) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreRace(MelRecord): """Race.""" rec_sig = b'RACE' @@ -1816,6 +1861,7 @@ class MreRace(MelRecord): }) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreRefr(MelRecord): """Placed Object.""" rec_sig = b'REFR' @@ -1871,6 +1917,7 @@ def _pre_process_unpacked(self, unpacked_val): }) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreRegn(MelRecord): """Region.""" rec_sig = b'REGN' @@ -1933,6 +1980,7 @@ class MreRegn(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreRoad(MelRecord): """Road. Part of large worldspaces.""" ####Could probably be loaded via MelArray, @@ -1945,6 +1993,7 @@ class MreRoad(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreSbsp(MelRecord): """Subspace.""" rec_sig = b'SBSP' @@ -1955,6 +2004,7 @@ class MreSbsp(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreScpt(MelRecord): """Script.""" rec_sig = b'SCPT' @@ -1965,6 +2015,7 @@ class MreScpt(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreSgst(MreHasEffects, MelRecord): """Sigil Stone.""" rec_sig = b'SGST' @@ -1982,6 +2033,7 @@ class MreSgst(MreHasEffects, MelRecord): ).with_distributor(_effects_distributor) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreSkil(MelRecord): """Skill.""" rec_sig = b'SKIL' @@ -1999,6 +2051,7 @@ class MreSkil(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreSlgm(MelRecord): """Soul Gem.""" rec_sig = b'SLGM' @@ -2015,6 +2068,7 @@ class MreSlgm(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreSoun(MelRecord): """Sound.""" rec_sig = b'SOUN' @@ -2038,6 +2092,7 @@ class MreSoun(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreSpel(MreHasEffects, MelRecord): """Spell.""" rec_sig = b'SPEL' @@ -2092,6 +2147,7 @@ def parse_csv_line(cls, csv_fields, index_dict, reuse=False): """We are called for reading the 'detailed' attributes""" return attr_dict +#------------------------------------------------------------------------------ class MreStat(MelRecord): """Static.""" rec_sig = b'STAT' @@ -2102,6 +2158,7 @@ class MreStat(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreTree(MelRecord): """Tree.""" rec_sig = b'TREE' @@ -2127,6 +2184,7 @@ def _pre_process_unpacked(self, unpacked_val): unpacked_val = unpacked_val[:-1] return super(MelWatrData, self)._pre_process_unpacked(unpacked_val) +#------------------------------------------------------------------------------ class MreWatr(MelRecord): """Water.""" rec_sig = b'WATR' @@ -2162,6 +2220,7 @@ class MreWatr(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreWeap(MelRecord): """Weapon.""" rec_sig = b'WEAP' @@ -2181,6 +2240,7 @@ class MreWeap(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreWrld(MelRecord): """Worldspace.""" rec_sig = b'WRLD' @@ -2203,6 +2263,7 @@ class MreWrld(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ class MreWthr(MelRecord): """Weather.""" rec_sig = b'WTHR' From 709de7ec8737a78092f39a40d0def8d730951bf6 Mon Sep 17 00:00:00 2001 From: Infernio Date: Sun, 21 Aug 2022 16:54:43 +0200 Subject: [PATCH 03/13] FO4: Implement CMPO and COBJ --- Mopy/Docs/Wrye Bash Advanced Readme.html | 9 +++++ Mopy/bash/brec/common_records.py | 4 +- Mopy/bash/brec/common_subrecords.py | 9 +++++ Mopy/bash/brec/record_structs.py | 2 +- Mopy/bash/game/fallout3/records.py | 3 +- Mopy/bash/game/fallout4/__init__.py | 5 ++- Mopy/bash/game/fallout4/records.py | 48 +++++++++++++++++++++++- Mopy/bash/game/skyrim/records.py | 9 ++--- 8 files changed, 76 insertions(+), 13 deletions(-) diff --git a/Mopy/Docs/Wrye Bash Advanced Readme.html b/Mopy/Docs/Wrye Bash Advanced Readme.html index 9b4613df47..56568efbb2 100644 --- a/Mopy/Docs/Wrye Bash Advanced Readme.html +++ b/Mopy/Docs/Wrye Bash Advanced Readme.html @@ -6359,6 +6359,15 @@

Merge Filtering Back Skyrim, Enderal: Forgotten Stories & Skyrim: Special Edition + + (COBJ) Constructible Object + +
    +
  • (FVPA) Components
  • +
+ + Fallout 4 + (CONT) Container diff --git a/Mopy/bash/brec/common_records.py b/Mopy/bash/brec/common_records.py index 5f6b0a177b..6edbc46f73 100644 --- a/Mopy/bash/brec/common_records.py +++ b/Mopy/bash/brec/common_records.py @@ -328,7 +328,7 @@ def __init__(self, header, ins=None, do_unpack=False): self.de_records = None #--Set of items deleted by list (Delev and Relev mods) self.re_records = None #--Set of items relevelled by list (Relev mods) - def mergeFilter(self,modSet): + def mergeFilter(self, modSet): self.entries = [entry for entry in self.entries if entry.listId.mod_id in modSet] @@ -425,6 +425,6 @@ class MreActorBase(MreWithItems): __slots__ = [] def mergeFilter(self, modSet): - super(MreActorBase, self).mergeFilter(modSet) + super().mergeFilter(modSet) self.spells = [x for x in self.spells if x.mod_id in modSet] self.factions = [x for x in self.factions if x.faction.mod_id in modSet] diff --git a/Mopy/bash/brec/common_subrecords.py b/Mopy/bash/brec/common_subrecords.py index 6eb4ecfdce..99559ca793 100644 --- a/Mopy/bash/brec/common_subrecords.py +++ b/Mopy/bash/brec/common_subrecords.py @@ -297,6 +297,15 @@ def __init__(self, with_global=True): MelStruct(b'WLST', weather_fmt, *weather_elements), ), sort_by_attrs='weather') +#------------------------------------------------------------------------------ +class MelCobjOutput(MelSequential): + """Handles the COBJ subrecords CNAM and BNAM.""" + def __init__(self): + super().__init__( + MelFid(b'CNAM', 'created_object'), + MelFid(b'BNAM', 'workbench_keyword'), + ) + #------------------------------------------------------------------------------ class MelCoed(MelOptStruct): """Handles the COED (Owner Data) subrecord used for inventory items and diff --git a/Mopy/bash/brec/record_structs.py b/Mopy/bash/brec/record_structs.py index 0135c812a8..9e5c0fe70c 100644 --- a/Mopy/bash/brec/record_structs.py +++ b/Mopy/bash/brec/record_structs.py @@ -392,7 +392,7 @@ def getTypeCopy(self): myCopy.data = None return myCopy - def mergeFilter(self,modSet): + def mergeFilter(self, modSet): """This method is called by the bashed patch mod merger. The intention is to allow a record to be filtered according to the specified modSet. E.g. for a list record, items coming from mods not diff --git a/Mopy/bash/game/fallout3/records.py b/Mopy/bash/game/fallout3/records.py index 8946261824..aa1b05012c 100644 --- a/Mopy/bash/game/fallout3/records.py +++ b/Mopy/bash/game/fallout3/records.py @@ -585,7 +585,6 @@ class MreArmo(MelRecord): class MreAspc(MelRecord): """Acoustic Space.""" rec_sig = b'ASPC' - isKeyedByEid = True # NULL fids are acceptable melSet = MelSet( @@ -805,7 +804,7 @@ class MreClmt(MelRecord): #------------------------------------------------------------------------------ class MreCobj(MelRecord): - """Constructible Object (Recipes).""" + """Constructible Object.""" rec_sig = b'COBJ' melSet = MelSet( diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index 14d11ba425..1b5087ecb6 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -221,11 +221,12 @@ def init(cls): from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ + MreCmpo, MreCobj, \ 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, + MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -259,7 +260,7 @@ def init(cls): brec.MreRecord.type_class = {x.rec_sig: x for x in ( MreAact, MreActi, MreAddn, MreAech, MreAmdl, MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook, - MreBptd, MreCams, MreClas, MreClfm, MreClmt, + MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index 2e48400c5d..12c750e7e9 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -39,7 +39,8 @@ MelIcons2, MelBids, MelBamt, MelTemplateArmor, MelObjectTemplate, \ MelArtType, MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, \ MelBookText, MelBookDescription, MelInventoryArt, MelUnorderedGroups, \ - MelImageSpaceMod, MelClmtWeatherTypes, MelClmtTiming, MelClmtTextures + MelImageSpaceMod, MelClmtWeatherTypes, MelClmtTiming, MelClmtTextures, \ + MelCobjOutput ##: What about texture hashes? I carried discarding them forward from Skyrim, # but that was due to the 43-44 problems. See also #620. @@ -746,6 +747,51 @@ class MreClmt(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreCmpo(MelRecord): + """Component.""" + rec_sig = b'CMPO' + + melSet = MelSet( + MelEdid(), + MelBounds(), + MelFull(), + MelSoundCrafting(), + MelUInt32(b'DATA', 'auto_calc_value'), + MelFid(b'MNAM', 'scrap_item'), + MelFid(b'GNAM', 'mod_scrap_scalar'), + ) + __slots__ = melSet.getSlotsUsed() + +#------------------------------------------------------------------------------ +class MreCobj(MelRecord): + """Constructible Object.""" + rec_sig = b'COBJ' + ##: What about isKeyedByEid? + + melSet = MelSet( + MelEdid(), + MelSoundPickupDrop(), + MelSorted(MelArray('cobj_components', + MelStruct(b'FVPA', ['2I'], 'component_fid', 'component_count'), + ), sort_by_attrs='component_fid'), + MelDescription(), + MelConditionList(), + MelCobjOutput(), + MelBase(b'NAM1', 'unused1'), + MelBase(b'NAM2', 'unused2'), + MelBase(b'NAM3', 'unused3'), + MelFid(b'ANAM', 'menu_art_object'), + MelSorted(MelSimpleArray('category_keywords', MelFid(b'FNAM'))), + MelTruncatedStruct(b'INTV', ['2H'], 'created_object_count', + 'cobj_priority', old_versions={'H'}), + ) + __slots__ = melSet.getSlotsUsed() + + def mergeFilter(self, modSet): + self.cobj_components = [c for c in self.cobj_components + if c.component_fid.mod_id in modSet] + #------------------------------------------------------------------------------ class MreGmst(MreGmstBase): """Game Setting.""" diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index c3b61089e5..b98ca610bc 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -49,7 +49,7 @@ MelFootstepSound, MelArtObject, MelTemplateArmor, MelArtType, \ MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, MelBookText, \ MelBookDescription, MelInventoryArt, MelUnorderedGroups, MelExtra, \ - MelImageSpaceMod, MelClmtTiming, MelClmtTextures + MelImageSpaceMod, MelClmtTiming, MelClmtTextures, MelCobjOutput from ...exception import ModSizeError _is_sse = bush.game.fsName in ( @@ -926,7 +926,7 @@ class MreClmt(MelRecord): #------------------------------------------------------------------------------ class MreCobj(MreWithItems): - """Constructible Object (Recipes).""" + """Constructible Object.""" rec_sig = b'COBJ' isKeyedByEid = True # NULL fids are acceptable @@ -935,9 +935,8 @@ class MreCobj(MreWithItems): MelItemsCounter(), MelItems(), MelConditionList(), - MelFid(b'CNAM','resultingItem'), - MelFid(b'BNAM','craftingStation'), - MelUInt16(b'NAM1', 'resultingQuantity'), + MelCobjOutput(), + MelUInt16(b'NAM1', 'created_object_count'), ) __slots__ = melSet.getSlotsUsed() From 6fb5301852a9657443f138061e5e46798588e029 Mon Sep 17 00:00:00 2001 From: Infernio Date: Sun, 21 Aug 2022 18:18:51 +0200 Subject: [PATCH 04/13] Move COLL to brec Also refactor the init() overrides to move the brec imports into them. That way all the records imports (which I still dislike and would love to see replaced with a better system) sit in one place. This might actually let us import bush statically throughout brec? Probably not a good idea anyway though. Mopy/bash/brec/common_records.py: Sort the classes into two sections Base classes and actual, fully implemented classes. --- Mopy/bash/brec/common_records.py | 308 ++++++++++++++------------ Mopy/bash/game/enderal/__init__.py | 9 +- Mopy/bash/game/enderalse/__init__.py | 11 +- Mopy/bash/game/fallout3/__init__.py | 5 +- Mopy/bash/game/fallout4/__init__.py | 6 +- Mopy/bash/game/fallout4vr/__init__.py | 5 +- Mopy/bash/game/falloutnv/__init__.py | 7 +- Mopy/bash/game/morrowind/__init__.py | 3 +- Mopy/bash/game/nehrim/__init__.py | 5 +- Mopy/bash/game/oblivion/__init__.py | 5 +- Mopy/bash/game/skyrim/__init__.py | 10 +- Mopy/bash/game/skyrim/records.py | 20 -- Mopy/bash/game/skyrimse/__init__.py | 10 +- Mopy/bash/game/skyrimvr/__init__.py | 11 +- 14 files changed, 208 insertions(+), 207 deletions(-) diff --git a/Mopy/bash/brec/common_records.py b/Mopy/bash/brec/common_records.py index 6edbc46f73..3a88f102a7 100644 --- a/Mopy/bash/brec/common_records.py +++ b/Mopy/bash/brec/common_records.py @@ -27,17 +27,56 @@ from . import utils_constants from .advanced_elements import FidNotNullDecider, AttrValDecider, MelArray, \ - MelUnion, MelSorted + MelUnion, MelSorted, MelSimpleArray from .basic_elements import MelBase, MelFid, MelFids, MelFloat, MelGroups, \ MelLString, MelNull, MelStruct, MelUInt32, MelSInt32, MelFixedString, \ - MelUnicode, unpackSubHeader -from .common_subrecords import MelEdid + MelUnicode, unpackSubHeader, MelUInt32Flags, MelString +from .common_subrecords import MelEdid, MelDescription, MelColor from .record_structs import MelRecord, MelSet from .utils_constants import FID, FormId from .. import bolt, exception -from ..bolt import decoder, FName, struct_pack, structs_cache, \ +from ..bolt import decoder, FName, struct_pack, structs_cache, Flags, \ remove_newlines, to_unix_newlines, sig_to_str, to_win_newlines +#------------------------------------------------------------------------------ +# Base classes ---------------------------------------------------------------- +#------------------------------------------------------------------------------ +class MreWithItems(MelRecord): + """Base class for record types that contain a list of items (MelItems).""" + __slots__ = [] + + def mergeFilter(self, modSet): + self.items = [i for i in self.items if i.item.mod_id in modSet] + +#------------------------------------------------------------------------------ +class MreActorBase(MreWithItems): + """Base class for Creatures and NPCs.""" + __slots__ = [] + + def mergeFilter(self, modSet): + super().mergeFilter(modSet) + self.spells = [x for x in self.spells if x.mod_id in modSet] + self.factions = [x for x in self.factions if x.faction.mod_id in modSet] + +class MreGmstBase(MelRecord): + """Game Setting record. Base class, each game should derive from this + class.""" + Ids = None + rec_sig = b'GMST' + + melSet = MelSet( + MelEdid(), + MelUnion({ + u'b': MelUInt32(b'DATA', u'value'), # actually a bool + u'f': MelFloat(b'DATA', u'value'), + u's': MelLString(b'DATA', u'value'), + }, decider=AttrValDecider( + u'eid', transformer=lambda e: e[0] if e else u'i'), + fallback=MelSInt32(b'DATA', u'value') + ), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreHeaderBase(MelRecord): """File header. Base class for all 'TES4' like records""" @@ -167,133 +206,6 @@ def num_masters(self): return len(self.masters) __slots__ = [] -#------------------------------------------------------------------------------ -class MreFlst(MelRecord): - """FormID List.""" - rec_sig = b'FLST' - - melSet = MelSet( - MelEdid(), - MelFids('formIDInList', MelFid(b'LNAM')), # do *not* sort! - ) - - __slots__ = melSet.getSlotsUsed() + [u'mergeOverLast', u'mergeSources', - u'items', u'de_records', - u're_records'] - - def __init__(self, header, ins=None, do_unpack=False): - super(MreFlst, self).__init__(header, ins, do_unpack=do_unpack) - self.mergeOverLast = False #--Merge overrides last mod merged - self.mergeSources = None #--Set to list by other functions - self.items = None #--Set of items included in list - #--Set of items deleted by list (Deflst mods) unused for Skyrim - self.de_records = None #--Set of items deleted by list (Deflst mods) - self.re_records = None # unused, needed by patcher - - def mergeFilter(self, modSet): - self.formIDInList = [f for f in self.formIDInList if - f.mod_id in modSet] - - def mergeWith(self,other,otherMod): - """Merges newLevl settings and entries with self. - Requires that: self.items, other.de_records be defined.""" - #--Remove items based on other.removes - if other.de_records: - removeItems = self.items & other.de_records - self.formIDInList = [fi for fi in self.formIDInList - if fi not in removeItems] - self.items |= other.de_records - #--Add new items from other - newItems = set() - formIDInListAppend = self.formIDInList.append - newItemsAdd = newItems.add - for fi in other.formIDInList: - if fi not in self.items: - formIDInListAppend(fi) - newItemsAdd(fi) - if newItems: - self.items |= newItems - #--Is merged list different from other? (And thus written to patch.) - if len(self.formIDInList) != len(other.formIDInList): - self.mergeOverLast = True - else: - for selfEntry, otherEntry in zip(self.formIDInList, - other.formIDInList): - if selfEntry != otherEntry: - self.mergeOverLast = True - break - else: - self.mergeOverLast = False - if self.mergeOverLast: - self.mergeSources.append(otherMod) - else: - self.mergeSources = [otherMod] - self.setChanged() - -#------------------------------------------------------------------------------ -class MreGlob(MelRecord): - """Global record. Rather stupidly all values, despite their designation - (short,long,float), are stored as floats -- which means that very large - integers lose precision.""" - rec_sig = b'GLOB' - - melSet = MelSet( - MelEdid(), - MelFixedString(b'FNAM', u'global_format', 1, u's'), - MelFloat(b'FLTV', u'global_value'), - ) - __slots__ = melSet.getSlotsUsed() - -#------------------------------------------------------------------------------ -class MreGmstBase(MelRecord): - """Game Setting record. Base class, each game should derive from this - class.""" - Ids = None - rec_sig = b'GMST' - - melSet = MelSet( - MelEdid(), - MelUnion({ - u'b': MelUInt32(b'DATA', u'value'), # actually a bool - u'f': MelFloat(b'DATA', u'value'), - u's': MelLString(b'DATA', u'value'), - }, decider=AttrValDecider( - u'eid', transformer=lambda e: e[0] if e else u'i'), - fallback=MelSInt32(b'DATA', u'value') - ), - ) - __slots__ = melSet.getSlotsUsed() - -#------------------------------------------------------------------------------ -class MreLand(MelRecord): - """Land structure. Part of exterior cells.""" - rec_sig = b'LAND' - - melSet = MelSet( - MelBase(b'DATA', u'unknown'), - MelBase(b'VNML', u'vertex_normals'), - MelBase(b'VHGT', u'vertex_height_map'), - MelBase(b'VCLR', u'vertex_colors'), - MelSorted(MelGroups(u'layers', - # Start a new layer each time we hit one of these - MelUnion({ - b'ATXT': MelStruct(b'ATXT', [u'I', u'B', u's', u'h'], (FID, u'atxt_texture'), - u'quadrant', u'unknown', u'layer'), - b'BTXT': MelStruct(b'BTXT', [u'I', u'B', u's', u'h'], (FID, u'btxt_texture'), - u'quadrant', u'unknown', u'layer'), - }), - # VTXT only exists for ATXT layers, i.e. if ATXT's FormID is valid - MelUnion({ - True: MelBase(b'VTXT', u'alpha_layer_data'), # sorted - False: MelNull(b'VTXT'), - }, decider=FidNotNullDecider(u'atxt_texture')), - ), sort_by_attrs=(u'quadrant', u'layer')), - MelArray(u'vertex_textures', - MelFid(b'VTEX', u'vertex_texture'), - ), - ) - __slots__ = melSet.getSlotsUsed() - #------------------------------------------------------------------------------ class MreLeveledListBase(MelRecord): """Base type for leveled item/creature/npc/spells. @@ -412,19 +324,131 @@ def mergeWith(self,other,otherMod): self.setChanged(self.mergeOverLast) #------------------------------------------------------------------------------ -class MreWithItems(MelRecord): - """Base class for record types that contain a list of items (MelItems).""" - __slots__ = [] +# Full classes ---------------------------------------------------------------- +#------------------------------------------------------------------------------ +class MreColl(MelRecord): + """Collision Layer.""" + rec_sig = b'COLL' - def mergeFilter(self, modSet): - self.items = [i for i in self.items if i.item.mod_id in modSet] + _coll_flags = Flags.from_names('trigger_volume', 'sensor', + 'navmesh_obstacle') + + melSet = MelSet( + MelEdid(), + MelDescription(), + MelUInt32(b'BNAM', 'layer_index'), + MelColor(b'FNAM'), + MelUInt32Flags(b'GNAM', 'layer_flags', _coll_flags), + MelString(b'MNAM', 'layer_name'), + MelUInt32(b'INTV', 'interactables_count'), + MelSorted(MelSimpleArray('collides_with', MelFid(b'CNAM'))), + ) + __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreActorBase(MreWithItems): - """Base class for Creatures and NPCs.""" - __slots__ = [] +class MreFlst(MelRecord): + """FormID List.""" + rec_sig = b'FLST' + + melSet = MelSet( + MelEdid(), + MelFids('formIDInList', MelFid(b'LNAM')), # do *not* sort! + ) + + __slots__ = melSet.getSlotsUsed() + [u'mergeOverLast', u'mergeSources', + u'items', u'de_records', + u're_records'] + + def __init__(self, header, ins=None, do_unpack=False): + super(MreFlst, self).__init__(header, ins, do_unpack=do_unpack) + self.mergeOverLast = False #--Merge overrides last mod merged + self.mergeSources = None #--Set to list by other functions + self.items = None #--Set of items included in list + #--Set of items deleted by list (Deflst mods) unused for Skyrim + self.de_records = None #--Set of items deleted by list (Deflst mods) + self.re_records = None # unused, needed by patcher def mergeFilter(self, modSet): - super().mergeFilter(modSet) - self.spells = [x for x in self.spells if x.mod_id in modSet] - self.factions = [x for x in self.factions if x.faction.mod_id in modSet] + self.formIDInList = [f for f in self.formIDInList if + f.mod_id in modSet] + + def mergeWith(self,other,otherMod): + """Merges newLevl settings and entries with self. + Requires that: self.items, other.de_records be defined.""" + #--Remove items based on other.removes + if other.de_records: + removeItems = self.items & other.de_records + self.formIDInList = [fi for fi in self.formIDInList + if fi not in removeItems] + self.items |= other.de_records + #--Add new items from other + newItems = set() + formIDInListAppend = self.formIDInList.append + newItemsAdd = newItems.add + for fi in other.formIDInList: + if fi not in self.items: + formIDInListAppend(fi) + newItemsAdd(fi) + if newItems: + self.items |= newItems + #--Is merged list different from other? (And thus written to patch.) + if len(self.formIDInList) != len(other.formIDInList): + self.mergeOverLast = True + else: + for selfEntry, otherEntry in zip(self.formIDInList, + other.formIDInList): + if selfEntry != otherEntry: + self.mergeOverLast = True + break + else: + self.mergeOverLast = False + if self.mergeOverLast: + self.mergeSources.append(otherMod) + else: + self.mergeSources = [otherMod] + self.setChanged() + +#------------------------------------------------------------------------------ +class MreGlob(MelRecord): + """Global.""" + rec_sig = b'GLOB' + + melSet = MelSet( + MelEdid(), + MelFixedString(b'FNAM', u'global_format', 1, u's'), + # Rather stupidly all values, despite their designation (short, long, + # float), are stored as floats -- which means that very large integers + # lose precision + MelFloat(b'FLTV', u'global_value'), + ) + __slots__ = melSet.getSlotsUsed() + +#------------------------------------------------------------------------------ +class MreLand(MelRecord): + """Land.""" + rec_sig = b'LAND' + + melSet = MelSet( + MelBase(b'DATA', u'unknown'), + MelBase(b'VNML', u'vertex_normals'), + MelBase(b'VHGT', u'vertex_height_map'), + MelBase(b'VCLR', u'vertex_colors'), + MelSorted(MelGroups(u'layers', + # Start a new layer each time we hit one of these + MelUnion({ + b'ATXT': MelStruct(b'ATXT', [u'I', u'B', u's', u'h'], (FID, u'atxt_texture'), + u'quadrant', u'unknown', u'layer'), + b'BTXT': MelStruct(b'BTXT', [u'I', u'B', u's', u'h'], (FID, u'btxt_texture'), + u'quadrant', u'unknown', u'layer'), + }), + # VTXT only exists for ATXT layers, i.e. if ATXT's FormID is valid + MelUnion({ + True: MelBase(b'VTXT', u'alpha_layer_data'), # sorted + False: MelNull(b'VTXT'), + }, decider=FidNotNullDecider(u'atxt_texture')), + ), sort_by_attrs=(u'quadrant', u'layer')), + MelArray(u'vertex_textures', + MelFid(b'VTEX', u'vertex_texture'), + ), + ) + __slots__ = melSet.getSlotsUsed() diff --git a/Mopy/bash/game/enderal/__init__.py b/Mopy/bash/game/enderal/__init__.py index aa6163e979..476019ee1e 100644 --- a/Mopy/bash/game/enderal/__init__.py +++ b/Mopy/bash/game/enderal/__init__.py @@ -24,8 +24,6 @@ active game.""" from ..skyrim import SkyrimGameInfo -from ... import brec -from ...brec import MreFlst, MreGlob class EnderalGameInfo(SkyrimGameInfo): displayName = u'Enderal' @@ -121,8 +119,8 @@ class Bain(SkyrimGameInfo.Bain): _patcher_package = 'bash.game.enderal' # We need to override tweaks @classmethod def init(cls): - # Copy-pasted from Skyrim cls._dynamic_import_modules(__name__) + from ...brec import MreColl, MreFlst, MreGlob from ..skyrim.records import MreCell, MreWrld, MreFact, MreAchr, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ MreLvsp, MreEnch, MreProj, MreDlbr, MreRfct, MreMisc, MreActi, \ @@ -130,7 +128,7 @@ def init(cls): MreIdle, MreLtex, MreQust, MreMstt, MreNpc, MreIpds, MrePack, \ MreGmst, MreRevb, MreClmt, MreDebr, MreSmbn, MreLvli, MreSpel, \ MreKywd, MreLvln, MreAact, MreSlgm, MreRegn, MreFurn, MreGras, \ - MreAstp, MreWoop, MreMovt, MreCobj, MreShou, MreSmen, MreColl, \ + MreAstp, MreWoop, MreMovt, MreCobj, MreShou, MreSmen, MreNavm, \ MreArto, MreAddn, MreSopm, MreCsty, MreAppa, MreArma, MreArmo, \ MreKeym, MreTxst, MreHdpt, MreTes4, MreAlch, MreBook, MreSpgd, \ MreSndr, MreImgs, MreScrl, MreMust, MreFstp, MreFsts, MreMgef, \ @@ -139,7 +137,7 @@ def init(cls): MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk, MreRace, \ - MreDial, MreNavm + MreDial cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, @@ -159,6 +157,7 @@ def init(cls): MreRace, )} # 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'TXST', b'GLOB', b'CLAS', diff --git a/Mopy/bash/game/enderalse/__init__.py b/Mopy/bash/game/enderalse/__init__.py index c86e12483f..9a223e36f2 100644 --- a/Mopy/bash/game/enderalse/__init__.py +++ b/Mopy/bash/game/enderalse/__init__.py @@ -25,8 +25,6 @@ from ..enderal import EnderalGameInfo from ..skyrimse import SkyrimSEGameInfo -from ... import brec -from ...brec import MreFlst, MreGlob # We want the final chain of attribute lookups to be Enderal SE -> Enderal LE # -> Skyrim SE -> Skyrim LE -> Defaults, i.e. the narrower overrides first @@ -100,15 +98,13 @@ class Bain(EnderalGameInfo.Bain): _patcher_package = 'bash.game.enderalse' # We need to override tweaks @classmethod def init(cls): - # Copy-pasted from Skyrim cls._dynamic_import_modules(__name__) - # First import from skyrimse.records file + from ...brec import MreColl, MreFlst, MreGlob from ..skyrimse.records import MreVoli, MreLens - # then import rest of records from skyrim.records from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ - MreClfm, MreClmt, MreCobj, MreColl, MreCont, MreCpth, MreCsty, \ + MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ MreDebr, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ @@ -121,7 +117,7 @@ def init(cls): MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr, \ - MreRace, MreNavm + MreRace cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, @@ -142,6 +138,7 @@ def init(cls): MrePack, MreFact, MreRace, )} # 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'TXST', b'GLOB', b'CLAS', diff --git a/Mopy/bash/game/fallout3/__init__.py b/Mopy/bash/game/fallout3/__init__.py index d4ae37400b..d47b7d10e1 100644 --- a/Mopy/bash/game/fallout3/__init__.py +++ b/Mopy/bash/game/fallout3/__init__.py @@ -25,8 +25,7 @@ from os.path import join as _j from ..patch_game import GameInfo, PatchGame -from ... import brec, bolt -from ...brec import MreFlst, MreGlob +from ... import bolt class Fallout3GameInfo(PatchGame): displayName = u'Fallout 3' @@ -296,6 +295,7 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) + from ...brec import MreFlst, MreGlob from .records import MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, \ MreArma, MreArmo, MreAspc, MreAvif, MreBook, MreBptd, MreCams, \ MreClas, MreClmt, MreCobj, MreCont, MreCpth, MreCrea, MreCsty, \ @@ -325,6 +325,7 @@ def init(cls): MreWeap, MreWthr, MreGmst, )} # Setting RecordHeader class variables -------------------------------- + from ... import brec header_type = brec.RecordHeader header_type.top_grup_sigs = [ b'GMST', b'TXST', b'MICN', b'GLOB', b'CLAS', b'FACT', b'HDPT', diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index 1b5087ecb6..d973ddea0e 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -26,7 +26,7 @@ from ..patch_game import GameInfo, PatchGame from .. import WS_COMMON -from ... import brec, bolt +from ... import bolt class Fallout4GameInfo(PatchGame): displayName = u'Fallout 4' @@ -218,6 +218,7 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) + from ...brec import MreColl from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ @@ -227,9 +228,11 @@ def init(cls): MreAact, MreActi, MreAddn, MreAech, MreAmdl, MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj, + MreColl, 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', @@ -261,6 +264,7 @@ def init(cls): MreAact, MreActi, MreAddn, MreAech, MreAmdl, MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj, + MreColl, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/fallout4vr/__init__.py b/Mopy/bash/game/fallout4vr/__init__.py index 9f8a2fde11..28ddff6928 100644 --- a/Mopy/bash/game/fallout4vr/__init__.py +++ b/Mopy/bash/game/fallout4vr/__init__.py @@ -24,7 +24,7 @@ necessary.""" from ..fallout4 import Fallout4GameInfo -from ... import brec, bolt +from ... import bolt class Fallout4VRGameInfo(Fallout4GameInfo): displayName = u'Fallout 4 VR' @@ -88,14 +88,13 @@ class Esp(Fallout4GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - # First import FO4VR-specific record classes from .records import MreTes4 - # Then import from fallout4.records file from ..fallout4.records import MreGmst, MreLvli, MreLvln cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( MreGmst, MreLvli, MreLvln )} # 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', diff --git a/Mopy/bash/game/falloutnv/__init__.py b/Mopy/bash/game/falloutnv/__init__.py index 7de8b5c0dd..fcfae54cde 100644 --- a/Mopy/bash/game/falloutnv/__init__.py +++ b/Mopy/bash/game/falloutnv/__init__.py @@ -23,8 +23,7 @@ """GameInfo override for Fallout NV.""" from ..fallout3 import Fallout3GameInfo -from ... import brec, bolt -from ...brec import MreFlst, MreGlob +from ... import bolt class FalloutNVGameInfo(Fallout3GameInfo): displayName = u'Fallout New Vegas' @@ -141,12 +140,11 @@ def _dynamic_import_modules(cls, package_name): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - # First import from our records file + from ...brec import MreFlst, MreGlob from .records import MreTes4, MreAloc, MreAmef, MreCcrd, MreCdck, \ MreChal, MreChip, MreCmny, MreCsno, MreDehy, MreDial, MreHung, \ MreImod, MreLsct, MreMset, MreRcct, MreRcpe, MreRepu, MreSlpd, \ MreWthr - # Then from fallout3.records from ..fallout3.records import MreCpth, MreIdle, MreMesg, MrePack, \ MrePerk, MreQust, MreSpel, MreTerm, MreNpc, MreAddn, MreAnio, \ MreAvif, MreBook, MreBptd, MreCams, MreClas, MreClmt, MreCobj, \ @@ -177,6 +175,7 @@ def init(cls): MreTxst, MreVtyp, MreWatr, MreWeap, MreWthr, MreGmst, )} # Setting RecordHeader class variables -------------------------------- + from ... import brec header_type = brec.RecordHeader header_type.top_grup_sigs = [ b'GMST', b'TXST', b'MICN', b'GLOB', b'CLAS', b'FACT', b'HDPT', diff --git a/Mopy/bash/game/morrowind/__init__.py b/Mopy/bash/game/morrowind/__init__.py index d77feebe45..3154c7c457 100644 --- a/Mopy/bash/game/morrowind/__init__.py +++ b/Mopy/bash/game/morrowind/__init__.py @@ -25,7 +25,7 @@ from ..patch_game import GameInfo, PatchGame from .. import WS_COMMON -from ... import brec, bolt +from ... import bolt class MorrowindGameInfo(PatchGame): displayName = u'Morrowind' @@ -136,6 +136,7 @@ def init(cls): MreRepa, MreScpt, MreSkil, MreSndg, MreSoun, MreSpel, MreSscr, \ MreStat, MreTes3, MreWeap # Setting RecordHeader class variables - Morrowind is special + from ... import brec header_type = brec.RecordHeader header_type.rec_header_size = 16 header_type.rec_pack_format = [u'=4s', u'I', u'I', u'I'] diff --git a/Mopy/bash/game/nehrim/__init__.py b/Mopy/bash/game/nehrim/__init__.py index d7006f94f8..41a97137e3 100644 --- a/Mopy/bash/game/nehrim/__init__.py +++ b/Mopy/bash/game/nehrim/__init__.py @@ -24,8 +24,7 @@ import struct as _struct from ..oblivion import OblivionGameInfo -from ... import brec, bolt -from ...brec import MreGlob, MreLand +from ... import bolt class NehrimGameInfo(OblivionGameInfo): displayName = u'Nehrim' @@ -105,6 +104,7 @@ def _dynamic_import_modules(cls, package_name): @classmethod def init(cls): cls._dynamic_import_modules(__name__) + from ...brec import MreGlob, MreLand from ..oblivion.records import MreActi, MreAlch, MreAmmo, MreAnio, \ MreArmo, MreBook, MreBsgn, MreClas, MreClot, MreCont, MreCrea, \ MreDoor, MreEfsh, MreEnch, MreEyes, MreFact, MreFlor, MreFurn, \ @@ -129,6 +129,7 @@ def init(cls): cls.readClasses = (b'MGEF', b'SCPT') cls.writeClasses = (b'MGEF',) # Setting RecordHeader class variables - Oblivion is special + from ... import brec header_type = brec.RecordHeader header_type.rec_header_size = 20 header_type.rec_pack_format = [u'=4s', u'I', u'I', u'I', u'I'] diff --git a/Mopy/bash/game/oblivion/__init__.py b/Mopy/bash/game/oblivion/__init__.py index 3e1c5f9241..7f4f7336c5 100644 --- a/Mopy/bash/game/oblivion/__init__.py +++ b/Mopy/bash/game/oblivion/__init__.py @@ -26,8 +26,7 @@ from ..patch_game import GameInfo, PatchGame from .. import WS_COMMON -from ... import brec, bolt -from ...brec import MreGlob, MreLand +from ... import bolt class OblivionGameInfo(PatchGame): displayName = u'Oblivion' @@ -301,6 +300,7 @@ def _dynamic_import_modules(cls, package_name): @classmethod def init(cls): cls._dynamic_import_modules(__name__) + from ...brec import MreGlob, MreLand from .records import MreActi, MreAlch, MreAmmo, MreAnio, MreAppa, \ MreArmo, MreBook, MreBsgn, MreClas, MreClot, MreCont, MreCrea, \ MreDoor, MreEfsh, MreEnch, MreEyes, MreFact, MreFlor, MreFurn, \ @@ -325,6 +325,7 @@ def init(cls): cls.readClasses = (b'MGEF', b'SCPT') cls.writeClasses = (b'MGEF',) # Setting RecordHeader class variables - Oblivion is special + from ... import brec header_type = brec.RecordHeader header_type.rec_header_size = 20 header_type.rec_pack_format = [u'=4s', u'I', u'I', u'I', u'I'] diff --git a/Mopy/bash/game/skyrim/__init__.py b/Mopy/bash/game/skyrim/__init__.py index ccc86893d8..c1f0ad4eed 100644 --- a/Mopy/bash/game/skyrim/__init__.py +++ b/Mopy/bash/game/skyrim/__init__.py @@ -25,8 +25,7 @@ from os.path import join as _j from ..patch_game import GameInfo, PatchGame -from ... import brec, bolt -from ...brec import MreFlst, MreGlob +from ... import bolt class SkyrimGameInfo(PatchGame): displayName = u'Skyrim' @@ -281,6 +280,7 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) + from ...brec import MreColl, MreFlst, MreGlob from .records import MreCell, MreWrld, MreFact, MreAchr, MreDial, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ MreLvsp, MreEnch, MreProj, MreDlbr, MreRfct, MreMisc, MreActi, \ @@ -288,7 +288,7 @@ def init(cls): MreIdle, MreLtex, MreQust, MreMstt, MreNpc, MreIpds, MrePack, \ MreGmst, MreRevb, MreClmt, MreDebr, MreSmbn, MreLvli, MreSpel, \ MreKywd, MreLvln, MreAact, MreSlgm, MreRegn, MreFurn, MreGras, \ - MreAstp, MreWoop, MreMovt, MreCobj, MreShou, MreSmen, MreColl, \ + MreAstp, MreWoop, MreMovt, MreCobj, MreShou, MreSmen, MreNavm, \ MreArto, MreAddn, MreSopm, MreCsty, MreAppa, MreArma, MreArmo, \ MreKeym, MreTxst, MreHdpt, MreTes4, MreAlch, MreBook, MreSpgd, \ MreSndr, MreImgs, MreScrl, MreMust, MreFstp, MreFsts, MreMgef, \ @@ -296,8 +296,7 @@ def init(cls): MreLscr, MreDlvw, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ - MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk, MreRace, \ - MreNavm + MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk, MreRace cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, @@ -317,6 +316,7 @@ def init(cls): MreRace, )} # 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'TXST', b'GLOB', b'CLAS', diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index b98ca610bc..2033776318 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -940,26 +940,6 @@ class MreCobj(MreWithItems): ) __slots__ = melSet.getSlotsUsed() -#------------------------------------------------------------------------------ -class MreColl(MelRecord): - """Collision Layer.""" - rec_sig = b'COLL' - - CollisionLayerFlags = Flags.from_names('triggerVolume', 'sensor', - 'navmeshObstacle') - - melSet = MelSet( - MelEdid(), - MelDescription(), - MelUInt32(b'BNAM', 'layerID'), - MelColor(b'FNAM'), - MelUInt32Flags(b'GNAM', u'flags', CollisionLayerFlags,), - MelString(b'MNAM', u'col_layer_name',), - MelUInt32(b'INTV', 'interactablesCount'), - MelSorted(MelSimpleArray('collidesWith', MelFid(b'CNAM'))), - ) - __slots__ = melSet.getSlotsUsed() - #------------------------------------------------------------------------------ class MreCont(MreWithItems): """Container.""" diff --git a/Mopy/bash/game/skyrimse/__init__.py b/Mopy/bash/game/skyrimse/__init__.py index ac8f8c5fbd..42ac716242 100644 --- a/Mopy/bash/game/skyrimse/__init__.py +++ b/Mopy/bash/game/skyrimse/__init__.py @@ -24,8 +24,6 @@ from ..skyrim import SkyrimGameInfo from .. import WS_COMMON -from ... import brec -from ...brec import MreFlst, MreGlob class SkyrimSEGameInfo(SkyrimGameInfo): displayName = u'Skyrim Special Edition' @@ -273,13 +271,12 @@ class Esp(SkyrimGameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - # First import from skyrimse.records file + from ...brec import MreColl, MreFlst, MreGlob from .records import MreVoli, MreLens - # then import rest of records from skyrim.records from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ - MreClfm, MreClmt, MreCobj, MreColl, MreCont, MreCpth, MreCsty, \ + MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ MreDebr, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ @@ -292,7 +289,7 @@ def init(cls): MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr, \ - MreRace, MreNavm + MreRace cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, @@ -313,6 +310,7 @@ def init(cls): MrePack, MreFact, MreRace, )} # 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'TXST', b'GLOB', b'CLAS', diff --git a/Mopy/bash/game/skyrimvr/__init__.py b/Mopy/bash/game/skyrimvr/__init__.py index fcd8f01017..b949d0d9aa 100644 --- a/Mopy/bash/game/skyrimvr/__init__.py +++ b/Mopy/bash/game/skyrimvr/__init__.py @@ -20,12 +20,9 @@ # https://github.com/wrye-bash # # ============================================================================= - """GameInfo override for TES V: Skyrim VR.""" from ..skyrimse import SkyrimSEGameInfo -from ... import brec -from ...brec import MreFlst, MreGlob class SkyrimVRGameInfo(SkyrimSEGameInfo): displayName = u'Skyrim VR' @@ -77,13 +74,12 @@ class Bain(SkyrimSEGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - # First import from skyrimse.records file + from ...brec import MreColl, MreFlst, MreGlob from ..skyrimse.records import MreVoli, MreLens - # then import rest of records from skyrim.records from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ - MreClfm, MreClmt, MreCobj, MreColl, MreCont, MreCpth, MreCsty, \ + MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ MreDebr, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ @@ -96,7 +92,7 @@ def init(cls): MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr, \ - MreRace, MreNavm + MreRace cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, @@ -117,6 +113,7 @@ def init(cls): MrePack, MreFact, MreRace, )} # 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'TXST', b'GLOB', b'CLAS', From 200751edfa55ad9a7b46b9d1cbf6d66e755bf6ca Mon Sep 17 00:00:00 2001 From: Infernio Date: Sun, 21 Aug 2022 21:26:32 +0200 Subject: [PATCH 05/13] Better names for brec base classes So that they start with 'A' like our other abstract classes. --- Mopy/bash/brec/common_records.py | 11 +++++---- Mopy/bash/game/fallout3/records.py | 26 ++++++++++---------- Mopy/bash/game/fallout4/records.py | 24 +++++++++---------- Mopy/bash/game/fallout4vr/records.py | 10 ++++---- Mopy/bash/game/falloutnv/records.py | 10 ++++---- Mopy/bash/game/morrowind/records.py | 20 ++++++++-------- Mopy/bash/game/oblivion/records.py | 28 +++++++++++----------- Mopy/bash/game/skyrim/records.py | 36 ++++++++++++++-------------- 8 files changed, 83 insertions(+), 82 deletions(-) diff --git a/Mopy/bash/brec/common_records.py b/Mopy/bash/brec/common_records.py index 3a88f102a7..e1d0f08ffd 100644 --- a/Mopy/bash/brec/common_records.py +++ b/Mopy/bash/brec/common_records.py @@ -41,7 +41,7 @@ #------------------------------------------------------------------------------ # Base classes ---------------------------------------------------------------- #------------------------------------------------------------------------------ -class MreWithItems(MelRecord): +class AMreWithItems(MelRecord): """Base class for record types that contain a list of items (MelItems).""" __slots__ = [] @@ -49,7 +49,7 @@ def mergeFilter(self, modSet): self.items = [i for i in self.items if i.item.mod_id in modSet] #------------------------------------------------------------------------------ -class MreActorBase(MreWithItems): +class AMreActor(AMreWithItems): """Base class for Creatures and NPCs.""" __slots__ = [] @@ -58,7 +58,8 @@ def mergeFilter(self, modSet): self.spells = [x for x in self.spells if x.mod_id in modSet] self.factions = [x for x in self.factions if x.faction.mod_id in modSet] -class MreGmstBase(MelRecord): +#------------------------------------------------------------------------------ +class AMreGmst(MelRecord): """Game Setting record. Base class, each game should derive from this class.""" Ids = None @@ -78,7 +79,7 @@ class MreGmstBase(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreHeaderBase(MelRecord): +class AMreHeader(MelRecord): """File header. Base class for all 'TES4' like records""" # Subrecords that can appear after the masters block - must be set per game _post_masters_sigs: set[bytes] @@ -207,7 +208,7 @@ def num_masters(self): return len(self.masters) __slots__ = [] #------------------------------------------------------------------------------ -class MreLeveledListBase(MelRecord): +class AMreLeveledList(MelRecord): """Base type for leveled item/creature/npc/spells. it requires the base class to use the following: classAttributes: diff --git a/Mopy/bash/game/fallout3/records.py b/Mopy/bash/game/fallout3/records.py index aa1b05012c..a5e4ac9aee 100644 --- a/Mopy/bash/game/fallout3/records.py +++ b/Mopy/bash/game/fallout3/records.py @@ -28,8 +28,8 @@ from ... import bush from ...bolt import Flags, structs_cache, TrimmedFlags from ...brec import MelRecord, MelGroups, MelStruct, FID, MelGroup, \ - MelString, MelSet, MelFid, MelOptStruct, MelFids, MreHeaderBase, MelRace, \ - MelBase, MelSimpleArray, MreGmstBase, MelBodyParts, MelMODS, MelFactions, \ + MelString, MelSet, MelFid, MelOptStruct, MelFids, AMreHeader, MelRace, \ + MelBase, MelSimpleArray, AMreGmst, MelBodyParts, MelMODS, MelFactions, \ MelReferences, MelColorInterpolator, MelValueInterpolator, MelAnimations, \ MelUnion, AttrValDecider, MelRegnEntrySubrecord, SizeDecider, MelFloat, \ MelSInt8, MelSInt16, MelSInt32, MelUInt8, MelUInt16, MelUInt32, \ @@ -37,7 +37,7 @@ MelRaceVoices, MelBounds, null1, null2, MelScriptVars, MelSorted, \ MelSequential, MelTruncatedStruct, PartialLoadDecider, MelReadOnly, \ MelSkipInterior, MelIcons, MelIcons2, MelIcon, MelIco2, MelEdid, MelFull, \ - MelArray, MelWthrColors, MreLeveledListBase, MreActorBase, MreWithItems, \ + MelArray, MelWthrColors, AMreLeveledList, AMreActor, AMreWithItems, \ MelRef3D, MelXlod, MelNull, MelWorldBounds, MelEnableParent, MelPerkData, \ MelRefScale, MelMapMarker, MelActionFlags, MelEnchantment, MelScript, \ MelDecalData, MelDescription, MelLists, MelSoundPickupDrop, MelBookText, \ @@ -47,7 +47,7 @@ MelReflectedRefractedBy, MelValueWeight, SpellFlags, MelBaseR, MelExtra, \ MelSound, MelSoundActivation, MelWaterType, MelConditionsFo3, \ MelNodeIndex, MelAddnDnam, MelEffectsFo3, MelShortName, PerkEpdfDecider, \ - MelPerkParamsGroups, MelAspcRdat, MelUnorderedGroups, MelImageSpaceMod + MelPerkParamsGroups, MelUnorderedGroups, MelImageSpaceMod, MelAspcRdat from ...exception import ModSizeError _is_fnv = bush.game.fsName == u'FalloutNV' @@ -121,7 +121,7 @@ def __init__(self): super().__init__(b'XATO', 'activation_prompt') #------------------------------------------------------------------------------ -class MreActor(MreActorBase): +class MreActor(AMreActor): """Creatures and NPCs.""" TemplateFlags = Flags.from_names( 'useTraits', @@ -284,7 +284,7 @@ def dumpData(self, record, out): super(MelRaceHeadPart, self).dumpData(record, out) #------------------------------------------------------------------------------ -class MreLeveledList(MreLeveledListBase): +class MreLeveledList(AMreLeveledList): """Leveled item/creature/spell list..""" top_copy_attrs = (u'chanceNone', u'glob') entry_copy_attrs = (u'listId', u'level', u'count', u'owner', u'condition') @@ -293,7 +293,7 @@ class MreLeveledList(MreLeveledListBase): MelEdid(), MelBounds(), MelLevListLvld(b'LVLD', u'chanceNone'), - MelUInt8Flags(b'LVLF', u'flags', MreLeveledListBase._flags), + MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelFid(b'LVLG', u'glob'), MelSorted(MelGroups(u'entries', MelLevListLvlo(b'LVLO', [u'h', u'2s', u'I', u'h', u'2s'], u'level', @@ -310,7 +310,7 @@ class MreLeveledList(MreLeveledListBase): #------------------------------------------------------------------------------ # Fallout3 Records ------------------------------------------------------------ #------------------------------------------------------------------------------ -class MreTes4(MreHeaderBase): +class MreTes4(AMreHeader): """TES4 Record. File header.""" rec_sig = b'TES4' _post_masters_sigs = {b'ONAM', b'SCRN'} @@ -320,9 +320,9 @@ class MreTes4(MreHeaderBase): ('nextObject', 0x800)), MelNull(b'OFST'), # obsolete MelNull(b'DELE'), # obsolete - MreHeaderBase.MelAuthor(), - MreHeaderBase.MelDescription(), - MreHeaderBase.MelMasterNames(), + AMreHeader.MelAuthor(), + AMreHeader.MelDescription(), + AMreHeader.MelMasterNames(), MelSimpleArray('overrides', MelFid(b'ONAM')), MelBase(b'SCRN', 'screenshot'), ) @@ -820,7 +820,7 @@ class MreCobj(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreCont(MreWithItems): +class MreCont(AMreWithItems): """Container.""" rec_sig = b'CONT' @@ -1251,7 +1251,7 @@ class MreFurn(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreGmst(MreGmstBase): +class MreGmst(AMreGmst): """Game Setting.""" isKeyedByEid = True # NULL fids are acceptable. __slots__ = () diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index 12c750e7e9..b56edfd78e 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -22,10 +22,10 @@ # ============================================================================= """This module contains the Fallout 4 record classes.""" from ...bolt import Flags -from ...brec import MelBase, MelGroup, MreHeaderBase, MelSet, MelString, \ - MelStruct, MelNull, MelSimpleArray, MreLeveledListBase, MelFid, MelAttx, \ +from ...brec import MelBase, MelGroup, AMreHeader, MelSet, MelString, \ + MelStruct, MelNull, MelSimpleArray, AMreLeveledList, MelFid, MelAttx, \ FID, MelLString, MelUInt8, MelFloat, MelBounds, MelEdid, MelUnloadEvent, \ - MelArray, MreGmstBase, MelUInt8Flags, MelSorted, MelGroups, MelShortName, \ + MelArray, AMreGmst, MelUInt8Flags, MelSorted, MelGroups, MelShortName, \ MelUInt32, MelRecord, MelColorO, MelFull, MelBaseR, MelKeywords, MelRace, \ MelColor, MelSound, MelSoundActivation, MelWaterType, MelAlchEnit, \ MelActiFlags, MelInteractionKeyword, MelConditions, MelTruncatedStruct, \ @@ -223,7 +223,7 @@ class _VmadContextFo4(AVmadContext): #------------------------------------------------------------------------------ # Fallout 4 Records ----------------------------------------------------------- #------------------------------------------------------------------------------ -class MreTes4(MreHeaderBase): +class MreTes4(AMreHeader): """TES4 Record. File header.""" rec_sig = b'TES4' _post_masters_sigs = {b'ONAM', b'SCRN', b'TNAM', b'INTV', b'INCC'} @@ -233,9 +233,9 @@ class MreTes4(MreHeaderBase): (u'nextObject', 0x001)), MelNull(b'OFST'), # obsolete MelNull(b'DELE'), # obsolete - MreHeaderBase.MelAuthor(), - MreHeaderBase.MelDescription(), - MreHeaderBase.MelMasterNames(), + AMreHeader.MelAuthor(), + AMreHeader.MelDescription(), + AMreHeader.MelMasterNames(), MelSimpleArray('overrides', MelFid(b'ONAM')), MelBase(b'SCRN', 'screenshot'), MelGroups('transient_types', @@ -793,13 +793,13 @@ def mergeFilter(self, modSet): if c.component_fid.mod_id in modSet] #------------------------------------------------------------------------------ -class MreGmst(MreGmstBase): +class MreGmst(AMreGmst): """Game Setting.""" isKeyedByEid = True # NULL fids are acceptable. __slots__ = () #------------------------------------------------------------------------------ -class MreLvli(MreLeveledListBase): +class MreLvli(AMreLeveledList): """Leveled Item.""" rec_sig = b'LVLI' @@ -811,7 +811,7 @@ class MreLvli(MreLeveledListBase): MelBounds(), MelUInt8(b'LVLD', 'chanceNone'), MelUInt8(b'LVLM', 'maxCount'), - MelUInt8Flags(b'LVLF', u'flags', MreLeveledListBase._flags), + MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelFid(b'LVLG', 'glob'), MelLLItems(), MelArray('filterKeywordChances', @@ -823,7 +823,7 @@ class MreLvli(MreLeveledListBase): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreLvln(MreLeveledListBase): +class MreLvln(AMreLeveledList): """Leveled NPC.""" rec_sig = b'LVLN' @@ -835,7 +835,7 @@ class MreLvln(MreLeveledListBase): MelBounds(), MelUInt8(b'LVLD', 'chanceNone'), MelUInt8(b'LVLM', 'maxCount'), - MelUInt8Flags(b'LVLF', u'flags', MreLeveledListBase._flags), + MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelFid(b'LVLG', 'glob'), MelLLItems(), MelArray('filterKeywordChances', diff --git a/Mopy/bash/game/fallout4vr/records.py b/Mopy/bash/game/fallout4vr/records.py index c9fd363e9f..5876b3b6f4 100644 --- a/Mopy/bash/game/fallout4vr/records.py +++ b/Mopy/bash/game/fallout4vr/records.py @@ -23,12 +23,12 @@ """This module contains only the overrides of record classes needed for FO4VR.""" -from ...brec import MreHeaderBase, MelSet, MelStruct, MelBase, MelFid, \ +from ...brec import AMreHeader, MelSet, MelStruct, MelBase, MelFid, \ MelSimpleArray, MelNull, MelGroups, MelUInt32 # Only difference from FO4 is the default version, but this seems less hacky # than adding a game var just for this and dynamically importing it in FO4 -class MreTes4(MreHeaderBase): +class MreTes4(AMreHeader): """TES4 Record. File header.""" rec_sig = b'TES4' _post_masters_sigs = {b'ONAM', b'SCRN', b'TNAM', b'INTV', b'INCC'} @@ -38,9 +38,9 @@ class MreTes4(MreHeaderBase): (u'nextObject', 0x800)), MelNull(b'OFST'), # obsolete MelNull(b'DELE'), # obsolete - MreHeaderBase.MelAuthor(), - MreHeaderBase.MelDescription(), - MreHeaderBase.MelMasterNames(), + AMreHeader.MelAuthor(), + AMreHeader.MelDescription(), + AMreHeader.MelMasterNames(), MelSimpleArray('overrides', MelFid(b'ONAM')), MelBase(b'SCRN', 'screenshot'), MelGroups('transient_types', diff --git a/Mopy/bash/game/falloutnv/records.py b/Mopy/bash/game/falloutnv/records.py index dc4d04d76c..0f6c7e3834 100644 --- a/Mopy/bash/game/falloutnv/records.py +++ b/Mopy/bash/game/falloutnv/records.py @@ -24,7 +24,7 @@ from ..fallout3.records import MelDestructible, MelModel from ...bolt import Flags, struct_calcsize from ...brec import MelRecord, MelGroups, MelStruct, FID, MelString, MelSet, \ - MelFid, MelFids, MelBase, MelSimpleArray, MreHeaderBase, MelFloat, \ + MelFid, MelFids, MelBase, MelSimpleArray, AMreHeader, MelFloat, \ MelUInt32, MelBounds, null1, MelTruncatedStruct, MelIcons, MelIcon, \ MelIco2, MelEdid, MelFull, MelArray, MelObject, MelNull, MelScript, \ MelDescription, MelSoundPickupDrop, MelUInt8Flags, MelSInt32, \ @@ -34,7 +34,7 @@ #------------------------------------------------------------------------------ # FalloutNV Records ----------------------------------------------------------- #------------------------------------------------------------------------------ -class MreTes4(MreHeaderBase): +class MreTes4(AMreHeader): """TES4 Record. File header.""" rec_sig = b'TES4' _post_masters_sigs = {b'ONAM', b'SCRN'} @@ -44,9 +44,9 @@ class MreTes4(MreHeaderBase): ('nextObject', 0x800)), MelNull(b'OFST'), # obsolete MelNull(b'DELE'), # obsolete - MreHeaderBase.MelAuthor(), - MreHeaderBase.MelDescription(), - MreHeaderBase.MelMasterNames(), + AMreHeader.MelAuthor(), + AMreHeader.MelDescription(), + AMreHeader.MelMasterNames(), MelSimpleArray('overrides', MelFid(b'ONAM')), MelBase(b'SCRN', 'screenshot'), ) diff --git a/Mopy/bash/game/morrowind/records.py b/Mopy/bash/game/morrowind/records.py index b0991f6d87..2214611f70 100644 --- a/Mopy/bash/game/morrowind/records.py +++ b/Mopy/bash/game/morrowind/records.py @@ -27,13 +27,13 @@ from ...bolt import Flags from ...brec import MelBase, MelSet, MelString, MelStruct, MelArray, \ - MreHeaderBase, MelUnion, SaveDecider, MelNull, MelSequential, MelRecord, \ + AMreHeader, MelUnion, SaveDecider, MelNull, MelSequential, MelRecord, \ MelGroup, MelGroups, MelUInt8, MelDescription, MelUInt32, MelColorO,\ MelOptStruct, MelCounter, MelRefScale, MelRef3D, MelBookText, \ - MelIcons, MelFloat, MelSInt32, MelEffectsTes3, \ - MelFixedString, FixedString, AutoFixedString, MreGmstBase, \ - MreLeveledListBase, MelUInt16, SizeDecider, MelLists, \ - MelTruncatedStruct, MelColor, MelStrings, MelUInt32Flags + MelIcons, MelFloat, MelSInt32, MelEffectsTes3, MelFixedString, \ + FixedString, AutoFixedString, AMreGmst, AMreLeveledList, MelUInt16, \ + SizeDecider, MelLists, MelTruncatedStruct, MelColor, MelStrings, \ + MelUInt32Flags #------------------------------------------------------------------------------ # Record Elements ------------------------------------------------------------- @@ -211,7 +211,7 @@ def __init__(self): ) #------------------------------------------------------------------------------ -class MreLeveledList(MreLeveledListBase): +class MreLeveledList(AMreLeveledList): """Base class for LEVC and LEVI.""" _lvl_flags = Flags.from_names( u'calcFromAllLevels', @@ -220,7 +220,7 @@ class MreLeveledList(MreLeveledListBase): top_copy_attrs = (u'chanceNone',) entry_copy_attrs = (u'listId', u'level') # no count - # Bad names to mirror the other games (needed by MreLeveledListBase) + # Bad names to mirror the other games (needed by AMreLeveledList) melSet = MelSet( MelMWId(), MelUInt32Flags(b'DATA', u'flags', _lvl_flags), @@ -236,7 +236,7 @@ class MreLeveledList(MreLeveledListBase): #------------------------------------------------------------------------------ # Shared (plugins + saves) record classes ------------------------------------- #------------------------------------------------------------------------------ -class MreTes3(MreHeaderBase): +class MreTes3(AMreHeader): """TES3 Record. File header.""" rec_sig = b'TES3' _post_masters_sigs = {b'GMDT', b'SCRD', b'SCRS'} @@ -245,7 +245,7 @@ class MreTes3(MreHeaderBase): MelStruct(b'HEDR', ['f', 'I', '32s', '256s', 'I'], ('version', 1.3), 'esp_flags', (AutoFixedString(32), 'author_pstr'), (AutoFixedString(256), 'description_pstr'), 'numRecords'), - MreHeaderBase.MelMasterNames(), + AMreHeader.MelMasterNames(), MelSavesOnly( # Wrye Mash calls unknown1 'day', but that seems incorrect? MelStruct(b'GMDT', [u'6f', u'64s', u'f', u'32s'], u'pc_curr_health', @@ -658,7 +658,7 @@ def _get_element_from_record(self, record): return self._get_element(self._fmt_mapping[format_char]) return super(MelGmstUnion, self)._get_element_from_record(record) -class MreGmst(MreGmstBase): +class MreGmst(AMreGmst): """Game Setting.""" melSet = MelSet( MelMWId(), diff --git a/Mopy/bash/game/oblivion/records.py b/Mopy/bash/game/oblivion/records.py index 67b88e0658..3170b13bba 100644 --- a/Mopy/bash/game/oblivion/records.py +++ b/Mopy/bash/game/oblivion/records.py @@ -28,14 +28,14 @@ from ...bolt import Flags, int_or_zero, structs_cache, str_or_none, \ int_or_none, str_to_sig, sig_to_str from ...brec import MelRecord, MelGroups, MelStruct, FID, MelGroup, MelString, \ - MreLeveledListBase, MelSet, MelFid, MelNull, MelOptStruct, MelFids, \ - MreHeaderBase, MelBase, MelSimpleArray, MelBodyParts, MelAnimations, \ - MreGmstBase, MelReferences, MelRegnEntrySubrecord, MelSorted, MelRegions, \ + AMreLeveledList, MelSet, MelFid, MelNull, MelOptStruct, MelFids, \ + AMreHeader, MelBase, MelSimpleArray, MelBodyParts, MelAnimations, \ + AMreGmst, MelReferences, MelRegnEntrySubrecord, MelSorted, MelRegions, \ MelFloat, MelSInt16, MelSInt32, MelUInt8, MelUInt16, MelUInt32, \ MelRaceParts, MelRaceVoices, null2, MelScriptVars, MelRelations, MelRace, \ MelSequential, MelUnion, FlagDecider, AttrValDecider, PartialLoadDecider, \ MelTruncatedStruct, MelSkipInterior, MelIcon, MelIco2, MelEdid, MelFull, \ - MelArray, MelWthrColors, MelEffectsTes4, MreActorBase, MreWithItems, \ + MelArray, MelWthrColors, MelEffectsTes4, AMreActor, AMreWithItems, \ MelReadOnly, MelRef3D, MelXlod, MelWorldBounds, MelEnableParent, MelObme, \ MelRefScale, MelMapMarker, MelActionFlags, MelPartialCounter, MelScript, \ MelDescription, BipedFlags, MelUInt8Flags, MelUInt32Flags, MelLists, \ @@ -443,14 +443,14 @@ def is_harmful(self, cached_hostile): return True #------------------------------------------------------------------------------ -class MreLeveledList(MreLeveledListBase): +class MreLeveledList(AMreLeveledList): """Leveled item/creature/spell list.""" top_copy_attrs = ('script_fid','template','chanceNone',) melSet = MelSet( MelEdid(), MelLevListLvld(), - MelUInt8Flags(b'LVLF', u'flags', MreLeveledListBase._flags), + MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelScript(), # LVLC only MelFid(b'TNAM','template'), MelSorted(MelGroups('entries', @@ -466,7 +466,7 @@ class MreLeveledList(MreLeveledListBase): #------------------------------------------------------------------------------ # Oblivion Records ------------------------------------------------------------ #------------------------------------------------------------------------------ -class MreTes4(MreHeaderBase): +class MreTes4(AMreHeader): """TES4 Record. File header.""" rec_sig = b'TES4' _post_masters_sigs = set() @@ -476,9 +476,9 @@ class MreTes4(MreHeaderBase): (u'nextObject', 0x800)), MelNull(b'OFST'), # obsolete MelNull(b'DELE'), # obsolete - MreHeaderBase.MelAuthor(), - MreHeaderBase.MelDescription(), - MreHeaderBase.MelMasterNames(), + AMreHeader.MelAuthor(), + AMreHeader.MelDescription(), + AMreHeader.MelMasterNames(), ) __slots__ = melSet.getSlotsUsed() @@ -760,7 +760,7 @@ class MreClot(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreCont(MreWithItems): +class MreCont(AMreWithItems): """Container.""" rec_sig = b'CONT' @@ -779,7 +779,7 @@ class MreCont(MreWithItems): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreCrea(MreActorBase): +class MreCrea(AMreActor): """Creature.""" rec_sig = b'CREA' @@ -1051,7 +1051,7 @@ class MreFurn(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreGmst(MreGmstBase): +class MreGmst(AMreGmst): """Game Setting.""" __slots__ = () @@ -1569,7 +1569,7 @@ class MreMisc(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreNpc(MreActorBase): +class MreNpc(AMreActor): """Non-Player Character.""" rec_sig = b'NPC_' diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index 2033776318..ccffe3c4db 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -24,16 +24,16 @@ from ... import bush from ...bolt import Flags, structs_cache, TrimmedFlags from ...brec import MelRecord, MelGroups, MelStruct, FID, MelAttx, MelRace, \ - MelGroup, MelString, MreLeveledListBase, MelSet, MelFid, MelNull, \ - MelOptStruct, MelFids, MreHeaderBase, MelBase, MelSimpleArray, MelWeight, \ - MreGmstBase, MelLString, MelMODS, MelColorInterpolator, MelRegions, \ + MelGroup, MelString, AMreLeveledList, MelSet, MelFid, MelNull, \ + MelOptStruct, MelFids, AMreHeader, MelBase, MelSimpleArray, MelWeight, \ + AMreGmst, MelLString, MelMODS, MelColorInterpolator, MelRegions, \ MelValueInterpolator, MelUnion, AttrValDecider, MelRegnEntrySubrecord, \ PartialLoadDecider, FlagDecider, MelFloat, MelSInt8, MelSInt32, MelUInt8, \ MelUInt16, MelUInt32, MelActionFlags, MelCounter, MelRaceData, MelBaseR, \ MelPartialCounter, MelBounds, null3, null4, MelSequential, MelKeywords, \ MelTruncatedStruct, MelIcons, MelIcons2, MelIcon, MelIco2, MelEdid, \ MelFull, MelArray, MelWthrColors, MelFactions, MelReadOnly, MelRelations, \ - MreActorBase, MreWithItems, MelRef3D, MelXlod, MelActiFlags, AMelNvnm, \ + AMreActor, AMreWithItems, MelRef3D, MelXlod, MelActiFlags, AMelNvnm, \ MelWorldBounds, MelEnableParent, MelRefScale, MelMapMarker, MelMdob, \ MelEnchantment, MelDecalData, MelDescription, MelSInt16, MelSkipInterior, \ MelSoundPickupDrop, MelActivateParents, BipedFlags, MelColor, \ @@ -349,7 +349,7 @@ def __init__(self): #------------------------------------------------------------------------------ # Skyrim Records -------------------------------------------------------------- #------------------------------------------------------------------------------ -class MreTes4(MreHeaderBase): +class MreTes4(AMreHeader): """TES4 Record. File header.""" rec_sig = b'TES4' _post_masters_sigs = {b'SCRN', b'INTV', b'INCC', b'ONAM'} @@ -359,9 +359,9 @@ class MreTes4(MreHeaderBase): ('nextObject', 0x800)), MelNull(b'OFST'), # obsolete MelNull(b'DELE'), # obsolete - MreHeaderBase.MelAuthor(), - MreHeaderBase.MelDescription(), - MreHeaderBase.MelMasterNames(), + AMreHeader.MelAuthor(), + AMreHeader.MelDescription(), + AMreHeader.MelMasterNames(), MelSimpleArray('overrides', MelFid(b'ONAM')), MelBase(b'SCRN', 'screenshot'), MelBase(b'INTV', 'unknownINTV'), @@ -925,7 +925,7 @@ class MreClmt(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreCobj(MreWithItems): +class MreCobj(AMreWithItems): """Constructible Object.""" rec_sig = b'COBJ' isKeyedByEid = True # NULL fids are acceptable @@ -941,7 +941,7 @@ class MreCobj(MreWithItems): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreCont(MreWithItems): +class MreCont(AMreWithItems): """Container.""" rec_sig = b'CONT' @@ -1492,7 +1492,7 @@ class MreFurn(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreGmst(MreGmstBase): +class MreGmst(AMreGmst): """Game Setting.""" isKeyedByEid = True # NULL fids are acceptable. __slots__ = () @@ -2098,7 +2098,7 @@ class MreLtex(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreLvli(MreLeveledListBase): +class MreLvli(AMreLeveledList): """Leveled Item.""" rec_sig = b'LVLI' top_copy_attrs = ('chanceNone','glob',) @@ -2107,14 +2107,14 @@ class MreLvli(MreLeveledListBase): MelEdid(), MelBounds(), MelUInt8(b'LVLD', 'chanceNone'), - MelUInt8Flags(b'LVLF', u'flags', MreLeveledListBase._flags), + MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelFid(b'LVLG', 'glob'), MelLLItems(), ) __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreLvln(MreLeveledListBase): +class MreLvln(AMreLeveledList): """Leveled NPC.""" rec_sig = b'LVLN' top_copy_attrs = ('chanceNone','model','modt_p',) @@ -2123,7 +2123,7 @@ class MreLvln(MreLeveledListBase): MelEdid(), MelBounds(), MelUInt8(b'LVLD', 'chanceNone'), - MelUInt8Flags(b'LVLF', u'flags', MreLeveledListBase._flags), + MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelFid(b'LVLG', 'glob'), MelLLItems(), MelString(b'MODL','model'), @@ -2132,7 +2132,7 @@ class MreLvln(MreLeveledListBase): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreLvsp(MreLeveledListBase): +class MreLvsp(AMreLeveledList): """Leveled Spell.""" rec_sig = b'LVSP' @@ -2142,7 +2142,7 @@ class MreLvsp(MreLeveledListBase): MelEdid(), MelBounds(), MelUInt8(b'LVLD', 'chanceNone'), - MelUInt8Flags(b'LVLF', u'flags', MreLeveledListBase._flags), + MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelLLItems(with_coed=False), ) __slots__ = melSet.getSlotsUsed() @@ -2413,7 +2413,7 @@ class MreNavm(MelRecord): __slots__ = melSet.getSlotsUsed() #------------------------------------------------------------------------------ -class MreNpc(MreActorBase): +class MreNpc(AMreActor): """Non-Player Character.""" rec_sig = b'NPC_' From 6f6ae195d3972f8a9c8e2e09849b17bba347ac2e Mon Sep 17 00:00:00 2001 From: Infernio Date: Sun, 21 Aug 2022 22:43:16 +0200 Subject: [PATCH 06/13] FO4: Implement CONT This turned into a mini-refactoring round. We now use AMelLLItems for all games and MelItems has been gained a base class in AMelItems. --- Mopy/Docs/Wrye Bash Advanced Readme.html | 4 +- Mopy/bash/brec/common_records.py | 3 +- Mopy/bash/brec/common_subrecords.py | 96 ++++++++++++++------ Mopy/bash/game/fallout3/patcher/__init__.py | 4 +- Mopy/bash/game/fallout3/records.py | 53 ++++++----- Mopy/bash/game/fallout4/__init__.py | 6 +- Mopy/bash/game/fallout4/records.py | 38 +++++++- Mopy/bash/game/falloutnv/patcher/__init__.py | 2 +- Mopy/bash/game/oblivion/patcher/__init__.py | 4 +- Mopy/bash/game/oblivion/records.py | 33 ++++--- Mopy/bash/game/skyrim/patcher/__init__.py | 4 +- Mopy/bash/game/skyrim/records.py | 42 +++------ 12 files changed, 170 insertions(+), 119 deletions(-) diff --git a/Mopy/Docs/Wrye Bash Advanced Readme.html b/Mopy/Docs/Wrye Bash Advanced Readme.html index 56568efbb2..e2b77f0f42 100644 --- a/Mopy/Docs/Wrye Bash Advanced Readme.html +++ b/Mopy/Docs/Wrye Bash Advanced Readme.html @@ -4913,7 +4913,7 @@

Bash Tags Back to top
  • (SNAM) Sound - Open
  • (QNAM) Sound - Close
  • -
  • (RNAM) Sound - Looping/Random - Fallout: New Vegas only
  • +
  • (RNAM) Sound - Random/Looping - Fallout: New Vegas only
  • (CREA) Creature: @@ -6375,7 +6375,7 @@

    Merge Filtering Back
  • (INAM) Items
  • - All but Fallout 4 + All games (CREA) Creature diff --git a/Mopy/bash/brec/common_records.py b/Mopy/bash/brec/common_records.py index e1d0f08ffd..748913ddef 100644 --- a/Mopy/bash/brec/common_records.py +++ b/Mopy/bash/brec/common_records.py @@ -42,7 +42,8 @@ # Base classes ---------------------------------------------------------------- #------------------------------------------------------------------------------ class AMreWithItems(MelRecord): - """Base class for record types that contain a list of items (MelItems).""" + """Base class for record types that contain a list of items (see + common_subrecords.AMelItems).""" __slots__ = [] def mergeFilter(self, modSet): diff --git a/Mopy/bash/brec/common_subrecords.py b/Mopy/bash/brec/common_subrecords.py index 99559ca793..18c5871adb 100644 --- a/Mopy/bash/brec/common_subrecords.py +++ b/Mopy/bash/brec/common_subrecords.py @@ -36,21 +36,52 @@ dict_sort, TrimmedFlags, structs_cache from ..exception import ModError, ModSizeError +#------------------------------------------------------------------------------ +class _MelCoed(MelOptStruct): + """Handles the COED (Owner Data) subrecord used for inventory items and + leveled lists since FO3.""" + ##: Needs custom unpacker to look at FormID type of owner. If owner is an + # NPC then it is followed by a FormID. If owner is a faction then it is + # followed by an signed integer or '=Iif' instead of '=IIf' - see #282 + def __init__(self): + super().__init__(b'COED', ['2I', 'f'], (FID, 'owner'), + (FID, 'glob'), 'itemCondition') + +#------------------------------------------------------------------------------ +class AMelItems(MelSequential): + """Base class for handling the CNTO (Items) subrecords defining items. Can + handle all games since Oblivion via the two kwargs.""" + def __init__(self, *, with_coed=True, with_counter=True): + items_elements = [MelStruct(b'CNTO', ['I', 'i'], (FID, 'item'), + 'count')] + items_sort_attrs = ('item', 'count') + if with_coed: + items_elements.append(_MelCoed()) + items_sort_attrs += ('itemCondition', 'owner', 'glob') + final_elements = [MelSorted(MelGroups('items', *items_elements), + sort_by_attrs=items_sort_attrs)] + if with_counter: + final_elements.insert(0, MelCounter( + MelUInt32(b'COCT', 'item_count'), counts='items')) + super().__init__(*final_elements) + #------------------------------------------------------------------------------ class AMelLLItems(MelSequential): - """Base class for handling the LVLO and LLCT subrecords defining leveled - list items in Skyrim and newer games.""" - def __init__(self, lvl_elements: list, with_coed=True): - final_elements = lvl_elements.copy() - final_sort_attrs = ('level', 'listId', 'count') + """Base class for handling the LVLO (and LLCT) subrecords defining leveled + list items. Can handle all games since Oblivion via the two kwargs.""" + def __init__(self, lvl_element: MelBase, *, with_coed=True, + with_counter=True): + lvl_elements = [lvl_element] + lvl_sort_attrs = ('level', 'listId', 'count') if with_coed: - final_elements.append(MelCoed()) - final_sort_attrs += ('itemCondition', 'owner', 'glob') - super().__init__( - MelCounter(MelUInt8(b'LLCT', 'entry_count'), counts='entries'), - MelSorted(MelGroups('entries', *final_elements), - sort_by_attrs=final_sort_attrs), - ) + lvl_elements.append(_MelCoed()) + lvl_sort_attrs += ('itemCondition', 'owner', 'glob') + final_elements = [MelSorted(MelGroups('entries', *lvl_elements), + sort_by_attrs=lvl_sort_attrs)] + if with_counter: + final_elements.insert(0, MelCounter( + MelUInt8(b'LLCT', 'entry_count'), counts='entries')) + super().__init__(*final_elements) #------------------------------------------------------------------------------ class MelActiFlags(MelUInt16Flags): @@ -306,17 +337,6 @@ def __init__(self): MelFid(b'BNAM', 'workbench_keyword'), ) -#------------------------------------------------------------------------------ -class MelCoed(MelOptStruct): - """Handles the COED (Owner Data) subrecord used for inventory items and - leveled lists since Skyrim.""" - ##: Needs custom unpacker to look at FormID type of owner. If owner is an - # NPC then it is followed by a FormID. If owner is a faction then it is - # followed by an signed integer or '=Iif' instead of '=IIf' - see #282 - def __init__(self): - super().__init__(b'COED', ['I', 'I', 'f'], (FID, 'owner'), - (FID, 'glob'), 'itemCondition') - #------------------------------------------------------------------------------ class MelColor(MelStruct): """Required Color.""" @@ -341,6 +361,17 @@ def __init__(self, color_sig=b'CNAM'): super().__init__(color_sig, ['4B'], 'red', 'green', 'blue', 'unused_alpha') +#------------------------------------------------------------------------------ +class MelContData(MelStruct): + """Handles the CONT subrecord DATA (Data).""" + # Flags 1 & 3 introduced in Skyrim, treat as unknown for earlier games + _cont_flags = Flags.from_names('allow_sounds_when_animation', + 'cont_respawns', 'show_owner') + + def __init__(self): + super().__init__(b'DATA', ['B', 'f'], (self._cont_flags, 'cont_flags'), + 'cont_weight') + #------------------------------------------------------------------------------ class MelDebrData(MelStruct): def __init__(self): @@ -503,8 +534,7 @@ def __init__(self): #------------------------------------------------------------------------------ class MelKeywords(MelSequential): - """Wraps MelSequential for the common task of defining a list of keywords - and a corresponding counter.""" + """Handles the KSIZ/KWDA (Keywords) subrecords.""" def __init__(self): super().__init__( MelCounter(MelUInt32(b'KSIZ', 'keyword_count'), counts='keywords'), @@ -864,17 +894,23 @@ def __init__(self, element): False: element, }, decider=FlagDecider('flags', ['isInterior'])) +#------------------------------------------------------------------------------ +class MelSound(MelFid): + """Handles the common SNAM (Sound) subrecord.""" + def __init__(self): + super().__init__(b'SNAM', 'sound') + #------------------------------------------------------------------------------ class MelSoundActivation(MelFid): - """Handles the VNAM (Sound - Activation) subrecord in ACTI records.""" + """Handles the ACTI subrecord VNAM (Sound - Activation).""" def __init__(self): super().__init__(b'VNAM', 'soundActivation') #------------------------------------------------------------------------------ -class MelSound(MelFid): - """Handles the common SNAM (Sound) subrecord.""" - def __init__(self): - super().__init__(b'SNAM', 'sound') +class MelSoundClose(MelFid): + """Handles the CONT/DOOR subrecord QNAM/ANAM (Sound - Close).""" + def __init__(self, sc_sig=b'QNAM'): + super().__init__(sc_sig, 'sound_close') #------------------------------------------------------------------------------ class MelSoundPickupDrop(MelSequential): diff --git a/Mopy/bash/game/fallout3/patcher/__init__.py b/Mopy/bash/game/fallout3/patcher/__init__.py index 32fe4646fe..d5acce7b5c 100644 --- a/Mopy/bash/game/fallout3/patcher/__init__.py +++ b/Mopy/bash/game/fallout3/patcher/__init__.py @@ -342,9 +342,9 @@ b'ARMO': (u'pickupSound', u'dropSound'), b'ASPC': ('sound', 'use_sound_from_region'), b'COBJ': (u'pickupSound', u'dropSound'), - b'CONT': ('sound', 'soundClose'), + b'CONT': ('sound', 'sound_close'), b'CREA': (u'footWeight', u'inheritsSoundsFrom', u'sounds'), - b'DOOR': ('sound', 'soundClose', 'soundLoop'), + b'DOOR': ('sound', 'sound_close', 'soundLoop'), b'EXPL': (u'soundLevel', u'sound1', u'sound2'), b'IPCT': ('soundLevel', 'sound', 'sound2'), b'LIGH': (u'sound',), diff --git a/Mopy/bash/game/fallout3/records.py b/Mopy/bash/game/fallout3/records.py index a5e4ac9aee..8f478fad00 100644 --- a/Mopy/bash/game/fallout3/records.py +++ b/Mopy/bash/game/fallout3/records.py @@ -47,7 +47,8 @@ MelReflectedRefractedBy, MelValueWeight, SpellFlags, MelBaseR, MelExtra, \ MelSound, MelSoundActivation, MelWaterType, MelConditionsFo3, \ MelNodeIndex, MelAddnDnam, MelEffectsFo3, MelShortName, PerkEpdfDecider, \ - MelPerkParamsGroups, MelUnorderedGroups, MelImageSpaceMod, MelAspcRdat + MelPerkParamsGroups, MelUnorderedGroups, MelImageSpaceMod, MelAspcRdat, \ + MelSoundClose, AMelItems, AMelLLItems, MelContData from ...exception import ModSizeError _is_fnv = bush.game.fsName == u'FalloutNV' @@ -216,14 +217,10 @@ def __init__(self): super().__init__(b'ETYP', 'equipment_type', -1) #------------------------------------------------------------------------------ -class MelItems(MelSorted): - """Wraps MelGroups for the common task of defining a list of items.""" +class MelItems(AMelItems): + """Handles the CNTO/COED subrecords defining items.""" def __init__(self): - super(MelItems, self).__init__(MelGroups(u'items', - MelStruct(b'CNTO', [u'I', u'i'], (FID, u'item'), (u'count', 1)), - MelOptStruct(b'COED', [u'2I', u'f'], (FID, u'owner'), (FID, u'glob'), - (u'condition', 1.0)), - ), sort_by_attrs=('item', 'count', 'condition', 'owner', 'glob')) + super().__init__(with_counter=False) #------------------------------------------------------------------------------ class MelLevListLvld(MelUInt8): @@ -251,6 +248,14 @@ def __init__(self): MelStruct(b'XDCR', ['2I'], (FID, 'reference'), 'unknown'), ), sort_by_attrs='reference') +#------------------------------------------------------------------------------ +class MelLLItems(AMelLLItems): + """Handles the LVLO/COED subrecords defining leveled list entries.""" + def __init__(self): + super().__init__(MelLevListLvlo(b'LVLO', ['h', '2s', 'I', 'h', '2s'], + 'level', 'unused1', (FID, 'listId'), ('count', 1), 'unused2', + old_versions={'iI'}), with_counter=False) + #------------------------------------------------------------------------------ class MelRaceHeadPart(MelGroup): """Implements special handling for ears, which can only contain an icon @@ -283,6 +288,13 @@ def dumpData(self, record, out): # Otherwise, delegate the dumpData call to MelGroup super(MelRaceHeadPart, self).dumpData(record, out) +#------------------------------------------------------------------------------ +class MelSoundRandomLooping(MelFid): + """Handles the common RNAM (Sound - Random/Looping) subrecord introduced in + FNV.""" + def __init__(self): + super().__init__(b'RNAM', 'sound_random_looping') + #------------------------------------------------------------------------------ class MreLeveledList(AMreLeveledList): """Leveled item/creature/spell list..""" @@ -295,14 +307,7 @@ class MreLeveledList(AMreLeveledList): MelLevListLvld(b'LVLD', u'chanceNone'), MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelFid(b'LVLG', u'glob'), - MelSorted(MelGroups(u'entries', - MelLevListLvlo(b'LVLO', [u'h', u'2s', u'I', u'h', u'2s'], u'level', - u'unused1', (FID, u'listId'), (u'count', 1), - u'unused2', old_versions={u'iI'}), - MelOptStruct(b'COED', [u'2I', u'f'], (FID, u'owner'), (FID, u'glob'), - (u'condition', 1.0)), - ), sort_by_attrs=('level', 'listId', 'count', 'condition', 'owner', - 'glob')), + MelLLItems(), MelModel(), ) __slots__ = melSet.getSlotsUsed() @@ -824,8 +829,6 @@ class MreCont(AMreWithItems): """Container.""" rec_sig = b'CONT' - _flags = Flags.from_names(None, 'respawns') - melSet = MelSet( MelEdid(), MelBounds(), @@ -834,10 +837,10 @@ class MreCont(AMreWithItems): MelScript(), MelItems(), MelDestructible(), - MelStruct(b'DATA', [u'B', u'f'],(_flags, u'flags'),'weight'), + MelContData(), MelSound(), - MelFid(b'QNAM','soundClose'), - fnv_only(MelFid(b'RNAM', 'soundRandomLooping')), + MelSoundClose(), + fnv_only(MelSoundRandomLooping()), ) __slots__ = melSet.getSlotsUsed() @@ -1065,7 +1068,7 @@ class MreDoor(MelRecord): MelScript(), MelDestructible(), MelSound(), - MelFid(b'ANAM','soundClose'), + MelSoundClose(b'ANAM'), MelFid(b'BNAM','soundLoop'), MelUInt8Flags(b'FNAM', u'flags', _flags), ) @@ -1627,7 +1630,7 @@ class MreKeym(MelRecord): MelDestructible(), MelSoundPickupDrop(), MelValueWeight(), - fnv_only(MelFid(b'RNAM', 'soundRandomLooping')), + fnv_only(MelSoundRandomLooping()), ) __slots__ = melSet.getSlotsUsed() @@ -1830,7 +1833,7 @@ class MreMisc(MelRecord): MelDestructible(), MelSoundPickupDrop(), MelValueWeight(), - fnv_only(MelFid(b'RNAM', 'soundRandomLooping')), + fnv_only(MelSoundRandomLooping()), ) __slots__ = melSet.getSlotsUsed() @@ -2878,7 +2881,7 @@ class MreStat(MelRecord): MelBounds(), MelModel(), fnv_only(MelSInt8(b'BRUS', 'passthroughSound', -1)), - fnv_only(MelFid(b'RNAM', 'soundRandomLooping')), + fnv_only(MelSoundRandomLooping()), ) __slots__ = melSet.getSlotsUsed() diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index d973ddea0e..44190ade7a 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -222,13 +222,13 @@ def init(cls): from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ - MreCmpo, MreCobj, \ + MreCmpo, MreCobj, MreCont, \ 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, + MreColl, MreCont, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -264,7 +264,7 @@ def init(cls): MreAact, MreActi, MreAddn, MreAech, MreAmdl, MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj, - MreColl, + MreColl, MreCont, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index b56edfd78e..33a24fd641 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -40,7 +40,7 @@ MelArtType, MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, \ MelBookText, MelBookDescription, MelInventoryArt, MelUnorderedGroups, \ MelImageSpaceMod, MelClmtWeatherTypes, MelClmtTiming, MelClmtTextures, \ - MelCobjOutput + MelCobjOutput, AMreWithItems, AMelItems, MelContData, MelSoundClose ##: What about texture hashes? I carried discarding them forward from Skyrim, # but that was due to the 43-44 problems. See also #620. @@ -157,13 +157,17 @@ class MelFtyp(MelFid): def __init__(self): super().__init__(b'FTYP', 'forced_loc_ref_type') +#------------------------------------------------------------------------------ +class MelItems(AMelItems): + """Handles the COCT/CNTO/COED subrecords defining items.""" + #------------------------------------------------------------------------------ class MelLLItems(AMelLLItems): - """Handles the LVLO and LLCT subrecords defining leveled list items""" + """Handles the LLCT/LVLO/COED subrecords defining leveled list entries.""" def __init__(self): - super().__init__([MelStruct(b'LVLO', ['H', '2s', 'I', 'H', 'B', 's'], + super().__init__(MelStruct(b'LVLO', ['H', '2s', 'I', 'H', 'B', 's'], 'level', 'unused1', (FID, 'listId'), ('count', 1), 'chance_none', - 'unused2')]) + 'unused2')) #------------------------------------------------------------------------------ class MelNativeTerminal(MelFid): @@ -792,6 +796,32 @@ def mergeFilter(self, modSet): self.cobj_components = [c for c in self.cobj_components if c.component_fid.mod_id in modSet] +#------------------------------------------------------------------------------ +class MreCont(AMreWithItems): + """Container.""" + rec_sig = b'CONT' + + melSet = MelSet( + MelEdid(), + MelVmad(), + MelBounds(), + MelPreviewTransform(), + MelFull(), + MelModel(), + MelItems(), + MelDestructible(), + MelContData(), + MelKeywords(), + MelFtyp(), + MelProperties(), + MelNativeTerminal(), + MelSound(), + MelSoundClose(), + MelFid(b'TNAM', 'sound_take_all'), + MelFid(b'ONAM', 'cont_filter_list'), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreGmst(AMreGmst): """Game Setting.""" diff --git a/Mopy/bash/game/falloutnv/patcher/__init__.py b/Mopy/bash/game/falloutnv/patcher/__init__.py index 0168470ffd..784de173dc 100644 --- a/Mopy/bash/game/falloutnv/patcher/__init__.py +++ b/Mopy/bash/game/falloutnv/patcher/__init__.py @@ -238,7 +238,7 @@ # Import Sounds #------------------------------------------------------------------------------ soundsTypes.update({ - b'CONT': ('sound', 'soundClose', 'soundRandomLooping'), + b'CONT': ('sound', 'sound_close', 'sound_random_looping'), b'WEAP': ('pickupSound', 'dropSound', 'sound', 'soundGunShot2D', 'soundGunShot3DLooping', 'soundMeleeSwingGunNoAmmo', 'soundBlock', 'idleSound', 'equipSound', 'unequipSound', diff --git a/Mopy/bash/game/oblivion/patcher/__init__.py b/Mopy/bash/game/oblivion/patcher/__init__.py index ca8ae84ccd..9de5fdf403 100644 --- a/Mopy/bash/game/oblivion/patcher/__init__.py +++ b/Mopy/bash/game/oblivion/patcher/__init__.py @@ -297,9 +297,9 @@ #------------------------------------------------------------------------------ soundsTypes = { b'ACTI': ('sound',), - b'CONT': ('sound', 'soundClose'), + b'CONT': ('sound', 'sound_close'), b'CREA': (u'footWeight', u'inheritsSoundsFrom', u'sounds'), - b'DOOR': ('sound', 'soundClose', 'soundLoop'), + b'DOOR': ('sound', 'sound_close', 'soundLoop'), b'LIGH': (u'sound',), b'MGEF': (u'castingSound', u'boltSound', u'hitSound', u'areaSound'), # b'REGN': ('entries.sounds',), diff --git a/Mopy/bash/game/oblivion/records.py b/Mopy/bash/game/oblivion/records.py index 3170b13bba..46384db2fa 100644 --- a/Mopy/bash/game/oblivion/records.py +++ b/Mopy/bash/game/oblivion/records.py @@ -43,7 +43,7 @@ MelClmtWeatherTypes, MelFactionRanks, MelLscrLocations, attr_csv_struct, \ MelEnchantment, MelValueWeight, null4, SpellFlags, MelOwnership, \ MelSound, MelWeight, MelEffectsTes4ObmeFull, MelBookText, MelClmtTiming, \ - MelClmtTextures + MelClmtTextures, MelSoundClose, AMelItems, AMelLLItems, MelContData #------------------------------------------------------------------------------ # Record Elements ------------------------------------------------------------- @@ -117,12 +117,10 @@ def __init__(self, with_script_vars=False): super(MelEmbeddedScript, self).__init__(*seq_elements) #------------------------------------------------------------------------------ -class MelItems(MelSorted): - """Wraps MelGroups for the common task of defining a list of items.""" +class MelItems(AMelItems): + """Handles the CNTO subrecords defining items.""" def __init__(self): - super(MelItems, self).__init__(MelGroups(u'items', - MelStruct(b'CNTO', [u'I', u'i'], (FID, u'item'), u'count'), - ), sort_by_attrs='item') + super().__init__(with_coed=False, with_counter=False) #------------------------------------------------------------------------------ class MelLevListLvld(MelUInt8): @@ -146,6 +144,14 @@ def _pre_process_unpacked(self, unpacked_val): unpacked_val = (unpacked_val[0], null2, unpacked_val[1]) return super(MelLevListLvlo, self)._pre_process_unpacked(unpacked_val) +#------------------------------------------------------------------------------ +class MelLLItems(AMelLLItems): + """Handles the LVLO subrecords defining leveled list entries.""" + def __init__(self): + super().__init__(MelLevListLvlo(b'LVLO', ['h', '2s', 'I', 'h', '2s'], + 'level', 'unused1', (FID, 'listId'), ('count', 1), 'unused2', + old_versions={'iI'}), with_coed=False, with_counter=False) + #------------------------------------------------------------------------------ class MelOwnershipTes4(MelOwnership): """Handles XOWN, XRNK, and XGLB for cells and cell children.""" @@ -453,12 +459,7 @@ class MreLeveledList(AMreLeveledList): MelUInt8Flags(b'LVLF', u'flags', AMreLeveledList._flags), MelScript(), # LVLC only MelFid(b'TNAM','template'), - MelSorted(MelGroups('entries', - MelLevListLvlo(b'LVLO', [u'h', u'2s', u'I', u'h', u'2s'], - u'level', u'unused1', - (FID, u'listId'), (u'count', 1), - u'unused2', old_versions={u'iI'}), - ), sort_by_attrs=('level', 'listId', 'count')), + MelLLItems(), MelNull(b'DATA'), ) __slots__ = melSet.getSlotsUsed() @@ -764,17 +765,15 @@ class MreCont(AMreWithItems): """Container.""" rec_sig = b'CONT' - _flags = Flags.from_names(None,'respawns') - melSet = MelSet( MelEdid(), MelFull(), MelModel(), MelScript(), MelItems(), - MelStruct(b'DATA', [u'B', u'f'],(_flags, u'flags'),'weight'), + MelContData(), MelSound(), - MelFid(b'QNAM','soundClose'), + MelSoundClose(), ) __slots__ = melSet.getSlotsUsed() @@ -918,7 +917,7 @@ class MreDoor(MelRecord): MelModel(), MelScript(), MelSound(), - MelFid(b'ANAM','soundClose'), + MelSoundClose(b'ANAM'), MelFid(b'BNAM','soundLoop'), MelUInt8Flags(b'FNAM', u'flags', _flags), MelSorted(MelFids('destinations', MelFid(b'TNAM'))), diff --git a/Mopy/bash/game/skyrim/patcher/__init__.py b/Mopy/bash/game/skyrim/patcher/__init__.py index 46d224d687..e8c992d826 100644 --- a/Mopy/bash/game/skyrim/patcher/__init__.py +++ b/Mopy/bash/game/skyrim/patcher/__init__.py @@ -495,8 +495,8 @@ b'ARMO': (u'pickupSound', u'dropSound'), b'ASPC': ('sound', 'use_sound_from_region', 'aspc_reverb'), b'BOOK': (u'pickupSound', u'dropSound'), - b'CONT': ('sound', 'soundClose'), - b'DOOR': ('sound', 'soundClose', 'soundLoop'), + b'CONT': ('sound', 'sound_close'), + b'DOOR': ('sound', 'sound_close', 'soundLoop'), b'EFSH': (u'ambientSound',), ##: This is also in graphicsTypes! b'EXPL': (u'sound1', u'sound2'), b'FLOR': ('sound',), diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index ccffe3c4db..de8b1a646f 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -40,7 +40,7 @@ MelColorO, MelSpells, MelFixedString, MelUInt8Flags, MelUInt16Flags, \ MelUInt32Flags, MelOwnership, MelDebrData, MelClmtWeatherTypes, AMelVmad, \ MelActorSounds, MelFactionRanks, MelSorted, MelReflectedRefractedBy, \ - perk_effect_key, MelValueWeight, MelCoed, MelSound, MelWaterType, \ + perk_effect_key, MelValueWeight, MelSound, MelWaterType, \ MelSoundActivation, MelInteractionKeyword, MelConditionList, MelAddnDnam, \ MelConditions, ANvnmContext, MelNodeIndex, MelEquipmentType, MelAlchEnit, \ MelEffects, AMelLLItems, MelUnloadEvent, MelShortName, AVmadContext, \ @@ -49,7 +49,8 @@ MelFootstepSound, MelArtObject, MelTemplateArmor, MelArtType, \ MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, MelBookText, \ MelBookDescription, MelInventoryArt, MelUnorderedGroups, MelExtra, \ - MelImageSpaceMod, MelClmtTiming, MelClmtTextures, MelCobjOutput + MelImageSpaceMod, MelClmtTiming, MelClmtTextures, MelCobjOutput, \ + MelSoundClose, AMelItems, MelContData from ...exception import ModSizeError _is_sse = bush.game.fsName in ( @@ -200,19 +201,8 @@ def __init__(self, attr): ) #------------------------------------------------------------------------------ -class MelItems(MelSorted): - """Wraps MelGroups for the common task of defining a list of items.""" - def __init__(self): - super(MelItems, self).__init__(MelGroups('items', - MelStruct(b'CNTO', [u'I', u'i'], (FID, u'item'), u'count'), - MelCoed(), - ), sort_by_attrs=('item', 'count', 'itemCondition', 'owner', 'glob')) - -class MelItemsCounter(MelCounter): - """Wraps MelCounter for the common task of defining an items counter.""" - def __init__(self): - super(MelItemsCounter, self).__init__(MelUInt32(b'COCT', 'item_count'), - counts='items') +class MelItems(AMelItems): + """Handles the COCT/CNTO/COED subrecords defining items.""" #------------------------------------------------------------------------------ class MelLinkedReferences(MelSorted): @@ -226,12 +216,11 @@ def __init__(self): #------------------------------------------------------------------------------ class MelLLItems(AMelLLItems): - """Handles the LVLO and LLCT subrecords defining leveled list items""" + """Handles the LLCT/LVLO/COED subrecords defining leveled list entries.""" def __init__(self, with_coed=True): - super().__init__([ - MelStruct(b'LVLO', ['H', '2s', 'I', 'H', '2s'], 'level', - 'unknown1', (FID, 'listId'), ('count', 1), 'unknown2')], - with_coed) + super().__init__(MelStruct(b'LVLO', ['H', '2s', 'I', 'H', '2s'], + 'level', 'unknown1', (FID, 'listId'), ('count', 1), 'unknown2'), + with_coed=with_coed) #------------------------------------------------------------------------------ class MelLocation(MelUnion): @@ -932,7 +921,6 @@ class MreCobj(AMreWithItems): melSet = MelSet( MelEdid(), - MelItemsCounter(), MelItems(), MelConditionList(), MelCobjOutput(), @@ -945,21 +933,17 @@ class MreCont(AMreWithItems): """Container.""" rec_sig = b'CONT' - ContTypeFlags = Flags.from_names('allowSoundsWhenAnimation', 'respawns', - 'showOwner') - melSet = MelSet( MelEdid(), MelVmad(), MelBounds(), MelFull(), MelModel(), - MelItemsCounter(), MelItems(), MelDestructible(), - MelStruct(b'DATA', [u'B', u'f'],(ContTypeFlags, u'flags'),'weight'), + MelContData(), MelSound(), - MelFid(b'QNAM','soundClose'), + MelSoundClose(), ) __slots__ = melSet.getSlotsUsed() @@ -1106,7 +1090,7 @@ class MreDoor(MelRecord): MelModel(), MelDestructible(), MelSound(), - MelFid(b'ANAM','soundClose'), + MelSoundClose(b'ANAM'), MelFid(b'BNAM','soundLoop'), MelUInt8Flags(b'FNAM', u'flags', DoorTypeFlags), MelSorted(MelFids('random_teleports', MelFid(b'TNAM'))), @@ -2498,7 +2482,6 @@ class MreNpc(AMreActor): MelSorted(MelGroups('perks', MelOptStruct(b'PRKR', [u'I', u'B', u'3s'],(FID, 'perk'),'rank','prkrUnused'), ), sort_by_attrs='perk'), - MelItemsCounter(), MelItems(), MelStruct(b'AIDT', [u'B', u'B', u'B', u'B', u'B', u'B', u'B', u'B', u'I', u'I', u'I'], 'aggression', 'confidence', 'energyLevel', 'responsibility', 'mood', 'assistance', @@ -2969,7 +2952,6 @@ class MreQust(MelRecord): ), MelConditionList(), MelKeywords(), - MelItemsCounter(), MelItems(), MelFid(b'SPOR','spectatorOverridePackageList'), MelFid(b'OCOR','observeDeadBodyOverridePackageList'), From 62482e9397a11ecbff7238d440f9ba8c992a5aaf Mon Sep 17 00:00:00 2001 From: Infernio Date: Sun, 21 Aug 2022 22:54:31 +0200 Subject: [PATCH 07/13] FO4: Implement CPTH and CSTY CSTY is a really ugly record, so I formatted the ones in the older games. Doesn't really help, but hey (no need to worry about usages, CSTY has no usages outside records.py files and the init() methods). All C* records done. --- Mopy/bash/brec/common_subrecords.py | 11 ++++ Mopy/bash/game/fallout3/records.py | 79 +++++++++++++++-------------- Mopy/bash/game/fallout4/__init__.py | 6 +-- Mopy/bash/game/fallout4/records.py | 68 ++++++++++++++++++++++++- Mopy/bash/game/oblivion/records.py | 63 +++++++++++------------ Mopy/bash/game/skyrim/records.py | 48 +++++++++++------- 6 files changed, 183 insertions(+), 92 deletions(-) diff --git a/Mopy/bash/brec/common_subrecords.py b/Mopy/bash/brec/common_subrecords.py index 18c5871adb..772ce06819 100644 --- a/Mopy/bash/brec/common_subrecords.py +++ b/Mopy/bash/brec/common_subrecords.py @@ -372,6 +372,17 @@ def __init__(self): super().__init__(b'DATA', ['B', 'f'], (self._cont_flags, 'cont_flags'), 'cont_weight') +#------------------------------------------------------------------------------ +class MelCpthShared(MelSequential): + """Handles the CPTH subrecords ANAM, DATA and SNAM. Identical between all + games' CPTH records.""" + def __init__(self): + super().__init__( + MelSimpleArray('related_camera_paths', MelFid(b'ANAM')), + MelUInt8(b'DATA', 'camera_zoom'), + MelFids('camera_shots', MelFid(b'SNAM')), + ), + #------------------------------------------------------------------------------ class MelDebrData(MelStruct): def __init__(self): diff --git a/Mopy/bash/game/fallout3/records.py b/Mopy/bash/game/fallout3/records.py index 8f478fad00..ab58ddb17d 100644 --- a/Mopy/bash/game/fallout3/records.py +++ b/Mopy/bash/game/fallout3/records.py @@ -48,7 +48,7 @@ MelSound, MelSoundActivation, MelWaterType, MelConditionsFo3, \ MelNodeIndex, MelAddnDnam, MelEffectsFo3, MelShortName, PerkEpdfDecider, \ MelPerkParamsGroups, MelUnorderedGroups, MelImageSpaceMod, MelAspcRdat, \ - MelSoundClose, AMelItems, AMelLLItems, MelContData + MelSoundClose, AMelItems, AMelLLItems, MelContData, MelCpthShared from ...exception import ModSizeError _is_fnv = bush.game.fsName == u'FalloutNV' @@ -852,9 +852,7 @@ class MreCpth(MelRecord): melSet = MelSet( MelEdid(), MelConditionsFo3(), - MelSimpleArray('relatedCameraPaths', MelFid(b'ANAM')), - MelUInt8(b'DATA', 'cameraZoom'), - MelFids('cameraShots', MelFid(b'SNAM')), + MelCpthShared(), ) __slots__ = melSet.getSlotsUsed() @@ -946,40 +944,45 @@ class MreCsty(MelRecord): """Combat Style.""" rec_sig = b'CSTY' - _flagsA = Flags.from_names( - (0, 'advanced'), - (1, 'useChanceForAttack'), - (2, 'ignoreAllies'), - (3, 'willYield'), - (4, 'rejectsYields'), - (5, 'fleeingDisabled'), - (6, 'prefersRanged'), - (7, 'meleeAlertOK'), - ) - - melSet = MelSet( - MelEdid(), - MelOptStruct(b'CSTD', [u'2B', u'2s', u'8f', u'2B', u'2s', u'3f', u'B', u'3s', u'2f', u'5B', u'3s', u'2f', u'H', u'2s', u'2B', u'2s', u'f'],'dodgeChance', - 'lrChance','unused1','lrTimerMin','lrTimerMax', - 'forTimerMin','forTimerMax','backTimerMin','backTimerMax', - 'idleTimerMin','idleTimerMax','blkChance','atkChance', - 'unused2','atkBRecoil','atkBunc','atkBh2h', - 'pAtkChance','unused3','pAtkBRecoil','pAtkBUnc', - 'pAtkNormal','pAtkFor','pAtkBack','pAtkL','pAtkR', - 'unused4','holdTimerMin','holdTimerMax', - (_flagsA,'flagsA'),'unused5','acroDodge', - ('rushChance',25),'unused6',('rushMult',1.0)), - MelOptStruct(b'CSAD', [u'21f'], 'dodgeFMult', 'dodgeFBase', 'encSBase', 'encSMult', - 'dodgeAtkMult', 'dodgeNAtkMult', 'dodgeBAtkMult', 'dodgeBNAtkMult', - 'dodgeFAtkMult', 'dodgeFNAtkMult', 'blockMult', 'blockBase', - 'blockAtkMult', 'blockNAtkMult', 'atkMult','atkBase', 'atkAtkMult', - 'atkNAtkMult', 'atkBlockMult', 'pAtkFBase', 'pAtkFMult'), - MelOptStruct(b'CSSD', [u'9f', u'4s', u'I', u'5f'], 'coverSearchRadius', 'takeCoverChance', - 'waitTimerMin', 'waitTimerMax', 'waitToFireTimerMin', - 'waitToFireTimerMax', 'fireTimerMin', 'fireTimerMax', - 'rangedWeaponRangeMultMin','unknown1','weaponRestrictions', - 'rangedWeaponRangeMultMax','maxTargetingFov','combatRadius', - 'semiAutomaticFireDelayMultMin','semiAutomaticFireDelayMultMax'), + _csty_flags = Flags.from_names( + 'advanced', + 'use_chance_for_attack', + 'ignore_allies', + 'will_yield', + 'rejects_yields', + 'fleeing_disabled', + 'prefers_ranged', + 'melee_alert_ok', + ) + + melSet = MelSet( + MelEdid(), + MelOptStruct(b'CSTD', + ['2B', '2s', '8f', '2B', '2s', '3f', 'B', '3s', '2f', '5B', '3s', + '2f', 'H', '2s', '2B', '2s', 'f'], 'dodge_chance', 'lr_chance', + 'unused1', 'lr_timer_min', 'lr_timer_max', 'for_timer_min', + 'for_timer_max', 'back_timer_min', 'back_timer_max', + 'idle_timer_min', 'idle_timer_max', 'blk_chance', 'atk_chance', + 'unused2', 'atk_brecoil', 'atk_bunc', 'atk_bh_2_h', 'p_atk_chance', + 'unused3', 'p_atk_brecoil', 'p_atk_bunc', 'p_atk_normal', + 'p_atk_for', 'p_atk_back', 'p_atk_l', 'p_atk_r', 'unused4', + 'hold_timer_min', 'hold_timer_max', (_csty_flags, 'csty_flags'), + 'unused5', 'acro_dodge', ('rush_chance', 25), 'unused6', + ('rush_mult', 1.0)), + MelOptStruct(b'CSAD', ['21f'], 'dodge_fmult', 'dodge_fbase', + 'enc_sbase', 'enc_smult', 'dodge_atk_mult', 'dodge_natk_mult', + 'dodge_batk_mult', 'dodge_bnatk_mult', 'dodge_fatk_mult', + 'dodge_fnatk_mult', 'block_mult', 'block_base', 'block_atk_mult', + 'block_natk_mult', 'atk_mult', 'atk_base', 'atk_atk_mult', + 'atk_natk_mult', 'atk_block_mult', 'p_atk_fbase', 'p_atk_fmult'), + MelOptStruct(b'CSSD', ['9f', '4s', 'I', '5f'], 'cover_search_radius', + 'take_cover_chance', 'wait_timer_min', 'wait_timer_max', + 'wait_to_fire_timer_min', 'wait_to_fire_timer_max', + 'fire_timer_min', 'fire_timer_max', 'ranged_weapon_range_mult_min', + 'unknown1', 'weapon_restrictions', 'ranged_weapon_range_mult_max', + 'max_targeting_fov', 'combat_radius', + 'semi_automatic_fire_delay_mult_min', + 'semi_automatic_fire_delay_mult_max'), ) __slots__ = melSet.getSlotsUsed() diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index 44190ade7a..2c35c7d580 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -222,13 +222,13 @@ def init(cls): from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ - MreCmpo, MreCobj, MreCont, \ + MreCmpo, MreCobj, MreCont, MreCpth, MreCsty, \ 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, + MreColl, MreCont, MreCpth, MreCsty, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -264,7 +264,7 @@ def init(cls): MreAact, MreActi, MreAddn, MreAech, MreAmdl, MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, MreCmpo, MreCobj, - MreColl, MreCont, + MreColl, MreCont, MreCpth, MreCsty, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index 33a24fd641..65c1e1dcbc 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -40,7 +40,8 @@ MelArtType, MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, \ MelBookText, MelBookDescription, MelInventoryArt, MelUnorderedGroups, \ MelImageSpaceMod, MelClmtWeatherTypes, MelClmtTiming, MelClmtTextures, \ - MelCobjOutput, AMreWithItems, AMelItems, MelContData, MelSoundClose + MelCobjOutput, AMreWithItems, AMelItems, MelContData, MelSoundClose, \ + MelCpthShared ##: What about texture hashes? I carried discarding them forward from Skyrim, # but that was due to the 43-44 problems. See also #620. @@ -822,6 +823,71 @@ class MreCont(AMreWithItems): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreCpth(MelRecord): + """Camera Path.""" + rec_sig = b'CPTH' + + melSet = MelSet( + MelEdid(), + MelConditionList(), + MelCpthShared(), + ) + __slots__ = melSet.getSlotsUsed() + +#------------------------------------------------------------------------------ +class MreCsty(MelRecord): + rec_sig = b'CSTY' + + _csty_flags = Flags.from_names('dueling', 'flanking', + 'allow_dual_wielding', 'charging', 'retarget_any_nearby_melee_target') + + melSet = MelSet( + MelEdid(), + MelStruct(b'CSGD', ['12f'], 'general_offensive_mult', + 'general_defensive_mult', 'general_group_offensive_mult', + 'general_equipment_score_mult_melee', + 'general_equipment_score_mult_magic', + 'general_equipment_score_mult_ranged', + 'general_equipment_score_mult_shout', + 'general_equipment_score_mult_unarmed', + 'general_equipment_score_mult_staff', + 'general_avoid_threat_chance', 'general_dodge_threat_chance', + 'general_evade_threat_chance'), + MelBase(b'CSMD', 'unknown1'), + MelTruncatedStruct(b'CSME', ['10f'], 'melee_attack_staggered_mult', + 'melee_power_attack_staggered_mult', + 'melee_power_attack_blocking_mult', + 'melee_bash_mult', 'melee_bash_recoil_mult', + 'melee_bash_attack_mult', 'melee_bash_power_attack_mult', + 'melee_special_attack_mult', 'melee_block_when_staggered_mult', + 'melee_attack_when_staggered_mult', old_versions={'9f'}), + MelFloat(b'CSRA', 'ranged_accuracy_mult'), + MelStruct(b'CSCR', ['9f', 'I', 'f'], 'close_range_dueling_circle_mult', + 'close_range_dueling_fallback_mult', + 'close_range_flanking_flank_distance', + 'close_range_flanking_stalk_time', + 'close_range_charging_charge_distance', + 'close_range_charging_throw_probability', + 'close_range_charging_sprint_fast_probability', + 'close_range_charging_sideswipe_probability', + 'close_range_charging_disengage_probability', + 'close_range_charging_throw_max_targets', + 'close_range_flanking_flank_variance'), + MelTruncatedStruct(b'CSLR', ['5f'], 'long_range_strafe_mult', + 'long_range_adjust_range_mult', 'long_range_crouch_mult', + 'long_range_wait_mult', 'long_range_range_mult', + old_versions={'4f', '3f'}), + MelFloat(b'CSCV', 'cover_search_distance_mult'), + MelStruct(b'CSFL', ['8f'], 'flight_hover_chance', + 'flight_dive_bomb_chance', 'flight_ground_attack_chance', + 'flight_hover_time', 'flight_ground_attack_time', + 'flight_perch_attack_chance', 'flight_perch_attack_time', + 'flight_flying_attack_chance'), + MelUInt32Flags(b'DATA', 'csty_flags', _csty_flags), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreGmst(AMreGmst): """Game Setting.""" diff --git a/Mopy/bash/game/oblivion/records.py b/Mopy/bash/game/oblivion/records.py index 46384db2fa..ded889698f 100644 --- a/Mopy/bash/game/oblivion/records.py +++ b/Mopy/bash/game/oblivion/records.py @@ -843,49 +843,48 @@ class MreCrea(AMreActor): class MreCsty(MelRecord): """Combat Style.""" rec_sig = b'CSTY' - _flagsA = Flags.from_names( - ( 0,'advanced'), - ( 1,'useChanceForAttack'), - ( 2,'ignoreAllies'), - ( 3,'willYield'), - ( 4,'rejectsYields'), - ( 5,'fleeingDisabled'), - ( 6,'prefersRanged'), - ( 7,'meleeAlertOK'), + + _csty_flags1 = Flags.from_names( + 'advanced', + 'use_chance_for_attack', + 'ignore_allies', + 'will_yield', + 'rejects_yields', + 'fleeing_disabled', + 'prefers_ranged', + 'melee_alert_ok', ) - _flagsB = Flags.from_names('doNotAcquire') + _csty_flags2 = Flags.from_names('do_not_acquire') melSet = MelSet( MelEdid(), MelTruncatedStruct(b'CSTD', - [u'2B', u'2s', u'8f', u'2B', u'2s', u'3f', u'B', u'3s', u'2f', - u'5B', u'3s', u'2f', u'2B', u'2s', u'7f', u'B', u'3s', u'f', - u'I'], 'dodgeChance', - 'lrChance', 'unused1', 'lrTimerMin', 'lrTimerMax', - 'forTimerMin', 'forTimerMax', 'backTimerMin', 'backTimerMax', - 'idleTimerMin', 'idleTimerMax', 'blkChance', 'atkChance', - 'unused2', 'atkBRecoil', 'atkBunc', 'atkBh2h', - 'pAtkChance', 'unused3', 'pAtkBRecoil', 'pAtkBUnc', - 'pAtkNormal', 'pAtkFor', 'pAtkBack', 'pAtkL', 'pAtkR', - 'unused4', 'holdTimerMin', 'holdTimerMax', - (_flagsA, 'flagsA'), 'acroDodge', 'unused5', - ('rMultOpt', 1.0), ('rMultMax', 1.0), ('mDistance', 250.0), - ('rDistance', 1000.0), ('buffStand', 325.0), ('rStand', 500.0), - ('groupStand', 325.0), ('rushChance', 25), 'unused6', - ('rushMult', 1.0), (_flagsB, 'flagsB'), old_versions={ + ['2B', '2s', '8f', '2B', '2s', '3f', 'B', '3s', '2f', '5B', '3s', + '2f', '2B', '2s', '7f', 'B', '3s', 'f', 'I'], 'dodge_chance', + 'lr_chance', 'unused1', 'lr_timer_min', 'lr_timer_max', + 'for_timer_min', 'for_timer_max', 'back_timer_min', + 'back_timer_max', 'idle_timer_min', 'idle_timer_max', 'blk_chance', + 'atk_chance', 'unused2', 'atk_brecoil', 'atk_bunc', 'atk_bh_2_h', + 'p_atk_chance', 'unused3', 'p_atk_brecoil', 'p_atk_bunc', + 'p_atk_normal', 'p_atk_for', 'p_atk_back', 'p_atk_l', 'p_atk_r', + 'unused4', 'hold_timer_min', 'hold_timer_max', + (_csty_flags1, 'csty_flags1'), 'acro_dodge', 'unused5', + ('r_mult_opt', 1.0), ('r_mult_max', 1.0), ('m_distance', 250.0), + ('r_distance', 1000.0), ('buff_stand', 325.0), ('r_stand', 500.0), + ('group_stand', 325.0), ('rush_chance', 25), 'unused6', + ('rush_mult', 1.0), (_csty_flags2, 'csty_flags2'), old_versions={ '2B2s8f2B2s3fB3s2f5B3s2f2B2s7fB3sf', '2B2s8f2B2s3fB3s2f5B3s2f2B2s7f', '2B2s8f2B2s3fB3s2f5B3s2f2B2s5f', '2B2s8f2B2s3fB3s2f5B3s2f2B2s2f', '2B2s8f2B2s3fB3s2f5B3s2f2B2s', }), - MelOptStruct(b'CSAD', [u'21f'], 'dodgeFMult', 'dodgeFBase', 'encSBase', - 'encSMult', 'dodgeAtkMult', 'dodgeNAtkMult', - 'dodgeBAtkMult', 'dodgeBNAtkMult', 'dodgeFAtkMult', - 'dodgeFNAtkMult', 'blockMult', 'blockBase', - 'blockAtkMult', 'blockNAtkMult', 'atkMult', 'atkBase', - 'atkAtkMult', 'atkNAtkMult', 'atkBlockMult', 'pAtkFBase', - 'pAtkFMult'), + MelOptStruct(b'CSAD', ['21f'], 'dodge_fmult', 'dodge_fbase', + 'enc_sbase', 'enc_smult', 'dodge_atk_mult', 'dodge_natk_mult', + 'dodge_batk_mult', 'dodge_bnatk_mult', 'dodge_fatk_mult', + 'dodge_fnatk_mult', 'block_mult', 'block_base', 'block_atk_mult', + 'block_natk_mult', 'atk_mult', 'atk_base', 'atk_atk_mult', + 'atk_natk_mult', 'atk_block_mult', 'p_atk_fbase', 'p_atk_fmult'), ) __slots__ = melSet.getSlotsUsed() diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index de8b1a646f..4d7bb9ca07 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -50,7 +50,7 @@ MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, MelBookText, \ MelBookDescription, MelInventoryArt, MelUnorderedGroups, MelExtra, \ MelImageSpaceMod, MelClmtTiming, MelClmtTextures, MelCobjOutput, \ - MelSoundClose, AMelItems, MelContData + MelSoundClose, AMelItems, MelContData, MelCpthShared from ...exception import ModSizeError _is_sse = bush.game.fsName in ( @@ -955,9 +955,7 @@ class MreCpth(MelRecord): melSet = MelSet( MelEdid(), MelConditionList(), - MelSimpleArray('relatedCameraPaths', MelFid(b'ANAM')), - MelUInt8(b'DATA', 'cameraZoom'), - MelFids('cameraShots', MelFid(b'SNAM')), + MelCpthShared(), ) __slots__ = melSet.getSlotsUsed() @@ -966,23 +964,37 @@ class MreCsty(MelRecord): """Combat Style.""" rec_sig = b'CSTY' - CstyTypeFlags = Flags.from_names('dueling', 'flanking', - 'allowDualWielding') + _csty_flags = Flags.from_names('dueling', 'flanking', + 'allow_dual_wielding') melSet = MelSet( MelEdid(), - # esm = Equipment Score Mult - MelStruct(b'CSGD', [u'10f'],'offensiveMult','defensiveMult','groupOffensiveMult', - 'esmMelee','esmMagic','esmRanged','esmShout','esmUnarmed','esmStaff', - 'avoidThreatChance',), - MelBase(b'CSMD','unknownValue'), - MelStruct(b'CSME', [u'8f'],'atkStaggeredMult','powerAtkStaggeredMult','powerAtkBlockingMult', - 'bashMult','bashRecoilMult','bashAttackMult','bashPowerAtkMult','specialAtkMult',), - MelStruct(b'CSCR', [u'4f'],'circleMult','fallbackMult','flankDistance','stalkTime',), - MelFloat(b'CSLR', 'strafeMult'), - MelStruct(b'CSFL', [u'8f'],'hoverChance','diveBombChance','groundAttackChance','hoverTime', - 'groundAttackTime','perchAttackChance','perchAttackTime','flyingAttackChance',), - MelUInt32Flags(b'DATA', u'flags', CstyTypeFlags), + MelStruct(b'CSGD', ['10f'], 'general_offensive_mult', + 'general_defensive_mult', 'general_group_offensive_mult', + 'general_equipment_score_mult_melee', + 'general_equipment_score_mult_magic', + 'general_equipment_score_mult_ranged', + 'general_equipment_score_mult_shout', + 'general_equipment_score_mult_unarmed', + 'general_equipment_score_mult_staff', + 'general_avoid_threat_chance'), + MelBase(b'CSMD', 'unknown1'), + MelStruct(b'CSME', ['8f'], 'melee_attack_staggered_mult', + 'melee_power_attack_staggered_mult', + 'melee_power_attack_blocking_mult', + 'melee_bash_mult', 'melee_bash_recoil_mult', + 'melee_bash_attack_mult', 'melee_bash_power_attack_mult', + 'melee_special_attack_mult'), + MelStruct(b'CSCR', ['4f'], 'close_range_circle_mult', + 'close_range_fallback_mult', 'close_range_flank_distance', + 'close_range_stalk_time'), + MelFloat(b'CSLR', 'long_range_strafe_mult'), + MelStruct(b'CSFL', ['8f'], 'flight_hover_chance', + 'flight_dive_bomb_chance', 'flight_ground_attack_chance', + 'flight_hover_time', 'flight_ground_attack_time', + 'flight_perch_attack_chance', 'flight_perch_attack_time', + 'flight_flying_attack_chance'), + MelUInt32Flags(b'DATA', 'csty_flags', _csty_flags), ) __slots__ = melSet.getSlotsUsed() From f2ba9939699a8fe5527abb55652970503f4a8a2b Mon Sep 17 00:00:00 2001 From: Infernio Date: Sun, 21 Aug 2022 23:49:35 +0200 Subject: [PATCH 08/13] Move DEBR to brec Note that our DATA handling was entirely broken, fixed it. --- Mopy/bash/brec/common_records.py | 18 +++++++++++++++++- Mopy/bash/brec/common_subrecords.py | 20 ++++++++++++-------- Mopy/bash/game/enderal/__init__.py | 7 +++---- Mopy/bash/game/enderalse/__init__.py | 7 +++---- Mopy/bash/game/fallout3/__init__.py | 7 +++---- Mopy/bash/game/fallout3/records.py | 16 ---------------- Mopy/bash/game/fallout4/__init__.py | 6 +++--- Mopy/bash/game/falloutnv/__init__.py | 6 +++--- Mopy/bash/game/skyrim/__init__.py | 6 +++--- Mopy/bash/game/skyrim/records.py | 16 ---------------- Mopy/bash/game/skyrimse/__init__.py | 7 +++---- Mopy/bash/game/skyrimvr/__init__.py | 7 +++---- 12 files changed, 53 insertions(+), 70 deletions(-) diff --git a/Mopy/bash/brec/common_records.py b/Mopy/bash/brec/common_records.py index 748913ddef..84cc08f090 100644 --- a/Mopy/bash/brec/common_records.py +++ b/Mopy/bash/brec/common_records.py @@ -31,7 +31,7 @@ from .basic_elements import MelBase, MelFid, MelFids, MelFloat, MelGroups, \ MelLString, MelNull, MelStruct, MelUInt32, MelSInt32, MelFixedString, \ MelUnicode, unpackSubHeader, MelUInt32Flags, MelString -from .common_subrecords import MelEdid, MelDescription, MelColor +from .common_subrecords import MelEdid, MelDescription, MelColor, MelDebrData from .record_structs import MelRecord, MelSet from .utils_constants import FID, FormId from .. import bolt, exception @@ -347,6 +347,22 @@ class MreColl(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreDebr(MelRecord): + """Debris.""" + rec_sig = b'DEBR' + + melSet = MelSet( + MelEdid(), + MelGroups('debr_models', + MelDebrData(), + # Ignore texture hashes - they're only an optimization, plenty + # of records in Skyrim.esm are missing them + MelNull(b'MODT'), + ), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreFlst(MelRecord): """FormID List.""" diff --git a/Mopy/bash/brec/common_subrecords.py b/Mopy/bash/brec/common_subrecords.py index 772ce06819..e28d6fb0bb 100644 --- a/Mopy/bash/brec/common_subrecords.py +++ b/Mopy/bash/brec/common_subrecords.py @@ -385,27 +385,31 @@ def __init__(self): #------------------------------------------------------------------------------ class MelDebrData(MelStruct): + """Handles the DEBR subrecord DATA (Data).""" + _debr_flags = Flags.from_names('has_collision_data', 'collision') + def __init__(self): # Format doesn't matter, struct.Struct('') works! ##: MelStructured - super().__init__(b'DATA', [], 'percentage', ('modPath', null1), - 'flags') + super().__init__(b'DATA', [], 'debr_percentage', ('modPath', null1), + (self._debr_flags, 'debr_flags')) @staticmethod def _expand_formats(elements, struct_formats): return [0] * len(elements) - def load_mel(self, record, ins, sub_type, size_, *debug_strs): + def load_mel(self, record, ins, sub_type, size_, *debug_strs, + __unpack_byte=structs_cache['B'].unpack): byte_data = ins.read(size_, *debug_strs) - record.percentage = unpack_byte(ins, byte_data[0:1])[0] + record.debr_percentage = __unpack_byte(byte_data[0:1])[0] record.modPath = byte_data[1:-2] - if byte_data[-2] != null1: + if byte_data[-2:-1] != null1: raise ModError(ins.inName, f'Unexpected subrecord: {debug_strs}') - record.flags = struct_unpack('B', byte_data[-1])[0] + record.debr_flags = self._debr_flags(__unpack_byte(byte_data[-1:])[0]) def pack_subrecord_data(self, record): return b''.join( - [struct_pack('B', record.percentage), record.modPath, null1, - struct_pack('B', record.flags)]) + [struct_pack('B', record.debr_percentage), record.modPath, null1, + struct_pack('B', record.debr_flags.dump())]) #------------------------------------------------------------------------------ class MelDecalData(MelOptStruct): diff --git a/Mopy/bash/game/enderal/__init__.py b/Mopy/bash/game/enderal/__init__.py index 476019ee1e..7ff3e21f04 100644 --- a/Mopy/bash/game/enderal/__init__.py +++ b/Mopy/bash/game/enderal/__init__.py @@ -120,13 +120,13 @@ class Bain(SkyrimGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreFlst, MreGlob from ..skyrim.records import MreCell, MreWrld, MreFact, MreAchr, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ MreLvsp, MreEnch, MreProj, MreDlbr, MreRfct, MreMisc, MreActi, \ MreEqup, MreCpth, MreDoor, MreAnio, MreHazd, MreIdlm, MreEczn, \ MreIdle, MreLtex, MreQust, MreMstt, MreNpc, MreIpds, MrePack, \ - MreGmst, MreRevb, MreClmt, MreDebr, MreSmbn, MreLvli, MreSpel, \ + MreGmst, MreRevb, MreClmt, MreDial, MreSmbn, MreLvli, MreSpel, \ MreKywd, MreLvln, MreAact, MreSlgm, MreRegn, MreFurn, MreGras, \ MreAstp, MreWoop, MreMovt, MreCobj, MreShou, MreSmen, MreNavm, \ MreArto, MreAddn, MreSopm, MreCsty, MreAppa, MreArma, MreArmo, \ @@ -136,8 +136,7 @@ def init(cls): MreLscr, MreDlvw, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ - MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk, MreRace, \ - MreDial + MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk, MreRace cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, diff --git a/Mopy/bash/game/enderalse/__init__.py b/Mopy/bash/game/enderalse/__init__.py index 9a223e36f2..4b19cc0850 100644 --- a/Mopy/bash/game/enderalse/__init__.py +++ b/Mopy/bash/game/enderalse/__init__.py @@ -99,13 +99,13 @@ class Bain(EnderalGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreFlst, MreGlob from ..skyrimse.records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreDebr, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -116,8 +116,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr, \ - MreRace + MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, diff --git a/Mopy/bash/game/fallout3/__init__.py b/Mopy/bash/game/fallout3/__init__.py index d47b7d10e1..9815ad1efc 100644 --- a/Mopy/bash/game/fallout3/__init__.py +++ b/Mopy/bash/game/fallout3/__init__.py @@ -295,11 +295,11 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreFlst, MreGlob + from ...brec import MreDebr, MreFlst, MreGlob from .records import MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, \ MreArma, MreArmo, MreAspc, MreAvif, MreBook, MreBptd, MreCams, \ MreClas, MreClmt, MreCobj, MreCont, MreCpth, MreCrea, MreCsty, \ - MreDebr, MreDobj, MreDoor, MreEczn, MreEfsh, MreEnch, MreExpl, \ + MreWrld, MreDobj, MreDoor, MreEczn, MreEfsh, MreEnch, MreExpl, \ MreEyes, MreFact, MreFurn, MreGras, MreHair, MreHdpt, MreTes4, \ MreIdle, MreIdlm, MreImad, MreImgs, MreIngr, MreIpct, MreIpds, \ MreKeym, MreLgtm, MreLigh, MreLscr, MreLtex, MreLvlc, MreLvli, \ @@ -308,8 +308,7 @@ def init(cls): MreRace, MreRads, MreRegn, MreRgdl, MreScol, MreScpt, MreSoun, \ MreSpel, MreStat, MreTact, MreTerm, MreTree, MreTxst, MreVtyp, \ MreWatr, MreWeap, MreWthr, MreAchr, MreAcre, MreCell, MreDial, \ - MreGmst, MreInfo, MreNavi, MreNavm, MrePgre, MrePmis, MreRefr, \ - MreWrld + MreGmst, MreInfo, MreNavi, MreNavm, MrePgre, MrePmis, MreRefr cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreArma, MreArmo, MreAspc, MreAvif, MreBook, MreBptd, MreCams, MreClas, MreClmt, diff --git a/Mopy/bash/game/fallout3/records.py b/Mopy/bash/game/fallout3/records.py index ab58ddb17d..4b3e7ed322 100644 --- a/Mopy/bash/game/fallout3/records.py +++ b/Mopy/bash/game/fallout3/records.py @@ -986,22 +986,6 @@ class MreCsty(MelRecord): ) __slots__ = melSet.getSlotsUsed() -#------------------------------------------------------------------------------ -class MreDebr(MelRecord): - """Debris.""" - rec_sig = b'DEBR' - - dataFlags = Flags.from_names(u'hasCollissionData') - - melSet = MelSet( - MelEdid(), - MelGroups(u'models', - MelDebrData(), - MelBase(b'MODT', u'modt_p'), - ), - ) - __slots__ = melSet.getSlotsUsed() - #------------------------------------------------------------------------------ class MreDial(MelRecord): """Dialogue.""" diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index 2c35c7d580..a9f62fe790 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -218,7 +218,7 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl + from ...brec import MreColl, MreDebr from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ @@ -228,7 +228,7 @@ def init(cls): 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, + MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -264,7 +264,7 @@ def init(cls): 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, + MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/falloutnv/__init__.py b/Mopy/bash/game/falloutnv/__init__.py index fcfae54cde..84f4e5f94d 100644 --- a/Mopy/bash/game/falloutnv/__init__.py +++ b/Mopy/bash/game/falloutnv/__init__.py @@ -140,7 +140,7 @@ def _dynamic_import_modules(cls, package_name): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreFlst, MreGlob + from ...brec import MreDebr, MreFlst, MreGlob from .records import MreTes4, MreAloc, MreAmef, MreCcrd, MreCdck, \ MreChal, MreChip, MreCmny, MreCsno, MreDehy, MreDial, MreHung, \ MreImod, MreLsct, MreMset, MreRcct, MreRcpe, MreRepu, MreSlpd, \ @@ -148,7 +148,7 @@ def init(cls): from ..fallout3.records import MreCpth, MreIdle, MreMesg, MrePack, \ MrePerk, MreQust, MreSpel, MreTerm, MreNpc, MreAddn, MreAnio, \ MreAvif, MreBook, MreBptd, MreCams, MreClas, MreClmt, MreCobj, \ - MreCrea, MreDebr, MreDoor, MreEczn, MreEfsh, MreExpl, MreEyes, \ + MreCrea, MreWeap, MreDoor, MreEczn, MreEfsh, MreExpl, MreEyes, \ MreFurn, MreGras, MreHair, MreIdlm, MreImgs, MreIngr, MreRace, \ MreIpds, MreLgtm, MreLtex, MreLvlc, MreLvli, MreLvln, MreMgef, \ MreMicn, MreMstt, MreNavi, MreNavm, MreNote, MrePwat, MreRads, \ @@ -157,7 +157,7 @@ def init(cls): MreCont, MreAchr, MreAcre, MreCell, MreCsty, MreDobj, MreEnch, \ MreFact, MreGmst, MreHdpt, MreImad, MreInfo, MreIpct, MreKeym, \ MreLigh, MreLscr, MreMisc, MreMusc, MrePgre, MrePmis, MreProj, \ - MreRefr, MreRegn, MreSoun, MreStat, MreTact, MreWeap + MreRefr, MreRegn, MreSoun, MreStat, MreTact cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( MreActi, MreAddn, MreAlch, MreAloc, MreAmef, MreAmmo, MreAnio, MreArma, MreArmo, MreAspc, MreAvif, MreBook, MreBptd, MreCams, diff --git a/Mopy/bash/game/skyrim/__init__.py b/Mopy/bash/game/skyrim/__init__.py index c1f0ad4eed..de9a523638 100644 --- a/Mopy/bash/game/skyrim/__init__.py +++ b/Mopy/bash/game/skyrim/__init__.py @@ -280,13 +280,13 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreFlst, MreGlob from .records import MreCell, MreWrld, MreFact, MreAchr, MreDial, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ MreLvsp, MreEnch, MreProj, MreDlbr, MreRfct, MreMisc, MreActi, \ MreEqup, MreCpth, MreDoor, MreAnio, MreHazd, MreIdlm, MreEczn, \ MreIdle, MreLtex, MreQust, MreMstt, MreNpc, MreIpds, MrePack, \ - MreGmst, MreRevb, MreClmt, MreDebr, MreSmbn, MreLvli, MreSpel, \ + MreGmst, MreRevb, MreClmt, MreRace, MreSmbn, MreLvli, MreSpel, \ MreKywd, MreLvln, MreAact, MreSlgm, MreRegn, MreFurn, MreGras, \ MreAstp, MreWoop, MreMovt, MreCobj, MreShou, MreSmen, MreNavm, \ MreArto, MreAddn, MreSopm, MreCsty, MreAppa, MreArma, MreArmo, \ @@ -296,7 +296,7 @@ def init(cls): MreLscr, MreDlvw, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ - MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk, MreRace + MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index 4d7bb9ca07..a534899461 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -998,22 +998,6 @@ class MreCsty(MelRecord): ) __slots__ = melSet.getSlotsUsed() -#------------------------------------------------------------------------------ -class MreDebr(MelRecord): - """Debris.""" - rec_sig = b'DEBR' - - dataFlags = Flags.from_names('hasCollissionData') - - melSet = MelSet( - MelEdid(), - MelGroups('models', - MelDebrData(), - MelBase(b'MODT','modt_p'), - ), - ) - __slots__ = melSet.getSlotsUsed() - #------------------------------------------------------------------------------ class MreDial(MelRecord): """Dialogue.""" diff --git a/Mopy/bash/game/skyrimse/__init__.py b/Mopy/bash/game/skyrimse/__init__.py index 42ac716242..d84edd8046 100644 --- a/Mopy/bash/game/skyrimse/__init__.py +++ b/Mopy/bash/game/skyrimse/__init__.py @@ -271,13 +271,13 @@ class Esp(SkyrimGameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreFlst, MreGlob from .records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreDebr, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -288,8 +288,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr, \ - MreRace + MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, diff --git a/Mopy/bash/game/skyrimvr/__init__.py b/Mopy/bash/game/skyrimvr/__init__.py index b949d0d9aa..0f5b507a47 100644 --- a/Mopy/bash/game/skyrimvr/__init__.py +++ b/Mopy/bash/game/skyrimvr/__init__.py @@ -74,13 +74,13 @@ class Bain(SkyrimSEGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreFlst, MreGlob from ..skyrimse.records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreDebr, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -91,8 +91,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr, \ - MreRace + MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, From b94172aef8fa3a4640a4a31561e1c38831340bbd Mon Sep 17 00:00:00 2001 From: Infernio Date: Mon, 22 Aug 2022 10:06:56 +0200 Subject: [PATCH 09/13] FO4: Implement DFOB --- Mopy/bash/game/fallout4/__init__.py | 6 +++--- Mopy/bash/game/fallout4/records.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index a9f62fe790..d2878bfbaa 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -222,13 +222,13 @@ def init(cls): from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ - MreCmpo, MreCobj, MreCont, MreCpth, MreCsty, \ + MreCmpo, MreCobj, MreCont, MreCpth, MreCsty, MreDfob, \ 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, + MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreDfob, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -264,7 +264,7 @@ def init(cls): 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, + MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreDfob, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index 65c1e1dcbc..5c0572b06a 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -888,6 +888,17 @@ class MreCsty(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreDfob(MelRecord): + """Default Object.""" + rec_sig = b'DFOB' + + melSet = MelSet( + MelEdid(), + MelFid(b'DATA', 'default_object'), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreGmst(AMreGmst): """Game Setting.""" From dcbce061531605ef22f8b275976afa3557d10adb Mon Sep 17 00:00:00 2001 From: Infernio Date: Mon, 22 Aug 2022 10:13:33 +0200 Subject: [PATCH 10/13] Move DLBR to brec --- Mopy/bash/brec/common_records.py | 16 ++++++++++++++++ Mopy/bash/game/enderal/__init__.py | 6 +++--- Mopy/bash/game/enderalse/__init__.py | 6 +++--- Mopy/bash/game/fallout4/__init__.py | 6 +++--- Mopy/bash/game/skyrim/__init__.py | 6 +++--- Mopy/bash/game/skyrim/records.py | 16 ---------------- Mopy/bash/game/skyrimse/__init__.py | 6 +++--- Mopy/bash/game/skyrimvr/__init__.py | 6 +++--- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Mopy/bash/brec/common_records.py b/Mopy/bash/brec/common_records.py index 84cc08f090..217ed19e30 100644 --- a/Mopy/bash/brec/common_records.py +++ b/Mopy/bash/brec/common_records.py @@ -363,6 +363,22 @@ class MreDebr(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreDlbr(MelRecord): + """Dialog Branch.""" + rec_sig = b'DLBR' + + _dlbr_flags = Flags.from_names('top_level', 'blocking', 'exclusive') + + melSet = MelSet( + MelEdid(), + MelFid(b'QNAM', 'dlbr_quest'), + MelUInt32(b'TNAM', 'dlbr_category'), + MelUInt32Flags(b'DNAM', 'dlbr_flags', _dlbr_flags), + MelFid(b'SNAM', 'starting_topic'), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreFlst(MelRecord): """FormID List.""" diff --git a/Mopy/bash/game/enderal/__init__.py b/Mopy/bash/game/enderal/__init__.py index 7ff3e21f04..1e07be4860 100644 --- a/Mopy/bash/game/enderal/__init__.py +++ b/Mopy/bash/game/enderal/__init__.py @@ -120,10 +120,10 @@ class Bain(SkyrimGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob from ..skyrim.records import MreCell, MreWrld, MreFact, MreAchr, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ - MreLvsp, MreEnch, MreProj, MreDlbr, MreRfct, MreMisc, MreActi, \ + MreLvsp, MreEnch, MreProj, MreRace, MreRfct, MreMisc, MreActi, \ MreEqup, MreCpth, MreDoor, MreAnio, MreHazd, MreIdlm, MreEczn, \ MreIdle, MreLtex, MreQust, MreMstt, MreNpc, MreIpds, MrePack, \ MreGmst, MreRevb, MreClmt, MreDial, MreSmbn, MreLvli, MreSpel, \ @@ -136,7 +136,7 @@ def init(cls): MreLscr, MreDlvw, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ - MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk, MreRace + MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, diff --git a/Mopy/bash/game/enderalse/__init__.py b/Mopy/bash/game/enderalse/__init__.py index 4b19cc0850..afc51b766e 100644 --- a/Mopy/bash/game/enderalse/__init__.py +++ b/Mopy/bash/game/enderalse/__init__.py @@ -99,13 +99,13 @@ class Bain(EnderalGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob from ..skyrimse.records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreRace, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreWthr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -116,7 +116,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr + MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index d2878bfbaa..8a2911994b 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -218,7 +218,7 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr + from ...brec import MreColl, MreDebr, MreDlbr from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ @@ -228,7 +228,7 @@ def init(cls): 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, + MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreDfob, MreDlbr, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -264,7 +264,7 @@ def init(cls): 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, + MreColl, MreCont, MreCpth, MreCsty, MreDebr, MreDfob, MreDlbr, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/skyrim/__init__.py b/Mopy/bash/game/skyrim/__init__.py index de9a523638..9b6e6d42c1 100644 --- a/Mopy/bash/game/skyrim/__init__.py +++ b/Mopy/bash/game/skyrim/__init__.py @@ -280,10 +280,10 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob from .records import MreCell, MreWrld, MreFact, MreAchr, MreDial, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ - MreLvsp, MreEnch, MreProj, MreDlbr, MreRfct, MreMisc, MreActi, \ + MreLvsp, MreEnch, MreProj, MrePerk, MreRfct, MreMisc, MreActi, \ MreEqup, MreCpth, MreDoor, MreAnio, MreHazd, MreIdlm, MreEczn, \ MreIdle, MreLtex, MreQust, MreMstt, MreNpc, MreIpds, MrePack, \ MreGmst, MreRevb, MreClmt, MreRace, MreSmbn, MreLvli, MreSpel, \ @@ -296,7 +296,7 @@ def init(cls): MreLscr, MreDlvw, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ - MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk + MreAspc, MreRela, MreEfsh, MreSnct, MreOtft cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index a534899461..0fdad513cd 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -1018,22 +1018,6 @@ class MreDial(MelRecord): ) __slots__ = melSet.getSlotsUsed() -#------------------------------------------------------------------------------ -class MreDlbr(MelRecord): - """Dialog Branch.""" - rec_sig = b'DLBR' - - DialogBranchFlags = Flags.from_names('topLevel', 'blocking', 'exclusive') - - melSet = MelSet( - MelEdid(), - MelFid(b'QNAM','quest',), - MelUInt32(b'TNAM', u'category'), - MelUInt32Flags(b'DNAM', u'flags', DialogBranchFlags), - MelFid(b'SNAM','startingTopic',), - ) - __slots__ = melSet.getSlotsUsed() - #------------------------------------------------------------------------------ class MreDlvw(MelRecord): """Dialog View""" diff --git a/Mopy/bash/game/skyrimse/__init__.py b/Mopy/bash/game/skyrimse/__init__.py index d84edd8046..6cf72ba769 100644 --- a/Mopy/bash/game/skyrimse/__init__.py +++ b/Mopy/bash/game/skyrimse/__init__.py @@ -271,13 +271,13 @@ class Esp(SkyrimGameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob from .records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreRace, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreWthr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -288,7 +288,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr + MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, diff --git a/Mopy/bash/game/skyrimvr/__init__.py b/Mopy/bash/game/skyrimvr/__init__.py index 0f5b507a47..a6c146b8c0 100644 --- a/Mopy/bash/game/skyrimvr/__init__.py +++ b/Mopy/bash/game/skyrimvr/__init__.py @@ -74,13 +74,13 @@ class Bain(SkyrimSEGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob from ..skyrimse.records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreRace, MreDial, MreDlbr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreWthr, MreDlvw, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -91,7 +91,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap, MreWthr + MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, From 0c5a4267f4f7075e445f428fae5eda0bcfc1fae6 Mon Sep 17 00:00:00 2001 From: Infernio Date: Mon, 22 Aug 2022 10:24:10 +0200 Subject: [PATCH 11/13] Move DLVW to brec --- Mopy/bash/brec/common_records.py | 17 +++++++++++++++++ Mopy/bash/game/enderal/__init__.py | 7 ++++--- Mopy/bash/game/enderalse/__init__.py | 7 ++++--- Mopy/bash/game/fallout4/__init__.py | 4 +++- Mopy/bash/game/skyrim/__init__.py | 7 ++++--- Mopy/bash/game/skyrim/records.py | 17 ----------------- Mopy/bash/game/skyrimse/__init__.py | 7 ++++--- Mopy/bash/game/skyrimvr/__init__.py | 7 ++++--- 8 files changed, 40 insertions(+), 33 deletions(-) diff --git a/Mopy/bash/brec/common_records.py b/Mopy/bash/brec/common_records.py index 217ed19e30..d2249f866f 100644 --- a/Mopy/bash/brec/common_records.py +++ b/Mopy/bash/brec/common_records.py @@ -379,6 +379,23 @@ class MreDlbr(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreDlvw(MelRecord): + """Dialog View""" + rec_sig = b'DLVW' + + melSet = MelSet( + MelEdid(), + MelFid(b'QNAM', 'dlvw_quest'), + MelFids('dlvw_branches', MelFid(b'BNAM')), + MelGroups('unknown_tnam', + MelBase(b'TNAM', 'unknown1'), + ), + MelBase(b'ENAM', 'unknown_enam'), + MelBase(b'DNAM', 'unknown_dnam'), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreFlst(MelRecord): """FormID List.""" diff --git a/Mopy/bash/game/enderal/__init__.py b/Mopy/bash/game/enderal/__init__.py index 1e07be4860..56acdf239f 100644 --- a/Mopy/bash/game/enderal/__init__.py +++ b/Mopy/bash/game/enderal/__init__.py @@ -120,7 +120,8 @@ class Bain(SkyrimGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreDlvw, MreFlst, \ + MreGlob from ..skyrim.records import MreCell, MreWrld, MreFact, MreAchr, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ MreLvsp, MreEnch, MreProj, MreRace, MreRfct, MreMisc, MreActi, \ @@ -133,10 +134,10 @@ def init(cls): MreKeym, MreTxst, MreHdpt, MreTes4, MreAlch, MreBook, MreSpgd, \ MreSndr, MreImgs, MreScrl, MreMust, MreFstp, MreFsts, MreMgef, \ MreLgtm, MreMusc, MreClas, MreLctn, MreTact, MreBptd, MreDobj, \ - MreLscr, MreDlvw, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ + MreLscr, MrePerk, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ - MreAspc, MreRela, MreEfsh, MreSnct, MreOtft, MrePerk + MreAspc, MreRela, MreEfsh, MreSnct, MreOtft cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, diff --git a/Mopy/bash/game/enderalse/__init__.py b/Mopy/bash/game/enderalse/__init__.py index afc51b766e..2cc7e3d9ee 100644 --- a/Mopy/bash/game/enderalse/__init__.py +++ b/Mopy/bash/game/enderalse/__init__.py @@ -99,13 +99,14 @@ class Bain(EnderalGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreDlvw, MreFlst, \ + MreGlob from ..skyrimse.records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreRace, MreDial, MreWthr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreWthr, MreWeap, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -116,7 +117,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap + MreAmmo, MreLtex, MreMato, MreStat, MreWatr cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index 8a2911994b..246e880789 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -218,7 +218,7 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreDlbr + from ...brec import MreColl, MreDebr, MreDlbr, MreDlvw from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ @@ -229,6 +229,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, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -265,6 +266,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, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/skyrim/__init__.py b/Mopy/bash/game/skyrim/__init__.py index 9b6e6d42c1..38900a7468 100644 --- a/Mopy/bash/game/skyrim/__init__.py +++ b/Mopy/bash/game/skyrim/__init__.py @@ -280,7 +280,8 @@ class Esp(GameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreDlvw, MreFlst, \ + MreGlob from .records import MreCell, MreWrld, MreFact, MreAchr, MreDial, \ MreInfo, MreCams, MreWthr, MreDual, MreMato, MreVtyp, MreMatt, \ MreLvsp, MreEnch, MreProj, MrePerk, MreRfct, MreMisc, MreActi, \ @@ -293,10 +294,10 @@ def init(cls): MreKeym, MreTxst, MreHdpt, MreTes4, MreAlch, MreBook, MreSpgd, \ MreSndr, MreImgs, MreScrl, MreMust, MreFstp, MreFsts, MreMgef, \ MreLgtm, MreMusc, MreClas, MreLctn, MreTact, MreBptd, MreDobj, \ - MreLscr, MreDlvw, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ + MreLscr, MreOtft, MreTree, MreWatr, MreFlor, MreEyes, MreWeap, \ MreIngr, MreClfm, MreMesg, MreLigh, MreExpl, MreLcrt, MreStat, \ MreAmmo, MreSmqn, MreImad, MreSoun, MreAvif, MreCont, MreIpct, \ - MreAspc, MreRela, MreEfsh, MreSnct, MreOtft + MreAspc, MreRela, MreEfsh, MreSnct cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in (# MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, MreAstp, MreAvif, MreBook, diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index 0fdad513cd..e56114e771 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -1018,23 +1018,6 @@ class MreDial(MelRecord): ) __slots__ = melSet.getSlotsUsed() -#------------------------------------------------------------------------------ -class MreDlvw(MelRecord): - """Dialog View""" - rec_sig = b'DLVW' - - melSet = MelSet( - MelEdid(), - MelFid(b'QNAM','quest',), - MelFids('branches', MelFid(b'BNAM')), - MelGroups('unknownTNAM', - MelBase(b'TNAM','unknown',), - ), - MelBase(b'ENAM','unknownENAM'), - MelBase(b'DNAM','unknownDNAM'), - ) - __slots__ = melSet.getSlotsUsed() - #------------------------------------------------------------------------------ class MreDobj(MelRecord): """Default Object Manager.""" diff --git a/Mopy/bash/game/skyrimse/__init__.py b/Mopy/bash/game/skyrimse/__init__.py index 6cf72ba769..ad6d984858 100644 --- a/Mopy/bash/game/skyrimse/__init__.py +++ b/Mopy/bash/game/skyrimse/__init__.py @@ -271,13 +271,14 @@ class Esp(SkyrimGameInfo.Esp): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreDlvw, MreFlst, \ + MreGlob from .records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreRace, MreDial, MreWthr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreWthr, MreWeap, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -288,7 +289,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap + MreAmmo, MreLtex, MreMato, MreStat, MreWatr cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, diff --git a/Mopy/bash/game/skyrimvr/__init__.py b/Mopy/bash/game/skyrimvr/__init__.py index a6c146b8c0..709784eb96 100644 --- a/Mopy/bash/game/skyrimvr/__init__.py +++ b/Mopy/bash/game/skyrimvr/__init__.py @@ -74,13 +74,14 @@ class Bain(SkyrimSEGameInfo.Bain): @classmethod def init(cls): cls._dynamic_import_modules(__name__) - from ...brec import MreColl, MreDebr, MreDlbr, MreFlst, MreGlob + from ...brec import MreColl, MreDebr, MreDlbr, MreDlvw, MreFlst, \ + MreGlob from ..skyrimse.records import MreVoli, MreLens from ..skyrim.records import MreAact, MreAchr, MreActi, MreAddn, \ MreAlch, MreAnio, MreAppa, MreArma, MreArmo, MreArto, MreAspc, \ MreAstp, MreAvif, MreBook, MreBptd, MreCams, MreCell, MreClas, \ MreClfm, MreClmt, MreCobj, MreNavm, MreCont, MreCpth, MreCsty, \ - MreRace, MreDial, MreWthr, MreDlvw, MreDobj, MreDoor, MreDual, \ + MreRace, MreDial, MreWthr, MreWeap, MreDobj, MreDoor, MreDual, \ MreEczn, MreEfsh, MreEnch, MreEqup, MreExpl, MreEyes, MreFact, \ MreFlor, MreFstp, MreFsts, MreFurn, MreGmst, MreGras, MrePack, \ MreHazd, MreHdpt, MreTes4, MreIdle, MreIdlm, MreImad, MreImgs, \ @@ -91,7 +92,7 @@ def init(cls): MreRela, MreRevb, MreRfct, MreScrl, MreShou, MreSlgm, MreSmbn, \ MreSmen, MreSmqn, MreSnct, MreSndr, MreSopm, MreSoun, MreSpel, \ MreSpgd, MreTact, MreTree, MreTxst, MreVtyp, MreWoop, MreWrld, \ - MreAmmo, MreLtex, MreMato, MreStat, MreWatr, MreWeap + MreAmmo, MreLtex, MreMato, MreStat, MreWatr cls.mergeable_sigs = {clazz.rec_sig: clazz for clazz in ( # MreAchr, MreDial, MreInfo, MreAact, MreActi, MreAddn, MreAlch, MreAmmo, MreAnio, MreAppa, From 9cbf30865d4d28e367e30be77db0addc4ef9936d Mon Sep 17 00:00:00 2001 From: Infernio Date: Mon, 22 Aug 2022 11:05:58 +0200 Subject: [PATCH 12/13] FO4: Implement DMGT The first record type for which upgrading is entirely out of the question, meaning we need a framework for skipping form version upgrades and a decider for handling form version info. --- Mopy/bash/brec/advanced_elements.py | 20 ++++++++++++++++++++ Mopy/bash/brec/mod_io.py | 15 ++++++++++----- Mopy/bash/game/fallout4/__init__.py | 10 +++++++--- Mopy/bash/game/fallout4/records.py | 28 ++++++++++++++++++++++++---- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/Mopy/bash/brec/advanced_elements.py b/Mopy/bash/brec/advanced_elements.py index 39e4b54246..7582d33ecd 100644 --- a/Mopy/bash/brec/advanced_elements.py +++ b/Mopy/bash/brec/advanced_elements.py @@ -29,6 +29,7 @@ __author__ = u'Infernio' import copy +import operator from collections import OrderedDict from itertools import chain @@ -680,6 +681,25 @@ def _decide_common(self, record): return all(getattr(flags_val, flag_name) for flag_name in self._required_flags) +class FormVersionDecider(ACommonDecider): + """Decider that checks if the record's form version against a target form + version.""" + def __init__(self, comp_op, target_form_ver: int): + """Creates a new SinceFormVersionDecider with the specified target form + version. + + :param comp_op: A callable that takes two integers. The first will be + the record's form version and the second will be target_form_ver. + The return value of this callable will be what's returned by the + decider. operator.ge is an example of a valid callable here. + :param target_form_ver: The form version in which the change was + introduced.""" + self._comp_op = comp_op + self._target_form_ver = target_form_ver + + def _decide_common(self, record): + return self._comp_op(record.header.form_version, self._target_form_ver) + class PartialLoadDecider(ADecider): """Partially loads a subrecord using a given loader, then rewinds the input stream and delegates to a given decider. Can decide at dump-time diff --git a/Mopy/bash/brec/mod_io.py b/Mopy/bash/brec/mod_io.py index e1855c3b16..28d29f3631 100644 --- a/Mopy/bash/brec/mod_io.py +++ b/Mopy/bash/brec/mod_io.py @@ -60,6 +60,9 @@ class RecordHeader(object): valid_header_sigs = set() #--Plugin form version, we must pack this in the TES4 header plugin_form_version = 0 + # A set of record types for which to skip upgrading to the latest Form + # Version, usually because it's impossible + skip_form_version_upgrade = set() is_top_group_header = False __slots__ = (u'recType', u'size', u'extra') @@ -98,11 +101,13 @@ def pack_head(self, __rh=RecordHeader): pack_args = [__rh.rec_pack_format_str, self.recType, self.size, self.flags1, self.fid.dump(), self.flags2] if __rh.plugin_form_version: - extra1, extra2 = struct_unpack(u'=2h', - struct_pack(u'=I', self.extra)) - extra1 = __rh.plugin_form_version - self.extra = \ - struct_unpack(u'=I', struct_pack(u'=2h', extra1, extra2))[0] + # Upgrade to latest form version unless we were told to skip that + if self.recType not in __rh.skip_form_version_upgrade: + extra1, extra2 = struct_unpack('=2h', struct_pack( + '=I', self.extra)) + extra1 = __rh.plugin_form_version + self.extra = struct_unpack('=I', struct_pack( + '=2h', extra1, extra2))[0] pack_args.append(self.extra) return struct_pack(*pack_args) diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index 246e880789..c46e94824e 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -222,14 +222,14 @@ def init(cls): from .records import MreAact, MreActi, MreAddn, MreAech, MreAmdl, \ MreAnio, MreAoru, MreArma, MreArmo, MreArto, MreAstp, MreAvif, \ MreBnds, MreBook, MreBptd, MreCams, MreClas, MreClfm, MreClmt, \ - MreCmpo, MreCobj, MreCont, MreCpth, MreCsty, MreDfob, \ + MreCmpo, MreCobj, MreCont, MreCpth, MreCsty, MreDfob, MreDmgt, \ 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, + MreDlvw, MreDmgt, MreGmst, MreLvli, MreLvln, MrePerk, )} # Setting RecordHeader class variables -------------------------------- @@ -261,12 +261,16 @@ def init(cls): b'PBEA', b'PFLA', b'PCON', b'PBAR', b'PHZD', b'LAND', b'NAVM', b'DIAL', b'INFO'}) header_type.plugin_form_version = 131 + # DMGT\DNAM changed completely in Form Version 78 and it's not possible + # to upgrade it (unless someone reverse engineers what the game does to + # it when loading) + header_type.skip_form_version_upgrade = {b'DMGT'} brec.MreRecord.type_class = {x.rec_sig: x for x 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, + MreDlvw, MreDmgt, MreGmst, MreLvli, MreLvln, MrePerk, MreTes4, )} brec.MreRecord.simpleTypes = ( diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index 5c0572b06a..2b7b069fb4 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -21,6 +21,8 @@ # # ============================================================================= """This module contains the Fallout 4 record classes.""" +import operator + from ...bolt import Flags from ...brec import MelBase, MelGroup, AMreHeader, MelSet, MelString, \ MelStruct, MelNull, MelSimpleArray, AMreLeveledList, MelFid, MelAttx, \ @@ -41,7 +43,7 @@ MelBookText, MelBookDescription, MelInventoryArt, MelUnorderedGroups, \ MelImageSpaceMod, MelClmtWeatherTypes, MelClmtTiming, MelClmtTextures, \ MelCobjOutput, AMreWithItems, AMelItems, MelContData, MelSoundClose, \ - MelCpthShared + MelCpthShared, FormVersionDecider ##: What about texture hashes? I carried discarding them forward from Skyrim, # but that was due to the 43-44 problems. See also #620. @@ -137,13 +139,13 @@ class MelDestructible(MelGroup): def __init__(self): super().__init__('destructible', MelStruct(b'DEST', ['i', '2B', '2s'], 'health', 'count', - (MelDestructible._dest_header_flags, 'dest_flags'), + (self._dest_header_flags, 'dest_flags'), 'dest_unknown'), MelResistances(b'DAMC'), MelGroups('stages', MelStruct(b'DSTD', ['4B', 'i', '2I', 'i'], 'health', 'index', 'damage_stage', - (MelDestructible._dest_stage_flags, 'stage_flags'), + (self._dest_stage_flags, 'stage_flags'), 'self_damage_per_second', (FID, 'explosion'), (FID, 'debris'), 'debris_count'), MelString(b'DSTA', 'sequence_name'), @@ -778,7 +780,8 @@ class MreCobj(MelRecord): MelEdid(), MelSoundPickupDrop(), MelSorted(MelArray('cobj_components', - MelStruct(b'FVPA', ['2I'], 'component_fid', 'component_count'), + MelStruct(b'FVPA', ['2I'], (FID, 'component_fid'), + 'component_count'), ), sort_by_attrs='component_fid'), MelDescription(), MelConditionList(), @@ -899,6 +902,23 @@ class MreDfob(MelRecord): ) __slots__ = melSet.getSlotsUsed() +#------------------------------------------------------------------------------ +class MreDmgt(MelRecord): + """Damage Type.""" + rec_sig = b'DMGT' + + melSet = MelSet( + MelEdid(), + MelUnion({ + True: MelArray('damage_types', + MelStruct(b'DNAM', ['2I'], (FID, 'dt_actor_value'), + (FID, 'dt_spell')), + ), + False: MelSimpleArray('damage_types', MelUInt32(b'DNAM')), + }, decider=FormVersionDecider(operator.ge, 78)), + ) + __slots__ = melSet.getSlotsUsed() + #------------------------------------------------------------------------------ class MreGmst(AMreGmst): """Game Setting.""" From 47d601b102e2a57454458e326c05d31e0f4973f2 Mon Sep 17 00:00:00 2001 From: Infernio Date: Mon, 22 Aug 2022 11:14:38 +0200 Subject: [PATCH 13/13] FO4: Implement DOBJ, DOOR and DUAL 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. --- Mopy/bash/brec/common_subrecords.py | 43 +++++++++++++++- Mopy/bash/game/fallout3/patcher/__init__.py | 2 +- Mopy/bash/game/fallout3/records.py | 16 ++---- Mopy/bash/game/fallout4/__init__.py | 23 ++++----- Mopy/bash/game/fallout4/records.py | 55 ++++++++++++++++++++- Mopy/bash/game/fallout4vr/__init__.py | 18 +++---- Mopy/bash/game/oblivion/patcher/__init__.py | 2 +- Mopy/bash/game/oblivion/records.py | 12 ++--- Mopy/bash/game/skyrim/patcher/__init__.py | 2 +- Mopy/bash/game/skyrim/records.py | 32 +++++------- 10 files changed, 140 insertions(+), 65 deletions(-) diff --git a/Mopy/bash/brec/common_subrecords.py b/Mopy/bash/brec/common_subrecords.py index e28d6fb0bb..2cc928d9e3 100644 --- a/Mopy/bash/brec/common_subrecords.py +++ b/Mopy/bash/brec/common_subrecords.py @@ -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 #------------------------------------------------------------------------------ @@ -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.""" @@ -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.).""" @@ -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. diff --git a/Mopy/bash/game/fallout3/patcher/__init__.py b/Mopy/bash/game/fallout3/patcher/__init__.py index d5acce7b5c..db8d3e1dc3 100644 --- a/Mopy/bash/game/fallout3/patcher/__init__.py +++ b/Mopy/bash/game/fallout3/patcher/__init__.py @@ -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',), diff --git a/Mopy/bash/game/fallout3/records.py b/Mopy/bash/game/fallout3/records.py index 4b3e7ed322..8df1e64d88 100644 --- a/Mopy/bash/game/fallout3/records.py +++ b/Mopy/bash/game/fallout3/records.py @@ -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' @@ -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(), @@ -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() diff --git a/Mopy/bash/game/fallout4/__init__.py b/Mopy/bash/game/fallout4/__init__.py index c46e94824e..f0e9db49f0 100644 --- a/Mopy/bash/game/fallout4/__init__.py +++ b/Mopy/bash/game/fallout4/__init__.py @@ -223,13 +223,14 @@ 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 -------------------------------- @@ -237,11 +238,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', @@ -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', @@ -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 = ( diff --git a/Mopy/bash/game/fallout4/records.py b/Mopy/bash/game/fallout4/records.py index 2b7b069fb4..6c4c88155f 100644 --- a/Mopy/bash/game/fallout4/records.py +++ b/Mopy/bash/game/fallout4/records.py @@ -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. @@ -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.""" diff --git a/Mopy/bash/game/fallout4vr/__init__.py b/Mopy/bash/game/fallout4vr/__init__.py index 28ddff6928..c7e2680fa0 100644 --- a/Mopy/bash/game/fallout4vr/__init__.py +++ b/Mopy/bash/game/fallout4vr/__init__.py @@ -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', @@ -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', diff --git a/Mopy/bash/game/oblivion/patcher/__init__.py b/Mopy/bash/game/oblivion/patcher/__init__.py index 9de5fdf403..2448067142 100644 --- a/Mopy/bash/game/oblivion/patcher/__init__.py +++ b/Mopy/bash/game/oblivion/patcher/__init__.py @@ -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',), diff --git a/Mopy/bash/game/oblivion/records.py b/Mopy/bash/game/oblivion/records.py index ded889698f..fc5b83d096 100644 --- a/Mopy/bash/game/oblivion/records.py +++ b/Mopy/bash/game/oblivion/records.py @@ -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 ------------------------------------------------------------- @@ -907,9 +908,6 @@ class MreDoor(MelRecord): """Door.""" rec_sig = b'DOOR' - _flags = Flags.from_names('oblivionGate', 'automatic', 'hidden', - 'minimalUse') - melSet = MelSet( MelEdid(), MelFull(), @@ -917,9 +915,9 @@ class MreDoor(MelRecord): 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() diff --git a/Mopy/bash/game/skyrim/patcher/__init__.py b/Mopy/bash/game/skyrim/patcher/__init__.py index e8c992d826..2fbdc1d6c4 100644 --- a/Mopy/bash/game/skyrim/patcher/__init__.py +++ b/Mopy/bash/game/skyrim/patcher/__init__.py @@ -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',), diff --git a/Mopy/bash/game/skyrim/records.py b/Mopy/bash/game/skyrim/records.py index e56114e771..16a7c82656 100644 --- a/Mopy/bash/game/skyrim/records.py +++ b/Mopy/bash/game/skyrim/records.py @@ -38,7 +38,7 @@ MelEnchantment, MelDecalData, MelDescription, MelSInt16, MelSkipInterior, \ MelSoundPickupDrop, MelActivateParents, BipedFlags, MelColor, \ MelColorO, MelSpells, MelFixedString, MelUInt8Flags, MelUInt16Flags, \ - MelUInt32Flags, MelOwnership, MelDebrData, MelClmtWeatherTypes, AMelVmad, \ + MelUInt32Flags, MelOwnership, MelClmtWeatherTypes, AMelVmad, \ MelActorSounds, MelFactionRanks, MelSorted, MelReflectedRefractedBy, \ perk_effect_key, MelValueWeight, MelSound, MelWaterType, \ MelSoundActivation, MelInteractionKeyword, MelConditionList, MelAddnDnam, \ @@ -50,7 +50,8 @@ MelAspcRdat, MelAspcBnam, MelAstpTitles, MelAstpData, MelBookText, \ MelBookDescription, MelInventoryArt, MelUnorderedGroups, MelExtra, \ MelImageSpaceMod, MelClmtTiming, MelClmtTextures, MelCobjOutput, \ - MelSoundClose, AMelItems, MelContData, MelCpthShared + MelSoundClose, AMelItems, MelContData, MelCpthShared, MelDoorFlags, \ + MelRandomTeleports, MelSoundLooping, MelDualData from ...exception import ModSizeError _is_sse = bush.game.fsName in ( @@ -1026,9 +1027,10 @@ class MreDobj(MelRecord): melSet = MelSet( MelEdid(), # This subrecord can have <=7 bytes of noise at the end - MelExtra(MelSorted(MelArray('objects', - MelStruct(b'DNAM', ['2I'], 'object_use', (FID, 'object_fid')), - ), sort_by_attrs='object_use'), extra_attr='unknown_dnam'), + MelExtra(MelSorted(MelArray('default_objects', + MelStruct(b'DNAM', ['2I'], 'default_object_use', + (FID, 'default_object_fid')), + ), sort_by_attrs='default_object_use'), extra_attr='unknown_dnam'), ) __slots__ = melSet.getSlotsUsed() @@ -1037,14 +1039,6 @@ class MreDoor(MelRecord): """Door.""" rec_sig = b'DOOR' - DoorTypeFlags = Flags.from_names( - (1, 'automatic'), - (2, 'hidden'), - (3, 'minimalUse'), - (4, 'slidingDoor'), - (5, 'doNotOpenInCombatSearch'), - ) - melSet = MelSet( MelEdid(), MelVmad(), @@ -1054,9 +1048,9 @@ class MreDoor(MelRecord): MelDestructible(), MelSound(), MelSoundClose(b'ANAM'), - MelFid(b'BNAM','soundLoop'), - MelUInt8Flags(b'FNAM', u'flags', DoorTypeFlags), - MelSorted(MelFids('random_teleports', MelFid(b'TNAM'))), + MelSoundLooping(), + MelDoorFlags(), + MelRandomTeleports(), ) __slots__ = melSet.getSlotsUsed() @@ -1065,14 +1059,10 @@ class MreDual(MelRecord): """Dual Cast Data.""" rec_sig = b'DUAL' - DualCastDataFlags = Flags.from_names('hitEffectArt', 'projectile', - 'explosion') - melSet = MelSet( MelEdid(), MelBounds(), - MelStruct(b'DATA', [u'6I'],(FID,'projectile'),(FID,'explosion'),(FID,'effectShader'), - (FID,'hitEffectArt'),(FID,'impactDataSet'),(DualCastDataFlags, u'flags'),), + MelDualData(), ) __slots__ = melSet.getSlotsUsed()