Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "oot-model.h"
- #include <math.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <emscripten/emscripten.h>
- #define true 1
- #define false 0
- #define HASHSIZE 101
- #define max(a, b) (((a) > (b)) ? (a) : (b))
- #define min(a, b) (((a) < (b)) ? (a) : (b))
- #define abs(a) (((a) > 0) ? (a) : (-(a)))
- // LUT offsets for adult and child
- #define Offsets_ADULT_LINK_LUT_DL_WAIST 0x06005090
- #define Offsets_ADULT_LINK_LUT_DL_RTHIGH 0x06005098
- #define Offsets_ADULT_LINK_LUT_DL_RSHIN 0x060050A0
- #define Offsets_ADULT_LINK_LUT_DL_RFOOT 0x060050A8
- #define Offsets_ADULT_LINK_LUT_DL_LTHIGH 0x060050B0
- #define Offsets_ADULT_LINK_LUT_DL_LSHIN 0x060050B8
- #define Offsets_ADULT_LINK_LUT_DL_LFOOT 0x060050C0
- #define Offsets_ADULT_LINK_LUT_DL_HEAD 0x060050C8
- #define Offsets_ADULT_LINK_LUT_DL_HAT 0x060050D0
- #define Offsets_ADULT_LINK_LUT_DL_COLLAR 0x060050D8
- #define Offsets_ADULT_LINK_LUT_DL_LSHOULDER 0x060050E0
- #define Offsets_ADULT_LINK_LUT_DL_LFOREARM 0x060050E8
- #define Offsets_ADULT_LINK_LUT_DL_RSHOULDER 0x060050F0
- #define Offsets_ADULT_LINK_LUT_DL_RFOREARM 0x060050F8
- #define Offsets_ADULT_LINK_LUT_DL_TORSO 0x06005100
- #define Offsets_ADULT_LINK_LUT_DL_LHAND 0x06005108
- #define Offsets_ADULT_LINK_LUT_DL_LFIST 0x06005110
- #define Offsets_ADULT_LINK_LUT_DL_LHAND_BOTTLE 0x06005118
- #define Offsets_ADULT_LINK_LUT_DL_RHAND 0x06005120
- #define Offsets_ADULT_LINK_LUT_DL_RFIST 0x06005128
- #define Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATH 0x06005130
- #define Offsets_ADULT_LINK_LUT_DL_SWORD_HILT 0x06005138
- #define Offsets_ADULT_LINK_LUT_DL_SWORD_BLADE 0x06005140
- #define Offsets_ADULT_LINK_LUT_DL_LONGSWORD_HILT 0x06005148
- #define Offsets_ADULT_LINK_LUT_DL_LONGSWORD_BLADE 0x06005150
- #define Offsets_ADULT_LINK_LUT_DL_LONGSWORD_BROKEN 0x06005158
- #define Offsets_ADULT_LINK_LUT_DL_SHIELD_HYLIAN 0x06005160
- #define Offsets_ADULT_LINK_LUT_DL_SHIELD_MIRROR 0x06005168
- #define Offsets_ADULT_LINK_LUT_DL_HAMMER 0x06005170
- #define Offsets_ADULT_LINK_LUT_DL_BOTTLE 0x06005178
- #define Offsets_ADULT_LINK_LUT_DL_BOW 0x06005180
- #define Offsets_ADULT_LINK_LUT_DL_OCARINA_TIME 0x06005188
- #define Offsets_ADULT_LINK_LUT_DL_HOOKSHOT 0x06005190
- #define Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFOREARM 0x06005198
- #define Offsets_ADULT_LINK_LUT_DL_UPGRADE_LHAND 0x060051A0
- #define Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFIST 0x060051A8
- #define Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFOREARM 0x060051B0
- #define Offsets_ADULT_LINK_LUT_DL_UPGRADE_RHAND 0x060051B8
- #define Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFIST 0x060051C0
- #define Offsets_ADULT_LINK_LUT_DL_BOOT_LIRON 0x060051C8
- #define Offsets_ADULT_LINK_LUT_DL_BOOT_RIRON 0x060051D0
- #define Offsets_ADULT_LINK_LUT_DL_BOOT_LHOVER 0x060051D8
- #define Offsets_ADULT_LINK_LUT_DL_BOOT_RHOVER 0x060051E0
- #define Offsets_ADULT_LINK_LUT_DL_FPS_LFOREARM 0x060051E8
- #define Offsets_ADULT_LINK_LUT_DL_FPS_LHAND 0x060051F0
- #define Offsets_ADULT_LINK_LUT_DL_FPS_RFOREARM 0x060051F8
- #define Offsets_ADULT_LINK_LUT_DL_FPS_RHAND 0x06005200
- #define Offsets_ADULT_LINK_LUT_DL_FPS_HOOKSHOT 0x06005208
- #define Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_CHAIN 0x06005210
- #define Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_HOOK 0x06005218
- #define Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_AIM 0x06005220
- #define Offsets_ADULT_LINK_LUT_DL_BOW_STRING 0x06005228
- #define Offsets_ADULT_LINK_LUT_DL_BLADEBREAK 0x06005230
- #define Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATHED 0x06005238
- #define Offsets_ADULT_LINK_LUT_DL_SHIELD_HYLIAN_BACK 0x06005258
- #define Offsets_ADULT_LINK_LUT_DL_SHIELD_MIRROR_BACK 0x06005268
- #define Offsets_ADULT_LINK_LUT_DL_SWORD_SHIELD_HYLIAN 0x06005278
- #define Offsets_ADULT_LINK_LUT_DL_SWORD_SHIELD_MIRROR 0x06005288
- #define Offsets_ADULT_LINK_LUT_DL_SHEATH0_HYLIAN 0x06005298
- #define Offsets_ADULT_LINK_LUT_DL_SHEATH0_MIRROR 0x060052A8
- #define Offsets_ADULT_LINK_LUT_DL_LFIST_SWORD 0x060052B8
- #define Offsets_ADULT_LINK_LUT_DL_LFIST_LONGSWORD 0x060052D0
- #define Offsets_ADULT_LINK_LUT_DL_LFIST_LONGSWORD_BROKEN 0x060052E8
- #define Offsets_ADULT_LINK_LUT_DL_LFIST_HAMMER 0x06005300
- #define Offsets_ADULT_LINK_LUT_DL_RFIST_SHIELD_HYLIAN 0x06005310
- #define Offsets_ADULT_LINK_LUT_DL_RFIST_SHIELD_MIRROR 0x06005320
- #define Offsets_ADULT_LINK_LUT_DL_RFIST_BOW 0x06005330
- #define Offsets_ADULT_LINK_LUT_DL_RFIST_HOOKSHOT 0x06005340
- #define Offsets_ADULT_LINK_LUT_DL_RHAND_OCARINA_TIME 0x06005350
- #define Offsets_ADULT_LINK_LUT_DL_FPS_RHAND_BOW 0x06005360
- #define Offsets_ADULT_LINK_LUT_DL_FPS_LHAND_HOOKSHOT 0x06005370
- #define Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU 0x060050D0
- #define Offsets_CHILD_LINK_LUT_DL_WAIST 0x060050D8
- #define Offsets_CHILD_LINK_LUT_DL_RTHIGH 0x060050E0
- #define Offsets_CHILD_LINK_LUT_DL_RSHIN 0x060050E8
- #define Offsets_CHILD_LINK_LUT_DL_RFOOT 0x060050F0
- #define Offsets_CHILD_LINK_LUT_DL_LTHIGH 0x060050F8
- #define Offsets_CHILD_LINK_LUT_DL_LSHIN 0x06005100
- #define Offsets_CHILD_LINK_LUT_DL_LFOOT 0x06005108
- #define Offsets_CHILD_LINK_LUT_DL_HEAD 0x06005110
- #define Offsets_CHILD_LINK_LUT_DL_HAT 0x06005118
- #define Offsets_CHILD_LINK_LUT_DL_COLLAR 0x06005120
- #define Offsets_CHILD_LINK_LUT_DL_LSHOULDER 0x06005128
- #define Offsets_CHILD_LINK_LUT_DL_LFOREARM 0x06005130
- #define Offsets_CHILD_LINK_LUT_DL_RSHOULDER 0x06005138
- #define Offsets_CHILD_LINK_LUT_DL_RFOREARM 0x06005140
- #define Offsets_CHILD_LINK_LUT_DL_TORSO 0x06005148
- #define Offsets_CHILD_LINK_LUT_DL_LHAND 0x06005150
- #define Offsets_CHILD_LINK_LUT_DL_LFIST 0x06005158
- #define Offsets_CHILD_LINK_LUT_DL_LHAND_BOTTLE 0x06005160
- #define Offsets_CHILD_LINK_LUT_DL_RHAND 0x06005168
- #define Offsets_CHILD_LINK_LUT_DL_RFIST 0x06005170
- #define Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATH 0x06005178
- #define Offsets_CHILD_LINK_LUT_DL_SWORD_HILT 0x06005180
- #define Offsets_CHILD_LINK_LUT_DL_SWORD_BLADE 0x06005188
- #define Offsets_CHILD_LINK_LUT_DL_SLINGSHOT 0x06005190
- #define Offsets_CHILD_LINK_LUT_DL_OCARINA_FAIRY 0x06005198
- #define Offsets_CHILD_LINK_LUT_DL_OCARINA_TIME 0x060051A0
- #define Offsets_CHILD_LINK_LUT_DL_DEKU_STICK 0x060051A8
- #define Offsets_CHILD_LINK_LUT_DL_BOOMERANG 0x060051B0
- #define Offsets_CHILD_LINK_LUT_DL_SHIELD_HYLIAN_BACK 0x060051B8
- #define Offsets_CHILD_LINK_LUT_DL_BOTTLE 0x060051C0
- #define Offsets_CHILD_LINK_LUT_DL_MASTER_SWORD 0x060051C8
- #define Offsets_CHILD_LINK_LUT_DL_GORON_BRACELET 0x060051D0
- #define Offsets_CHILD_LINK_LUT_DL_FPS_RIGHT_ARM 0x060051D8
- #define Offsets_CHILD_LINK_LUT_DL_SLINGSHOT_STRING 0x060051E0
- #define Offsets_CHILD_LINK_LUT_DL_MASK_BUNNY 0x060051E8
- #define Offsets_CHILD_LINK_LUT_DL_MASK_GERUDO 0x060051F0
- #define Offsets_CHILD_LINK_LUT_DL_MASK_GORON 0x060051F8
- #define Offsets_CHILD_LINK_LUT_DL_MASK_KEATON 0x06005200
- #define Offsets_CHILD_LINK_LUT_DL_MASK_SPOOKY 0x06005208
- #define Offsets_CHILD_LINK_LUT_DL_MASK_TRUTH 0x06005210
- #define Offsets_CHILD_LINK_LUT_DL_MASK_ZORA 0x06005218
- #define Offsets_CHILD_LINK_LUT_DL_MASK_SKULL 0x06005220
- #define Offsets_CHILD_LINK_DL_SWORD_SHEATHED 0x06005228
- #define Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATHED 0x06005248
- #define Offsets_CHILD_LINK_DL_SHIELD_DEKU_ODD 0x06005250
- #define Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_ODD 0x06005260
- #define Offsets_CHILD_LINK_DL_SHIELD_DEKU_BACK 0x06005268
- #define Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_BACK 0x06005278
- #define Offsets_CHILD_LINK_DL_SWORD_SHIELD_HYLIAN 0x06005280
- #define Offsets_CHILD_LINK_LUT_DL_SWORD_SHIELD_HYLIAN 0x06005290
- #define Offsets_CHILD_LINK_DL_SWORD_SHIELD_DEKU 0x06005298
- #define Offsets_CHILD_LINK_LUT_DL_SWORD_SHIELD_DEKU 0x060052A8
- #define Offsets_CHILD_LINK_DL_SHEATH0_HYLIAN 0x060052B0
- #define Offsets_CHILD_LINK_LUT_DL_SHEATH0_HYLIAN 0x060052C0
- #define Offsets_CHILD_LINK_DL_SHEATH0_DEKU 0x060052C8
- #define Offsets_CHILD_LINK_LUT_DL_SHEATH0_DEKU 0x060052D8
- #define Offsets_CHILD_LINK_DL_LFIST_SWORD 0x060052E0
- #define Offsets_CHILD_LINK_LUT_DL_LFIST_SWORD 0x060052F8
- #define Offsets_CHILD_LINK_DL_LHAND_PEDESTALSWORD 0x06005300
- #define Offsets_CHILD_LINK_LUT_DL_LHAND_PEDESTALSWORD 0x06005310
- #define Offsets_CHILD_LINK_DL_LFIST_BOOMERANG 0x06005318
- #define Offsets_CHILD_LINK_LUT_DL_LFIST_BOOMERANG 0x06005328
- #define Offsets_CHILD_LINK_DL_RFIST_SHIELD_DEKU 0x06005330
- #define Offsets_CHILD_LINK_LUT_DL_RFIST_SHIELD_DEKU 0x06005340
- #define Offsets_CHILD_LINK_DL_RFIST_SLINGSHOT 0x06005348
- #define Offsets_CHILD_LINK_LUT_DL_RFIST_SLINGSHOT 0x06005358
- #define Offsets_CHILD_LINK_DL_RHAND_OCARINA_FAIRY 0x06005360
- #define Offsets_CHILD_LINK_LUT_DL_RHAND_OCARINA_FAIRY 0x06005370
- #define Offsets_CHILD_LINK_DL_RHAND_OCARINA_TIME 0x06005378
- #define Offsets_CHILD_LINK_LUT_DL_RHAND_OCARINA_TIME 0x06005388
- #define Offsets_CHILD_LINK_DL_FPS_RARM_SLINGSHOT 0x06005390
- #define Offsets_CHILD_LINK_LUT_DL_FPS_RARM_SLINGSHOT 0x060053A0
- typedef struct Piece {
- const char* key;
- int LUT;
- int offset;
- } Piece;
- typedef struct Skip {
- const char* key;
- int start;
- int end;
- } Skip;
- typedef struct Limb {
- int x;
- int y;
- int z;
- } Limb;
- // Adult model pieces and their offsets, both in the LUT and in vanilla
- const Piece AdultPieces[] = {
- {"Sheath", Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATH, 0x249D8},
- {"FPS.Hookshot", Offsets_ADULT_LINK_LUT_DL_FPS_HOOKSHOT, 0x2A738},
- {"Hilt.2", Offsets_ADULT_LINK_LUT_DL_SWORD_HILT, 0x22060}, // 0x21F78 + 0xE8, skips blade
- {"Hilt.3", Offsets_ADULT_LINK_LUT_DL_LONGSWORD_HILT, 0x238C8},
- {"Blade.2", Offsets_ADULT_LINK_LUT_DL_SWORD_BLADE, 0x21F78},
- {"Hookshot.Spike", Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_HOOK, 0x2B288},
- {"Hookshot", Offsets_ADULT_LINK_LUT_DL_HOOKSHOT, 0x24D70},
- {"Fist.L", Offsets_ADULT_LINK_LUT_DL_LFIST, 0x21CE8},
- {"Fist.R", Offsets_ADULT_LINK_LUT_DL_RFIST, 0x226E0},
- {"FPS.Forearm.L", Offsets_ADULT_LINK_LUT_DL_FPS_LFOREARM, 0x29FA0},
- {"FPS.Forearm.R", Offsets_ADULT_LINK_LUT_DL_FPS_RFOREARM, 0x29918},
- {"Gauntlet.Fist.L", Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFIST, 0x25438},
- {"Gauntlet.Fist.R", Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFIST, 0x257B8},
- {"Gauntlet.Forearm.L", Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFOREARM, 0x25218},
- {"Gauntlet.Forearm.R", Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFOREARM, 0x25598},
- {"Gauntlet.Hand.L", Offsets_ADULT_LINK_LUT_DL_UPGRADE_LHAND, 0x252D8},
- {"Gauntlet.Hand.R", Offsets_ADULT_LINK_LUT_DL_UPGRADE_RHAND, 0x25658},
- {"Bottle.Hand.L", Offsets_ADULT_LINK_LUT_DL_LHAND_BOTTLE, 0x29600},
- {"FPS.Hand.L", Offsets_ADULT_LINK_LUT_DL_FPS_LHAND, 0x24B58},
- {"FPS.Hand.R", Offsets_ADULT_LINK_LUT_DL_FPS_RHAND, 0x29C20},
- {"Bow.String", Offsets_ADULT_LINK_LUT_DL_BOW_STRING, 0x2B108},
- {"Bow", Offsets_ADULT_LINK_LUT_DL_BOW, 0x22DA8},
- {"Blade.3.Break", Offsets_ADULT_LINK_LUT_DL_BLADEBREAK, 0x2BA38},
- {"Blade.3", Offsets_ADULT_LINK_LUT_DL_LONGSWORD_BLADE, 0x23A28}, // 0x238C8 + 0x160, skips hilt
- {"Bottle", Offsets_ADULT_LINK_LUT_DL_BOTTLE, 0x2AD58},
- {"Broken.Blade.3", Offsets_ADULT_LINK_LUT_DL_LONGSWORD_BROKEN,
- 0x23EB0}, // 0x23D50 + 0x160, skips hilt
- {"Foot.2.L", Offsets_ADULT_LINK_LUT_DL_BOOT_LIRON, 0x25918},
- {"Foot.2.R", Offsets_ADULT_LINK_LUT_DL_BOOT_RIRON, 0x25A60},
- {"Foot.3.L", Offsets_ADULT_LINK_LUT_DL_BOOT_LHOVER, 0x25BA8},
- {"Foot.3.R", Offsets_ADULT_LINK_LUT_DL_BOOT_RHOVER, 0x25DB0},
- {"Hammer", Offsets_ADULT_LINK_LUT_DL_HAMMER, 0x233E0},
- {"Hookshot.Aiming.Reticule", Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_AIM, 0x2CB48},
- {"Hookshot.Chain", Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_CHAIN, 0x2AFF0},
- {"Ocarina.2", Offsets_ADULT_LINK_LUT_DL_OCARINA_TIME, 0x248D8}, // 0x24698 + 0x240, skips hand
- {"Shield.2", Offsets_ADULT_LINK_LUT_DL_SHIELD_HYLIAN, 0x22970},
- {"Shield.3", Offsets_ADULT_LINK_LUT_DL_SHIELD_MIRROR, 0x241C0},
- {"Limb 1", Offsets_ADULT_LINK_LUT_DL_WAIST, 0x35330},
- {"Limb 3", Offsets_ADULT_LINK_LUT_DL_RTHIGH, 0x35678},
- {"Limb 4", Offsets_ADULT_LINK_LUT_DL_RSHIN, 0x358B0},
- {"Limb 5", Offsets_ADULT_LINK_LUT_DL_RFOOT, 0x358B0},
- {"Limb 6", Offsets_ADULT_LINK_LUT_DL_LTHIGH, 0x35CB8},
- {"Limb 7", Offsets_ADULT_LINK_LUT_DL_LSHIN, 0x35EF0},
- {"Limb 8", Offsets_ADULT_LINK_LUT_DL_LFOOT, 0x361A0},
- {"Limb 10", Offsets_ADULT_LINK_LUT_DL_HEAD, 0x365E8},
- {"Limb 11", Offsets_ADULT_LINK_LUT_DL_HAT, 0x36D30},
- {"Limb 12", Offsets_ADULT_LINK_LUT_DL_COLLAR, 0x362F8},
- {"Limb 13", Offsets_ADULT_LINK_LUT_DL_LSHOULDER, 0x37210},
- {"Limb 14", Offsets_ADULT_LINK_LUT_DL_LFOREARM, 0x373D8},
- {"Limb 15", Offsets_ADULT_LINK_LUT_DL_LHAND, 0x21AA8},
- {"Limb 16", Offsets_ADULT_LINK_LUT_DL_RSHOULDER, 0x36E58},
- {"Limb 17", Offsets_ADULT_LINK_LUT_DL_RFOREARM, 0x37018},
- {"Limb 18", Offsets_ADULT_LINK_LUT_DL_RHAND, 0x22498},
- {"Limb 20", Offsets_ADULT_LINK_LUT_DL_TORSO, 0x363B8},
- };
- // Note: Some skips which can be implemented by skipping the beginning portion of the model
- // rather than specifying those indices here, simply have their offset in the table above
- // increased by whatever amount of starting indices would be skipped.
- const Skip adultSkips[] = {
- {"FPS.Hookshot", 0x2F0, 0x618},
- {"Hilt.2", 0x1E8, 0x430},
- {"Hilt.3", 0x160, 0x480},
- {"Blade.2", 0xE8, 0x518},
- {"Hookshot", 0x250, 0x4A0},
- {"Bow", 0x158, 0x3B0},
- {"Blade.3", 0xB8, 0x320},
- {"Broken.Blade.3", 0xA0, 0x308},
- {"Hammer", 0x278, 0x4E0},
- {"Shield.2", 0x158, 0x2B8}, // Fist is in 2 pieces
- {"Shield.2", 0x3A8, 0x430}, // Fist is in 2 pieces
- {"Shield.3", 0x1B8, 0x3E8},
- };
- const Limb adultSkeleton[] = {
- {0xFFC7, 0x0D31, 0x0000}, // Limb 0
- {0x0000, 0x0000, 0x0000}, // Limb 1
- {0x03B1, 0x0000, 0x0000}, // Limb 2
- {0xFE71, 0x0045, 0xFF07}, // Limb 3
- {0x051A, 0x0000, 0x0000}, // Limb 4
- {0x04E8, 0x0005, 0x000B}, // Limb 5
- {0xFE74, 0x004C, 0x0108}, // Limb 6
- {0x0518, 0x0000, 0x0000}, // Limb 7
- {0x04E9, 0x0006, 0x0003}, // Limb 8
- {0x0000, 0x0015, 0xFFF9}, // Limb 9
- {0x0570, 0xFEFD, 0x0000}, // Limb 10
- {0xFED6, 0xFD44, 0x0000}, // Limb 11
- {0x0000, 0x0000, 0x0000}, // Limb 12
- {0x040F, 0xFF54, 0x02A8}, // Limb 13
- {0x0397, 0x0000, 0x0000}, // Limb 14
- {0x02F2, 0x0000, 0x0000}, // Limb 15
- {0x040F, 0xFF53, 0xFD58}, // Limb 16
- {0x0397, 0x0000, 0x0000}, // Limb 17
- {0x02F2, 0x0000, 0x0000}, // Limb 18
- {0x03D2, 0xFD4C, 0x0156}, // Limb 19
- {0x0000, 0x0000, 0x0000}, // Limb 20
- };
- const Piece ChildPieces[] = {
- {"Slingshot.String", Offsets_CHILD_LINK_LUT_DL_SLINGSHOT_STRING, 0x221A8},
- {"Sheath", Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATH, 0x15408},
- {"Blade.2", Offsets_CHILD_LINK_LUT_DL_MASTER_SWORD, 0x15698}, // 0x15540 + 0x158, skips fist
- {"Blade.1", Offsets_CHILD_LINK_LUT_DL_SWORD_BLADE,
- 0x14110}, // 0x13F38 + 0x1D8, skips fist and hilt
- {"Boomerang", Offsets_CHILD_LINK_LUT_DL_BOOMERANG, 0x14660},
- {"Fist.L", Offsets_CHILD_LINK_LUT_DL_LFIST, 0x13E18},
- {"Fist.R", Offsets_CHILD_LINK_LUT_DL_RFIST, 0x14320},
- {"Hilt.1", Offsets_CHILD_LINK_LUT_DL_SWORD_HILT, 0x14048}, // 0x13F38 + 0x110, skips fist
- {"Shield.1", Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU, 0x14440},
- {"Slingshot", Offsets_CHILD_LINK_LUT_DL_SLINGSHOT, 0x15F08}, // 0x15DF0 + 0x118, skips fist
- {"Ocarina.1", Offsets_CHILD_LINK_LUT_DL_OCARINA_FAIRY, 0x15BA8},
- {"Bottle", Offsets_CHILD_LINK_LUT_DL_BOTTLE, 0x18478},
- {"Ocarina.2", Offsets_CHILD_LINK_LUT_DL_OCARINA_TIME, 0x15AB8}, // 0x15958 + 0x160, skips hand
- {"Bottle.Hand.L", Offsets_CHILD_LINK_LUT_DL_LHAND_BOTTLE,
- 0x18478}, // Just the bottle, couldn't find one with hand and bottle
- {"GoronBracelet", Offsets_CHILD_LINK_LUT_DL_GORON_BRACELET, 0x16118},
- {"Mask.Bunny", Offsets_CHILD_LINK_LUT_DL_MASK_BUNNY, 0x2CA38},
- {"Mask.Skull", Offsets_CHILD_LINK_LUT_DL_MASK_SKULL, 0x2AD40},
- {"Mask.Spooky", Offsets_CHILD_LINK_LUT_DL_MASK_SPOOKY, 0x2AF70},
- {"Mask.Gerudo", Offsets_CHILD_LINK_LUT_DL_MASK_GERUDO, 0x2B788},
- {"Mask.Goron", Offsets_CHILD_LINK_LUT_DL_MASK_GORON, 0x2B350},
- {"Mask.Keaton", Offsets_CHILD_LINK_LUT_DL_MASK_KEATON, 0x2B060},
- {"Mask.Truth", Offsets_CHILD_LINK_LUT_DL_MASK_TRUTH, 0x2B1F0},
- {"Mask.Zora", Offsets_CHILD_LINK_LUT_DL_MASK_ZORA, 0x2B580},
- {"FPS.Forearm.R", Offsets_CHILD_LINK_LUT_DL_FPS_RIGHT_ARM, 0x18048},
- {"DekuStick", Offsets_CHILD_LINK_LUT_DL_DEKU_STICK, 0x6CC0},
- {"Shield.2", Offsets_CHILD_LINK_LUT_DL_SHIELD_HYLIAN_BACK,
- 0x14C30}, // 0x14B40 + 0xF0, skips sheath
- {"Limb 1", Offsets_CHILD_LINK_LUT_DL_WAIST, 0x202A8},
- {"Limb 3", Offsets_CHILD_LINK_LUT_DL_RTHIGH, 0x204F0},
- {"Limb 4", Offsets_CHILD_LINK_LUT_DL_RSHIN, 0x206E8},
- {"Limb 5", Offsets_CHILD_LINK_LUT_DL_RFOOT, 0x20978},
- {"Limb 6", Offsets_CHILD_LINK_LUT_DL_LTHIGH, 0x20AD8},
- {"Limb 7", Offsets_CHILD_LINK_LUT_DL_LSHIN, 0x20CD0},
- {"Limb 8", Offsets_CHILD_LINK_LUT_DL_LFOOT, 0x20F60},
- {"Limb 10", Offsets_CHILD_LINK_LUT_DL_HEAD, 0x21360},
- {"Limb 11", Offsets_CHILD_LINK_LUT_DL_HAT, 0x219B0},
- {"Limb 12", Offsets_CHILD_LINK_LUT_DL_COLLAR, 0x210C0},
- {"Limb 13", Offsets_CHILD_LINK_LUT_DL_LSHOULDER, 0x21E18},
- {"Limb 14", Offsets_CHILD_LINK_LUT_DL_LFOREARM, 0x21FE8},
- {"Limb 15", Offsets_CHILD_LINK_LUT_DL_LHAND, 0x13CB0},
- {"Limb 16", Offsets_CHILD_LINK_LUT_DL_RSHOULDER, 0x21AE8},
- {"Limb 17", Offsets_CHILD_LINK_LUT_DL_RFOREARM, 0x21CB8},
- {"Limb 18", Offsets_CHILD_LINK_LUT_DL_RHAND, 0x141C0},
- {"Limb 20", Offsets_CHILD_LINK_LUT_DL_TORSO, 0x21130},
- };
- const Skip childSkips[] = {
- {"Boomerang", 0x140, 0x240},
- {"Hilt.1", 0xC8, 0x170},
- {"Shield.1", 0x140, 0x218},
- {"Ocarina.1", 0x110, 0x240},
- };
- const Limb childSkeleton[] = {
- {0x0000, 0x0948, 0x0000}, // Limb 0
- {0xFFFC, 0xFF98, 0x0000}, // Limb 1
- {0x025F, 0x0000, 0x0000}, // Limb 2
- {0xFF54, 0x0032, 0xFF42}, // Limb 3
- {0x02B9, 0x0000, 0x0000}, // Limb 4
- {0x0339, 0x0005, 0x000B}, // Limb 5
- {0xFF56, 0x0039, 0x00C0}, // Limb 6
- {0x02B7, 0x0000, 0x0000}, // Limb 7
- {0x0331, 0x0008, 0x0004}, // Limb 8
- {0x0000, 0xFF99, 0xFFF9}, // Limb 9
- {0x03E4, 0xFF37, 0xFFFF}, // Limb 10
- {0xFE93, 0xFD62, 0x0000}, // Limb 11
- {0x0000, 0x0000, 0x0000}, // Limb 12
- {0x02B8, 0xFF51, 0x01D2}, // Limb 13
- {0x0245, 0x0000, 0x0000}, // Limb 14
- {0x0202, 0x0000, 0x0000}, // Limb 15
- {0x02B8, 0xFF51, 0xFE2E}, // Limb 16
- {0x0241, 0x0000, 0x0000}, // Limb 17
- {0x020D, 0x0000, 0x0000}, // Limb 18
- {0x0291, 0xFDF5, 0x016F}, // Limb 19
- {0x0000, 0x0000, 0x0000}, // Limb 20
- };
- // Misc. constants
- const uint BASE_OFFSET = 0x06000000;
- const uint LUT_START = 0x00005000;
- const uint LUT_END = 0x00005800;
- const uint PRE_CONSTANT_START = 0X0000500C;
- const uint ADULT_START = 0x00F86000;
- const uint ADULT_SIZE = 0x00037800;
- const uint ADULT_HIERARCHY = 0x06005380;
- const uint ADULT_POST_START = 0x00005238;
- const uint CHILD_START = 0x00FBE000;
- const uint CHILD_SIZE = 0x0002CF80;
- const uint CHILD_HIERARCHY = 0x060053A8;
- const uint CHILD_POST_START = 0x00005228;
- const int endianVal = 1;
- uint EndianSwap32(uint val) {
- bool smallEndian = ((*(char*)&endianVal) != 0);
- if (smallEndian) {
- uint new_val = 0;
- for (int i = 0; i < 4; i++) {
- new_val <<= 8;
- new_val |= (val & 0x00FF);
- val = val >> 8;
- }
- return new_val;
- }
- return val;
- }
- uint EndianSwap16(ushort val) {
- bool smallEndian = ((*(char*)&endianVal) != 0);
- if (smallEndian) {
- ushort new_val = 0;
- for (int i = 0; i < 2; i++) {
- new_val <<= 8;
- new_val |= (val & 0x00FF);
- val = val >> 8;
- }
- return new_val;
- }
- return val;
- }
- typedef struct IntEntry {
- int key;
- int value;
- struct IntEntry* next;
- } IntEntry;
- typedef struct IntMap {
- IntEntry* hashTable[HASHSIZE];
- } IntMap;
- void IntMap_Init(IntMap* map) {
- for (int i = 0; i < HASHSIZE; i++) {
- map->hashTable[i] = NULL;
- }
- }
- int hash(int key) { return (key * 31) % HASHSIZE; }
- bool IntMap_has(IntMap* map, int key) {
- IntEntry* entry = map->hashTable[hash(key)];
- for (; entry != NULL; entry = entry->next) {
- if (key == entry->key) {
- return true;
- }
- }
- return false;
- }
- int IntMap_get(IntMap* map, int key) {
- IntEntry* entry = map->hashTable[hash(key)];
- for (; entry != NULL; entry = entry->next) {
- if (key == entry->key) {
- return entry->value;
- }
- }
- return 0;
- }
- void IntMap_set(IntMap* map, int key, int value) {
- bool found = false;
- IntEntry* entry = map->hashTable[hash(key)];
- for (; entry != NULL; entry = entry->next) {
- if (key == entry->key) {
- found = true;
- break;
- }
- }
- if (!found) {
- entry = (IntEntry*)malloc(sizeof(entry));
- if (entry == NULL) {
- return;
- }
- entry->key = key;
- int index = hash(key);
- entry->next = map->hashTable[index];
- map->hashTable[index] = entry;
- }
- entry->value = value;
- }
- void IntMap_free(IntMap* map) {
- for (int i = 0; i < HASHSIZE; i++) {
- IntEntry* entry = map->hashTable[i];
- IntEntry* nextentry;
- while (entry != NULL) {
- nextentry = entry->next;
- free(entry);
- entry = nextentry;
- }
- map->hashTable[i] = NULL;
- }
- }
- typedef struct IntMapIterator {
- IntMap* map;
- int tableIndex;
- IntEntry* next;
- } IntMapIterator;
- void IntMapIterator_Init(IntMapIterator* it, IntMap* map) {
- it->map = map;
- it->tableIndex = 0;
- it->next = NULL;
- }
- IntEntry* IntMapIterator_Next(IntMapIterator* it) {
- if (it->tableIndex >= HASHSIZE) {
- return NULL;
- }
- for (; it->tableIndex < HASHSIZE; it->tableIndex++) {
- if (it->next == NULL) {
- it->next = it->map->hashTable[it->tableIndex];
- if (it->next == NULL) {
- continue;
- }
- return it->next;
- }
- it->next = it->next->next;
- if (it->next == NULL) {
- continue;
- }
- return it->next;
- }
- return NULL;
- }
- typedef struct Vector {
- uint8_t* data;
- int len;
- int size;
- } Vector;
- void Vector_Init(Vector* vector) {
- vector->len = 0;
- vector->size = 32;
- vector->data = (uint8_t*)malloc(vector->size);
- if (vector->data == NULL) {
- vector->size = 0;
- }
- }
- bool Vector_grow(Vector* vector) {
- int size_new = vector->size * 2;
- if (vector->size == 0) {
- size_new = 32;
- }
- uint8_t* data_new = (uint8_t*)malloc(size_new);
- if (data_new == NULL) {
- return false;
- }
- if (vector->size > 0) {
- memcpy(data_new, vector->data, vector->size);
- }
- if (vector->data != NULL)
- free(vector->data);
- vector->data = data_new;
- vector->size = size_new;
- return true;
- }
- void Vector_push(Vector* vector, uint8_t b) {
- while (vector->len >= vector->size) {
- if (!Vector_grow(vector)) {
- return;
- }
- }
- vector->data[vector->len] = b;
- vector->len++;
- }
- uint8_t Vector_pop(Vector* vector) {
- if (vector->len == 0) {
- return 0;
- }
- uint8_t val = vector->data[vector->len - 1];
- vector->len--;
- return val;
- }
- void Vector_extend(Vector* vector, const uint8_t* new_data, int length) {
- while ((vector->len + length) >= vector->size) {
- if (!Vector_grow(vector)) {
- return;
- }
- }
- memcpy(vector->data + vector->len, new_data, length);
- vector->len += length;
- }
- void Vector_free(Vector* vector) {
- if (vector->data != NULL) {
- free(vector->data);
- vector->data = NULL;
- }
- vector->size = 0;
- vector->len = 0;
- }
- typedef enum ModelBaseName {
- Code,
- Player,
- Hook,
- Shield,
- Stick,
- GraveyardKid,
- Guard,
- RunningMan
- } ModelBaseName;
- // Used for writer model pointers to the rom in place of the vanilla pointers
- typedef struct ModelPointerWriter {
- uint8_t* rom;
- int offset;
- int advance;
- int base;
- } ModelPointerWriter;
- void ModelPointerWriter_SetBase(ModelPointerWriter* writer, ModelBaseName base_name) {
- switch (base_name) {
- case Code:
- writer->base = 0x00A87000; // start of code
- break;
- case Player:
- writer->base = 0x00BCDB70;
- break;
- case Hook:
- writer->base = 0x00CAD2C0;
- break;
- case Shield:
- writer->base = 0x00DB1F40;
- break;
- case Stick:
- writer->base = 0x00EAD0F0;
- break;
- case GraveyardKid:
- writer->base = 0x00E60920;
- break;
- case Guard:
- writer->base = 0x00D1A690;
- break;
- case RunningMan:
- writer->base = 0x00E50440;
- break;
- }
- }
- void ModelPointerWriter_Init(ModelPointerWriter* writer) {
- writer->offset = 0;
- writer->advance = 4;
- writer->base = 0;
- ModelPointerWriter_SetBase(writer, Code);
- }
- void ModelPointerWriter_GoTo(ModelPointerWriter* writer, int dest) { writer->offset = dest; }
- void ModelPointerWriter_SetAdvance(ModelPointerWriter* writer, int adv) { writer->advance = adv; }
- int ModelPointerWriter_GetAddress(ModelPointerWriter* writer) {
- return writer->base + writer->offset;
- }
- void ModelPointerWriter_WriteModelData(ModelPointerWriter* writer, uint data) {
- *(uint*)(writer->rom + ModelPointerWriter_GetAddress(writer)) = EndianSwap32(data);
- writer->offset += writer->advance;
- }
- void ModelPointerWriter_WriteModelData16(ModelPointerWriter* writer, ushort data) {
- *(ushort*)(writer->rom + ModelPointerWriter_GetAddress(writer)) = EndianSwap16(data);
- writer->offset += 2;
- }
- void ModelPointerWriter_WriteModelDataHi(ModelPointerWriter* writer, uint data) {
- ModelPointerWriter_WriteModelData16(writer, (ushort)(data >> 16));
- }
- void ModelPointerWriter_WriteModelDataLo(ModelPointerWriter* writer, uint data) {
- ModelPointerWriter_WriteModelData16(writer, (ushort)data);
- }
- // Either return the starting index of the requested data (when start == 0)
- // or the offset of the element in the footer, if it exists (start > 0)
- int scan(const uint8_t* bytes, int byteslen, const char* data, int datalen, int start) {
- int dataindex = 0;
- if ((bytes == NULL) || (byteslen == 0) || (data == NULL)) {
- // printf("[C]Scan data empty, abort\n");
- return -1;
- }
- bool isStr = false;
- if (datalen < 0) {
- isStr = true;
- datalen = strlen(data);
- }
- for (int i = start; i < byteslen; i++) {
- // Byte matches next byte in string
- if (bytes[i] == (uint8_t)data[dataindex]) {
- dataindex += 1;
- // Special case: Bottle, Bow, Slingshot, Fist.L, and Fist.R are subsets of
- // Bottle.Hand.L, Bow.String, Slingshot.String, Gauntlet.Fist.L, and Gauntlet.Fist.R
- // respectively And Hookshot which is a subset of Hookshot.Spike, Hookshot.Chain,
- // Hookshot.Aiming.Reticule This leads to false positives. So if the next byte is . (0x2E)
- // then reset the count.
- if ((isStr) && (i < (byteslen - 1)) && (bytes[i + 1] == 0x2E) &&
- ((strncmp(data, "Bottle", datalen) == 0) || (strncmp(data, "Bow", datalen) == 0) ||
- (strncmp(data, "Slingshot", datalen) == 0) ||
- (strncmp(data, "Hookshot", datalen) == 0) || (strncmp(data, "Fist.L", datalen) == 0) ||
- (strncmp(data, "Fist.R", datalen) == 0) || (strncmp(data, "Blade.3", datalen) == 0))) {
- // Blade.3 is even wackier, as it is a subset of Blade.3.Break,
- // and also a forward subset of Broken.Blade.3, and has a period in it
- if (strncmp(data, "Blade.3", datalen) == 0) {
- bool resetCount = false;
- // If current byte is the "e" in "Blade.3", the period detected is the expected one- Carry
- // on If it isn't, then reset the count
- if (bytes[i] != 0x65) {
- resetCount = true;
- }
- // Make sure i is large enough, "Broken.Blad" is 11 chars (remember we're currently at the
- // e)
- if (!resetCount && (i > 10)) {
- // Check if "Broken." immediately preceeds this string
- if (strncmp((const char*)(bytes - 11), "Broken.", 7) == 0) {
- resetCount = true;
- }
- }
- if (resetCount) {
- dataindex = 0;
- }
- }
- // Fist.L and Fist.R are forward subsets of Gauntlet.Fist.x, check for "Gauntlet."
- // "Gauntlet.Fis" is 12 chars (we are currently at the t)
- else if (((strncmp(data, "Fist.L", datalen) == 0) ||
- (strncmp(data, "Fist.R", datalen) == 0)) &&
- (i > 11)) {
- // Check if "Gauntlet." immediately preceeds this string
- if (strncmp((const char*)(bytes - 12), "Gauntlet.", 8) == 0) {
- dataindex = 0;
- }
- }
- // Default case for Bottle, Bow, Slingshot, Hookshot, reset count
- else {
- dataindex = 0;
- }
- }
- // Special case for Hookshot: Forward subset of FPS.Hookshot, "FPS." is 4 chars
- // (Blade.3 and fists can check in the previous stanza since a . will be encountered at some
- // point)
- if ((isStr) && (strncmp(data, "Hookshot", datalen) == 0) && (dataindex == 1) && (i > 3)) {
- // Check if "FPS." immediately preceeds this string
- if (strncmp((const char*)(bytes - 4), "FPS.", 4) == 0) {
- dataindex = 0;
- }
- }
- // All bytes have been found, so a match
- if (dataindex == datalen) {
- // If start is 0 then looking for the footer, return the index
- if (start == 0) {
- return i + 1;
- }
- // Else, we want to know the offset, which will be after the footer and 1 padding byte
- else {
- i += 2;
- return EndianSwap32(*(uint*)(bytes + i));
- }
- }
- }
- // Match has been broken, reset to start of string
- else {
- dataindex = 0;
- }
- }
- // printf("[C]Scan found nothing, aborting\n");
- return -1;
- }
- // Follows pointers from the LUT until finding the actual DList, and returns the offset of the DList
- int unwrap(uint8_t* zobj, int address) {
- // An entry in the LUT will look something like 0xDE 01 0000 06014050
- // Only the last 3 bytes should be necessary.
- uint data = EndianSwap32(*(uint*)(zobj + address + 4)) & 0x00FFFFFF;
- // If the data here points to another entry in the LUT, keep searching until
- // an address outside the table is found.
- while ((LUT_START <= data) && (data <= LUT_END)) {
- address = data;
- data = EndianSwap32(*(uint*)(zobj + address + 4)) & 0x00FFFFFF;
- }
- return address;
- }
- // Used to overwrite pointers in the displaylist with new ones
- void WriteDLPointer(uint8_t* dl, int index, uint data) {
- *((uint*)(dl + index)) = EndianSwap32(data);
- }
- // An extensive function which loads pieces from the vanilla Link model to add to the user-provided
- // zobj Based on
- // https://github.com/hylian-modding/ML64-Z64Lib/blob/master/cores/Z64Lib/API/zzoptimize.ts function
- // optimize()
- Vector LoadVanilla(uint8_t* rom, int rebase, int linkstart, int linksize, const Piece pieces[],
- bool missing[], uint DLOffsets[], int pieceCount, const Skip skips[], int skipCount) {
- // Get vanilla "zobj" of Link's model
- const uint8_t* vanillaData = rom + linkstart;
- int vanillaDataSize = linksize;
- int segment = 0x06;
- IntMap vertices;
- IntMap matrices;
- IntMap textures;
- IntMap_Init(&vertices);
- IntMap_Init(&matrices);
- IntMap_Init(&textures);
- Vector* displayLists = calloc(pieceCount, sizeof(Vector));
- uint* offsets = malloc(pieceCount * sizeof(uint));
- // For each missing piece, grab data from its vanilla display list
- for (int m = 0; m < pieceCount; m++) {
- if (!missing[m]) {
- continue;
- }
- const char* item = pieces[m].key;
- int offset = pieces[m].offset;
- int i = offset;
- Vector* displayList = &displayLists[m];
- Vector_Init(displayList);
- // Crawl displaylist bytecode and handle each command
- while (i < vanillaDataSize) {
- // Check if these bytes need to be skipped
- bool skipped = false;
- for (int s = 0; s < skipCount; s++) {
- Skip skip = skips[s];
- if (strcmp(item, skip.key) == 0) {
- uint itemIndex = i - offset;
- if ((skip.start <= itemIndex) && (itemIndex < skip.end)) {
- skipped = true;
- break;
- }
- }
- }
- if (skipped) {
- i += 8;
- continue;
- }
- uint8_t op = vanillaData[i];
- uint8_t seg = vanillaData[i + 4];
- uint lo = EndianSwap32(*((uint*)(vanillaData + i + 4)));
- // Source for displaylist bytecode: https://hack64.net/wiki/doku.php?id=f3dex2
- if (op == 0xDF) { // End of list
- // DF: G_ENDDL
- // Terminates the current displaylist
- // DF 00 00 00 00 00 00 00
- Vector_extend(displayList, vanillaData + i, 8); // Make sure to write the DF
- break;
- }
- // Shouldn't have to deal with DE (branch to new display list)
- else if ((op == 0x01) && (seg == segment)) { // Vertex data
- // 01: G_VTX
- // Fills the vertex buffer with vertex information
- // 01 0[N N]0 [II] [SS SS SS SS]
- // N: Number of vertices
- // I: Where to start writing vertices inside the vertex buffer (start = II - N*2)
- // S: Segmented address to load vertices from
- // Grab the address from the low byte without teh base offset
- int vtxStart = lo & 0x00FFFFFF;
- // Grab the length of vertices from the instruction
- // (Number of vertices will be from the 4th and 5th nibble as shown above, but each length
- // 16)
- ushort vtxLen = EndianSwap16(*((ushort*)(vanillaData + i + 1)));
- if ((!IntMap_has(&vertices, vtxStart)) || (IntMap_get(&vertices, vtxStart) < vtxLen)) {
- IntMap_set(&vertices, vtxStart, vtxLen);
- }
- } else if ((op == 0xDA) && (seg == segment)) { // Push matrix
- // DA: G_MTX
- // Apply transformation matrix
- // DA 38 00 [PP] [AA AA AA AA]
- // P: Parameters for matrix
- // A: Segmented address of vectors of matrix
- // Grab the address from the low byte without the base offset
- int mtxStart = lo & 0x00FFFFFF;
- if (!IntMap_has(&matrices, mtxStart)) {
- IntMap_set(&matrices, mtxStart, 0x40); // Matrices always 0x40 long
- }
- } else if ((op == 0xFD) && (seg == segment)) { // Texture
- // G_SETTIMG
- // Sets the texture image offset
- // FD [fi] 00 00 [bb bb bb bb]
- // [fi] -> fffi i000
- // f: Texture format
- // i: Texture bitsize
- // b: Segmented address of texture
- // Use 3rd nibble to get the texture type
- int textureType = (vanillaData[i + 1] >> 3) & 0x1F;
- // Find the number of texel bits from the type
- int numTexelBits = 4 * pow(2, textureType & 0x03);
- // Get how many bytes there are per texel
- int bytesPerTexel = (int)(numTexelBits / 8);
- // Grab the address from the low byte without the base offset
- int texOffset = lo & 0x00FFFFFF;
- int numTexels = -1;
- Vector returnStack;
- Vector_Init(&returnStack);
- int j = i + 8;
- // The point of this loop is just to find the number of texels
- // so that it may be multiplied by the bytesPerTexel so we know
- // the length of the texture.
- while ((j < vanillaDataSize) && (numTexels == -1)) {
- uint8_t opJ = vanillaData[j];
- uint8_t segJ = vanillaData[j + 4];
- uint loJ = EndianSwap32(*((uint*)(vanillaData + j + 4)));
- if (opJ == 0xDF) {
- // End of branched texture, or something wrong
- if (returnStack.len == 0) {
- numTexels = 0;
- break;
- } else {
- j = Vector_pop(&returnStack);
- }
- } else if (opJ == 0xFD) {
- // Another texture command encountered, something wrong
- numTexels = 0;
- break;
- } else if (opJ == 0xDE) {
- // Branch to another texture
- if (segJ == segment) {
- if (vanillaData[j + 1] == 0x0) {
- Vector_push(&returnStack, j);
- }
- j = loJ & 0x00FFFFFF;
- }
- } else if (opJ == 0xF0) {
- // F0: G_LOADTLUT
- // Loads a number of colors for a pallette
- // F0 00 00 00 0[t] [cc c]0 00
- // t: Tile descriptor to load from
- // c: ((colour count-1) & 0x3FF) << 2
- // Just grab c from the instruction above
- // Shift right 12 to get past the first 3 0s, then
- // 2 more since c is shifted left twice, then add 1
- // to get the color count of this pallette.
- numTexels = ((loJ & 0x00FFF000) >> 14) + 1;
- break;
- // Also error if numTexels > 256
- } else if (opJ == 0xF3) {
- // F3: G_LOADBLOCK
- // Determines how much data to load after SETTIMG
- // F3 [SS S][T TT] 0[I] [XX X][D DD]
- // S: Upper left corner of texture's S-axis
- // T: Upper left corner of texture's T-axis
- // I: Tile descriptor
- // X: Number of texels to load, minus one
- // D: dxt (?)
- // Just grab X from the instruction, shift
- // right 12 times to get past 0s
- numTexels = ((loJ & 0x00FFF000) >> 12) + 1;
- break;
- }
- j += 8;
- }
- int dataLen = bytesPerTexel * numTexels;
- if ((!IntMap_has(&textures, texOffset)) || (IntMap_get(&textures, texOffset) < dataLen)) {
- IntMap_set(&textures, texOffset, dataLen);
- }
- Vector_free(&returnStack);
- }
- Vector_extend(displayList, vanillaData + i, 8);
- i += 8;
- }
- offsets[m] = offset;
- }
- // Create vanilla zobj of the pieces from data collected during crawl
- Vector vanillaZobj;
- Vector_Init(&vanillaZobj);
- IntMapIterator iterator;
- IntEntry* entry;
- // Add textures, vertices, and matrices to the beginning of the zobj
- // Textures
- IntMap oldTex2New;
- IntMap_Init(&oldTex2New);
- IntMapIterator_Init(&iterator, &textures);
- while ((entry = IntMapIterator_Next(&iterator)) != NULL) {
- IntMap_set(&oldTex2New, entry->key, vanillaZobj.len);
- Vector_extend(&vanillaZobj, vanillaData + entry->key, entry->value);
- }
- // Vertices
- IntMap oldVer2New;
- IntMap_Init(&oldVer2New);
- IntMapIterator_Init(&iterator, &vertices);
- while ((entry = IntMapIterator_Next(&iterator)) != NULL) {
- IntMap_set(&oldVer2New, entry->key, vanillaZobj.len);
- Vector_extend(&vanillaZobj, vanillaData + entry->key, entry->value);
- }
- // Matrices
- IntMap oldMtx2New;
- IntMap_Init(&oldMtx2New);
- IntMapIterator_Init(&iterator, &matrices);
- while ((entry = IntMapIterator_Next(&iterator)) != NULL) {
- IntMap_set(&oldMtx2New, entry->key, vanillaZobj.len);
- Vector_extend(&vanillaZobj, vanillaData + entry->key, entry->value);
- }
- // Now add display lists which will reference the data from the beginning of the zobj
- // Display lists
- IntMap oldDL2New;
- IntMap_Init(&oldDL2New);
- for (int e = 0; e < pieceCount; e++) {
- if (!missing[e]) {
- continue;
- }
- Vector displayList = displayLists[e];
- uint8_t* dl = displayList.data;
- int offset = offsets[e];
- IntMap_set(&oldDL2New, offset, vanillaZobj.len);
- for (int i = 0; i < displayList.len; i += 8) {
- uint8_t op = dl[i];
- uint8_t seg = dl[i + 4];
- int lo = EndianSwap32(*((uint*)(dl + i + 4)));
- if (seg == segment) {
- // If this instruction points to some data, it must be repointed
- switch (op) {
- case 0x01: {
- int vertEntry = IntMap_get(&oldVer2New, lo & 0x00FFFFFF);
- WriteDLPointer(dl, i + 4, BASE_OFFSET + vertEntry + rebase);
- } break;
- case 0xDA: {
- int mtxEntry = IntMap_get(&oldMtx2New, lo & 0x00FFFFFF);
- WriteDLPointer(dl, i + 4, BASE_OFFSET + mtxEntry + rebase);
- } break;
- case 0xFD: {
- int texEntry = IntMap_get(&oldTex2New, lo & 0x00FFFFFF);
- WriteDLPointer(dl, i + 4, BASE_OFFSET + texEntry + rebase);
- } break;
- case 0xDE: {
- int dlEntry = IntMap_get(&oldDL2New, lo & 0x00FFFFFF);
- WriteDLPointer(dl, i + 4, BASE_OFFSET + dlEntry + rebase);
- } break;
- default:
- break;
- }
- }
- }
- Vector_extend(&vanillaZobj, dl, displayList.len);
- // Pad to nearest multiple of 16
- while ((vanillaZobj.len % 0x10) != 0) {
- Vector_push(&vanillaZobj, 0x00);
- }
- }
- // Now find the relation of items to new offsets
- for (int m = 0; m < pieceCount; m++) {
- if (!missing[m]) {
- continue;
- }
- DLOffsets[m] = IntMap_get(&oldDL2New, pieces[m].offset);
- }
- IntMap_free(&vertices);
- IntMap_free(&matrices);
- IntMap_free(&textures);
- IntMap_free(&oldTex2New);
- IntMap_free(&oldVer2New);
- IntMap_free(&oldMtx2New);
- IntMap_free(&oldDL2New);
- IntMap_free(&vertices);
- IntMap_free(&vertices);
- for (int i = 0; i < pieceCount; i++) {
- Vector_free(&displayLists[i]);
- }
- free(displayLists);
- free(offsets);
- return vanillaZobj;
- }
- // Finds the address of the model's hierarchy so we can write the hierarchy pointer
- // Based on
- // https://github.com/hylian-modding/Z64Online/blob/master/src/Z64Online/common/cosmetics/UniversalAliasTable.ts
- // function findHierarchy()
- int FindHierarchy(uint8_t* zobj, int zobjlen, const char* agestr) {
- // Scan until we find a segmented pointer which is 0x0C or 0x10 more than
- // the preceeding data and loop until something that's not a segmented pointer is found
- // then return the position of the last segemented pointer.
- for (int i = 0; i < zobjlen; i += 4) {
- if (zobj[i] == 0x06) {
- int possible = EndianSwap32(*(int*)(zobj + i)) & 0x00FFFFFF;
- if (possible < zobjlen) {
- int possible2 = EndianSwap32(*(int*)(zobj + i - 4)) & 0x00FFFFFF;
- int diff = possible - possible2;
- if ((diff == 0x0C) || (diff == 0x10)) {
- int pos = i + 4;
- int count = 1;
- while (zobj[pos] == 0x06) {
- pos += 4;
- count += 1;
- }
- uint8_t a = zobj[pos];
- if (a != count) {
- continue;
- }
- // printf("[C]FindHierarchy returns pos: %i, possible1: %X, possible2: %X\n", pos - 4,
- // possible, possible2);
- return pos - 4;
- }
- }
- }
- }
- printf("[C]ModelDefinitionError: No hierarchy found in %s model- Did you check \"Link hierarchy "
- "format\" in zzconvert?\n",
- agestr);
- return -1;
- }
- #define TOLERANCE 0x100
- bool CheckDiff(int limb, int skeleton) {
- // The normal difference
- int normalDiff = abs(limb - skeleton);
- // Underflow/overflow diff
- // For example, if limb is 0xFFFF and skeleton is 0x0001, then they are technically only 2 apart
- // So subtract 0xFFFF from the absolute value of the difference to get the true differene in this
- // case Necessary since values are signed, but not represented as signed here
- int flowDiff = abs(normalDiff - 0xFFFF);
- // Take the minimum of the two differences
- int diff = min(normalDiff, flowDiff);
- // Return true if diff is too big
- return diff > TOLERANCE;
- }
- bool CheckSkeleton(uint8_t* zobj, int zobjlen, const Limb* skeleton, const char* agestr) {
- // Get the hierarchy pointer
- int hierarchy = FindHierarchy(zobj, zobjlen, agestr);
- // Get what the hierarchy pointer points to (pointer to limb 0)
- int limbPointer = EndianSwap32(*(int*)(zobj + hierarchy)) & 0x00FFFFFF;
- // Get the limb this points to
- int limb = EndianSwap32(*(int*)(zobj + limbPointer)) & 0x00FFFFFF;
- // Go through each limb in the table
- bool hasVanillaSkeleton = true;
- bool withinTolerance = true;
- for (int i = 0; i < 21; i++) {
- int offset = limb + i * 0x10;
- // X, Y, Z components are 2 bytes each
- int limbX = EndianSwap16(*(uint16_t*)(zobj + offset));
- int limbY = EndianSwap16(*(uint16_t*)(zobj + offset + 2));
- int limbZ = EndianSwap16(*(uint16_t*)(zobj + offset + 4));
- int skeletonX = skeleton[i].x;
- int skeletonY = skeleton[i].y;
- int skeletonZ = skeleton[i].z;
- // Check if the X, Y, and Z components all match
- if (limbX != skeletonX || limbY != skeletonY || limbZ != skeletonZ) {
- hasVanillaSkeleton = false;
- // Now check if the components are within a tolerance
- // Exclude limb 0 since that one is always zeroed out on models for some reason
- if (i > 0 && (CheckDiff(limbX, skeletonX) || CheckDiff(limbY, skeletonY) || CheckDiff(limbZ, skeletonZ))) {
- withinTolerance = false;
- break;
- }
- }
- }
- uint8_t tmpBytes[6];
- if (!hasVanillaSkeleton && withinTolerance) {
- hasVanillaSkeleton = true;
- for (int i = 0; i < 21; i++) {
- int offset = limb + i * 0x10;
- Limb limb = skeleton[i];
- tmpBytes[0] = (limb.x >> 8) & 0xFF;
- tmpBytes[1] = limb.x & 0xFF;
- tmpBytes[2] = (limb.y >> 8) & 0xFF;
- tmpBytes[3] = limb.y & 0xFF;
- tmpBytes[4] = (limb.z >> 8) & 0xFF;
- tmpBytes[5] = limb.z & 0xFF;
- memcpy(zobj + offset, tmpBytes, sizeof(tmpBytes));
- }
- }
- return hasVanillaSkeleton;
- }
- // Loads model from file and processes it by adding vanilla pieces and setting up the LUT if
- // necessary.
- int LoadModel(uint8_t* rom, uint8_t* zobj, int zobjlen, int age, uint8_t* preConstData,
- int preConstDataLen, uint8_t* postConstData, int postConstDataLen) {
- Vector new_zobj;
- Vector_Init(&new_zobj);
- bool missing[max(sizeof(AdultPieces) / sizeof(*AdultPieces),
- sizeof(ChildPieces) / sizeof(*ChildPieces))] = {false};
- uint DLOffsets[max(
- sizeof(AdultPieces) / sizeof(*AdultPieces), sizeof(ChildPieces) / sizeof(*ChildPieces))] = {0};
- // age 0 = adult, 1 = child
- int linkstart = ADULT_START;
- int linksize = ADULT_SIZE;
- int hierarchy = ADULT_HIERARCHY;
- int postconstantstart = ADULT_POST_START;
- const Piece* pieces = AdultPieces;
- const Skip* skips = adultSkips;
- const Limb* skeleton = adultSkeleton;
- int pieceCount = sizeof(AdultPieces) / sizeof(*AdultPieces);
- int skipCount = sizeof(adultSkips) / sizeof(*adultSkips);
- const char* agestr = "adult"; // Juse used for error messages
- if (age == 1) {
- linkstart = CHILD_START;
- linksize = CHILD_SIZE;
- hierarchy = CHILD_HIERARCHY;
- postconstantstart = CHILD_POST_START;
- pieces = ChildPieces;
- skips = childSkips;
- skeleton = childSkeleton;
- pieceCount = sizeof(ChildPieces) / sizeof(*ChildPieces);
- skipCount = sizeof(childSkips) / sizeof(*childSkips);
- agestr = "child";
- }
- if (zobjlen > linksize) {
- printf("[C]ModelDefinitionError: Model for %s too large- It is %i bytes, but must be at most "
- "%i bytes\n",
- agestr, zobjlen, linksize);
- return -1;
- }
- // See if the string MODLOADER64 appears before the LUT- if so this is a PlayAs model and needs no
- // further processing
- if (scan(zobj, zobjlen, "MODLOADER64", -1, 0) == -1) {
- // First, make sure all important bytes are zeroed out
- memset(zobj + LUT_START, 0x00, LUT_END - LUT_START);
- // Find which pieces are missing from this model
- int footerstart = scan(zobj, zobjlen, "!PlayAsManifest0", -1, 0);
- if (footerstart == -1) {
- printf("[C]ModelDefinitionError: No manifest found in %s model- Did you check \"Embed "
- "play-as data\" in zzconvert?\n",
- agestr);
- return -2;
- }
- int startaddr = footerstart - strlen("!PlayAsManifest0");
- bool anyMissing = false;
- for (int i = 0; i < pieceCount; i++) {
- Piece piece = pieces[i];
- int offset = scan(zobj, zobjlen, piece.key, -1, footerstart);
- if (offset == -1) {
- missing[i] = true;
- anyMissing = true;
- } else {
- missing[i] = false;
- DLOffsets[i] = offset;
- }
- }
- if (anyMissing) {
- // Load vanilla model data for missing pieces
- Vector vanillaZobj = LoadVanilla(rom, startaddr, linkstart, linksize, pieces, missing,
- DLOffsets, pieceCount, skips, skipCount);
- // Write vanilla zobj data to end of model zobj
- Vector_extend(&new_zobj, zobj, startaddr);
- Vector_extend(&new_zobj, vanillaZobj.data, vanillaZobj.len);
- Vector_extend(&new_zobj, zobj + startaddr, zobjlen - startaddr);
- zobj = new_zobj.data;
- zobjlen = new_zobj.len;
- if (zobjlen > linksize) {
- //FILE* test = fopen("/testModel.zobj", "wb");
- //fwrite(zobj, 1, zobjlen, test);
- //fclose(test);
- printf("[C]ModelDefinitionError: After processing, model for %s too large- It is %i bytes, "
- "but must be at most %i bytes\n",
- agestr, zobjlen, linksize);
- return -3;
- }
- // Now we have to set the lookup table for each item
- for (int i = 0; i < pieceCount; i++) {
- // Add the starting address to each offset so they're accurate to the updated zobj
- if (missing[i]) {
- DLOffsets[i] += startaddr;
- } else if (DLOffsets[i] >= startaddr) {
- DLOffsets[i] += vanillaZobj.len;
- }
- }
- Vector_free(&vanillaZobj);
- }
- for (int p = 0; p < pieceCount; p++) {
- Piece piece = pieces[p];
- uint lut = piece.LUT - BASE_OFFSET;
- uint entry = unwrap(zobj, lut);
- zobj[entry] = 0xDE;
- zobj[entry + 1] = 0x01;
- entry += 4;
- uint dladdress = DLOffsets[p] + BASE_OFFSET;
- *(uint*)(zobj + entry) = EndianSwap32(dladdress);
- }
- // Put prefix for easily finding LUT in RAM
- memcpy(zobj + LUT_START, "HEYLOOKHERE", strlen("HEYLOOKHERE"));
- // Set constants in the LUT
- memcpy(zobj + PRE_CONSTANT_START, preConstData, preConstDataLen);
- memcpy(zobj + postconstantstart, postConstData, postConstDataLen);
- // Set up hierarchy pointer
- int hierarchyOffset = FindHierarchy(zobj, zobjlen, agestr);
- if (hierarchyOffset == -1) {
- //FILE* test = fopen("/testModel.zobj", "wb");
- //fwrite(zobj, 1, zobjlen, test);
- //fclose(test);
- printf(
- "[C]ModelHierarchyError: After processing, found no hierarchy for model for %s\n", agestr);
- return -4;
- }
- uint hierarchyBytes = *(uint*)(zobj + hierarchyOffset); // Get the data the offset points to
- *(uint*)(zobj + hierarchy - BASE_OFFSET) = hierarchyBytes;
- zobj[hierarchy - BASE_OFFSET + 4] = 0x15; // Number of limbs
- zobj[hierarchy - BASE_OFFSET + 8] = 0x12; // Number of limbs to draw
- // // Save zobj for testing
- // with open(path + "Test_Processed.zobj", "wb") as f:
- // f.write(zobj)
- }
- // Check skeleton
- if (!CheckSkeleton(zobj, zobjlen, skeleton, agestr)) {
- // If skeleton not vanilla, display message in pause screen informing of this
- // rom.write_int16(rom.sym('illegal_model'), 1)
- printf(
- "[C]ModelSkeletonWarning: The used model has a modified skeleton and is not race legal!\n");
- char scriptBuffer[255];
- sprintf(scriptBuffer, "raceIllegalModelUsed('%s')", agestr);
- emscripten_run_script(scriptBuffer);
- }
- // Write zobj to vanilla object (object_link_boy or object_link_child)
- memcpy(rom + linkstart, zobj, zobjlen);
- Vector_free(&new_zobj);
- // Finally, want to return an address with a DF instruction for use when writing the model data
- const char dfBytes[] = {0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- int dfScan = scan(zobj, zobjlen, dfBytes, 8, 0);
- if (dfScan == -1) {
- //FILE* test = fopen("/testModel.zobj", "wb");
- //fwrite(zobj, 1, zobjlen, test);
- //fclose(test);
- printf("[C]ModelSignatureError: After processing, found no DF instruction for model for %s\n",
- agestr);
- return -5;
- }
- return dfScan - 8;
- }
- // Write in the adult model and repoint references to it
- int patch_model_adult(uint8_t* rom, uint8_t* zobj, int zobjlen, uint8_t* preConstData,
- int preConstDataLen, uint8_t* postConstData, int postConstDataLen) {
- // Load and process model
- int dfAddress = LoadModel(
- rom, zobj, zobjlen, 0, preConstData, preConstDataLen, postConstData, postConstDataLen);
- if (dfAddress < 0) {
- printf("[C]ModelError: Model patcher adult aborts with error code: %i\n", dfAddress);
- return dfAddress;
- }
- dfAddress |= 0x06000000; // Add segment to DF address
- // Write adult Link pointer data
- ModelPointerWriter writer = {rom};
- ModelPointerWriter_Init(&writer);
- ModelPointerWriter_GoTo(&writer, 0xE6718);
- ModelPointerWriter_SetAdvance(&writer, 8);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_SHIELD_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_SHIELD_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_SHIELD_MIRROR);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_SHIELD_MIRROR);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHIELD_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHIELD_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHIELD_MIRROR);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHIELD_MIRROR);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SHEATH0_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SHEATH0_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SHEATH0_MIRROR);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SHEATH0_MIRROR);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_LONGSWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_LONGSWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_LONGSWORD_BROKEN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_LONGSWORD_BROKEN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_SWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_SWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_BOW);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_BOW);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_WAIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_WAIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_BOW);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_BOW);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RHAND_OCARINA_TIME);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RHAND_OCARINA_TIME);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RHAND_OCARINA_TIME);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RHAND_OCARINA_TIME);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_HOOKSHOT);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RFIST_HOOKSHOT);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_HAMMER);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LFIST_HAMMER);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LHAND_BOTTLE);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_LHAND_BOTTLE);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_FPS_LFOREARM);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_FPS_LHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_RSHOULDER);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_FPS_RFOREARM);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_FPS_RHAND_BOW);
- ModelPointerWriter_GoTo(&writer, 0xE6A4C);
- ModelPointerWriter_SetAdvance(&writer, 4);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_BOOT_LIRON);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_BOOT_RIRON);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_BOOT_LHOVER);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_BOOT_RHOVER);
- ModelPointerWriter_GoTo(&writer, 0xE6B28);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_BOTTLE);
- ModelPointerWriter_GoTo(&writer, 0xE6B64);
- ModelPointerWriter_SetAdvance(&writer, 4);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_BOW_STRING);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000); // string anchor x: 0.0
- ModelPointerWriter_WriteModelData(&writer, 0xC3B43333); // string anchor y: -360.4
- ModelPointerWriter_GoTo(&writer, 0x69112);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFOREARM);
- ModelPointerWriter_GoTo(&writer, 0x69116);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFOREARM);
- ModelPointerWriter_GoTo(&writer, 0x6912E);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFOREARM);
- ModelPointerWriter_GoTo(&writer, 0x69132);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFOREARM);
- ModelPointerWriter_GoTo(&writer, 0x6914E);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFIST);
- ModelPointerWriter_GoTo(&writer, 0x69162);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_LFIST);
- ModelPointerWriter_GoTo(&writer, 0x69166);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_LHAND);
- ModelPointerWriter_GoTo(&writer, 0x69172);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_LHAND);
- ModelPointerWriter_GoTo(&writer, 0x6919E);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFIST);
- ModelPointerWriter_GoTo(&writer, 0x691A2);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_RFIST);
- ModelPointerWriter_GoTo(&writer, 0x691AE);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_RHAND);
- ModelPointerWriter_GoTo(&writer, 0x691B2);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_UPGRADE_RHAND);
- ModelPointerWriter_GoTo(&writer, 0x69DEA);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_FPS_LHAND_HOOKSHOT);
- ModelPointerWriter_GoTo(&writer, 0x69DEE);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_FPS_LHAND_HOOKSHOT);
- ModelPointerWriter_GoTo(&writer, 0x6A666);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_AIM);
- ModelPointerWriter_GoTo(&writer, 0x6A66A);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_AIM);
- ModelPointerWriter_SetBase(&writer, Hook);
- ModelPointerWriter_GoTo(&writer, 0xA72);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_HOOK);
- ModelPointerWriter_GoTo(&writer, 0xA76);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_HOOK);
- ModelPointerWriter_GoTo(&writer, 0xB66);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_CHAIN);
- ModelPointerWriter_GoTo(&writer, 0xB6A);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_ADULT_LINK_LUT_DL_HOOKSHOT_CHAIN);
- ModelPointerWriter_GoTo(&writer, 0xBA8);
- ModelPointerWriter_WriteModelData16(&writer, 0x0014);
- ModelPointerWriter_SetBase(&writer, Stick);
- ModelPointerWriter_GoTo(&writer, 0x32C);
- ModelPointerWriter_WriteModelData(&writer, Offsets_ADULT_LINK_LUT_DL_BLADEBREAK);
- ModelPointerWriter_GoTo(&writer, 0x328);
- ModelPointerWriter_WriteModelData16(&writer, 0x0014);
- ModelPointerWriter_SetBase(&writer, Code);
- ModelPointerWriter_GoTo(&writer, 0xE65A0);
- ModelPointerWriter_WriteModelData(&writer, ADULT_HIERARCHY); // Hierarchy pointer
- return 0;
- }
- // Write in the child model and repoint references to it
- int patch_model_child(uint8_t* rom, uint8_t* zobj, int zobjlen, uint8_t* preConstData,
- int preConstDataLen, uint8_t* postConstData, int postConstDataLen) {
- // Load and process model
- int dfAddress = LoadModel(
- rom, zobj, zobjlen, 1, preConstData, preConstDataLen, postConstData, postConstDataLen);
- if (dfAddress < 0) {
- printf("[C]ModelError: Model patcher child aborts with error code: %i\n", dfAddress);
- return dfAddress;
- }
- dfAddress |= 0x06000000; // Add segment to DF address
- // Write child Link pointer data
- ModelPointerWriter writer = {rom};
- ModelPointerWriter_Init(&writer);
- ModelPointerWriter_GoTo(&writer, 0xE671C);
- ModelPointerWriter_SetAdvance(&writer, 8);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST_SHIELD_DEKU);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST_SHIELD_DEKU);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHIELD_DEKU);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHIELD_DEKU);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHIELD_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHIELD_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_BACK);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_BACK);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHEATH0_DEKU);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHEATH0_DEKU);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHEATH0_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHEATH0_HYLIAN);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, dfAddress);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_BACK);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_BACK);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND_PEDESTALSWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND_PEDESTALSWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND_PEDESTALSWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND_PEDESTALSWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST_SWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST_SWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST_SWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST_SWORD);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RHAND);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST_SLINGSHOT);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST_SLINGSHOT);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATHED);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SWORD_SHEATH);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_WAIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_WAIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST_SLINGSHOT);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST_SLINGSHOT);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RHAND_OCARINA_FAIRY);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RHAND_OCARINA_FAIRY);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RHAND_OCARINA_TIME);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RHAND_OCARINA_TIME);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST_BOOMERANG);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LFIST_BOOMERANG);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND_BOTTLE);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_LHAND_BOTTLE);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_RSHOULDER);
- ModelPointerWriter_WriteModelData(&writer, 0x00000000);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_FPS_RARM_SLINGSHOT);
- ModelPointerWriter_GoTo(&writer, 0xE6B2C);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_BOTTLE);
- ModelPointerWriter_GoTo(&writer, 0xE6B74);
- ModelPointerWriter_SetAdvance(&writer, 4);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_SLINGSHOT_STRING);
- ModelPointerWriter_WriteModelData(&writer, 0x44178000); // string anchor x: 606.0
- ModelPointerWriter_WriteModelData(&writer, 0x436C0000); // string anchor y: 236.0
- ModelPointerWriter_GoTo(&writer, 0x6922E);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_CHILD_LINK_LUT_DL_GORON_BRACELET);
- ModelPointerWriter_GoTo(&writer, 0x69232);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_CHILD_LINK_LUT_DL_GORON_BRACELET);
- ModelPointerWriter_GoTo(&writer, 0x6A80E);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_CHILD_LINK_LUT_DL_DEKU_STICK);
- ModelPointerWriter_GoTo(&writer, 0x6A812);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_CHILD_LINK_LUT_DL_DEKU_STICK);
- ModelPointerWriter_SetBase(&writer, Stick);
- ModelPointerWriter_GoTo(&writer, 0x334);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_DEKU_STICK);
- ModelPointerWriter_GoTo(&writer, 0x330);
- ModelPointerWriter_WriteModelData16(&writer, 0x0015);
- ModelPointerWriter_SetBase(&writer, Shield);
- ModelPointerWriter_GoTo(&writer, 0x7EE);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_ODD);
- ModelPointerWriter_GoTo(&writer, 0x7F2);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_CHILD_LINK_LUT_DL_SHIELD_DEKU_ODD);
- ModelPointerWriter_SetBase(&writer, Player);
- ModelPointerWriter_GoTo(&writer, 0x2253C);
- ModelPointerWriter_SetAdvance(&writer, 4);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_KEATON);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_SKULL);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_SPOOKY);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_BUNNY);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_GORON);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_ZORA);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_GERUDO);
- ModelPointerWriter_WriteModelData(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_TRUTH);
- ModelPointerWriter_SetBase(&writer, GraveyardKid);
- ModelPointerWriter_GoTo(&writer, 0xE62);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_SPOOKY);
- ModelPointerWriter_GoTo(&writer, 0xE66);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_SPOOKY);
- ModelPointerWriter_SetBase(&writer, Guard);
- ModelPointerWriter_GoTo(&writer, 0x1EA2);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_KEATON);
- ModelPointerWriter_GoTo(&writer, 0x1EA6);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_KEATON);
- ModelPointerWriter_SetBase(&writer, RunningMan);
- ModelPointerWriter_GoTo(&writer, 0x1142);
- ModelPointerWriter_WriteModelDataHi(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_BUNNY);
- ModelPointerWriter_GoTo(&writer, 0x1146);
- ModelPointerWriter_WriteModelDataLo(&writer, Offsets_CHILD_LINK_LUT_DL_MASK_BUNNY);
- ModelPointerWriter_SetBase(&writer, Code);
- ModelPointerWriter_GoTo(&writer, 0xE65A4);
- ModelPointerWriter_WriteModelData(&writer, CHILD_HIERARCHY); // Hierarchy pointer
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement