https://towerreversed.neocities.org/dump/ffl-meat-theory.txt thoughts on the ffl meat system in the context of randomised roms flavour combination table: 0AFD3 ~ 0B2A7 (25 rows of 29 bytes) result lists: 0B2A8 ~ 0B437 (25 lists of 16 bytes) meat levels: 0B438 ~ 0B4FF (low nybbles of 200 bytes) meat flavours: derived from lpic ids at 0B900 ~ 0B9C7 (see code at 00E02) main meat page: https://towerreversed.neocities.org/fflsaga/meat.html a monster eats the meat of another monster and transforms into something else. the meat levels of the two monsters are combined (just take the higher value) to get a result level. the flavours of the two monsters are taken together to look up a result list id from a table. meat and target levels each monster has a meat level of between 0 and E (hexadecimal). this correlates with other measures, like encounter region or stats levels, but is not quite the same as either. monsters in ffl are grouped into families of six that share a common picture. each family has exactly one member at the unencountered top level, with a meat level of E. each family has exactly one member at the final encounter level, with a meat level of either C or D. the result lists each correspond to one of the families (though are not listed in the same order as the meat flavours, so i try to avoid talking about "result flavour".) these consist of sixteen character ids for each of sixteen result levels (0~F). for symmetry you could represent these result lists in the form of "target levels" as in the main meat page; the minimum result level required to become a particular family member. by definition the lowest member always has a target level of 0. for example, the eye family (big eye, gazer, seeker, watcher, evil eye, and beholder) have meat levels of 368BDE in ffl, and the result list 5A 5A 5A 5A 5A 5B 5B 5C 5C 5C 5D 5D 5E 5E 5F 5F which could be read as target levels 057ACE. in ffl, the target levels generally allow you to become monsters one meat level higher than either participant. this contrasts with ffl2, where you can only ever become a certain level with meat (or eater) of at least that level. (except for the imp or minidragon you start with, of course. see below.) an important exception is that final-level monsters (C/D) can never become top-level monsters (E) without E meat. modified or randomised monsters how then to generate appropriate result lists when monsters have been randomised somehow? we assume that the monsters are still in families that follow the conventions proposed above. something like this: - for each family's result list: - initialise char id to the first member of the family - for each level byte from 0~C: - if this result level is the same as the meat level of any family member, then set the result byte to that member's char id; else: - if this result level is exactly one more than the meat level of any family member, then set the result byte to that member's char id; else: - set the result byte to the last written char id. - next level byte - then set byte D to fifth member (per the "important exception") - and set bytes E and F to sixth member - next family if this algorithm is applied to the families in unmodified ffl, you end up with result lists that are mostly the same as the result lists in ffl, which seems like a good sign. interestingly, the synthesised lists include the level changes seen in wsc saga. there are a couple of other discrepancies (ghosts, dragons) as well. (can a more accurate algorithm be found that exactly reproduces ffl?) however, if the randomisation process has only rearranged the existing ffl meat level profiles among new monster families, then it's probably easier to just forget all this and transfer the target level profile of the source family across as well, because by definition that will be ffl-appropriate. (eg. using the eye family example, whichever new family inherits the eyes' meat level profile of 368BDE could have its results list set to whatever monster ids correspond to: 1st 1st 1st 1st 1st 2nd 2nd 3rd 3rd 3rd 4th 4th 5th 5th 6th 6th) flavour breaking even with appropriate result lists, it's still possible for game balance to be wrecked through transformations. in ffl, for instance, changing into a level 0 golem would give you a woodman - the lowest golem available - but a woodman is still too powerful (meat level 4) to "deserve" to be the result of a low-level transformation. ffl handles this by having a strict tier system implicit in the flavour table. early-type monsters eating early-type meat can never change into late-type monsters (regardless of the levels.) any combination that leads you to the golem group necessarily involves monsters that are high-level enough to "deserve" to result in woodman. you can see the same idea more explicitly in ffl2. to use amuseum's terminology, a class A monster eating class A meat will never become a class B or C monster. (but this is also why the starting minidragon is so broken, because as a class C monster, it naturally transforms into class B and C monsters, so that even though it's low level, the resulting monster is much more powerful than it "deserves" to be.) but in a rom where monster levels and flavours have been modified, this tier system is likely to break down. how then to prevent game-breaking transformations? the most failproof solution is to sabotage the result lists, substituting lower level bytes with monster ids from different families. a level 0 golem, rather than giving you a woodman or any other kind of golem, would give you something like a skeleton or wererat (say) instead. - for each family's result list: - the first family member stays in place at the byte equal to their level, and also at the byte one below their level. (where they're still considered "within reach") - for each byte lower than that, overwrite with a randomly chosen monster whose meat level is the same as or one higher than the result level you're writing to. (or, lower? remember monsters should go down as well as up.) it might be possible to refine this method further for better results. appendix: flavour assignment by lpicid ffl large pics are grouped in batches according to their dimensions. the lpicid byte is a combination of batch-id (high nybble) and pic-id-within-batch (low nybble). 0x00E02 CD DB 05 call 05DB - (sets b to batch, c to id, ...) 0x00E05 21 16 0E ld hl,0E16 - flavour offsets address 0x00E08 78 ld a,b 0x00E09 C7 rst 0 - (adds value of a to hl) 0x00E0A 7E ld a,(hl) - load flavour offset for this batch 0x00E0B 81 add c - add id, to get final flavour value 0x00E0C C9 ret 0x00E16 00 0x00E17 07 0x00E18 12 0x00E19 1B (in saga, code is at 0E57, data is at 0E6B.) ffl flavour ids: 00: insect 00 01: fish 01 02: eye 02 03: slime 03 04: snake 04 05: worm 05 06: ghost 06 10: snakewoman 07 11: birdman 08 12: tiger 09 13: lizard 0A 14: plant 0B 15: skeleton 0C 16: wolfman 0D 17: crab 0E 18: insectman 0F 19: octopus 10 1A: zombie 11 1B: killer (12) 1C: wizard (13) 1D: samurai (14) 1E: robot (15) 20: golem 12 21: demon 13 22: rhino 14 23: chimera 15 24: dragon 16 25: bird 17 26: oni 18 27: machine (19) 28: genbu 1A 29: seiryu 1B 30: byakko 1B 31: suzaku 1C 32: creator (1D) 40: ashura (?) batch 4 does not have a flavour offset defined. trying to determine ashura's flavour id will read F5 from 0E1A (actually code, not data). this will then give screwy results if you try and plug it into the flavour combination code. do not involve ashura in meat.