#Making a new map/hideout location

1564 messages ยท Page 2 of 2 (latest)

lone sparrow
#

Well, in this case, an enum is just a special type of mapping object.

#

It doesn't actually do anything outside of the stringify, here.

#

Its sole purpose is pretty much just readability.

rancid silo
#

Alright, I just saw at the bottom the enums and it kinda looked like flow and how it operated.

#

Is it something you have to declare in the class? Cause I'm looking at the BGM code and I don't really see anything to do with the enums. Sorry if I'm just not reading correctly.

lone sparrow
#

Hm, maybe I'm misremembering... but it should only be in the stringify method.

#

It doesn't factor into the read/write.

rancid silo
#

is it hex(self.BitFlagSection << 16), self.BitFlagId ?

#

return "Field Major ID: {}, Field Minor ID: {}, Date Range: {:02d}/{:02d} - {:02d}/{:02d}, Unknown Type: {}, Weather Type: {}, Field Type: {}, BGM Cue ID: {}, BitFlag: {} + {}".format(
self.FieldMajorId, self.FieldMinorId,
self.MinMonth, self.MinDay, self.MaxMonth, self.MaxDay,
UnknownTypes(self.UnknownType).name, WeatherTypes(self.WeatherType).name, FieldTypes(self.FieldType).name,
self.BgmCueId, hex(self.BitFlagSection << 16), self.BitFlagId,
) this is all thats there

lone sparrow
#

No, it should be like WeatherTypes(...).name

rancid silo
#

oh

lone sparrow
#

That's what maps the number to the string when printed.

rancid silo
#

I was right then

#

I get this now

#

whats the criteria for putting the ANY = 255 in the enums?

lone sparrow
#

More convention than anything -- if you see a field that's like 0, 1, 2, 3, 4... and then just 255, that's the max uint8 value / equivalent to the int8 -1. The convention the BGM table is following is that that big number means that field's value isn't considered for that entry.

#

Max int16 is 65535, which you might also spot here.

#

You'll see that number in the field IDs of the output, as well. It means that the condition is going to apply to any field.

rancid silo
#

I see so then

                Wood = 1,
                Stone = 2,
                Grass = 3,
                Soil = 4,
                Carpet = 5,
                Metal = 6,
                Bare = 7,
                Crawl = 8,
                Sand = 9,

Would have the any = 255

lone sparrow
#

It's only really relevant if it's actually observed, though. It won't be relevant for every field.

#

I wouldn't add it to the footsteps one unless it's observed.

#

And in that case, it might actually mean NONE or something similar.

#

The actual use of the sort of "weird" final field value is just a question of what's being done with it in the game's code.

rancid silo
#

what happens if it isn't put in the enum but then 255 gets called by the script? Would it display at all?

lone sparrow
#

The stringify method would give an error!

#

Enums have the added function of helping to make sure you're covering all observed values.

#

(Because enum-using code will die if you try to give it a not-defined value.)

rancid silo
#

I see, just wanted to make sure before it blew up my pc or something (you never know)

lone sparrow
#

Lol, no, it'll just give a regular, non-explosive error. Probably.

rancid silo
#

So if it's under an enum do I define it in the init or do I leave them out? I assume leave it but I want to make sure.

lone sparrow
#

The only thing that needs to be in the init is the actual variable the number gets read into. Then, in stringify, the enum can optionally be used to map that number to a string for readability.

rancid silo
#

Alright cool. Footstep should be done soon then.

lone sparrow
#

Nice. This is an interesting way to learn Python, eh? ๐Ÿ˜„

rancid silo
#

And I wouldn't have it any other way.

#

class FLDFOOTSTEPCND(Serializable):

    def __init__(self):
                     self.FieldMajorId         = None
                     self.FieldMinorId         = None
                     self.FootstepTypes        = None


    def __rw_hook__(self, rw, datasize):
                     self.FieldMajorId         = rw.rw_uint16(self.FieldMajorId)
                     self.FieldMinorId         = rw.rw_uint16(self.FieldMinorId)
                     self.FootstepTypes        = rw.rw_uint16(self.FootstepTypes)


                     

    def stringify(self):
                return "Field Major ID: {}, Field Minor ID: {}, Footstep Type {}".format(
                    self.FieldMajorId, self.FieldMinorId, FootstepTypes(self.FootstepType).name,
                    
        
        )

I appear to be having an assertion error.

#

class FootstepTypes(Enum):
Wood = 1
Stone = 2
Grass = 3
Soil = 4
Carpet = 5
Metal = 6
Bare = 7
Crawl = 8
Sand = 9
Wet = 10
Creak = 11
Wood_And_Creak = 12
Silence = 13
Thin_Metal = 14

this is my enum btw

#

hmm, how complex is GUI coding for python?

#

I wonder if it'd be a good idea to have the scripts be a GUI thing rather than commandline.

lone sparrow
#

You can certainly do it, but distributing it is annoying because Microsoft blocks that shit like craaazy.

#

Fortunately, these can be ported directly to C#, which is what I do for EVTUI. including making them in python first because it's quicker for dev/testing lol

#

I've definitely thought about basically making 010 Editor 2, lmao.

#

But that would inherently have less flexibility than the scripts. Moving toward a GUI comes with an inherent loss of flexibility... which, in some cases, can be fine!

rancid silo
#

Thats true. It was just on my mind and was curious. I'd be down to help you out with 010 Editor 2 though. Since this is pretty fun so far.

lone sparrow
#

I think my main idea with the scripts is that they can just have some general-purpose / sample tools, but if something seems like it would be good as a bigger independent project, then it should split off accordingly.

#

So like, my ACB/AWB/ADX parsers aren't in here, because they're a separate project.

rancid silo
#

Understandable. You wouldn't want to bloat the project with stuff that can be split off.

lone sparrow
#

But if you have a vision for a GUI version of the FTD code, whether it's just 010 2 or something slightly different, that could be neat ๐Ÿ‘€

rancid silo
#

Maybe, idk. I'll think about it after I get done helping you with all of these files that need interpreting.

rancid silo
lone sparrow
#

What's the assertion error?

rancid silo
#

File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Scripts\PrintTable.py", line 19, in <module>
main()
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Scripts\PrintTable.py", line 14, in main
table.read(args.table_path, filename=(args.table_name if args.table_name else Path(args.table_path).stem))
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\exbip\Serializable\Traits.py", line 6, in read
rw.rw_obj(self, *args, **kwargs)
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 82, in rw_hook
self.Entries[i] = rw.rw_obj(self.Entries[i], FtdList, filename)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 157, in rw_hook
assert rw.tell() == self.DataSize
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

lone sparrow
#

You're missing a field! There should be one more for Padding.

rancid silo
#

ohhhhhhh

#

Man I need to sleep;-;

lone sparrow
#

(The error means the entry was too short. i.e., not enough fields being read.)

#

Aw, yeah, you should get to bed.

rancid silo
#

not until this is done

lone sparrow
#

๐Ÿซก

rancid silo
#

hmm, it seems to not be recognizing FootstepTypes(self.FootstepType).name, even though it's the same as your weather one WeatherTypes(self.WeatherType).name,

#

Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Scripts\PrintTable.py", line 19, in <module>
main()
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Scripts\PrintTable.py", line 15, in main
table.pretty_print()
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 38, in pretty_print
self.Entries[i].pretty_print(indent_level=indent_level+1)
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 126, in pretty_print
print("{}({}) {}".format(" "*indent_level, i, self.Entries[i].stringify()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 343, in stringify
self.FieldMajorId, self.FieldMinorId, FootstepTypes(self.FootstepType).name, self.Padding,
^^^^^^^^^^^^^^^^^
AttributeError: 'FLDFOOTSTEPCND' object has no attribute 'FootstepType'. Did you mean: 'FootstepTypes'?

lone sparrow
#

Your variable in the class is also called FootstepTypes, so you should rename it in the init/rw methods if you want.

rancid silo
#

I just did that. Same error.

#

class FLDFOOTSTEPCND(Serializable):

    def __init__(self):
                     self.FieldMajorId         = None
                     self.FieldMinorId         = None
                     self.FootstepType        = None
                     self.Padding              = None

    def __rw_hook__(self, rw, datasize):
                     self.FieldMajorId         = rw.rw_uint16(self.FieldMajorId)
                     self.FieldMinorId         = rw.rw_uint16(self.FieldMinorId)
                     self.FootstepType        = rw.rw_uint16(self.FootstepTypes)
                     self.Padding              = rw.rw_uint16(self.Padding)  

                     

    def stringify(self):
                return "Field Major ID: {}, Field Minor ID: {}, Footstep Type {}".format(
                    self.FieldMajorId, self.FieldMinorId, FootstepTypes(self.FootstepType).name, self.Padding,
                    
        
        )
#

updated version

#

oh

lone sparrow
#

You left one called FootstepTypes in the rw_hook.

rancid silo
#

yeah

lone sparrow
#

That should be all, I think.

rancid silo
#

File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Scripts\PrintTable.py", line 19, in <module>
main()
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Scripts\PrintTable.py", line 15, in main
table.pretty_print()
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 38, in pretty_print
self.Entries[i].pretty_print(indent_level=indent_level+1)
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 126, in pretty_print
print("{}({}) {}".format(" "*indent_level, i, self.Entries[i].stringify()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\Parser\ParserPlayground-main\Formats\FTD.py", line 343, in stringify
self.FieldMajorId, self.FieldMinorId, FootstepTypes(self.FootstepType).name, self.Padding,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Freeman Cavarretta\AppData\Local\Programs\Python\Python312\Lib\enum.py", line 757, in call
return cls.new(cls, value)
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Freeman Cavarretta\AppData\Local\Programs\Python\Python312\Lib\enum.py", line 1171, in new
raise ve_exc
ValueError: 0 is not a valid FootstepTypes

lone sparrow
#

Gotta add a 0 entry to the enum, apparently ๐Ÿค”

#

Odd, because that's not in the template.

#

I'm guessing 0 = none.

#

But no, that's 13... hm....

#

You can try just making it UNK for now, just to get the code to work.

rancid silo
#

nice, it works now

#

but yeah odd

#

I see a couple UNKs in the table.

#

guess we'll figure that out later.

#

        def __init__(self):
                         self.FieldMajorId         = None
                         self.FieldMinorId         = None
                         self.FootstepType        = None
                         self.Padding              = None

        def __rw_hook__(self, rw, datasize):
                         self.FieldMajorId         = rw.rw_uint16(self.FieldMajorId)
                         self.FieldMinorId         = rw.rw_uint16(self.FieldMinorId)
                         self.FootstepType        = rw.rw_uint16(self.FootstepType)
                         self.Padding              = rw.rw_uint16(self.Padding)  

                         

        def stringify(self):
                    return "Field Major ID: {}, Field Minor ID: {}, Footstep Type {}".format(
                        self.FieldMajorId, self.FieldMinorId, FootstepTypes(self.FootstepType).name, self.Padding,
                        
            
            )```
#

that should be both the enum and the main code

lone sparrow
#

Might be worth double-checking this enum for accuracy. Which, I guess could be done with some modding.

rancid silo
#

How do you do that bash thing where the whole messages gets highlighted like this

#

Yeah i'll try that out tomorrow.

lone sparrow
#

Wrap the code block in angle quotes: ```your code here```

rancid silo
#

perfect thank you

lone sparrow
#

In any case, nice work!

rancid silo
#
        UNK = 0
        Wood = 1
        Stone = 2
        Grass = 3
        Soil = 4
        Carpet = 5
        Metal = 6
        Bare = 7
        Crawl = 8
        Sand = 9
        Wet = 10
        Creak = 11
        Wood_And_Creak = 12
        Silence = 13
        Thin_Metal = 14```
#

Now that I know a bit more I'm gonna grind out as many as I can tomorrow. And check up on that UNK.

lone sparrow
#

P5R but every footstep is... wet?

rancid silo
#

P5R but every footstep is UNK

lone sparrow
#

Finally....

rancid silo
#

P5R has one good mod

lone sparrow
#

Lol, anyway. Get some rest!

rancid silo
#

While you're on. How hard is it to decipher new filetypes?

#

Since sooner or later all the FTDs will be done

lone sparrow
#

It's a lot of guess-and-checking, ime.

#

Most things have SOME basic template, at least. Just a lot of UNKs in there.

#

So the biggest challenge is figuring out what those mean.

#

I'm not sure there's any file type with absolutely nothing for it... other than maybe the menu star vector animation, which is weirdly unique.

#

Which I have a semi-formed parser for, lmao.

rancid silo
#

Alright, and I assume how you check it is just to change values then load up the game? Or is there any quicker way to do it?

lone sparrow
#

That's the only actual way to do it, though I often find ways to reference images or videos to save myself the effort.

#

(I do not think finding videos would save any effort in this case.)

rancid silo
#

very true, i'd be very surprised if there were any

lone sparrow
#

It'd have to be a full playthrough, if anything.

rancid silo
#

In any case that makes sense. I just wanted to make sure that I wasn't privy to any faster way to figure it out. But loading up the game isn't too bad. Now that my question was answered I'm gonna sleep. Thank you for all of this help. I know I keep saying it but man am I glad you spare your time to help. Just know that I appreciate it every time.

lone sparrow
#

It's fun to help those who appreciate it!

#

Have a nice rest, and again, good work ๐Ÿ‘

rancid silo
#

You too. femc

lone sparrow
#

Ahhhh, I figured out how FLDPLACENO.FTD actually assigns the name maps.

lone sparrow
lone sparrow
#

Updated the repo with your classes (with a couple new bits of info!) and a new script Scripts.CombineFieldNumbersAndNames :3

#

I definitely think it's worth double-checking that footsteps enum with the game, though, since the template was slightly inaccurate.

rancid silo
#

and i'll check out the footsteps ingame in a sec. Just got up

rancid silo
#

hmm, would it be possible to make a dynamic logger? So that you could load up a file and it'll log all of the table stuff that gets used like a normal logger.

#

okay, so another idea. Would it be possible to make it so the table gets printed (lets say to a txt file for example) then you could edit it however you want. Then repack it back into the FTD file?

rancid silo
#

So I checked footstep again. Most of the roomIDs are 0. That doesn't seem correct. Though the roomID could be per map.

rancid silo
#

Just interpreted FLDSYMMODELSCL

#

        def __init__(self):
            self.ShadowID                = None
            self.ModelScale                = None


        def __rw_hook__(self, rw, datasize):
            self.ShadowID                = rw.rw_uint16(self.ShadowID)
            self.ModelScale                = rw.rw_unit16(self.ModelScale)

        def stringify(self):
            return "Shadow ID: {}, Model Scale: {}".format(
                self.ShadowID, self.ModelScale,
            )```
#

And FLDSYMMODELNO aswell


        def __init__(self):
            self.ShadowOffset        = None


        def __rw_hook__(self, rw, datasize):
            self.ShadowOffset        = rw.rw_uint16(self.ShadowOffset)

        def stringify(self):
            return "Shadow Offset: {}".format(
                self.ShadowOffset,
            )```
#

so that leaves:
FLDWIREANIMDATA
fclPublicShopDataTable
FLDMODELSE
FLDGIMMICKSE
FLDDOORSE
FLDADDACTANIM
FLDDOORANIM
fclCombElectItemTable
fclItemLineUpAccTable
fclItemLineUpTable
FLDLMAPFARE
FLDLMAPSTATION
FLDWHOLEMAPTABLE and FLDWHOLEMAPTABLEDNG
FLDDNGPACK

And then a couple more give or take any mistakes.

rancid silo
#

Out of curiosity I looked at the files for the crowds and damn. Theres a whole bunch of unkowns. But it's crowds so that should be easy to test whenever we get to that.

lone sparrow
#

I feel like Cornflakes may have been working on the debug console having a live table editing capability...? But I could be wildly bullshitting there.

rancid silo
lone sparrow
#

Ohhh, no, that's just my commandline.

#

The signature purple of the Ubuntu terminal....

rancid silo
#

oh i see

rancid silo
lone sparrow
#

The main issue there would be having access to wherever the game stores a copy of the table in memory, since I'm pretty sure it doesn't access the file every time (only on startup).

#

With that, you could get a code mod to do whatever, probably.

heady sparrowBOT
#

started early work on some table stuff, probably need a cleaner way to select which one

Jump

[Go to message!](#1234534003277828137 message)

lone sparrow
rancid silo
#

I see, was just curious. I assume you also figured out it was wrong based on inference?

lone sparrow
#

Yeah, I tried to treat it as padding/reserve and checked that it was always zero, but it was sometimes 256 or 512. Those are very specific large numbers that suggest the one int16 field is actually two int8s. And that the first of those two int8s can be 0, 1, or 2, which makes much more sense.

#

(And corresponds to room IDs.)

rancid silo
#

I see, i'll try and work that into the interpretations if need be.

#

But yeah, I have a better way to explain it now. Would it be possible to have something similar to the atlus script tools for the parser? So that editing them would be as simple as the script tools. Since a lot of these are gonna have to be tested extensively.

lone sparrow
#

Hm, you mean a way to decompile the tables to a human-readable file format, which can then be (modified and) recompiled back into FTDs.

#

It would be possible, if we could think of a reasonable format. Although at that point a GUI might in fact be easier to set up ๐Ÿค” I only haven't done this because my workflow is just to have a script that modifies and prints the output, and to run that over and over ๐Ÿ˜…

rancid silo
#

I see, yeah cause stuff like the crowd files have tons of unknown variables and that would not be fun to actually test for. Granted I haven't really made a script that edits stuff so it might be less annoying than I think it would be.

lone sparrow
#

That part is gonna suck no matter what, tbh.

#

Sooo many unknowns ๐Ÿ˜ญ

rancid silo
#

Kinda. But if the process doesn't require a ton of tinkering I can get into a good flow of it and really knock out stuff (like the backpack flag and whatnot)

#

Thats probably why I like bruteforcing. I can just get in the zone.

lone sparrow
#

True! There may be a pure-script way that's just as easy as having an output format, since even in the latter case, you'd still have to run the compile script every time.

#

It would probably be a matter of just like. Setting up all the variables. Hmmm....

#

I will ponder this....

#

Before that, I can probably pull together a script that checks what all the observed values are for the different unknowns.

#

That would help save some time, too.

rancid silo
#

Yeah that could be cool. In any case, what does s32 from the templates transfer to in the py script?

lone sparrow
#

s32... probably int32?

rancid silo
#

Alright.

tall vault
#

It's probably just a normal int, yes. Signed 32 bit value

rancid silo
#

so im looking at fldWireAnimData. Theres a bunch of unanmed fields. Too many to where it can't be interpreted without an enum. But I don't know which ones to put in said enum because they're unamed.

lone sparrow
#

Hmm, it's hard to say how far enums will get us without knowing what the possible values are. Maybe I'll cook up a script that can show all observed values for each field in a table, so we can see which are just empty fields vs. which seem like an unknown enum.

rancid silo
#

Yeah, cause a couple in here seem pretty hard if we don't have something like that.

#

funny idea I just had. We call it 020 editor.

lone sparrow
#

LMAO.

#

But yeah, I usually have a script for collating observed values like this, but mostly for specific formats. Like that's how I do a lot of EVT analysis.

#

Should be reasonably generalizable for different FTD types, though ๐Ÿค”

rancid silo
#

I see, that makes sense.

rancid silo
lone sparrow
#

It's a struct defined in the 010 FTD template.

#
typedef struct 
{
  u16 EncounterID;
  u8 Weight;
  u8 Padding; // always 0
} ENC <optimize=false, read=Str( "%d"+" Encounter: "+"%d", Weight, EncounterID )>;
rancid silo
#

oh mb, should've looked a bit more.

#

How exactly do I interpret that?

lone sparrow
#

In the Python scripts, that would be translated as a new Serializable class, which gets read via rw_obj. There're some rw_objs in the code for an example, but I could also do that part if it's confusing.

rancid silo
#

I see, I think I get it. I'll get back to it once im done with FLDADDACTANIM

rancid silo
#

on FLDADDACTANIM (sorry had other things to do so im getting to it now) theres this comment

//readString=Str("m%03d_%03d || PlayerAnim Gap ID -> %d", fldObjMajorId, fldObjMinorId, fldAnimGapID);

Is whats inside the comment something I have to interpret or is it just fluff?

lone sparrow
#

Looks like it's the equivalent of a stringify, though in this case to indicate the GAP file + animation ID being referenced. Purely a print-formatting thing.

#

Or maybe the animations are stored in the field model itself...? Well, either way.

rancid silo
#

I see, I was thinking it was something like stringify but I wasn't sure. Didn't want to try and add it if it wasn't anything.

lone sparrow
#

Yep, just string formatting stuff that would only matter for display purposes.

rancid silo
#

clyde blocked the message? lol

#

class FLDADDACTANIM(Serializable):

    def __init__(self):
        self.FieldObjMajorId            = None
        self.FieldObjMinorId            = None
        self.FLDAnimGapID            = None
        self.UNKNOWN0                = None
        self.UNKNOWN01                = None
        self.UNKNOWN1                = None
        self.UNKNOWN2                = None
        self.UNKNOWN3                    = None
        self.UNKNOWN4                   = None
        self.UNKNOWN5                   = None
        self.UNKNOWN6                   = None

    def __rw_hook__(self, rw, datasize):
        self.FieldObjMajorId        = rw.rw_int16(self.FieldObjMajorId)
        self.FieldObjMinorId        = rw.rw_int16(self.FieldObjMinorId)
        self.FLDAnimGapID        = rw.rw_uint8(self.FLDAnimGapID)
        self.UNKNOWN0                = rw.rw_uint8(self.UNKNOWN0)
        self.UNKNOWN01                = rw.rw_int16(self.UNKNOWN01)
        self.UNKNOWN1                = rw.rw_int16(self.UNKNOWN1)
        self.UNKNOWN2                = rw.rw_int16(self.UNKNOWN2)
        self.UNKNOWN3                    = rw.rw_int32(self.UNKNOWN3)
        self.UNKNOWN4                   = rw.rw_int16(self.UNKNOWN4)
        self.UNKNOWN5                   = rw.rw_int16(self.UNKNOWN5)
        self.UNKNOWN6                   = rw.rw_int32(self.UNKNOWN6)

    def stringify(self):
        return "Field Major ID: {}, Field Minor ID: {}, FLD AnimGap ID: {}, UNKNOWN 0: {}, UNKNOWN 01: {}, UNKNOWN 1: {}, UNKNOWN 2: {}, UNKNOWN 3: {}, UNKNOWN 4: {}, UNKNOWN 5: {}, UNKNOWN 6: {}".format(
            self.FieldMajorId, self.FieldMinorId,
            self.FLDAnimGapID, self.UNKNOWN0, self.UNKNOWN1,
            self.UNKNOWN01, self.UNKNOWN2, self.UNKNOWN3, self.UNKNOWN4, self.UNKNOWN5, self.UNKNOWN6,
                    )
#

so it's fine with the code but noit my explanation?

#

As I was going to say. This is what I have so far for FLDADDACTANIM. Im getting an assertion error but I think I know what it is.

lone sparrow
rancid silo
#

true

rancid silo
#

okay nvm the thing I was thinking about wasn't it.

#

is it the unkowns? I hope not cause that'd suck

lone sparrow
#

What's the error?

rancid silo
#

Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Scripts\PrintTable.py", line 19, in <module>
main()
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Scripts\PrintTable.py", line 14, in main
table.read(args.table_path, filename=(args.table_name if args.table_name else Path(args.table_path).stem))
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Serializable\Traits.py", line 6, in read
rw.rw_obj(self, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 80, in rw_hook
self.Entries[i] = rw.rw_obj(self.Entries[i], FtdList, filename)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 175, in rw_hook
assert rw.tell() == self.DataSize
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

lone sparrow
#

Hm, not the right number/size of fields, then.

rancid silo
#

I though that the first time (I added UNKOWN1 cause I forgot about it) but I guess theres more?

#

Though the template doesn't say any more

#

ADDACTANIM":
s16 fldObjMajorId;
s16 fldObjMinorId;
u8 fldAnimGapID;
u8 unk0;
s16 unk01;
s16 unk1;
s16 unk2;
s32 unk3;
s16 unk4;
s16 unk5;
s32 unk6;

lone sparrow
#

There's an unk7 I see in SecreC's fork.

#

An s16.

rancid silo
#

this is their fork

#

But I guess that answers it

#

Finally it works now

#

Odd how it didn't show up for me but oh well. Hopefully thats the only one.

#

In any case. Heres the code

#

;-; clyde

#

Your message could not be delivered. This is usually because you don't share a server with the recipient or the recipient is only accepting direct messages from friends.

#

New discord feature ig

#

        def init(self):
            self.FieldObjMajorId            = None
            self.FieldObjMinorId            = None
            self.FLDAnimGapID            = None
            self.UNKNOWN0                = None
            self.UNKNOWN01                = None
            self.UNKNOWN1                = None
            self.UNKNOWN2                = None
            self.UNKNOWN3                    = None
            self.UNKNOWN4                   = None
            self.UNKNOWN5                   = None
            self.UNKNOWN6                   = None
            self.UNKNOWN7                   = None```
#
            self.FieldObjMajorId        = rw.rw_int16(self.FieldObjMajorId)
            self.FieldObjMinorId        = rw.rw_int16(self.FieldObjMinorId)
            self.FLDAnimGapID        = rw.rw_uint8(self.FLDAnimGapID)
            self.UNKNOWN0                = rw.rw_uint8(self.UNKNOWN0)
            self.UNKNOWN01                = rw.rw_int16(self.UNKNOWN01)
            self.UNKNOWN1                = rw.rw_int16(self.UNKNOWN1)
            self.UNKNOWN2                = rw.rw_int16(self.UNKNOWN2)
            self.UNKNOWN3                    = rw.rw_int32(self.UNKNOWN3)
            self.UNKNOWN4                   = rw.rw_int16(self.UNKNOWN4)
            self.UNKNOWN5                   = rw.rw_int16(self.UNKNOWN5)
            self.UNKNOWN6                   = rw.rw_int32(self.UNKNOWN6)
            self.UNKNOWN7                   = rw.rw_int16(self.UNKNOWN7)


        def stringify(self):
            return "FieldObj Major ID: {}, FieldObj Minor ID: {}, FLD AnimGap ID: {}, UNKNOWN 0: {}, UNKNOWN 01: {}, UNKNOWN 1: {}, UNKNOWN 2: {}, UNKNOWN 3: {}, UNKNOWN 4: {}, UNKNOWN 5: {}, UNKNOWN 6: {}, UNKNOWN 7: {}".format(
                self.FieldObjMajorId, self.FieldObjMinorId,
                self.FLDAnimGapID, self.UNKNOWN0,self.UNKNOWN01, self.UNKNOWN1, self.UNKNOWN7,
                 self.UNKNOWN2, self.UNKNOWN3, self.UNKNOWN4, self.UNKNOWN5, self.UNKNOWN6,
                        )```
#

there we go

rancid silo
#

Yeah I have no idea. I guess maybe some new broken automated thing detecting the code?

#

To go back to ENCs. The example you were referencing was from FLDBGMCND right?

lone sparrow
#

There should be a few examples of rw_obj, including in the main FTD class up top.

rancid silo
#

Yeah I just saw it ;-;. How would I go about adding it? Would it be added to every self. that includes ENC? Or would it be similar to the enums

lone sparrow
#

Hm, it's probably easier for me to show by example and then explain.

rancid silo
#

damn

lone sparrow
#

That's possibly more my skill issue for the explaining part, but the idea here is... every Serializable class works the same way, and rw_obj lets one pass the reading onto another one to keep things simpler.

#

The ENC class represents a common bundle of encounter data, so it ends up being convenient to let it read those three fields rather than explicitly coding those three same fields in a bunch of different places.

rancid silo
#

I see, so I looked at the rw_obj in the main FTD. So if im getting this right. You write down one ENC bit and then it kinda acts like the enums where then the other parts that need to reference it can just reference it there?

lone sparrow
#

A bit, yeah, but this time it does actually affect the rw part, unlike the enums.

#

It might take some extra logic to make the stringify part work for the ENC objects, though.

rancid silo
#

Okay, so then I would write down one self. that has the ENC code then I assume I have to write something down for the other ENC tied selfs then it'll be referenced? Am I getting this right?

#

and then put something in the stringify

#

Probably not. Though I mostly get that from self.Entries = rw.rw_objs(self.Entries, FtdEntryTypes.__dict__.get(filename, FtdEntryTypes.Generic), self.EntryCount, self.DataSize//self.EntryCount)

lone sparrow
#

You'd make a new Serializable ENC class, much like the other Serializable classes, and probably down near the enums. And sure, give it a stringify, too.

Then, pass ENC as one of the arguments to rw_obj, looking something like self.ThisIsAnEncObj = rw.rw_obj(self.ThisIsAnEncObj, ENC).

And when you go to stringify the parent class, you'll want to include self.ThisIsAnEncObj.stringify() to display that object as desired.

rancid silo
#

ohhhhhhhhh that makes so much sense

lone sparrow
#

Not relevant to what you're trying to do at the moment.

rancid silo
#

I hope im not too overbearing with my questions. Trust me im learning so much from this you have no idea.

lone sparrow
#

I'm kinda just teaching you Python and OOP in one go, lol, so you're actually picking up an impressive amount very quickly. There may be a point where we want to move this to DMs, but to be fair, it has been related to parsing field tables so far ๐Ÿ˜…

rancid silo
#

Pretty soon I want to start parsing the map related stuff honestly. This is just a stepping stone to that.

lone sparrow
#

Yessss ๐Ÿ‘€

rancid silo
#

But thank you. I never prided myself on being a quick learner before honestly but you've been a great teacher so far so maybe I was just having a skill issue before.

lone sparrow
#

It's much easier to be a quick learner when you're applying stuff immediately to a project you care about!

rancid silo
#

Thats very true. Honestly this kinda reignited my passion for IT. Highschool ruined that for me due to bad teachers and whatnot. And honestly I'm really having fun with it again after so long. It feels nice.

lone sparrow
#

High school and even college coding courses are really hit-or-miss, and most people who teach it are, uh... bad at doing that ๐Ÿ˜… All of my best experiences with it have been working on super applied topics/projects. All my experiences teaching it, too, heh

rancid silo
#

Yeah, they just didn't really teach us at all. They just gave us testout and that was it. God that was immensely boring. There also was a whole ton of drama and stuff (especially with the teachers) that really dragged down the experience.

lone sparrow
#

Yeah, lame....

rancid silo
#

class ENC(Serializable):

    def __init__(self):
        self.EncounterID        = None
        self.Weight                = None
        self.Padding                = None


    def __rw_hook__(self, rw, datasize):
        self.EncounterID        = rw.rw_uint16(self.EncounterID)
        self.Weight                = rw.rw_uint8(self.Weight)
                    self.Padding                = rw.rw_uint8(self.Padding)
    def stringify(self):
        return "Encounter ID: {}, Weight: {}, Padding: {}".format(
            self.ShadowID, self.ModelScale, self.ShadowID,
        )

So this is what I have for the ENC class. I know im missing something but im not sure what it is.

#

u16 EncounterID;
u8 Weight;
u8 Padding; // always 0
} ENC <optimize=false, read=Str( "%d"+" Encounter: "+"%d", Weight, EncounterID )>;

this is the ENC code btw

lone sparrow
#

Looks reasonable at a glance. Are you getting an error?

rancid silo
#

Not yet. I just wanted to see if I was actually doing it right.

lone sparrow
#

It looks correct to me!

rancid silo
#

nice

rancid silo
#

hmm, it seems to think ENC isn't defined. Am I doing the code right?

class DATENCOUNTPACK(Serializable): 

    def init(self):
        self.field_0            = None
        self.UnusedSlot                = None
        self.AmbushList                = None
        self.NormalEncounter        = None
        self.NormalPinchEncounter    = None
        self.WhatDo                = None
        self.TheseOnesDo            = None
        self.StrongEncounter        = None
        self.StrongPinchEncounter    = None
        self.ReaperEncounter        = None
        self.Padding                = None
#

def rw_hook(self, rw, datasize):
self.field_0 = rw.rw_uint8(self.field_0)
self.UnusedSlot = rw.rw_uint8(self.UnusedSlot)
self.AmbushList = rw.rw_uint16(self.AmbushList)
self.NormalEncounter = rw.rw_obj(self.NormalEncounter, ENC)
self.NormalPinchEncounter = rw.rw_obj(self.NormalPinchEncounter, ENC)
self.WhatDo = rw.rw_obj(self.WhatDo, ENC)
self.TheseOnesDo = rw.rw_obj(self.TheseOnesDo, ENC)
self.StrongEncounter = rw.rw_obj(self.StrongEncounter, ENC)
self.StrongPinchEncounter = rw.rw_obj(self.StrongPinchEncounter, ENC)
self.ReaperEncounter = rw.rw_obj(self.ReaperEncounter, ENC)
self.Padding = rw.rw_uint32(self.Padding)

    def stringify(self):
        return "field 0: {}, Unused Slot: {}, Ambush List: {}, Normal Encounter: {}, Normal Pinch Encounter: {}, What Do: {}, These Ones Do: {}, Strong Encounter: {}, Strong Pinch Encounter: {}, Reaper Encounter: {}, Padding: {}".format(
            self.field_0, self.UnusedSlot, self.AmbushList,
                            self.NormalEncounter.stringify(), self.NormalPinchEncounter.stringify(), self.WhatDo.stringify(),
                            self.TheseOnesDo.stringify(), self.StrongEncounter.stringify(), self.Padding,
                            self.StrongPinchEncounter.stringify(), self.ReaperEncounter.stringify(),
        )
#

discord keeps nuking me code ;-; had to split it up in 2 messages

lone sparrow
#

Where'd you put the ENC definition? Is it inside of another class? It should be on the same indentation level as the enums.

rancid silo
#

so thats my problem

lone sparrow
#

Yep, just calling it ENC assumes it's not inside anything else.

rancid silo
#

File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 34, in construct
out.append(binary_target.rw_obj(value, constructor, *args, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 509, in rw_hook
self.NormalEncounter = rw.rw_obj(self.NormalEncounter, ENC)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
^^^^^^^^^^^^^^^^^
AttributeError: 'ENC' object has no attribute 'rw_hook'

Do you have to put something inside the hook?

lone sparrow
#

Oh, oops, my bad. You should get rid of the datasize argument from its __rw_hook__.

rancid silo
#

do you replace it with ENC?

#

or just get rid of it

lone sparrow
#

Inside of ENC, I mean!

rancid silo
#

ohhh

lone sparrow
#

It doesn't use that argument, and you're not providing it (rightly), so the call doesn't recognize the extra-argument definition.

rancid silo
#

still same error

lone sparrow
#

Hmmm....

#

You've formatted the name correctly? As __rw_hook__? And it's at the right indent level within the class?

rancid silo
#

Do I move them all the way to the left like the class?

#

also yes I finally figured out dark mode

lone sparrow
#

Ah, both the init and the hook need two underscores before and after the names.

#

The underscores mean they are special boys.

rancid silo
#

how'd that happen?? ;-;

lone sparrow
#

Underscores get treated as formatting on Discord, so if you did any copy/pasting, it might have removed them.

rancid silo
#

true

#

alright now on to just the normal errors

lone sparrow
#

Progress!

rancid silo
#

do the selfs have to be indented like the Enums?

lone sparrow
#

You probably have too many indents here, lol. The def lines should have one indent, and the stuff under those lines (inside the methods) should have two.

#

Leading indents, of course. The ones before the = are just for readability.

#

Think of the indentation like how you'd organize a nested bullet-point list.

rancid silo
#

I did that yet the error persists. Probably should've posted the error before.

File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 34, in construct
out.append(binary_target.rw_obj(value, constructor, *args, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 509, in rw_hook
self.NormalEncounter = rw.rw_obj(self.NormalEncounter, ENC)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 535, in rw_hook
self.EncounterID = rw.rw_uint16(self.EncounterID)
^^^^^^^^^^^^^^^^
AttributeError: 'ENC' object has no attribute 'EncounterID'

lone sparrow
#

Did you fix the name of __init__, too?

rancid silo
#

;-;

lone sparrow
#

It also needs the double underscores to get called.

rancid silo
#

now just an assertion

File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 175, in rw_hook
assert rw.tell() == self.DataSize
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

lone sparrow
#

Too few fields... I think some of these may actually be arrays in the template ๐Ÿค”

#

So self.UnusedSlot = rw.uint8s(self.UnusedSlot, 7), to turn it into an array of 7 uint8s.

#

And the same for the rest in the template that have the [ 7 ] type of things at the end. Adjusting for the right number.

#

So there are actually 13 normal encounters.

rancid silo
#

oh, the numbers there mean something? Do I add the numbers from all of them in their corresponding self or just the 7?

lone sparrow
#

Replace the 7 with whatever number is there in the template!

rancid silo
#

oh okay just making sure

#

cool

lone sparrow
#

It's different for each one, yeah.

rancid silo
#

you never know with atlus

#

so then like this?

#

self.field_0 = rw.rw_uint8(self.field_0)
self.UnusedSlot = rw.rw_uint8(self.UnusedSlot, 7)
self.AmbushList = rw.rw_uint16(self.AmbushList, 8)
self.NormalEncounter = rw.rw_obj(self.NormalEncounter, ENC, 13)
self.NormalPinchEncounter = rw.rw_obj(self.NormalPinchEncounter, ENC, 5)
self.WhatDo = rw.rw_obj(self.WhatDo, ENC, 5)
self.TheseOnesDo = rw.rw_obj(self.TheseOnesDo, ENC, 5)
self.StrongEncounter = rw.rw_obj(self.StrongEncounter, ENC, 5)
self.StrongPinchEncounter = rw.rw_obj(self.StrongPinchEncounter, ENC, 5)
self.ReaperEncounter = rw.rw_obj(self.ReaperEncounter, ENC, 1)
self.Padding = rw.rw_uint32(self.Padding)

#

if so. Heres the funny error.

File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 34, in construct
out.append(binary_target.rw_obj(value, constructor, *args, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 507, in rw_hook
self.UnusedSlot = rw.rw_uint8(self.UnusedSlot, 7)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Primitives.py", line 13, in construct
return binary_target._rw_typed(value, typecode, elem_size, endianness)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Core.py", line 27, in construct
return struct.unpack(endianness + typecode, serialized_value)[0]
~~~^~
TypeError: unsupported operand type(s) for +: 'int' and 'str'

lone sparrow
#

You have to add an s to the end of every rw if you're making it an array! So rw_uint8s, rw_objs, etc.

rancid silo
#

ahhh

#

makes sense

#

hmm, another assertion error. I should have the right amount of fields.

#

value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 80, in rw_hook
self.Entries[i] = rw.rw_obj(self.Entries[i], FtdList, filename)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 175, in rw_hook
assert rw.tell() == self.DataSize
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

#

sorry about all of the annoying questions and errors.

lone sparrow
#

Missing TreasureEncounter, I think.

rancid silo
#

im going insane

lone sparrow
#

โœจCodingโœจ

rancid silo
#

do you have to do something specific with the stringify?

#

self.NormalEncounter.stringify() should be like this right?

lone sparrow
#

Ooh, well, now that it's an array, you'd have to do it for each ENC element in the array...

#

Probably need to make this a multiline print to make it not an insanely long line ๐Ÿ˜…

rancid silo
#

I did that, it's 'list' object has no attribute 'stringify'

lone sparrow
#

Right, because each one is a list of ENCs, not a single ENC.

#

So it'd have to be like ", ".join(enc.stringify() for enc in self.NormalEncounter)

rancid silo
#

self.NormalEncounter.join(enc.stringify() ?

lone sparrow
#

No, just like I did above. That stringifies each ENC element of self.NormalEncounter and then combines them with commas.

rancid silo
#

so then 7 copies of .join(enc.stringify() tacked on?

#

sorry, trying to wrap my head around it

lone sparrow
#

Yep, exactly!

#

An insalely long string ๐Ÿ˜”

#

We can come up with alternatives once you get it working, lol.

rancid silo
#

so then it would be self.NormalEncounter.stringify() then the 7 copies? So like self.NormalEncounter.stringify(), .join(enc.stringify(), .join(enc.stringify(), .join(enc.stringify().join(enc.stringify(), .join(enc.stringify(), .join(enc.stringify(), .join(enc.stringify()

#

sorry if this is wrong im a persona fan so I can't read.

lone sparrow
rancid silo
lone sparrow
#

Nope, can't stringify NormalEncounter directly at all ๐Ÿ˜”

rancid silo
#

this is so sad.

lone sparrow
#

You could do self.NormalEncounter[0].stringify(), self.NormalEncounter[1].stringify() ... self.NormalEncounter[6].stringify()

rancid silo
#

thats a lot better

#

oh, that was what I was just looking at.

#

so then for the non ENC ones. It would be self.AmbushList[0] ?

lone sparrow
#

That'll give you the first element, yeah.

rancid silo
#

self.Entries[i].pretty_print(indent_level=indent_level+1)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 144, in pretty_print
print("{}({}) {}".format(" "*indent_level, i, self.Entries[i].stringify()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 522, in stringify
self.field_0, self.UnusedSlot, self.AmbushList, self.NormalEncounter[13].stringify(),
~~~~~~~~~~~~~~~~~~~~^^^^
IndexError: list index out of range

lone sparrow
#

The indexes go up to the sizes minus 1! So if it's size 13, it's 0-12.

rancid silo
#

man, this python sure is picky

lone sparrow
#

๐Ÿ

rancid silo
#

finally, the snake charming worked

lone sparrow
#

Giving you the longest lines of text known to man? ๐Ÿ˜„

rancid silo
#

you could say that

lone sparrow
#

Beautiful....

rancid silo
#

if it works it works

#

        def __init__(self):
            self.field_0            = None
            self.UnusedSlot                = None
            self.AmbushList                = None
            self.NormalEncounter        = None
            self.NormalPinchEncounter    = None
            self.WhatDo                = None
            self.TreasureEncounter        = None            
            self.TheseOnesDo            = None
            self.StrongEncounter        = None
            self.StrongPinchEncounter    = None
            self.ReaperEncounter        = None
            self.Padding                = None        

#
            self.field_0                = rw.rw_uint8(self.field_0)
            self.UnusedSlot                = rw.rw_uint8s(self.UnusedSlot, 7)
            self.AmbushList                = rw.rw_uint16s(self.AmbushList, 8)
            self.NormalEncounter        = rw.rw_objs(self.NormalEncounter, ENC, 13)
            self.NormalPinchEncounter    = rw.rw_objs(self.NormalPinchEncounter, ENC, 5)
            self.WhatDo                = rw.rw_objs(self.WhatDo, ENC, 5)
            self.TheseOnesDo        = rw.rw_objs(self.TheseOnesDo, ENC, 5)
            self.TreasureEncounter        = rw.rw_objs(self.TreasureEncounter, ENC, 5)            
            self.StrongEncounter        = rw.rw_objs(self.StrongEncounter, ENC, 5)
            self.StrongPinchEncounter    = rw.rw_objs(self.StrongPinchEncounter, ENC, 5)
            self.ReaperEncounter        = rw.rw_objs(self.ReaperEncounter, ENC, 1)
            self.Padding                = rw.rw_uint32(self.Padding)
            
        def stringify(self):
            return "field 0: {}, Unused Slot: {}, Ambush List: {}, Normal Encounter: {}, Normal Pinch Encounter: {}, What Do: {}, These Ones Do: {}, Strong Encounter: {}, Treasure Encounter: {}, Strong Pinch Encounter: {}, Reaper Encounter: {}, Padding: {}".format(
                self.field_0, self.UnusedSlot, self.AmbushList, self.NormalEncounter[12].stringify(),
                                self.NormalPinchEncounter[4].stringify(), self.WhatDo[4].stringify(),
                                self.StrongPinchEncounter[4].stringify(), self.ReaperEncounter[0].stringify(),
                                self.TheseOnesDo[4].stringify(), self.StrongEncounter[4].stringify(), self.TreasureEncounter[4].stringify(), self.Padding,     
            )```
#

        def __init__(self):
                self.EncounterID                = None
                self.Weight                     = None
                self.Padding                    = None


        def __rw_hook__(self, rw):
                self.EncounterID                = rw.rw_uint16(self.EncounterID)
                self.Weight             = rw.rw_uint8(self.Weight)
                self.Padding            = rw.rw_uint8(self.Padding)

        def stringify(self):
                    return "Encounter ID: {}, Weight: {}, Padding: {}".format(
                            self.EncounterID, self.Weight, self.Padding,
                       )```
#

that should be it.

lone sparrow
#

Nice ๐ŸŽ‰

rancid silo
#

we still have a few more to go through but I'm getting more 'confident'. Hopefully I can interpret every single non impossible one soon. Then we can move on to the other filetypes.

#

time to sleep. I shall continue tomorrow.

lone sparrow
#

๐Ÿซก Goodnight!

lone sparrow
#

Pushed the new table formats! Including some polish to how DATENCOUNTPACK gets printed, heheh.

#

It seems like a lot of these DNG tables treat the "dungeons" as a set of 12, but I have yet to figure out if there's a direct list of which is which, or corresponding fields.... FLDDNGPLACENO doesn't look like it, though I could be wrong....

lone sparrow
#

Akechi palace confirmed..............

rancid silo
#

I wonder how hard it would be to make a new palace?

rancid silo
#

oh man, I looked at FLDLMAPFARE and yesterday I had no idea how to interpret it. But looking at it today now I do. Thats so cool.

rancid silo
#

assertion error. But what field am I missing? hmm

rancid silo
#

there we go

#

okay I figured out my issue.

#

I was looking at the P5 version of the FTD rather than the P5R version

#

        def __init__(self):
            self.travelCost = None


        def __rw_hook__(self, rw, datasize):
            self.travelCost = rw.rw_int32s(self.travelCost, 36)

        def stringify(self):
            return "Travel cost to Lmap Destination: {}".format(
                self.travelCost,
            )```
#

heres the FLDLMAPFARE code.

rancid silo
#

        def __init__(self):
            self.DoorObjMajorId    = None
            self.DoorObjMinorId    = None
            self.DungeonAcbCueId    = None
            self.SecondaryCueId    = None

        def __rw_hook__(self, rw, datasize):
            self.DoorObjMajorId    = rw.rw_uint16(self.DoorObjMajorId)
            self.DoorObjMinorId    = rw.rw_uint16(self.DoorObjMinorId)
            self.DungeonAcbCueId    = rw.rw_int32(self.DungeonAcbCueId)
            self.SecondaryCueId    = rw.rw_int32(self.SecondaryCueId)


        def stringify(self):
            return "DoorObj Major Id: {}, DoorObj Minor Id: {}, DungeonAcb Cue Id: {}, Secondary Cue Id: {}".format(
                self.DoorObjMajorId, self.DoorObjMinorId,
                self.DungeonAcbCueId, self.SecondaryCueId,
            )```
#

FLDDOORSE done.

rancid silo
#

        def __init__(self):
            self.fldObjMajorId    = None
            self.fldObjMinorId    = None
            self.AnimationId    = None
            self.CueId            = None

        def __rw_hook__(self, rw, datasize):
            self.fldObjMajorId    = rw.rw_int16(self.fldObjMajorId)
            self.fldObjMinorId    = rw.rw_int16(self.fldObjMinorId)
            self.AnimationId    = rw.rw_uint32(self.AnimationId)
            self.CueId            = rw.rw_uint32(self.CueId)


        def stringify(self):
            return "fldObj Major Id: {}, fldObj Minor Id: {}, Animation Id: {}, Cue Id: {}".format(
                self.fldObjMajorId, self.fldObjMinorId,
                self.AnimationId, self.CueId,
            )```
#

FLDGIMMICKSE is also done

lone sparrow
#

Prolific! femc

lone sparrow
#

(Probabilities/weights, that is.)

rancid silo
#

I see, that makes sense.

#

im almost done with FLDDOORANIM then im gonna count up all the ones that are left.

#

        def __init__(self):
            self.DoorObjMajorId    = None
            self.DoorObjMinorId    = None
            self.FldAnimGapId    = None
            self.playerXOffset    = None
            self.playerYOffset    = None
            self.playerZOffset    = None
            self.playerXOffset2    = None
            self.playerYOffset2    = None
            self.playerZOffset2    = None
            self.UNKNOWN0            = None

        def __rw_hook__(self, rw, datasize):
            self.DoorObjMajorId    = rw.rw_uint16(self.DoorObjMajorId)
            self.DoorObjMinorId    = rw.rw_uint16(self.DoorObjMinorId)
            self.FldAnimGapId    = rw.rw_uint16(self.FldAnimGapId)
            self.playerXOffset    = rw.rw_int16(self.playerXOffset)
            self.playerYOffset    = rw.rw_int16(self.playerYOffset)
            self.playerZOffset    = rw.rw_int16(self.playerZOffset)
            self.playerXOffset2    = rw.rw_int16(self.playerXOffset2)
            self.playerYOffset2    = rw.rw_int16(self.playerYOffset2)
            self.playerZOffset2    = rw.rw_int16(self.playerZOffset2)
            self.UNKNOWN0            = rw.rw_int16(self.UNKNOWN0)

        def stringify(self):
            return "DoorObjMajorId: {}, DoorObjMinorId: {}, FldAnimGapId: {}, playerXOffset: {}, playerYOffset: {}, playerZOffset: {}, playerXOffset2: {}, playerYOffset2: {}, playerZOffset2: {}, UNKNOWN0: {}".format(
                self.DoorObjMajorId, self.DoorObjMinorId, self.FldAnimGapId,
                self.playerXOffset, self.playerYOffset, self.playerZOffset, self.playerXOffset2, 
                self.playerYOffset2, self.playerZOffset2, self.UNKNOWN0,

            )```
#

FLDDOORANIM is now done.

#

time to count

#

FLDOBJFLAG
DATTBOXRND
DATTBOX
FLDWHOLEMAPTABLEDNG
FLDLMAPSTATION
cmmFormat
cmmFunctionTable
cmmFunctionInfoTable
cmmHelp
cmpPsCoopSkillTable
fclItemLineUpTable
fclItemLineUpAccTable
fclCombElectItemTable
FLDMODELSE
FLDWIREANIMDATA(impossible currently)

#

im not really sure about the tables. Since idk if you've already implemented something similar to them just with a different name.

lone sparrow
#

If you don't see their names in the FTD file, I don't have anything for them.

rancid silo
#

alright cool, was just making sure.

#

so for the tables. How do i interpret them?

            ItemType Category : 4<format = hex, name = "Item Category">;
            short ItemId : 12<name = "Consumable ID">;
            readString=Str("%s %d", EnumToString(Category), ItemId);```
for example
lone sparrow
#

Hmmmm, I'm confused about this one in the template, because it looks like it's expecting one or two int16s, but I only see two bytes per entry in the file. Do you see the same thing, if you just print the table generically? Just two numbers per line?

rancid silo
#

i'll try it. I was working on FLDMODELSE since thats the last one I can read without asking you questions. But i'll check it rq

rancid silo
#

sorry, had to do a couple things. Where are the table stuff like fclItemLineUpTable stored?

lone sparrow
#

They're inside INIT/FCLTABLE.BIN.

rancid silo
#

ah

#

doesn't seem like it recognizes it. This is what I have for the code so maybe it's just a me issue.


        def __init__(self):
            self.ItemCategory    = None
            self.ConsumableID    = None
            self.RESERVE        = None

        def __rw_hook__(self, rw, datasize):
            self.ItemCategory    = rw.rw_int16(self.ItemCategory)
            self.ConsumableID    = rw.rw_int16(self.ConsumableID)

            self.RESERVE = rw.rw_uint32(self.RESERVE)
            assert self.RESERVE == 0

        def stringify(self):
            return "Item Category: {}, ConsumableID: {}".format(
                self.ItemCategory, self.ConsumableID
            )```
#

it also does 2 numbers per line forgot to say mb

#

(0) array('B', [48, 2])
(1) array('B', [48, 3])
(2) array('B', [48, 18])
(3) array('B', [48, 19])
(4) array('B', [48, 20])
(5) array('B', [48, 22])
(6) array('B', [48, 61])
(7) array('B', [49, 97])
(8) array('B', [0, 0])
(9) array('B', [48, 2])
(10) array('B', [48, 3])

lone sparrow
#

Okay, yeah, weird. That doesn't fit the template whatsoever, either for P5 or P5R ๐Ÿฅด

rancid silo
#

do we just skip them for now and do the rest of the non table FTDs?

lone sparrow
#

Yeah, I'd just skip for now. They're not field-related, anyway.

rancid silo
#

        def __init__(self):
            self.fldObjMajorId    = None
            self.fldObjMinorId    = None
            self.AnimationId    = None
            self.UNKNOWN1            = None
            self.UNKNOWN2            = None
            self.UNKNOWN3            = None
            self.UNKNOWN4            = None
            self.UNKNOWN5            = None
            self.DungeonAcbCueId    = None
            self.UNKNOWN6            = None

        def __rw_hook__(self, rw, datasize):
            self.fldObjMajorId    = rw.rw_uint16(self.fldObjMajorId)
            self.fldObjMinorId    = rw.rw_uint16(self.fldObjMinorId)
            self.AnimationId    = rw.rw_uint16(self.AnimationId)
            self.UNKNOWN1            = rw.rw_int16(self.UNKNOWN1)
            self.UNKNOWN2            = rw.rw_int16(self.UNKNOWN2)
            self.UNKNOWN3            = rw.rw_int16(self.UNKNOWN3)
            self.UNKNOWN4            = rw.rw_int16(self.UNKNOWN4)
            self.UNKNOWN5            = rw.rw_int16(self.UNKNOWN5, 4)
            self.DungeonAcbCueId    = rw.rw_int16(self.DungeonAcbCueId)
            self.UNKNOWN6            = rw.rw_int16(self.UNKNOWN6, 7)

        def stringify(self):
            return "fldObjMajorId: {}, DoorObjMinorId: {}, AnimationId: {}, UNKNOWN 1: {}, UNKNOWN 2: {}, UNKNOWN 3: {}, UNKNOWN 4: {}, UNKNOWN 5: {}, DungeonAcb Cue Id: {}, UNKNOWN 6: {}".format(
                self.fldObjMajorId, self.fldObjMinorId, self.AnimationId,
                self.UNKNOWN1, self.UNKNOWN2, self.UNKNOWN3, self.UNKNOWN4, 
                self.UNKNOWN5, self.DungeonAcbCueId, self.UNKNOWN6,

            )```
#

FLDMODELSE is done.

#

so the next one I'm looking at is FLDLMAPSTATION. And all it has is this. How exactly do I interpret this?

    fldMapTable Data;```
#

oh is that a struct?

#

okay cool it is

#

fldMapEntry entry[964 / 48] <optimize = false> is this more print?

lone sparrow
#

Looks like it's a list of... 964/48 entries of type fldMapEntry?

#

That's about 20, but it's not an even division, so that's a bit weird.

rancid silo
#

so then should I interpret it as a array for entry? it is quite puzzling.

lone sparrow
#

Yeah, it's an array.

#

The count of the array is the weird part....

rancid silo
#

I could just try stuff to see what happens. What would entrys int/u be?

lone sparrow
#

I guess try 20??

#

That's the rounded integer value for the division there....

rancid silo
#

would I get an assertion from wrong int/u or is it only because it needs more or less fields?

lone sparrow
#

I... hm..... it could be either, I think.

#

My approach here would be to treat the table as generic and print out the datasize as a point of reference.

#

That should help figure out the right counts.

rancid silo
#

alright

#

thats a really big table entry

lone sparrow
#

Lol, yeah, that's why you may want to add a print(datasize) to the rw temporarily just so you don't have to count manually.

rancid silo
#

how would I add that? Just tack it on like this?

lone sparrow
#

Yep!

#

Just so.

rancid silo
#

1124
1124
1124
1124
1124
1124
1124
1124
1124
1124
1124
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Scripts\PrintTable.py", line 19, in <module>
main()
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Scripts\PrintTable.py", line 14, in main
table.read(args.table_path, filename=(args.table_name if args.table_name else Path(args.table_path).stem))
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Serializable\Traits.py", line 6, in read
rw.rw_obj(self, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 80, in rw_hook
self.Entries[i] = rw.rw_obj(self.Entries[i], FtdList, filename)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 175, in rw_hook
assert rw.tell() == self.DataSize
^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

lone sparrow
#

1124, okay....

#

Hmmmmm.

#

This one is hard ๐Ÿ˜…

#

Can you send me what you've got?

rancid silo
#

class FLDWHOLEMAPTABLEDNG(Serializable):

    def __init__(self):
        self.entry = None
        self.Field3C0 = None
        self.Field3C2 = None


    def __rw_hook__(self, rw, datasize):
        self.entry = rw.rw_uint16s(self.entry, 20)
        self.Field3C0 = rw.rw_uint16(self.Field3C0)
        self.Field3C2 = rw.rw_uint16(self.Field3C2)

        print(datasize)
                    
    def stringify(self):
        return "entry: {}, Field3C0: {}, Field3C2: {}".format(
            self.entry, self.Field3C0, self.Field3C2,
        )
lone sparrow
#

Okie doke, let me take a crack at it....

rancid silo
#

I'll work on another one then.

rancid silo
#

How would I go about interpreting this?

            fldObj Objects[10];```
lone sparrow
#

An array of 10 fldObjs?

rancid silo
#

oh okay it's a struct I think

#

{
u32 Flag <format=hex>;
TboxIndex Items[ 6 ];
} fldObj <size=0x10, optimize=false, read=fldObj_Read>;

#

these last couple FTDs are getting pretty difficult

lone sparrow
#

A lot of nested structs and arrays just to really confuse you ๐Ÿ˜„

rancid silo
#

what would be the int/u for these fields that don't have one like TboxIndex?

lone sparrow
#

TBoxIndex is either a struct or an enum, so it's a matter of figuring that out first.

rancid silo
#

so entry is aswell?

#

truly an atlus creation

#

it is not im afriad

#

I don't think so

#

the only other mention of it is in DATTBOXRND

lone sparrow
#

A u16 enum.

rancid silo
#

ohhhhh

#

tunnel vision ;-;

#

mb

#

so then, would I have to add in all of the entries for TBoxIndex from the enum list into the py script?

#

I assume so but I want to make sure

lone sparrow
#

You could, but you could also just leave it as a uint16 for now, lol.

rancid silo
#

weird

#

alright

lone sparrow
#

Moving that huge enum sounds annoying ๐Ÿ˜…

rancid silo
#

true

#

hmm, so then since it's inside the fldobj. Would I have fldobj then TboxIndex and Flag? Or something similar to that?

lone sparrow
#

It would be another thing like ENC, yeah.

rancid silo
#

ahh, that makes sense

rancid silo
#

oh yeah sorry I haven't done much work today. I had to deal with a consultation which took a few hours and after that I just felt really lethargic. I should be back to really start tomorrow though. Did you ever take a crack at that weird FTD?

lone sparrow
#

Yep, just updated it! The template's enum for travel types was super incomplete, so I had to make some educated guesses in filling it in.

#

I added some other stuff, too -- including a script for validating that the FTD parser works across all tables, and a parser for the weather schedule.

rancid silo
#

oh nice, thats awesome ajda. So then all we need to do is finish up those last couple FTDs then we'll be done. I'll get started on it again after I stop being tired.

rancid silo
#

man it's really hard to wrap my brain around FLDOBJFLAG but I think I get it.

rancid silo
#

oh right, you changed the enc code.

rancid silo
#

me when assertion

#

thats not an assertion

#

File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 34, in construct
out.append(binary_target.rw_obj(value, constructor, *args, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 810, in rw_hook
self.fldObj = rw.rw_objs(self.fldObj, fldobj, 10)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 34, in construct
out.append(binary_target.rw_obj(value, constructor, *args, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\exbip\Descriptors\Object.py", line 12, in construct
value.rw_hook(binary_target, *args, **kwargs)
File "E:\Pictures\Rune\NewParser\ParserPlayground-main\Formats\FTD.py", line 897, in rw_hook
self.TboxIndex = rw.rw_objs(self.TboxIndex, 6)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: ObjectsDescriptor.construct() missing 1 required positional argument: 'shape'

lone sparrow
#

The name of the object/class needs to be in there as the second argument!

rancid silo
#

So you have to even though it's the 'ENC' part of the code?

lone sparrow
#

That's just how rw_objs works. If you're using it, you have to specify what type the objects are.

rancid silo
#

i see, so then it would be like this?

class fldobj(Serializable):

def __init__(self):
    self.TboxIndex            = None
    self.Flag        = None
    self.RESERVE        = None

def __rw_hook__(self, rw):
    self.TboxIndex            = rw.rw_objs(self.TboxIndex, fldobj, 6)
    self.Flag        = rw.rw_uint32(self.Flag)

    self.RESERVE = rw.rw_uint8(self.RESERVE)
    assert self.RESERVE == 0

def stringify(self):
    return "ID = {} ({}%)".format(
        self.TboxIndex[5], self.Flag
    )
lone sparrow
#

Oh, uh... no, there would probably need to be another class for whateer TboxIndex is. Not the same one you're in.

#

Let me refresh my memory....

rancid silo
#

yeah thats what I thought. So can enums be added into this like any other class?

lone sparrow
#

Okay, right, we wanted to forego the enum for now because it's too big to bother with. So then enums aren't treated quite the same way as other objects. They're fancy wrappers for regular numbers. So you should just use self.TboxIndex = rw.rw_uint16s(self.TboxIndex, 6).

#

If we want to add the actual enum in the future, that would get used only in the stringify.

rancid silo
#

Okay, that makes so much more sense. Sorry, my mind has had a really hard time figuring out this cause theres so many nested things.

#

now were back to assertions. I wonder if this has a similar issue to where it isn't documented completely?

lone sparrow
#

Looking at the template, it looks like Flag should get read before TboxIndex, and there should be no RESERVE.

rancid silo
#

Im not really sure why I thought that didn't matter. But good thing I know now.

#

perfect. it works now

#

        def __init__(self):
            self.fldObj    = None


        def __rw_hook__(self, rw, datasize):
            self.fldObj    = rw.rw_objs(self.fldObj, fldobj, 10)

        def stringify(self):
            return "Shadow ID: {}".format(
                self.fldObj[9],
            )```
#

Main code.

#

    def __init__(self):
        self.Flag        = None
        self.TboxIndex            = None

    def __rw_hook__(self, rw):
        self.Flag        = rw.rw_uint32(self.Flag)
        self.TboxIndex            = rw.rw_uint16s(self.TboxIndex, 6)

    def stringify(self):
        return "ID = {} ({}%)".format(
             self.Flag, self.TboxIndex[5],
        )```
#

fldobj 'ENC' code.

#

While were on the topic. I know you did your stringify ENC code differently. Though for that it was multiple ENCs within one FTD. How exactly do you go about making it work for just one ENC ? Do I just have to get rid of the ifs and leave the outside code?

lone sparrow
#

The ifs...?

rancid silo
lone sparrow
#

Oh, my printing shenanigans, lol.

#

Hm, still not sure exactly what you mean. ENC has its own stringify, so if that were all you had, then you would just do self.MyEncObj.stringify() and be done with it. The above class is specifically a bunch of lists of ENC objects, so those for loops go through and stringify each one in each list individually.

rancid silo
#

I was just curious, since it changed quite a bit from the original stringify code. And I thought I had just done it inefficiently or something similar.

#

thats good to know though.

lone sparrow
#

You were only stringifying one element from each list, rather than all of them.

#

I also added a bunch of extra logic to make it print nicely on more than one line for readability.

rancid silo
#

I see, that makes sense.

#

in any case. We have 3 more left then we'll be done with FTDs

lone sparrow
#

Done with all, or just the 010-documented ones?

rancid silo
#

010

#

I wasn't sure if you wanted to do all of them

lone sparrow
#

I've been pondering making a spreadsheet or a page on Amicitia to document it all. Both to see what all is left but also because I don't know that there's an actual source that explains what all the tables are for....

rancid silo
#

We could, I don't mind going through the files to see if any were missed or whatnot.

lone sparrow
#

Documentation would ultimately go beyond just the field tables, but for the current focus, yeah, that'd be a good reference to have.

rancid silo
#

alright, I'll take a look around.

rancid silo
rancid silo
#

Since most of the 010 documented stuff is done (and im working on making the list which is going well). How 'easy' is it to start interpreting new file types?

#

alright, update on the FTDs. Just finished jotting all of the FTDs that were in the folders. This doesn't include any of the nested ones (liked those tables) but other than that it should be comprehensive. Gonna cross reference with our documentation to see which ones haven't been documented/parsed

rancid silo
#

Sorry, had some other stuff to do so didn't really get to check up on what ones we've done. Though I can assume we still have to do quite a bit. Which is a shame since I have to get through those other filetypes as well. I still have a bit of time so i'll take a bit of a skim through to see any others I missed.

lone sparrow
#

We can prioritize! And I still have to think about a good way to make it so you can quickly plug in values to test them.

rancid silo
#

thats true

#

im not sure how possible it is. But maybe you could simply have it print the table like how it works normally. Then after editing it reconvert it back into the file it was?

lone sparrow
#

Yeah, I'll think about whether that'd be quicker/easier than setting up something programmatic ๐Ÿค”

#

Would probably be cool to have YAML deserialization of FTDs, anyway.

rancid silo
#

Alright, honestly I don't mind if the way is complicated. It just needs to be able to be editable without having to code it in like how you did with the field name.

rancid silo
#

skimmed through the doc. I definitely don't have all of them but I checked off the ones we did off the top of my head. I'll take a more deep dive tomorrow.

rancid silo
#

I've almost got all of the FTDs marked on the doc. Just a few more to go

rancid silo
#

yeah I think i've got everything now

lone sparrow
#

...And I went ahead and added some of the info to new FTD pages on Amicitia!

rancid silo
#

Just checked it out, real nice.

#

So then whats next on our journey?

lone sparrow
#

Hm, well we definitely got lost in the weeds a bit here, lmao.

#

This is ultimately about making new fields, so maybe we edit a few more of the tables to see what we can get to work and call it a thread?

#

I'm determined to try that field BGM one again.... I think it's just a matter of adding the new entry first rather than last ๐Ÿค”

#

Which ones have you used edits of so far?

rancid silo
#

let me check rq

#

Since I transitioned to using the accessway. I'm only using the FLDPLACENAME one to change the name.

#

But I guess now that I know it's possible to change stuff I could probably move back to using that unused field.

rancid silo
rancid silo
lone sparrow
rancid silo
#

Thats true. Breaking into new filetypes needs to be a thread.

#

were up to 1512 messages in this thread lol so yeah probably needs to be a new thread

#

we'll do the BGM thing then I'll make a new thread.

rancid silo
#

I might be stupid

#

I was just sitting here thinking about the music thing. And I just realized.

#

I had my music volume turned down

#

so let me test that old BGM file rq

lone sparrow
#

LOL. I still suspect it won't do anything.

#

If the file works how I expect it to (and isn't secretly useless and hardcoded-over dark)

rancid silo
#

i'll try it without the file but im fairly sure it does indeed work

lone sparrow
#

That's the default music, so I think that would have happened without my change.

rancid silo
#

yeah it isn't the file

#

good to get that done after such a long time though.

#

Honestly because of testing I just completely forget the music ever exists sometimes.

lone sparrow
#

Tokyo Daylight is basically the final "we don't know what to play here" field BGM option in the file, lol. To actually make changes, I think I'd need to add the new entry at the top of the table, not at the bottom.

lone sparrow
rancid silo
lone sparrow
#

Nope, if you look at the table, there's an entry at the bottom with a bunch of -1 entries to catch all remaining cases. That's Tokyo Daylight ๐Ÿ˜„

rancid silo
#

Ah i see,

#

In any case. Can't I just reuse your code from when you were trying to add a name entry for the BGM FTD?

#

Though im not sure how to make it go to the top instead of the bottom

lone sparrow
#

I don't think I put that code in the repo, but basically, you'd need to make a new entry and insert it at the 0th position in the table rather than appending it at the end.

#

It'll be super quick once I'm at my computer, but I'll add it as a script so you can see what I mean.

rancid silo
#
    table1.Entries[-1].Data = b"The Coolest Place\x00"```

So then just make this 0 instead of -1? (you've had it in the repo ever since you put it up)
lone sparrow
#

That's for the field name table!

#

And that line changes the entry after it already exists. We need to add the new entry, first. But then, yes, it would be at 0 instead of -1.

rancid silo
#

oh I thought thats what you meant.

#

oh I can do this then I think

lone sparrow
#

This would be an entry in the FLDBGMCND table, or whatever it's called.

rancid silo
#

I know : )

lone sparrow
#

Cool, cool.

rancid silo
#

oh man I forgot how complicated FLDBGMCND is. You win this time... Since I need to make 7ft tall lavenza.

lone sparrow
#

A noble goal unto itself.

rancid silo
#

very true

lone sparrow
#

Okie doke, added a script modifying the BGM table! And that includes a MODDED_FLDBGMCND.FTD in the repo, but I'll also just attach it here:

#

You can see its contents with python -m Scripts.PrintTable --table-path /path/to/MODDED_FLDBGMCND.FTD --table-name FLDBGMCND.

#

(I made sure to add entries for both F001_006 and F015_001 so that, if this is going to work at all, it should do so wherever you have the field currently.)

rancid silo
#

I shall check it out

#

It works

rancid silo
#

Since thats done I'm gonna make a new thread and we can focus on breaking into those other map files.

lone sparrow
#

I think a projects thread makes sense at this point! (too late anyway though lol)

lone sparrow
rancid silo
#

Yeah, I recorded it earlier let me get that

rancid silo
lone sparrow
#

I understood the file correctly LFGHEEFUCKINGHOOO

rancid silo
#

Yeah you did a great job.

#

Well you've been doing an amazing job consistently but yeah

lone sparrow
#

Now we can put a bow on this thread... and maybe pick a different track later ๐Ÿ˜„