#include <3ds.h> #include #include #include "savedata.h" #include "stringtool.h" #include "tonccpy.h" u8 saveRegion[4] = {0}; ss2character ss2CharacterData; ss3to4character ss4CharacterData; ss3to4emblem emblemData; const char* ss1SavePath; char ss1Save[0x100000]; char ss2Save[0x31736]; char ss3Save[0x174000]; char ss4Save[0xF0000]; char ss1PlayerName[10] = {0}; char ss2PlayerName[10] = {0}; char ss3PlayerName[10] = {0}; char ss4PlayerName[10] = {0}; char dlCharName[16] = {0}; static bool ss1SaveRead = false; static bool ss2SaveRead = false; static bool ss3SaveRead = false; static bool ss4SaveRead = false; static bool ss2SaveModified = false; static bool ss3SaveModified = false; //static bool ss4SaveModified = false; Handle handle4; FS_Archive archive4; #define SS4ToSS3SkinAmount 14 // Left: SS4, Right: SS3 static u8 SS4ToSS3SkinTable[SS4ToSS3SkinAmount][2] = { // Offset: 0x03 {0x09, 0x01}, // Alina {0x0A, 0x02}, // Rosie {0x0B, 0x05}, // Yolanda {0x0C, 0x01}, // ??? {0x0D, 0x01}, // Ethan {0x0E, 0x04}, // Tim {0x0F, 0x01}, // Johann {0x10, 0x03}, // Ken {0x11, 0x02}, // Melvin {0x12, 0x03}, // Xin {0x13, 0x07}, // Margot {0x14, 0x02}, // Camilla {0x15, 0x02}, // Fortman {0x16, 0x06}, // Oliver }; #define SS4ToSS3FaceShapeAmount 14 // Left: SS4, Right: SS3 static u8 SS4ToSS3FaceShapeTable[SS4ToSS3FaceShapeAmount][2] = { // Offset: 0x04 {0x07, 0x03}, // Alina {0x08, 0x01}, // Rosie {0x09, 0x03}, // Yolanda {0x0A, 0x03}, // Angélique {0x0B, 0x04}, // Ethan {0x0C, 0x06}, // Tim {0x0D, 0x05}, // Johann {0x0E, 0x04}, // Ken {0x0F, 0x04}, // Melvin {0x10, 0x01}, // Xin {0x11, 0x03}, // Margot {0x12, 0x01}, // Camilla {0x13, 0x04}, // Fortman {0x14, 0x04}, // Oliver }; #define SS3ToSS4EyeAmount 5 // Left: SS3, Right: SS4 static u8 SS3ToSS4EyeTable[SS3ToSS4EyeAmount][2] = { // Offset: 0x05 {0x04, 0x01}, {0x06, 0x0A}, {0x08, 0x17}, {0x0B, 0x0F}, {0x20, 0x1E}, }; #define SS4ToSS3EyeAmount 7 // Left: SS4, Right: SS3 static u8 SS4ToSS3EyeTable[SS4ToSS3EyeAmount][2] = { // Offset: 0x05 {0x24, 0x0A}, // Alina {0x25, 0x18}, // Rosie {0x26, 0x06}, // Yolanda {0x27, 0x01}, // Angélique {0x2D, 0x13}, // Xin {0x2E, 0x13}, // Margot {0x2F, 0x04}, // Camilla }; #define SS4FTMEyeAmount 27 // Left: Female, Right: Male static u8 SS4FTMEyeTable[SS4FTMEyeAmount][2] = { // Offset: 0x05 {0x01, 0x1E}, // P1, N1 {0x02, 0x1B}, // P1, N2 {0x03, 0x1E}, // P1, N3 {0x05, 0x1E}, // P1, N4 {0x07, 0x1B}, // P1, N5 {0x08, 0x20}, // P2, N1 {0x0A, 0x1E}, // P2, N2 {0x0C, 0x1A}, // P2, N3 {0x0D, 0x1E}, // P2, N4 {0x0E, 0x1E}, // P2, N5 {0x0F, 0x1A}, // P3, N1 {0x10, 0x1C}, // P3, N2 {0x11, 0x1E}, // P3, N3 {0x12, 0x1E}, // P3, N4 {0x13, 0x1A}, // P3, N5 {0x14, 0x1C}, // P4, N1 {0x15, 0x1E}, // P4, N2 {0x16, 0x1D}, // P4, N3 {0x17, 0x1E}, // P4, N4 {0x19, 0x1F}, // P4, N5 {0x24, 0x1A}, // Alina {0x25, 0x1E}, // Rosie {0x26, 0x1E}, // Yolanda {0x27, 0x1A}, // Angélique {0x2D, 0x1A}, // Xin {0x2E, 0x1A}, // Margot {0x2F, 0x1E}, // Camilla }; #define SS4MTFEyeAmount 15 // Left: Male, Right: Female static u8 SS4MTFEyeTable[SS4MTFEyeAmount][2] = { // Offset: 0x05 {0x1A, 0x0F}, // ??? -> P3, N1 {0x1B, 0x07}, // ??? -> P1, N5 {0x1C, 0x10}, // ??? -> P3, N2 {0x1D, 0x16}, // ??? -> P4, N3 {0x1E, 0x15}, // ??? -> P4, N2 {0x1F, 0x19}, // ??? -> P4, N5 {0x20, 0x08}, // ??? -> P2, N1 {0x21, 0x12}, // ??? -> P3, N4 {0x28, 0x07}, // Ethan -> P1, N5 {0x29, 0x19}, // Tim -> P4, N5 {0x2A, 0x10}, // Johann -> P3, N2 {0x2B, 0x16}, // Ken -> P4, N3 {0x2C, 0x16}, // Melvin -> P4, N3 {0x30, 0x07}, // Fortman -> P1, N5 {0x31, 0x19}, // Oliver -> P4, N5 }; #define SS3ToSS4MouthShapeAmount 8 // Left: SS3, Right: SS4 static u8 SS3ToSS4MouthShapeTable[SS3ToSS4MouthShapeAmount][2] = { // Offset: 0x06 {0x02, 0x0F}, {0x03, 0x0B}, {0x04, 0x0F}, {0x06, 0x03}, {0x0C, 0x0B}, {0x0E, 0x05}, {0x0D, 0x01}, {0x13, 0x10}, }; #define SS4ToSS3MouthShapeAmount 6 // Left: SS4, Right: SS3 static u8 SS4ToSS3MouthShapeTable[SS4ToSS3MouthShapeAmount][2] = { // Offset: 0x06 {0x03, 0x06}, {0x0B, 0x03}, {0x14, 0x05}, // Alina {0x15, 0x0D}, // Rosie {0x16, 0x06}, // Yolanda {0x17, 0x01}, // Angélique }; #define SS4FTMMouthShapeAmount 20 // Left: Female, Right: Male static u8 SS4FTMMouthShapeTable[SS4FTMMouthShapeAmount][2] = { // Offset: 0x06 {0x01, 0x10}, // P1, N1 {0x02, 0x11}, // P1, N2 {0x03, 0x11}, // P1, N3 {0x04, 0x11}, // P1, N4 {0x05, 0x12}, // P1, N5 {0x06, 0x11}, // P1, N6 {0x07, 0x12}, // P2, N1 {0x08, 0x11}, // P2, N2 {0x09, 0x11}, // P2, N3 {0x0A, 0x10}, // P2, N4 {0x0B, 0x10}, // P2, N5 {0x0D, 0x11}, // P2, N6 {0x0F, 0x11}, // P3, N1 {0x14, 0x12}, // Alina {0x15, 0x10}, // Rosie {0x16, 0x10}, // Yolanda {0x17, 0x11}, // Angélique {0x1D, 0x12}, // Xin {0x1E, 0x11}, // Margot {0x1F, 0x11}, // Camilla }; #define SS4MTFMouthShapeAmount 10 // Left: Male, Right: Female static u8 SS4MTFMouthShapeTable[SS4MTFMouthShapeAmount][2] = { // Offset: 0x06 {0x10, 0x0B}, // ??? -> P2, N5 {0x11, 0x0F}, // ??? -> P3, N1 {0x12, 0x05}, // ??? -> P1, N5 {0x18, 0x08}, // Ethan -> P2, N2 {0x19, 0x0B}, // Tim -> P2, N5 {0x1A, 0x0B}, // Johann -> P2, N5 {0x1B, 0x08}, // Ken -> P2, N2 {0x1C, 0x08}, // Melvin -> P2, N2 {0x20, 0x08}, // Fortman -> P2, N2 {0x21, 0x0B}, // Oliver -> P2, N5 }; #define SS3ToSS4EyebrowAmount 2 // Left: SS3, Right: SS4 static u8 SS3ToSS4EyebrowTable[SS3ToSS4EyebrowAmount][2] = { // Offset: 0x07 {0x04, 0x10}, {0x19, 0x17}, }; #define SS4ToSS3EyebrowAmount 4 // Left: SS4, Right: SS3 static u8 SS4ToSS3EyebrowTable[SS4ToSS3EyebrowAmount][2] = { // Offset: 0x07 {0x1E, 0x08}, // Alina {0x1F, 0x0F}, // Rosie {0x20, 0x0B}, // Yolanda {0x21, 0x10}, // Angélique }; #define SS4FTMEyebrowAmount 25 // Left: Female, Right: Male static u8 SS4FTMEyebrowTable[SS4FTMEyebrowAmount][2] = { // Offset: 0x07 {0x01, 0x17}, // Natural -> Fine Flat {0x02, 0x15}, // Fine Angle {0x03, 0x18}, // Full Flat -> Full Sharp Angle {0x05, 0x16}, // Short Full Taper {0x06, 0x18}, // Short Bold Round -> Full Sharp Angle {0x07, 0x19}, // Full Angled Flat {0x08, 0x17}, // Fine Round -> Fine Flat {0x09, 0x15}, // Fine Straight -> Fine Angle {0x0A, 0x1A}, // Ultra Short Angle {0x0B, 0x17}, // Fine Flat {0x0C, 0x17}, // Short Fine Taper -> Fine Flat {0x0D, 0x16}, // Full Soft Angle -> Natural Flat {0x0E, 0x18}, // Full Sharp Angle {0x0F, 0x23}, // Ultra Fine Arch -> Tim {0x10, 0x17}, // Fine Soft Arch -> Fine Flat {0x11, 0x24}, // Full Angle -> Johann {0x12, 0x16}, // Natural Flat {0x14, 0x23}, // Full Short Angle -> Tim {0x1E, 0x17}, // Alina -> Fine Flat {0x1F, 0x17}, // Rosie -> Fine Flat {0x20, 0x2B}, // Yolanda -> Oliver {0x21, 0x2A}, // Angélique -> Fortman {0x27, 0x17}, // Assistant (Xin) -> Fine Flat {0x28, 0x24}, // Margot -> Johann {0x29, 0x1A}, // Camilla -> Ultra Short Angle }; #define SS4MTFEyebrowAmount 13 // Left: Male, Right: Female static u8 SS4MTFEyebrowTable[SS4MTFEyebrowAmount][2] = { // Offset: 0x07 {0x15, 0x02}, // Fine Angle {0x16, 0x12}, // Natural Flat {0x17, 0x0B}, // Fine Flat {0x18, 0x0E}, // Full Sharp Angle {0x19, 0x07}, // Full Angled Flat {0x1A, 0x29}, // Ultra Short Angle -> Camilla {0x22, 0x09}, // Ethan -> Fine Straight {0x23, 0x14}, // Tim -> Full Short Angle {0x24, 0x28}, // Johann -> Margot {0x25, 0x0D}, // Ken -> Full Soft Angle {0x26, 0x0D}, // Melvin -> Full Soft Angle {0x2A, 0x21}, // Fortman -> Angélique {0x2B, 0x20}, // Oliver -> Yolanda }; #define SS3ToSS4LipstickAmount 19 // Left: SS3, Right: SS4 static u8 SS3ToSS4LipstickTable[SS3ToSS4LipstickAmount][2] = { // Offset: 0x0A {0x0F, 0x2B}, {0x15, 0x5E}, {0x17, 0x40}, {0x1A, 0x60}, {0x1F, 0x08}, {0x20, 0x39}, {0x21, 0x12}, {0x27, 0x2D}, {0x28, 0x5B}, {0x39, 0x6A}, {0x49, 0x71}, {0x51, 0x0F}, {0x55, 0x1E}, {0x5A, 0x63}, {0x65, 0x2C}, // Poinsettia -> Passionate Love {0x67, 0x02}, {0x68, 0x07}, {0x6F, 0x37}, {0x71, 0x31}, }; #define SS4LipstickAmount 117 // Left: SS4, Right: SS3 static u8 SS4ToSS3LipstickTable[SS4LipstickAmount][2] = { // Offset: 0x0A {0x01, 0x60}, // Strawberry Fancy -> Baby Pink {0x02, 0x67}, // Maple Macaroon -> Cherry Blossom {0x04, 0x67}, // Cranberry Cheesecake -> Cherry Blossom {0x05, 0x30}, // Baked Apple -> Starfish Orange {0x07, 0x68}, // Grape Splash -> City Pink {0x08, 0x6B}, // Berry Blast -> Soft Pink {0x0A, 0x67}, // Pearl Pink -> Cherry Blossom {0x10, 0x71}, // Soft Coral -> Hibiscus {0x13, 0x67}, // Earnest Glow -> Cherry Blossom {0x1F, 0x67}, // Pale Peach -> Cherry Blossom {0x22, 0x67}, // Ginseng -> Cherry Blossom {0x71, 0x67}, // Day Dreamer -> Cherry Blossom {0x06, 0x30}, // Lemon Drizzle -> Starfish Orange {0x0B, 0x30}, // Honey Tint -> Starfish Orange {0x0C, 0x30}, // Orange Kisses -> Starfish Orange {0x14, 0x30}, // Risky Blush -> Starfish Orange {0x20, 0x30}, // Pink Flush -> Starfish Orange {0x21, 0x49}, // Golden Wheat -> Champagne {0x23, 0x30}, // Orange Peel -> Starfish Orange {0x24, 0x30}, // Camomile -> Starfish Orange {0x25, 0x67}, // Rosebud -> Cherry Blossom {0x26, 0x6C}, // Beech Leaf -> Lemon Chiffon {0x27, 0x30}, // Wild Honey -> Starfish Orange {0x28, 0x30}, // Genmai -> Starfish Orange {0x29, 0x30}, // Salmon Pink -> Starfish Orange {0x2B, 0x17}, // Earthen Pink -> Marmalade {0x33, 0x15}, // Hot Chocolate -> Goldenrod {0x55, 0x15}, // Amber Smile -> Goldenrod {0x0E, 0x71}, // Reality Star -> Hibiscus {0x0F, 0x21}, // It Girl -> Celebration Pink {0x11, 0x65}, // Pink Spice -> Poinsettia {0x12, 0x20}, // Mulberry Crush -> Tiramisu {0x2A, 0x30}, // Coral Pink -> Starfish Orange {0x2C, 0x65}, // Passionate Love -> Poinsettia {0x2D, 0x53}, // True Love -> Fiery Rose {0x2E, 0x52}, // Eternal Love -> Chocolate Cake {0x31, 0x71}, // Sundae -> Hibiscus {0x34, 0x66}, // Rose Red -> Hot Pepper {0x38, 0x67}, // Camellia -> Cherry Blossom {0x39, 0x67}, // Rose Confection -> Cherry Blossom {0x69, 0x53}, // Amaranthine -> Fiery Rose {0x6A, 0x20}, // Pearled Rose -> Tiramisu {0x6B, 0x21}, // Dusky Cloud -> Celebration Pink {0x6C, 0x67}, // Shy Flamingo -> Cherry Blossom {0x1C, 0x22}, // Wrath -> Mahogany {0x35, 0x20}, // Misty Mauve -> Tiramisu {0x36, 0x24}, // Purple Rose -> Lantern Light {0x3B, 0x52}, // Burgundy Love -> Chocolate Cake {0x3C, 0x27}, // Crimson Future -> Rooibos Tea {0x3D, 0x4F}, // Mauve Mistake -> Bunny Purple {0x5B, 0x0E}, // Cherry Velvet -> Night Rose {0x5C, 0x29}, // Purple Tango -> Pansy {0x5D, 0x52}, // Terracotta Kiss -> Chocolate Cake {0x5E, 0x73}, // Harmonious -> Cocoa {0x5F, 0x24}, // Reckless Grin -> Lantern Light {0x60, 0x44}, // Delusion -> Redcurrant Cake {0x64, 0x1B}, // Citrus Mist -> Tabby Grey {0x67, 0x2E}, // Hot Cocoa -> Science Lion {0x6D, 0x52}, // Ashes of Roses -> Chocolate Cake {0x15, 0x15}, // Strategic Shimmer -> Goldenrod {0x16, 0x30}, // Lunar Gold -> Starfish Orange {0x17, 0x30}, // Serene Sparkle -> Starfish Orange {0x18, 0x6D}, // Divine Glow -> Yellow Balloon {0x19, 0x6C}, // Moonbeam -> Lemon Chiffon {0x1A, 0x30}, // Dawn Star -> Starfish Orange {0x1D, 0x6F}, // Acedia -> Maple Syrup {0x1E, 0x6F}, // Gluttony -> Maple Syrup {0x37, 0x74}, // Hidden Thorn -> Workbench Brown {0x3A, 0x72}, // Sepia Grey -> Walnut {0x63, 0x28}, // Mahogany Rose -> Glamorous Garnet {0x6E, 0x20}, // Late Roses -> Tiramisu {0x6F, 0x15}, // Dusty Roses -> Goldenrod {0x70, 0x15}, // Dreamer Girl -> Goldenrod {0x72, 0x49}, // Rose Moon -> Champagne {0x1B, 0x5C}, // Starshine -> Sunlight Sand {0x2F, 0x02}, // Angel's Whisper -> Snow White {0x30, 0x01}, // Angel's Wing -> Chalk White {0x3E, 0x28}, // Deep Heart -> Glamorous Garnet {0x51, 0x72}, // Californium Dreaming -> Walnut {0x53, 0x02}, // Precious Platinum -> Snow White {0x58, 0x76}, // Jack -> Railway Green {0x59, 0x56}, // King -> Cherrywood {0x5A, 0x1B}, // Ace -> Tabby Grey {0x65, 0x5B}, // Autumn Moon -> Night Sand {0x66, 0x44}, // Fine Vintage -> Redcurrant Cake {0x68, 0x73}, // Woodsmoke -> Cocoa {0x73, 0x10}, // Harvest Moon -> Chai Latte {0x74, 0x0A}, // Mystic Snowscape -> Owl Stone {0x75, 0x0F}, // Oblivion -> Jet Black {0x03, 0x6C}, // Orange Chiffon -> Lemon Chiffon {0x09, 0x2F}, // Orange Zest -> Banana {0x32, 0x61}, // Lavender Sorbet -> Meadow Pink {0x3F, 0x6B}, // Pink Charm -> Soft Pink {0x40, 0x17}, // Enchanting Orange -> Marmalade {0x41, 0x45}, // Spellbound Green -> Mint {0x42, 0x13}, // Bewitching Blue -> Blue Lagoon {0x43, 0x60}, // Pink Delight -> Baby Pink {0x44, 0x30}, // Marigold Girl -> Starfish Orange {0x45, 0x6D}, // Sunshine Idol -> Yellow Balloon {0x46, 0x1D}, // Aqua Darling -> Bicycle Blue {0x47, 0x6B}, // Candyfloss -> Soft Pink {0x48, 0x2F}, // Sunny Day -> Banana {0x49, 0x57}, // Apple Bliss -> Shrub Green {0x4A, 0x3B}, // Mermaid Splash -> Deep Azure {0x4B, 0x24}, // Geisha's Lips -> Lantern Light {0x4C, 0x3F}, // Green Tea -> Moss Green {0x4D, 0x57}, // Bamboo -> Shrub Green {0x4E, 0x65}, // Classic Red -> Poinsettia {0x4F, 0x6B}, // Matinee Violet -> Soft Pink {0x50, 0x3B}, // Eyecatching Blue -> Deep Azure {0x52, 0x6D}, // Solid Gold -> Yellow Balloon {0x54, 0x61}, // Amethyst Lips -> Meadow Pink {0x56, 0x17}, // Citrine Gloss -> Marmalade {0x57, 0x6D}, // Garnet Kiss -> Yellow Balloon {0x61, 0x1F}, // Candy Gelato -> Begonia {0x62, 0x6B}, // Foxglove -> Soft Pink }; #define SS3ToSS4MascaraAmount 13 // Left: SS3, Right: SS4 static u8 SS3ToSS4MascaraTable[SS3ToSS4MascaraAmount][2] = { // Offset: 0x0B {0x0B, 0x10}, {0x0F, 0x10}, {0x16, 0x20}, {0x22, 0x2F}, {0x28, 0x12}, {0x2A, 0x0E}, {0x33, 0x1C}, // Nocturne Blue -> Darkest Blue {0x42, 0x10}, {0x56, 0x02}, {0x5A, 0x2F}, {0x5D, 0x2F}, {0x5F, 0x2F}, {0x75, 0x10}, }; #define SS4MascaraAmount 48 // Left: SS4, Right: SS3 static u8 SS4ToSS3MascaraTable[SS4MascaraAmount][2] = { // Offset: 0x0B {0x01, 0x0D}, // Golden Brown -> Antique Door {0x02, 0x56}, // Butter Scone -> Cherrywood {0x03, 0x58}, // Marmalade -> Brick Tile {0x04, 0x2E}, // Espresso Shot -> Science Lion {0x05, 0x07}, // Iced Mocha -> Sawtooth Oak {0x0A, 0x5D}, // Ceylon Ebony -> Bitter Chocolate {0x0B, 0x22}, // Cuban Mahogany -> Mahogany {0x0C, 0x73}, // Sugar Maple -> Cocoa {0x18, 0x25}, // Butterfly Russet -> Maple {0x1B, 0x56}, // Quirky Wink -> Cherrywood {0x2F, 0x5D}, // Yeux Chocolats -> Bitter Chocolate {0x30, 0x0E}, // Coconut -> Night Rose {0x0D, 0x2A}, // Scandalous Scarlet -> Maroon {0x0E, 0x44}, // Villainous Violet -> Redcurrant Cake {0x0F, 0x46}, // Mischievous Mauve -> Mulberry {0x10, 0x00}, // True Obsidian -> None (Default Black) {0x11, 0x50}, // Volcanic Ash -> Amethyst Sky {0x12, 0x28}, // Lava Glow -> Glamorous Garnet {0x13, 0x62}, // Evening Sky -> Warm Brick {0x14, 0x5F}, // Still Waters -> Aubergine Entrée {0x19, 0x24}, // Cheeky Wink -> Lantern Light {0x06, 0x5E}, // Grunge Black -> Bass Charcoal {0x07, 0x5E}, // Punk Grey -> Bass Charcoal {0x08, 0x09}, // Indie Green -> Winter Green {0x09, 0x1B}, // Glam Grey -> Tabby Grey {0x15, 0x04}, // Moon Silver -> Station Grey {0x16, 0x18}, // Bumblebee Yellow -> Khaki {0x17, 0x54}, // Hummingbird Blue -> Tickled Blue {0x1A, 0x63}, // Charming Wink -> Metropolis Navy {0x1C, 0x33}, // Darkest Blue -> Nocturne Blue {0x1D, 0x50}, // Darkest Purple -> Amethyst Sky {0x1E, 0x3E}, // Darkest Green -> Green Shadow {0x1F, 0x48}, // Indigo -> Midnight Ocean {0x20, 0x39}, // Empire Line -> Sylvan Night {0x21, 0x3C}, // Lace Gloves -> Ivy Olive {0x22, 0x65}, // Vivacity -> Poinsettia {0x23, 0x71}, // Vermilion Orange -> Hibiscus {0x24, 0x4E}, // Grape Pop -> Rebel Violet {0x25, 0x1F}, // Paradise Gazer -> Begonia {0x26, 0x57}, // Cool Watermelon -> Shrub Green {0x27, 0x6D}, // Sweet Pineapple -> Yellow Balloon {0x28, 0x19}, // Tropical Night -> Lavender {0x29, 0x67}, // Secret Keeper -> Cherry Blossom {0x2A, 0x76}, // Soft Apple -> Railway Green {0x2B, 0x06}, // Delicate Indigo -> Lilac {0x2C, 0x13}, // Sea Ice -> Blue Lagoon {0x2D, 0x60}, // Winter Orchid -> Baby Pink {0x2E, 0x6E}, // Beachgazing -> Lemonade }; #define SS3ToSS4EyeshadowAmount 26 // Left: SS3, Right: SS4 static u8 SS3ToSS4EyeshadowTable[SS3ToSS4EyeshadowAmount][2] = { // Offset: 0x0C {0x02, 0x3D}, {0x04, 0x53}, {0x0A, 0x18}, {0x13, 0x40}, {0x14, 0x13}, {0x15, 0x3B}, {0x1A, 0x4E}, {0x1B, 0x56}, // Tabby Grey -> Devilishly Dark {0x1C, 0x4B}, {0x21, 0x3E}, {0x23, 0x2B}, {0x2A, 0x2B}, {0x2B, 0x08}, {0x31, 0x2F}, {0x32, 0x37}, // Gerbera -> Cool Peach {0x34, 0x50}, {0x36, 0x43}, {0x49, 0x18}, {0x5C, 0x3F}, {0x60, 0x5A}, {0x61, 0x32}, {0x69, 0x32}, {0x6A, 0x39}, {0x6E, 0x06}, {0x71, 0x0E}, // Hibiscus -> Afterparty {0x74, 0x29}, }; #define SS4EyeshadowAmount 94 // Left: SS4, Right: SS3 static u8 SS4ToSS3EyeshadowTable[SS4EyeshadowAmount][2] = { // Offset: 0x0C {0x01, 0x68}, // Candlelight Pink -> City Pink {0x02, 0x67}, // Shrinking Violet -> Cherry Blossom {0x03, 0x67}, // Sunset Clouds -> Cherry Blossom {0x04, 0x67}, // First Date Rose -> Cherry Blossom {0x05, 0x5C}, // Milky Tea -> Sunlight Sand {0x06, 0x68}, // Rose Tea -> City Pink {0x07, 0x6C}, // Cinnamon Tea -> Lemon Chiffon {0x08, 0x6C}, // Buttercream -> Lemon Chiffon {0x09, 0x68}, // Pink Fondant -> City Pink {0x0A, 0x68}, // Strawberry Marzipan -> City Pink {0x0B, 0x67}, // Sherbet Fizz -> Cherry Blossom {0x0C, 0x30}, // Jelly Bean -> Starfish Orange {0x0D, 0x30}, // Gum Drop -> Starfish Orange {0x5A, 0x60}, // Angel Eyed -> Baby Pink {0x0E, 0x71}, // Afterparty -> Hibiscus {0x0F, 0x67}, // Masterwork -> Cherry Blossom {0x10, 0x15}, // Matinée -> Goldenrod {0x11, 0x67}, // Curtain Rising -> Cherry Blossom {0x12, 0x71}, // Pink Lemonade -> Hibiscus {0x13, 0x15}, // Elderflower Cordial -> Goldenrod {0x14, 0x70}, // Ginger Ale -> Toasted Sesame {0x15, 0x10}, // Stylish Sister -> Chai Latte {0x16, 0x10}, // Dazzling Diva -> Chai Latte {0x17, 0x67}, // Fuchsia Fox -> Cherry Blossom {0x18, 0x15}, // Classy Lass -> Goldenrod {0x19, 0x30}, // Firelit Brush -> Starfish Orange {0x1A, 0x30}, // Fireheart -> Starfish Orange {0x1B, 0x12}, // Golden Flame -> Golden Arch {0x1C, 0x49}, // Candlewick -> Champagne {0x1D, 0x01}, // White Frost -> Chalk White {0x1E, 0x02}, // Morning Mist -> Snow White {0x20, 0x5B}, // Dewfall Grey -> Night Sand {0x2D, 0x0A}, // Night Dark -> Owl Stone {0x53, 0x07}, // Smooth Chocolate -> Sawtooth Oak {0x54, 0x49}, // Tea Biscuit -> Champagne {0x55, 0x5C}, // Champagne Pop -> Sunlight Sand {0x57, 0x0A}, // Devilishly Demure -> Owl Stone {0x58, 0x07}, // Devilishly Darling -> Sawtooth Oak {0x59, 0x03}, // Witch Child -> Misty Grey {0x5B, 0x20}, // Buccaneer Brown -> Tiramisu {0x5C, 0x5C}, // Apricutie -> Sunlight Sand {0x1F, 0x08}, // Evening Mist -> Antique Rose {0x21, 0x67}, // Plum Swallowtail -> Cherry Blossom {0x22, 0x08}, // Purple Emperor -> Antique Rose {0x23, 0x1E}, // Mischievous Mauve -> Blush Pink {0x24, 0x70}, // Meadow Brown -> Toasted Sesame {0x25, 0x60}, // Sweet Dreams -> Baby Pink {0x26, 0x08}, // Midnight Feast -> Antique Rose {0x27, 0x07}, // Dark Dawn -> Sawtooth Oak {0x28, 0x69}, // Evening Gown -> Strawberry Pink {0x29, 0x73}, // Lace Handkerchief -> Cocoa {0x2A, 0x23}, // Petticoats -> Elegant Rose {0x2B, 0x23}, // Trembling Flame -> Elegant Rose {0x2C, 0x08}, // Mystic Purple -> Antique Rose {0x4E, 0x08}, // Amethyst Appeal -> Antique Rose {0x52, 0x20}, // Earth Dancer -> Tiramisu {0x56, 0x1B}, // Devilishly Dark -> Tabby Grey {0x2E, 0x60}, // Strawberry Milkshake -> Baby Pink {0x2F, 0x2F}, // Mango Lassi -> Banana {0x30, 0x4A}, // Milky Melon -> Green Balloon {0x32, 0x6B}, // Guava -> Soft Pink {0x33, 0x71}, // Papaya -> Hibiscus {0x34, 0x2C}, // Liana Green -> Merry-Go-Green {0x36, 0x60}, // Cherry Sherbet -> Baby Pink {0x37, 0x17}, // Cool Peach -> Marmalade {0x3A, 0x71}, // Ruby Red -> Hibiscus {0x3B, 0x35}, // Topaz -> Golden Star {0x3E, 0x26}, // Moroccan Red -> Ruby {0x42, 0x66}, // Lotus Petal -> Hot Pepper {0x43, 0x12}, // Burnished Yellow -> Golden Arch {0x31, 0x1D}, // Cream Soda -> Bicycle Blue {0x35, 0x13}, // Scuba Blue -> Blue Lagoon {0x38, 0x05}, // Powder Purple -> Brilliant Purple {0x39, 0x13}, // Dreamy Blue -> Blue Lagoon {0x3C, 0x3F}, // Emerald -> Moss Green {0x3D, 0x4B}, // Sapphire -> Star Cerulean {0x3F, 0x57}, // India Green -> Shrub Green {0x40, 0x1C}, // Fijian Turquoise -> Emerald Ocean {0x41, 0x4B}, // Stormy Night -> Star Cerulean {0x44, 0x45}, // Olive Green -> Mint {0x45, 0x1C}, // Marina -> Emerald Ocean {0x46, 0x45}, // Milan -> Mint {0x47, 0x45}, // Prague -> Mint {0x48, 0x4A}, // Matcha Latte -> Green Balloon {0x49, 0x3F}, // London -> Moss Green {0x4A, 0x2C}, // Curtsy -> Merry-Go-Green {0x4B, 0x2D}, // Polite Society -> Lime {0x4C, 0x03}, // Steely Eye -> Misty Grey {0x4D, 0x3F}, // Strong Green Tea -> Moss Green {0x4F, 0x19}, // Night Hush -> Lavender {0x50, 0x3B}, // Fly By Night -> Deep Azure {0x51, 0x6A}, // Celestial -> Electric Blue {0x5D, 0x03}, // Lavender Ghost -> Misty Grey {0x5E, 0x13}, // Forest Hunter -> Blue Lagoon }; #define SS3ToSS4EyelinerAmount 16 // Left: SS3, Right: SS4 static u8 SS3ToSS4EyelinerTable[SS3ToSS4EyelinerAmount][2] = { // Offset: 0x0D {0x07, 0x30}, {0x0C, 0x07}, {0x0F, 0x14}, {0x10, 0x49}, {0x17, 0x44}, {0x1B, 0x5C}, {0x1C, 0x3B}, {0x21, 0x44}, // Celebration Pink -> Red Carpet {0x28, 0x14}, {0x36, 0x50}, {0x3B, 0x53}, {0x45, 0x19}, {0x4E, 0x2E}, {0x59, 0x42}, {0x73, 0x14}, {0x74, 0x06}, }; #define SS4EyelinerAmount 100 // Left: SS4, Right: SS3 static u8 SS4ToSS3EyelinerTable[SS4EyelinerAmount][2] = { // Offset: 0x0D {0x01, 0x68}, // Caramel Shot -> City Pink {0x02, 0x60}, // Rose Petal -> Baby Pink {0x03, 0x68}, // Cinnamon Sprinkles -> City Pink {0x04, 0x20}, // Cranberry Syrup -> Tiramisu {0x08, 0x67}, // Sweet Strawberry -> Cherry Blossom {0x09, 0x15}, // Mango Dream -> Goldenrod {0x0A, 0x21}, // Cassis Swirl -> Celebration Pink {0x1B, 0x67}, // Flamingo -> Cherry Blossom {0x1C, 0x68}, // Clover Blossom -> City Pink {0x1D, 0x67}, // Pink Oats -> Cherry Blossom {0x1E, 0x15}, // Ripe Corn -> Goldenrod {0x28, 0x67}, // Day's End -> Cherry Blossom {0x29, 0x06}, // Meadowsweet -> Lilac {0x2A, 0x69}, // Moirae Pink -> Strawberry Pink {0x2B, 0x72}, // Sepia Destiny -> Walnut {0x0B, 0x70}, // Cinnamon -> Toasted Sesame {0x0C, 0x14}, // Cumin -> Seaside Terrace {0x0D, 0x72}, // Pink Peppercorn -> Walnut {0x0E, 0x14}, // Solar Wind -> Seaside Terrace {0x0F, 0x70}, // Martian Soil -> Toasted Sesame {0x10, 0x2D}, // Comet Tail -> Lime {0x11, 0x67}, // Princess Pink -> Cherry Blossom {0x12, 0x30}, // Amber Crown -> Starfish Orange {0x13, 0x10}, // Crown Jewels -> Chai Latte {0x49, 0x2B}, // Bright Gold -> Gold Bell {0x4A, 0x6E}, // Sugarspun Yellow -> Lemonade {0x50, 0x2B}, // Starry Night -> Gold Bell {0x51, 0x35}, // A Dozen Red Roses -> Golden Star {0x05, 0x0A}, // Cocoa Butter -> Owl Stone {0x06, 0x73}, // Chocolate -> Cocoa {0x07, 0x72}, // Caramel Ribbon -> Walnut {0x17, 0x49}, // Ochre Loam -> Champagne {0x18, 0x68}, // Apricot Flower -> City Pink {0x19, 0x6C}, // Winter Earth -> Lemon Chiffon {0x1A, 0x5C}, // Nut Brown -> Sunlight Sand {0x1F, 0x68}, // Pearl Barley -> City Pink {0x20, 0x15}, // Melted Honey -> Goldenrod {0x21, 0x10}, // Creamed Honey -> Chai Latte {0x22, 0x5C}, // Honeycomb -> Sunlight Sand {0x5C, 0x0A}, // Chocoholic -> Owl Stone {0x5D, 0x49}, // Sunset Cloud -> Champagne {0x5E, 0x5C}, // Golden Hour -> Sunlight Sand {0x14, 0x5E}, // Pure Black -> Bass Charcoal {0x15, 0x73}, // Coffee Roast -> Cocoa {0x16, 0x0A}, // Bitter Brown -> Owl Stone {0x2C, 0x08}, // Fey Lilac -> Antique Rose {0x2D, 0x07}, // Bronze Kismet -> Sawtooth Oak {0x2E, 0x64}, // Graceful Violet -> Afternoon Rose {0x2F, 0x73}, // Bitter Rose -> Cocoa {0x30, 0x1E}, // Graceful Dahlia -> Blush Pink {0x31, 0x1B}, // Midnight Black -> Tabby Grey {0x32, 0x04}, // Shadow Grey -> Station Grey {0x33, 0x19}, // Starlit Blue -> Lavender {0x57, 0x76}, // Chaotic Green -> Railway Green {0x58, 0x08}, // Galactic Violet -> Antique Rose {0x59, 0x06}, // Anemone Blue -> Lilac {0x5A, 0x54}, // Moondark Blue -> Tickled Blue {0x5B, 0x6A}, // Mystic Dance -> Electric Blue {0x34, 0x60}, // Sugarspun Pink -> Baby Pink {0x35, 0x2F}, // Mango Mallow -> Banana {0x36, 0x57}, // Peppermint Thrill -> Shrub Green {0x37, 0x1D}, // Icing Sugar -> Bicycle Blue {0x38, 0x6B}, // Ferris Wheel -> Soft Pink {0x39, 0x71}, // Merry-Go-Round -> Hibiscus {0x3A, 0x2C}, // Waltzer -> Merry-Go-Green {0x3B, 0x1C}, // Teacups -> Emerald Ocean {0x3C, 0x60}, // Pink Flash -> Baby Pink {0x3D, 0x30}, // Orange Streak -> Starfish Orange {0x3E, 0x05}, // Lilac Gleam -> Brilliant Purple {0x3F, 0x13}, // Blue Burst -> Blue Lagoon {0x40, 0x71}, // Gourmet Truffles -> Hibiscus {0x41, 0x2B}, // Quail's Eggs -> Gold Bell {0x42, 0x3F}, // Soufflé -> Moss Green {0x43, 0x6A}, // Salmon Terrine -> Electric Blue {0x44, 0x26}, // Red Carpet -> Ruby {0x45, 0x57}, // Acceptance Speech -> Shrub Green {0x46, 0x13}, // Perfect Dress -> Blue Lagoon {0x47, 0x54}, // Guestlist Glitterati -> Tickled Blue {0x48, 0x67}, // Sunset Glow -> Cherry Blossom {0x4B, 0x57}, // Emerald River -> Shrub Green {0x52, 0x13}, // Diamond Ring -> Blue Lagoon {0x53, 0x54}, // Tosca -> Tickled Blue {0x54, 0x34}, // Macbeth -> Sapphire Snapshot {0x55, 0x37}, // Faust -> Taylor Green {0x56, 0x3C}, // The Valkyrie -> Ivy Olive {0x64, 0x54}, // Sweet Thunder -> Tickled Blue {0x23, 0x01}, // Spidersilk -> Chalk White {0x24, 0x02}, // Spinneret -> Snow White {0x25, 0x60}, // Lilac Mist -> Baby Pink {0x26, 0x60}, // Silken Web -> Baby Pink {0x27, 0x5C}, // Lambswool -> Sunlight Sand {0x4C, 0x4A}, // Harlequin -> Green Balloon {0x4D, 0x45}, // Lovebird -> Mint {0x4E, 0x4A}, // Muted Jade -> Green Balloon {0x4F, 0x76}, // Lyrebird -> Railway Green {0x5F, 0x6C}, // Nebula -> Lemon Chiffon {0x60, 0x01}, // Starshine Shower -> Chalk White {0x61, 0x02}, // Moondrop -> Snow White {0x62, 0x02}, // Angelic Heart -> Snow White {0x63, 0x1D}, // Rainy Girl -> Bicycle Blue }; #define SS3ToSS4ContactAmount 23 // Left: SS3, Right: SS4 static u8 SS3ToSS4ContactTable[SS3ToSS4ContactAmount][2] = { // Offset: 0x0E {0x0A, 0x2F}, {0x13, 0x17}, // Blue Lagoon -> Turquoise Blue {0x14, 0x52}, {0x1C, 0x18}, {0x1E, 0x3B}, {0x20, 0x10}, {0x22, 0x3B}, {0x23, 0x0F}, {0x24, 0x1C}, {0x2C, 0x12}, {0x2D, 0x21}, {0x2E, 0x30}, // ??? -> Slate Grey {0x31, 0x12}, {0x46, 0x1D}, {0x55, 0x3F}, {0x5A, 0x30}, // ??? -> Slate Grey {0x5B, 0x31}, {0x5D, 0x51}, {0x64, 0x39}, {0x6A, 0x18}, // Electric Blue -> Sky Blue {0x6F, 0x51}, {0x72, 0x52}, {0x73, 0x3A}, }; #define SS4ContactAmount 89 // Left: SS4, Right: SS3 static u8 SS4ToSS3ContactTable[SS4ContactAmount][2] = { // Offset: 0x0E {0x2E, 0x04}, // Silver Grey -> Station Grey {0x2F, 0x1B}, // Grey -> Tabby Grey {0x30, 0x5E}, // Slate Grey -> Bass Charcoal {0x31, 0x5C}, // Stone Grey -> Sunlight Sand {0x32, 0x5C}, // Oyster -> Sunlight Sand {0x33, 0x0A}, // Gunmetal Grey -> Owl Stone {0x34, 0x05}, // Smoky Grey -> Brilliant Purple {0x35, 0x1B}, // Misty Grey -> Tabby Grey {0x36, 0x4B}, // Ash Grey -> Star Cerulean {0x08, 0x13}, // Electric Blue -> Blue Lagoon {0x17, 0x13}, // Turquoise Blue -> Blue Lagoon {0x58, 0x13}, // Angelic Blue -> Blue Lagoon {0x26, 0x1C}, // Peacock -> Emerald Ocean {0x09, 0x6A}, // Pale Blue -> Electric Blue {0x18, 0x6A}, // Sky Blue -> Electric Blue {0x27, 0x3B}, // Night Sky Blue -> Deep Azure {0x56, 0x54}, // Moonlight Blue -> Tickled Blue {0x0A, 0x05}, // Baby Blue -> Brilliant Purple {0x19, 0x3B}, // Hyacinth Blue -> Deep Azure {0x28, 0x3B}, // Dark Hyacinth -> Deep Azure {0x29, 0x63}, // Dark Ultramarine -> Metropolis Navy {0x54, 0x4B}, // Azure -> Star Cerulean {0x0B, 0x06}, // Pale Violet -> Lilac {0x1A, 0x19}, // Ultramarine -> Lavender {0x2A, 0x1A}, // Dark Violet -> Violet {0x4E, 0x19}, // Grape -> Lavender {0x0C, 0x06}, // Lilac {0x1B, 0x19}, // Violet -> Lavender {0x2B, 0x4E}, // Royal Purple -> Rebel Violet {0x2C, 0x4E}, // Plum -> Rebel Violet {0x4D, 0x06}, // Purple -> Lilac {0x37, 0x08}, // Violet Grey -> Antique Rose {0x42, 0x60}, // Pearly Purple -> Baby Pink {0x43, 0x60}, // Pale Lavender -> Baby Pink {0x0D, 0x60}, // Soft Lavender -> Baby Pink {0x0E, 0x60}, // Candyfloss Pink -> Baby Pink {0x1C, 0x61}, // Raspberry -> Meadow Pink {0x1D, 0x1E}, // Warm Pink -> Blush Pink {0x4F, 0x68}, // Baby Pink -> City Pink {0x50, 0x6B}, // Pink -> Soft Pink {0x55, 0x69}, // Blossom Pink -> Strawberry Pink {0x01, 0x67}, // Carnation Pink -> Cherry Blossom {0x0F, 0x21}, // Terracotta -> Celebration Pink {0x1E, 0x27}, // Deep Reed -> Rooibos Tea {0x2D, 0x44}, // Dark Raspberry -> Redcurrant Cake {0x38, 0x21}, // Coral -> Celebration Pink {0x39, 0x64}, // Ruby Red -> Afternoon Rose {0x53, 0x53}, // Garnet -> Fiery Rose {0x02, 0x07}, // Light Brown -> Sawtooth Oak {0x10, 0x15}, // Brown -> Goldenrod {0x1F, 0x6F}, // Dark Brown -> Maple Syrup {0x3B, 0x23}, // Chocolate Brown -> Elegant Rose {0x3A, 0x07}, // Cocoa Brown -> Sawtooth Oak {0x52, 0x72}, // Mocha Brown -> Walnut {0x20, 0x14}, // Dark Amber -> Seaside Terrace {0x3C, 0x74}, // Sepia -> Workbench Brown {0x3D, 0x5C}, // Hazel Sepia -> Sunlight Sand {0x3E, 0x14}, // Khaki -> Seaside Terrace {0x3F, 0x0D}, // Burnt Umber -> Antique Door {0x51, 0x72}, // Almond -> Walnut {0x47, 0x5B}, // Amber Grey -> Night Sand {0x40, 0x17}, // Orange -> Marmalade {0x41, 0x25}, // Carrot Orange -> Maple {0x03, 0x11}, // Pale Amber Brown -> Caramel {0x11, 0x11}, // Amber Brown -> Caramel {0x04, 0x6E}, // Pale Yellow -> Lemonade {0x12, 0x12}, // Citrus Yellow -> Golden Arch {0x44, 0x2B}, // Yellow -> Gold Bell {0x45, 0x6D}, // Saffron Yellow -> Yellow Balloon {0x46, 0x32}, // Pumpkin -> Gerbera {0x05, 0x45}, // Spring Green -> Mint {0x13, 0x45}, // Apple Green -> Mint {0x21, 0x2D}, // Dark Hazel Green -> Lime {0x48, 0x2C}, // Yellowish Green -> Merry-Go-Green {0x06, 0x4A}, // Light Green -> Green Balloon {0x14, 0x3F}, // Leaf Green -> Moss Green {0x57, 0x57}, // Fresh Star Green -> Shrub Green {0x22, 0x57}, // Dark Moss Green -> Shrub Green {0x24, 0x57}, // Dark Green -> Shrub Green {0x23, 0x57}, // Dark Leaf Green -> Shrub Green {0x4C, 0x37}, // Moss Green -> Taylor Green {0x4B, 0x3F}, // Pine Green -> Moss Green {0x15, 0x76}, // Mint Green -> Railway Green {0x59, 0x1C}, // Friendship Green -> Emerald Ocean {0x4A, 0x40}, // Slate Green -> Jade Green {0x07, 0x13}, // Pale Green -> Blue Lagoon {0x16, 0x1C}, // Turquoise Green -> Emerald Ocean {0x25, 0x1C}, // Dark Aqua Green -> Emerald Ocean {0x49, 0x1C}, // Emerald Green -> Emerald Ocean }; #define SS3ToSS4BlusherAmount 16 // Left: SS3, Right: SS4 static u8 SS3ToSS4BlusherTable[SS3ToSS4BlusherAmount][2] = { // Offset: 0x0F {0x01, 0x0F}, // Chalk White -> Apple Blossom {0x0A, 0x0E}, {0x15, 0x0E}, {0x17, 0x11}, {0x1F, 0x12}, // Begonia -> Blossom Blush {0x20, 0x0A}, {0x21, 0x0A}, {0x23, 0x0E}, {0x2B, 0x09}, {0x30, 0x04}, {0x56, 0x0E}, {0x64, 0x12}, // ??? -> Blossom Blush {0x66, 0x1A}, {0x67, 0x10}, {0x68, 0x06}, // City Pink -> Maple Syrup {0x69, 0x0C}, }; #define SS4BlusherAmount 20 // Left: SS4, Right: SS3 static u8 SS4ToSS3BlusherTable[SS4BlusherAmount][2] = { // Offset: 0x0F {0x01, 0x60}, // Rosy Spirit -> Baby Pink {0x02, 0x68}, // Shy Fairy -> City Pink {0x04, 0x68}, // Coy Blush -> City Pink {0x06, 0x68}, // Maple Syrup -> City Pink {0x07, 0x68}, // Flapjack -> City Pink {0x0D, 0x01}, // Stage Musical -> Chalk White {0x0F, 0x01}, // Apple Blossom -> Chalk White {0x03, 0x60}, // Mischievous Glow -> Baby Pink {0x05, 0x68}, // First Kiss -> City Pink {0x0C, 0x60}, // Classical Ballet -> Baby Pink {0x11, 0x67}, // Divine Coral -> Cherry Blossom {0x12, 0x6B}, // Blossom Blush -> Soft Pink {0x13, 0x6B}, // Magenta Spring -> Soft Pink {0x14, 0x66}, // Bouquet Blush -> Hot Pepper {0x08, 0x30}, // Tangerine Freckles -> Starfish Orange {0x09, 0x6C}, // Lemon Dimples -> Lemon Chiffon {0x0A, 0x67}, // Apple Cheeked -> Cherry Blossom {0x0B, 0x5C}, // Light Opera -> Sunlight Sand {0x0E, 0x07}, // Cherry Valentine -> Sawtooth Oak {0x10, 0x30}, // Love Flush -> Starfish Orange }; #define SS3ToSS4HairStyleAmount 24 // Left: SS3, Right: SS4 static u8 SS3ToSS4HairStyleTable[SS3ToSS4HairStyleAmount][2] = { // Offset: 0x15 {0x01, 0x4B}, // Layered Crop -> Casual bob {0x03, 0x4B}, // Tousled Bob -> Casual bob {0x06, 0x4B}, // Mullet -> Casual bob {0x07, 0x4C}, // Volumised Midi -> Wavy bob {0x08, 0x4D}, // Straight Midi -> Curled under bob {0x0A, 0x4E}, // Long & Wavy -> Long elegant waves {0x0B, 0x4E}, // Volumised Long -> Long elegant waves {0x0D, 0x4F}, // Long Half Ponytail -> Long plaited half-updo {0x0F, 0x10}, // Side Plaited Pigtail -> Side low pigtail {0x12, 0x60}, // Straight Side Ponytail -> Casual side ponytail {0x13, 0x3C}, // Side Bun -> Ribbon curled side ponytail {0x15, 0x63}, // High Tousled Bun -> High ponytail {0x1B, 0x62}, // Ballet Bun {0x1C, 0x60}, // Volumized Side Ponytail -> Casual side ponytail {0x1F, 0x62}, // Topknot -> Ballet bun {0x25, 0x50}, // Spiky Punk -> Asymmetrical punk {0x27, 0x6D}, // Pixie Short Hair -> Chic short cut {0x28, 0x4E}, // Hippie Style -> Long elegant waves {0x29, 0x51}, // Afro -> Bouncy spiral curls {0x2D, 0x33}, // Male: ??? -> Pixie short {0x38, 0x64}, // Bouffant {0x41, 0x3C}, // Side Bun with pouring curl -> Ribbon curled side ponytail {0x48, 0x4E}, // Sausage Curls -> Long elegant waves {0x4A, 0x52}, // Short & Choppy -> Tousled crop }; #define SS4ToSS3HairStyleAmount 10 // Left: SS4, Right: SS3 static u8 SS4ToSS3HairStyleTable[SS4ToSS3HairStyleAmount][2] = { // Offset: 0x15 {0x4C, 0x07}, // Wavy bob -> Volumised Midi {0x4D, 0x08}, // Curled under bob -> Straight Midi {0x4E, 0x0A}, // Long elegant waves -> Long & Wavy {0x60, 0x12}, // Casual side ponytail -> Straight Side Ponytail {0x62, 0x1B}, // Ballet bun {0x64, 0x38}, // Bouffant {0x69, 0x3E}, // Volumised midi -> Medium Loose Curl {0x6A, 0x0A}, // Long loose ringlets -> Long & Wavy {0x6C, 0x09}, // Ear-tucked long -> Long & Straight {0x6D, 0x27}, // Chic short cut -> Pixie Short Hair }; #define SS4FTMHairStyleAmount 55 // Left: Female, Right: Male static u8 SS4FTMHairStyleTable[SS4FTMHairStyleAmount][2] = { // Offset: 0x15 {0x02, 0x2F}, // Flicked layers {0x04, 0x35}, // Straight bob -> Wavy midi {0x05, 0x2E}, // Slicked back {0x09, 0x59}, // Long and straight -> Johann {0x0C, 0x2E}, // Shoulder-length half ponytail -> Slicked back {0x0E, 0x59}, // Long ribbon curls -> Johann {0x10, 0x2E}, // Side ponytail -> Slicked back {0x11, 0x35}, // Plaited pigtails -> Wavy midi {0x14, 0x2E}, // Low ponytail -> Slicked back {0x16, 0x2E}, // Short pigtails -> Slicked back {0x17, 0x2E}, // Double buns -> Slicked back {0x1D, 0x2E}, // Chignon -> Slicked back {0x1E, 0x2E}, // Messy ponytail -> Slicked back {0x20, 0x2E}, // Long pigtails -> Slicked back {0x21, 0x2E}, // Volumised high pigtails -> Slicked back {0x22, 0x2E}, // Straight pigtails -> Slicked back {0x23, 0x2E}, // High ribbon curl pigtails -> Slicked back {0x26, 0x66}, // Side-swept bob -> Oliver {0x2A, 0x36}, // Curly crew cut {0x37, 0x2E}, // Messy buns -> Slicked back {0x39, 0x32}, // Pageboy -> ??? (with left-swept fringe) {0x3A, 0x2E}, // Natural side ponytail -> Slicked back {0x3B, 0x2E}, // Curly side ponytail -> Slicked back {0x3C, 0x2E}, // Ribbon curled side ponytail -> Slicked back {0x3D, 0x2B}, // Short and spiky {0x3E, 0x35}, // Medium loose curl -> Wavy midi {0x3F, 0x35}, // High side ponytail -> Wavy midi {0x40, 0x59}, // High half pigtails -> Johann {0x42, 0x2E}, // Side ponytail with braids -> Slicked back {0x43, 0x59}, // Side-swept waves -> Johann {0x44, 0x2E}, // Long plaited pigtails -> Slicked back {0x45, 0x2E}, // High plaited pigtails -> Slicked back {0x46, 0x2E}, // Hair bow -> Slicked back {0x47, 0x2E}, // Looped plaited pigtails -> Slicked back {0x49, 0x59}, // Cat ears -> Johann {0x4B, 0x31}, // Casual bob -> ??? {0x4C, 0x35}, // Wavy bob -> Wavy midi {0x4D, 0x35}, // Curled under bob -> Wavy midi {0x4E, 0x59}, // Long elegant waves -> Johann {0x4F, 0x59}, // Long plaited half-updo -> Johann {0x50, 0x5B}, // Asymmetrical punk -> Melvin {0x51, 0x59}, // Bouncy spiral curls -> Johann {0x52, 0x5A}, // Tousled crop -> Ken {0x5F, 0x2E}, // Bubble pigtails -> Slicked back {0x60, 0x2E}, // Casual side ponytail -> Slicked back {0x61, 0x2E}, // High hair bow -> Slicked back {0x62, 0x2E}, // Ballet bun -> Slicked back {0x63, 0x2E}, // High ponytail -> Slicked back {0x64, 0x59}, // Bouffant -> Johann {0x68, 0x59}, // Asymmetrical straight cut -> Johann {0x69, 0x35}, // Volumised midi -> Wavy midi {0x6A, 0x59}, // Long loose ringlets -> Johann {0x6B, 0x32}, // Straight casual short -> ??? (with left-swept fringe) {0x6C, 0x59}, // Ear-tucked long -> Johann {0x6D, 0x33}, // Chic short cut -> Pixie short }; #define SS4MTFHairStyleAmount 17 // Left: Male, Right: Female static u8 SS4MTFHairStyleTable[SS4MTFHairStyleAmount][2] = { // Offset: 0x15 {0x2B, 0x3D}, // Short and spiky {0x2C, 0x3D}, // Short and spiky with side burns -> Short and spiky {0x2E, 0x05}, // Slicked back {0x2F, 0x02}, // Flicked layers {0x31, 0x4B}, // ??? -> Casual bob {0x32, 0x4B}, // ??? (with left-swept fringe) -> Casual bob {0x33, 0x6D}, // Pixie short -> Chic short cut {0x34, 0x4C}, // Wavy midi with right-swept fringe -> Wavy bob {0x35, 0x4C}, // Wavy midi -> Wavy bob {0x36, 0x2A}, // Curly crew cut {0x57, 0x26}, // Ethan -> Side-swept bob {0x58, 0x6D}, // Tim -> Chic short cut {0x59, 0x6A}, // Johann -> Long loose ringlets {0x5A, 0x52}, // Ken -> Tousled crop {0x5B, 0x50}, // Melvin -> Asymmetrical punk {0x65, 0x05}, // Fortman -> Slicked back {0x66, 0x26}, // Oliver -> Side-swept bob }; #define SS4ToSS3HairColorAmount 2 // Left: SS4, Right: SS3 static u8 SS4ToSS3HairColorTable[SS4ToSS3HairColorAmount][2] = { // Offsets: 0x17 & 0x18 {0x77, 0x21}, // Rosie Strawberry -> Celebration Pink {0x7A, 0x6C}, // Angélique Blonde -> Lemon Chiffon }; #define SS3ToSS4InnerTopAmount 14 // Left: SS3, Right: SS4 static u16 SS3ToSS4InnerTopTable[SS3ToSS4InnerTopAmount][2] = { // Offsets: 0x1E & 0x20 (Table based on 0x1E) {0x1248, 0x3E87}, // Streetflow: Sleeveless Polo Shirt (White) -> Marzipan Sky: Flowery Sleevelss Shirt {0x25B8, 0x3D43}, // Streetflow: Sleeveless Polo Shirt (Light-Blue) -> Marzipan Sky: Lace-Panel Sleevelss Shirt {0x25BA, 0x4D1D}, // Streetflow: Sleeveless Polo Shirt (Green) -> Chorale: Lace-Belted Sleeveless Shirt {0x25BC, 0x2AB2}, // Streetflow: Sleeveless Polo Shirt (Magenta) -> Chorale: Sleeveless Shirt {0x25BE, 0x2AB6}, // Streetflow: Sleeveless Polo Shirt (Black) -> Chorale: Sleeveless Shirt {0x25C0, 0x52AA}, // Streetflow: Sleeveless Polo Shirt (Orange) -> April Bonbon: Funky Two-Tone Shirt {0x25C2, 0x4D25}, // Streetflow: Sleeveless Polo Shirt (Dark Beige) -> Chorale: Lace-Belted Sleeveless Shirt {0x399C, 0x3E85}, // Streetflow: Sleeveless Polo Shirt (Red) -> AZ-USA: Stripey Sleeveless Shirt {0x13CC, 0x13CB}, // Streetflow: Wave Design Shirt (White) -> Chorale: Sleeveless Shirt {0x25C4, 0x2AB2}, // Streetflow: Wave Design Shirt (Pink) -> Chorale: Sleeveless Shirt {0x25C6, 0x4D1D}, // Streetflow: Wave Design Shirt (Green) -> Chorale: Lace-Belted Sleeveless Shirt {0x25C8, 0x2AAE}, // Streetflow: Wave Design Shirt (Purple) -> Chorale: Sleeveless Shirt {0x25CA, 0x2AB6}, // Streetflow: Wave Design Shirt (Black) -> Chorale: Sleeveless Shirt {0x399E, 0x3E85}, // Streetflow: Wave Design Shirt (Red) -> AZ-USA: Stripey Sleeveless Shirt }; #define SS3ToSS4TopAmount 1 // Left: SS3, Right: SS4 static u16 SS3ToSS4TopTable[SS3ToSS4TopAmount][2] = { // Offset: 0x20 {0x5F6A, 0x5D0B}, // Soy: Jellyfish Top -> Soy: Notch Neck Gradient Tunic }; #define SS3ToSS4SkirtPantsAmount 16 // Left: SS3, Right: SS4 static u16 SS3ToSS4SkirtPantsTable[SS3ToSS4SkirtPantsAmount][2] = { // Offset: 0x2A {0x0463, 0x28BA}, // Streetflow: Butterfly Miniskirt (White) -> Basic U: Tiered Skirt {0x2083, 0x28C0}, // Streetflow: Butterfly Miniskirt (Light-Green) -> Basic U: Tiered Skirt {0x2084, 0x137F}, // Streetflow: Butterfly Miniskirt (Pink) -> April Bonbon: Frilly Denim Skirt {0x2085, 0x28B9}, // Streetflow: Butterfly Miniskirt (Black) -> Basic U: Tiered Skirt {0x2086, 0x015F}, // Streetflow: Butterfly Miniskirt (Purple) -> Basic U: Tiered Skirt {0x3D49, 0x28BE}, // Streetflow: Butterfly Miniskirt (Red) -> Basic U: Tiered Skirt {0x3A86, 0x28B8}, // Streetflow: Butterfly Miniskirt (Yellow) -> Basic U: Tiered Skirt {0x3A87, 0x20B2}, // Streetflow: Butterfly Miniskirt (Orange) -> AZ-USA: Tiered Lace Miniskirt {0x4237, 0x12D6}, // Streetflow: Sporty Miniskirt (Yellow-Green) -> April Bonbon: Miniskirt with Ribbon {0x4771, 0x4236}, // Streetflow: Sporty Miniskirt (Blue) -> AZ-USA: Gold-Buttoned Miniskirt {0x4772, 0x43F5}, // Streetflow: Sporty Miniskirt (Green) -> AZ-USA: Gold-Buttoned Miniskirt {0x4773, 0x36A2}, // Streetflow: Sporty Miniskirt (Orange) -> AZ-USA: Lace-Up Denim Mini {0x4774, 0x43F6}, // Streetflow: Sporty Miniskirt (Purple) -> AZ-USA: Gold-Buttoned Miniskirt {0x4775, 0x43FB}, // Streetflow: Sporty Miniskirt (Green-Blue) -> AZ-USA: Gold-Buttoned Miniskirt {0x4776, 0x43F7}, // Streetflow: Sporty Miniskirt (Magenta) -> AZ-USA: Gold-Buttoned Miniskirt {0x5F51, 0x1FB0}, // Soy: Undersea Flares -> Basic U: Bootcut Jeans }; #define SS3ToSS4HatAmount 7 // Left: SS3, Right: SS4 static u16 SS3ToSS4HatTable[SS3ToSS4HatAmount][2] = { // Offset: 0x30 {0x053C, 0x3E0C}, // Streetflow: Butterfly Sun Visor (White) -> April Bonbon: Sun Visor with Ribbon {0x247B, 0x3CA9}, // Streetflow: Butterfly Sun Visor (Pink) -> April Bonbon: Sun Visor with Ribbon (Magenta) {0x247C, 0x3E08}, // Streetflow: Butterfly Sun Visor (Light-Blue) -> April Bonbon: Sun Visor with Ribbon {0x247D, 0x3E09}, // Streetflow: Butterfly Sun Visor (Green) -> April Bonbon: Sun Visor with Ribbon {0x247E, 0x3E06}, // Streetflow: Butterfly Sun Visor (Black) -> April Bonbon: Sun Visor with Ribbon {0x247F, 0x3E0A}, // Streetflow: Butterfly Sun Visor (Yellow) -> April Bonbon: Sun Visor with Ribbon {0x3968, 0x3E0B}, // Streetflow: Butterfly Sun Visor (Red) -> April Bonbon: Sun Visor with Ribbon (Orange) }; static inline bool isHeadphone(const u16 headphone) { switch (headphone) { case 0x5F85: // April Bonbon: Headphones (Light Green) case 0x63A7: // April Bonbon: Headphones (Red) case 0x63A8: // April Bonbon: Headphones (Cyan) case 0x63A9: // April Bonbon: Headphones (Purple) case 0x63AA: // April Bonbon: Headphones (Yellow) case 0x60A8: // StageDive: Rock Headphones (Red) case 0x64ED: // StageDive: Rock Headphones (Cyan) case 0x675D: // StageDive: Rock Headphones (Blue) case 0x675E: // StageDive: Rock Headphones (Purple) case 0x675F: // StageDive: Rock Headphones (Yellow) case 0x6760: // StageDive: Rock Headphones (Magenta) case 0x6761: // StageDive: Rock Headphones (Green) return true; } return false; } void commitSaveData(void) { if (ss2SaveModified) { archiveCommitSaveData("ss2"); } if (ss3SaveModified) { archiveCommitSaveData("ss3"); } } /* Style Savvy */ void readSS1Save(void) { if (ss1SaveRead) return; FILE* saveData = fopen(ss1SavePath, "rb"); fread(ss1Save, (int)sizeof(ss1Save), 1, saveData); fclose(saveData); // Get playable character's name if (ss1Save[0x204] == 0x86 || ss1Save[0x204] == 0x87) { for (int i = 0; i < 9; i++) { ss1PlayerName[i] = ss1Save[0x3AB8+(i)]; } } else { for (int i = 0; i < 9; i++) { ss1PlayerName[i] = ss1Save[0x63B8+(i)]; } } ss2SaveRead = true; } void writeSS1Save(void) { remove(ss1SavePath); FILE* saveData = fopen(ss1SavePath, "wb"); fwrite(ss1Save, (int)sizeof(ss1Save), 1, saveData); fclose(saveData); } /* Style Savvy: Trendsetters */ void readSS2Save(void) { if (ss2SaveRead) return; FILE* saveData = fopen(ss2SavePath, "rb"); fread(ss2Save, (int)sizeof(ss2Save), 1, saveData); fclose(saveData); // Get playable character's name for (int i = 0; i < 9; i++) { ss2PlayerName[i] = ss2Save[0x1AC8+(i*2)]; } ss2SaveRead = true; } void writeSS2Save(void) { FILE* saveData = fopen(ss2SavePath, "wb"); fwrite(ss2Save, (int)sizeof(ss2Save), 1, saveData); fclose(saveData); ss2SaveModified = true; } void readSS2Character(void) { // Playable character tonccpy(&ss2CharacterData, (char*)ss2Save+(0x102), 0x3); tonccpy((char*)&ss2CharacterData+0x3, (char*)ss2Save+(0x106), 0x1); tonccpy((char*)&ss2CharacterData+0x4, (char*)ss2Save+(0x130), 0x18); tonccpy((char*)&ss2CharacterData+0x1C, (char*)ss2Save+(0x188), 0x20); } void writeSS2Character(void) { // Playable character tonccpy((char*)ss2Save+(0x102), &ss2CharacterData, 0x3); tonccpy((char*)ss2Save+(0x106), (char*)&ss2CharacterData+0x3, 0x1); tonccpy((char*)ss2Save+(0x130), (char*)&ss2CharacterData+0x4, 0x18); tonccpy((char*)ss2Save+(0x188), (char*)&ss2CharacterData+0x1C, 0x20); tonccpy((char*)ss2Save+(0x1C8), (char*)&ss2CharacterData+0x1C, 0x20); tonccpy((char*)ss2Save+(0x208), (char*)&ss2CharacterData+0x1C, 0x20); tonccpy((char*)ss2Save+(0x248), (char*)&ss2CharacterData+0x1C, 0x20); } void writeSS2CharacterToSave(void) { FILE* saveData = fopen(ss2SavePath, "rb+"); fseek(saveData, 0x102, SEEK_SET); fwrite(ss2Save+(0x102), 0x186, 1, saveData); fclose(saveData); ss2SaveModified = true; } void readSS2CharacterFile(const char* filename) { FILE* characterData = fopen(filename, "rb"); if (!characterData) return; // Playable character fseek(characterData, 0, SEEK_SET); fread((char*)ss2Save+(0x102), 0x3, 1, characterData); fseek(characterData, 3, SEEK_SET); fread((char*)ss2Save+(0x106), 0x1, 1, characterData); fread((char*)ss2Save+(0x130), 0x18, 1, characterData); fread((char*)ss2Save+(0x188), 0x20, 1, characterData); tonccpy((char*)ss2Save+(0x1C8), (char*)ss2Save+(0x188), 0x20); tonccpy((char*)ss2Save+(0x208), (char*)ss2Save+(0x188), 0x20); tonccpy((char*)ss2Save+(0x248), (char*)ss2Save+(0x188), 0x20); fclose(characterData); } void writeSS2CharacterFile(const char* filename) { FILE* characterData = fopen(filename, "wb"); if (!characterData) return; // Playable character fwrite((char*)ss2Save+(0x102), 0x3, 1, characterData); fwrite((char*)ss2Save+(0x106), 0x1, 1, characterData); fwrite((char*)ss2Save+(0x130), 0x18, 1, characterData); fwrite((char*)ss2Save+(0x188), 0x20, 1, characterData); fclose(characterData); } bool getSS2CharacterGender(void) { if ((strcmp(ss2PlayerName, "Robz") == 0) && (ss2CharacterData.hairStyle == 0x07)) { return true; // Robz is male, so return male } // true = male, false = female return (ss2Save[0x102] == 2); } bool getSS2CharacterGenderNoExceptions(void) { // true = male, false = female return (ss2Save[0x102] == 2); } u8 readSS2CharacterHeight(void) { return ss2CharacterData.height; } void writeSS2CharacterHeight(u8 height) { ss2CharacterData.height = height; } u8 readSS2CharacterPoseSet(void) { return ss2CharacterData.poseSet; } void writeSS2CharacterPoseSet(u8 poseSet) { ss2CharacterData.poseSet = poseSet; } /* Style Savvy: Fashion Forward */ void readSS3Save(void) { if (ss3SaveRead) return; u32 size = (saveRegion[2]==CFG_REGION_JPN ? 0x120000 : 0x174000); FILE* saveData = fopen(ss3SavePath, "rb"); fread(ss3Save, size, 1, saveData); fclose(saveData); // Get playable character's name u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x537DC : 0x54980); for (int i = 0; i < 9; i++) { ss3PlayerName[i] = ss3Save[offset+(i*2)]; } ss3SaveRead = true; } void writeSS3Save(void) { u32 size = (saveRegion[2]==CFG_REGION_JPN ? 0x120000 : 0x174000); FILE* saveData = fopen(ss3SavePath, "wb"); fwrite(ss3Save, size, 1, saveData); fclose(saveData); ss3SaveModified = true; } static u32 getSS3CharacterOffset(u16 id) { if (id == 0x7D1) { // Playable character return (saveRegion[2]==CFG_REGION_JPN ? 0x5387E : 0x54A22); } else if (id >= 0x0BB9) { // Downloaded character id -= 0x0BB9; return (saveRegion[2]==CFG_REGION_JPN ? 0x830D2 : 0x8427E) + (0x110*id); } else if (id == 0x0B87) { // Unused/Hidden character return (saveRegion[2]==CFG_REGION_JPN ? 0x82FC2 : 0x8416E); } else if (id == 0x0B55) { // Unused/Hidden character return (saveRegion[2]==CFG_REGION_JPN ? 0x82EB2 : 0x8405E); } else if (id == 0x0A8D) { // Unused/Hidden character return (saveRegion[2]==CFG_REGION_JPN ? 0x82DA2 : 0x83F4E); } else if (id == 0x0A29 || id == 0x0A2A) { // Unused/Hidden character id -= 0x0A29; return (saveRegion[2]==CFG_REGION_JPN ? 0x82B82 : 0x83D2E) + (0x110*id); } else if (id >= 0x09C5 && id <= 0x09C9) { // Unused/Hidden character id -= 0x09C5; return (saveRegion[2]==CFG_REGION_JPN ? 0x82632 : 0x837DE) + (0x110*id); } else if (id == 0x0961) { // Unused/Hidden character return (saveRegion[2]==CFG_REGION_JPN ? 0x82522 : 0x836CE); } else if (id >= 0x08FD && id <= 0x0901) { // Unused/Hidden character id -= 0x08FD; return (saveRegion[2]==CFG_REGION_JPN ? 0x81FD2 : 0x8317E) + (0x110*id); } else if (id == 0x0899) { // Unused/Hidden character return (saveRegion[2]==CFG_REGION_JPN ? 0x81EC2 : 0x8360E); } else if (id >= 0x0835 && id <= 0x0852) { // Unused/Hidden character id -= 0x0835; return (saveRegion[2]==CFG_REGION_JPN ? 0x7FEE2 : 0x8101E) + (0x110*id); } else if (id >= 0x044C && id <= 0x0469) { // Non-playable character id -= 0x044C; return (saveRegion[2]==CFG_REGION_JPN ? 0x7D9B2 : 0x7EB5E) + (0x110*id); } else if (id >= 0x041A && id <= 0x0437) { // Non-playable character id -= 0x041A; return (saveRegion[2]==CFG_REGION_JPN ? 0x7BD92 : 0x7CB7E) + (0x110*id); } else if (id >= 0x03E8 && id <= 0x0405) { // Non-playable character id -= 0x03E8; return (saveRegion[2]==CFG_REGION_JPN ? 0x799F2 : 0x7AB9E) + (0x110*id); } else if (id >= 0x0352 && id <= 0x036F) { // Non-playable character id -= 0x0352; return (saveRegion[2]==CFG_REGION_JPN ? 0x77A12 : 0x78BBE) + (0x110*id); } else if (id >= 0x0320 && id <= 0x033D) { // Non-playable character id -= 0x0320; return (saveRegion[2]==CFG_REGION_JPN ? 0x75A32 : 0x76BDE) + (0x110*id); } else if (id >= 0x02EE && id <= 0x030B) { // Non-playable character id -= 0x02EE; return (saveRegion[2]==CFG_REGION_JPN ? 0x73A52 : 0x74BFE) + (0x110*id); } else if (id >= 0x02BC && id <= 0x02D9) { // Non-playable character id -= 0x02BC; return (saveRegion[2]==CFG_REGION_JPN ? 0x71962 : 0x72C1E) + (0x110*id); } else if (id >= 0x028A && id <= 0x02A7) { // Non-playable character id -= 0x028A; return (saveRegion[2]==CFG_REGION_JPN ? 0x6FA92 : 0x70C3E) + (0x110*id); } else if (id >= 0x0258 && id <= 0x0275) { // Non-playable character id -= 0x0258; return (saveRegion[2]==CFG_REGION_JPN ? 0x6DAB2 : 0x6EC5E) + (0x110*id); } else if (id >= 0x0226 && id <= 0x0243) { // Non-playable character id -= 0x0226; return (saveRegion[2]==CFG_REGION_JPN ? 0x6BAD2 : 0x6CC7E) + (0x110*id); } else if (id >= 0x01F4 && id <= 0x0211) { // Non-playable character id -= 0x01F4; return (saveRegion[2]==CFG_REGION_JPN ? 0x69AF2 : 0x6AC9E) + (0x110*id); } else if (id >= 0x01C2 && id <= 0x01DF) { // Non-playable character id -= 0x01C2; return (saveRegion[2]==CFG_REGION_JPN ? 0x67B12 : 0x68CBE) + (0x110*id); } else if (id >= 0x0190 && id <= 0x01AD) { // Non-playable character id -= 0x0190; return (saveRegion[2]==CFG_REGION_JPN ? 0x65B32 : 0x66CDE) + (0x110*id); } else if (id >= 0x015E && id <= 0x017B) { // Non-playable character id -= 0x015E; return (saveRegion[2]==CFG_REGION_JPN ? 0x63B52 : 0x64CFE) + (0x110*id); } else if (id >= 0x012C && id <= 0x0149) { // Non-playable character id -= 0x012C; return (saveRegion[2]==CFG_REGION_JPN ? 0x61B72 : 0x62D1E) + (0x110*id); } else if (id >= 0xFA && id <= 0x0117) { // Non-playable character id -= 0xFA; return (saveRegion[2]==CFG_REGION_JPN ? 0x5FB92 : 0x60D3E) + (0x110*id); } else if (id >= 0xC8 && id <= 0xE5) { // Non-playable character id -= 0xC8; return (saveRegion[2]==CFG_REGION_JPN ? 0x5DBB2 : 0x5ED5E) + (0x110*id); } else if (id >= 0x96 && id <= 0xB3) { // Non-playable character id -= 0x96; return (saveRegion[2]==CFG_REGION_JPN ? 0x5BBD2 : 0x5CD7E) + (0x110*id); } else if (id >= 0x64 && id <= 0x81) { // Non-playable character id -= 0x64; return (saveRegion[2]==CFG_REGION_JPN ? 0x59BF2 : 0x5AD9E) + (0x110*id); } else if (id >= 0x32 && id <= 0x5E) { // Non-playable character id -= 0x32; return (saveRegion[2]==CFG_REGION_JPN ? 0x56C22 : 0x57DCE) + (0x110*id); } else { id--; // Non-playable character return (saveRegion[2]==CFG_REGION_JPN ? 0x54D52 : 0x55EFE) + (0x110*id); } } void readSS3Character(u16 id) { tonccpy(&ss4CharacterData, (char*)ss3Save+getSS3CharacterOffset(id), 0x36); } void readSS4CharacterToSS3(u16 id) { toncset(&ss4CharacterData, 0, sizeof(ss3to4character)); readSS4Character(id); // Convert the character int i = 0; // Skin color for (i = 0; i < SS4ToSS3SkinAmount; i++) { if (ss4CharacterData.skinColor == SS4ToSS3SkinTable[i][0]) { ss4CharacterData.skinColor = SS4ToSS3SkinTable[i][1]; break; } } // Face shape for (i = 0; i < SS4ToSS3FaceShapeAmount; i++) { if (ss4CharacterData.faceShape == SS4ToSS3FaceShapeTable[i][0]) { ss4CharacterData.faceShape = SS4ToSS3FaceShapeTable[i][1]; break; } } // Eyes for (i = 0; i < SS4ToSS3EyeAmount; i++) { if (ss4CharacterData.eyes == SS4ToSS3EyeTable[i][0]) { ss4CharacterData.eyes = SS4ToSS3EyeTable[i][1]; break; } } // Mouth shape for (i = 0; i < SS4ToSS3MouthShapeAmount; i++) { if (ss4CharacterData.mouthShape == SS4ToSS3MouthShapeTable[i][0]) { ss4CharacterData.mouthShape = SS4ToSS3MouthShapeTable[i][1]; break; } } // Eyebrows for (i = 0; i < SS4ToSS3EyebrowAmount; i++) { if (ss4CharacterData.eyebrows == SS4ToSS3EyebrowTable[i][0]) { ss4CharacterData.eyebrows = SS4ToSS3EyebrowTable[i][1]; break; } } // Lipstick if (ss4CharacterData.lipstickColor != 0) { for (i = 0; i < SS4LipstickAmount; i++) { if (ss4CharacterData.lipstickColor == SS4ToSS3LipstickTable[i][0]) { ss4CharacterData.lipstickColor = SS4ToSS3LipstickTable[i][1]; break; } } } // Mascara if (ss4CharacterData.mascaraColor != 0) { for (i = 0; i < SS4MascaraAmount; i++) { if (ss4CharacterData.mascaraColor == SS4ToSS3MascaraTable[i][0]) { ss4CharacterData.mascaraColor = SS4ToSS3MascaraTable[i][1]; break; } } } // Eyeshadow if (ss4CharacterData.eyeshadowColor != 0) { for (i = 0; i < SS4EyeshadowAmount; i++) { if (ss4CharacterData.eyeshadowColor == SS4ToSS3EyeshadowTable[i][0]) { ss4CharacterData.eyeshadowColor = SS4ToSS3EyeshadowTable[i][1]; break; } } } // Eyeliner if (ss4CharacterData.eyelinerColor != 0) { for (i = 0; i < SS4EyelinerAmount; i++) { if (ss4CharacterData.eyelinerColor == SS4ToSS3EyelinerTable[i][0]) { ss4CharacterData.eyelinerColor = SS4ToSS3EyelinerTable[i][1]; break; } } } // Contacts if (ss4CharacterData.contactColor != 0) { for (i = 0; i < SS4ContactAmount; i++) { if (ss4CharacterData.contactColor == SS4ToSS3ContactTable[i][0]) { ss4CharacterData.contactColor = SS4ToSS3ContactTable[i][1]; break; } } } // Blusher if (ss4CharacterData.blusherColor != 0) { for (i = 0; i < SS4BlusherAmount; i++) { if (ss4CharacterData.blusherColor == SS4ToSS3BlusherTable[i][0]) { ss4CharacterData.blusherColor = SS4ToSS3BlusherTable[i][1]; break; } } } // Overlaying Eyebrows for (i = 0; i < SS4ToSS3EyebrowAmount; i++) { if (ss4CharacterData.eyebrowOverlay == SS4ToSS3EyebrowTable[i][0]) { ss4CharacterData.eyebrowOverlay = SS4ToSS3EyebrowTable[i][1]; break; } } // Hair style for (i = 0; i < SS4ToSS3HairStyleAmount; i++) { if (ss4CharacterData.hairStyle == SS4ToSS3HairStyleTable[i][0]) { if (ss4CharacterData.hairStyle == 0x6C) { // Ear-tucked long ss4CharacterData.hairFringe = 0x0C; } ss4CharacterData.hairStyle = SS4ToSS3HairStyleTable[i][1]; break; } } // Hair color (Main) for (i = 0; i < SS4ToSS3HairColorAmount; i++) { if (ss4CharacterData.hairColorMain == SS4ToSS3HairColorTable[i][0]) { ss4CharacterData.hairColorMain = SS4ToSS3HairColorTable[i][1]; break; } } // Hair color (Highlights) for (i = 0; i < SS4ToSS3HairColorAmount; i++) { if (ss4CharacterData.hairColorHighlights == SS4ToSS3HairColorTable[i][0]) { ss4CharacterData.hairColorHighlights = SS4ToSS3HairColorTable[i][1]; break; } } // Fix offset 0x24 if (ss4CharacterData.necklaceScarfHeadphones == 0 || isHeadphone(ss4CharacterData.necklaceScarfHeadphones)) { ss4CharacterData.necklaceScarfHeadphones = ss4CharacterData.necklace; } // Fix offset 0x32 if (ss4CharacterData.glasses == 0) { ss4CharacterData.glasses = ss4CharacterData.earrings; } // Remove data exclusive to Styling Star ss4CharacterData.nailColor = 0; ss4CharacterData.eyeliner = 0; ss4CharacterData.unknown1C = 0; ss4CharacterData.eyebrowColor = 0; } void writeSS3Character(u16 id) { tonccpy((char*)ss3Save+getSS3CharacterOffset(id), &ss4CharacterData, 0x36); } void toggleSS3Character(u16 id, bool enable) { if (id == 0 || id == 0x7D1) return; *(u16*)((char*)ss3Save+getSS3CharacterOffset(id)+0xB0) = (enable ? 0x4013 : 0x0000); } bool existsSS3Character(u16 id) { if (id == 0 || id == 0x7D1) return true; u8 byte = *(u8*)((char*)ss3Save+getSS3CharacterOffset(id)+0xB1); return (byte & 0xF0) == 0x40; } void removeSS3CharacterBag(u16 id) { *(u16*)((char*)ss3Save+getSS3CharacterOffset(id)+0x34) = 0; } void readSS3CharacterFile(u16 id, const char* filename) { FILE* characterData = fopen(filename, "rb"); if (!characterData) return; fread((char*)ss3Save+getSS3CharacterOffset(id), 0x36, 1, characterData); fclose(characterData); } void writeSS3CharacterFile(u16 id, const char* filename) { FILE* characterData = fopen(filename, "wb"); if (!characterData) return; fwrite((char*)ss3Save+getSS3CharacterOffset(id), 0x36, 1, characterData); fclose(characterData); } void writeSS3CharacterToSave(u16 id) { FILE* saveData = fopen(ss3SavePath, "rb+"); fseek(saveData, getSS3CharacterOffset(id), SEEK_SET); fwrite(ss3Save+getSS3CharacterOffset(id), 0x804, 1, saveData); fclose(saveData); ss3SaveModified = true; } void backupSS3DLCharacters(const char* filename) { FILE* characterData = fopen(filename, "wb"); if (!characterData) return; // Backup downloaded characters fwrite((char*)ss3Save+(getSS3CharacterOffset(0x0BB9)-2), 0x103D4, 1, characterData); fclose(characterData); } void restoreSS3DLCharacters(const char* filename) { FILE* characterData = fopen(filename, "rb"); if (!characterData) return; // Restore downloaded characters fread((char*)ss3Save+(getSS3CharacterOffset(0x0BB9)-2), 0x103D4, 1, characterData); fclose(characterData); } bool getSS3CharacterGender(u16 id) { ss3to4character ss3CharacterGenderCheck; tonccpy(&ss3CharacterGenderCheck, (char*)ss3Save+getSS3CharacterOffset(id), 0x36); if ((id == 0x7D1) && (strcmp(ss3PlayerName, "Robz") == 0) && (ss3CharacterGenderCheck.hairStyle == 0x27)) { return true; // Robz is male, so return male } // true = male, false = female return (ss3CharacterGenderCheck.gender == 2); } bool getSS3CharacterGenderNoExceptions(u16 id) { ss3to4character ss3CharacterGenderCheck; tonccpy(&ss3CharacterGenderCheck, (char*)ss3Save+getSS3CharacterOffset(id), 0x36); // true = male, false = female return (ss3CharacterGenderCheck.gender == 2); } u8 readSS3CharacterHeight(u16 id) { ss3to4character ss3CharacterTemp; tonccpy(&ss3CharacterTemp, (char*)ss3Save+getSS3CharacterOffset(id), 0x36); return ss3CharacterTemp.height; } void writeSS3CharacterHeight(u16 id, u8 height) { ss3to4character ss3CharacterTemp; tonccpy(&ss3CharacterTemp, (char*)ss3Save+getSS3CharacterOffset(id), 0x36); ss3CharacterTemp.height = height; tonccpy((char*)ss3Save+getSS3CharacterOffset(id), &ss3CharacterTemp, 0x36); } u8 readSS3CharacterPoseSet(u16 id) { ss3to4character ss3CharacterTemp; tonccpy(&ss3CharacterTemp, (char*)ss3Save+getSS3CharacterOffset(id), 0x36); return ss3CharacterTemp.poseSet; } void writeSS3CharacterPoseSet(u16 id, u8 poseSet) { ss3to4character ss3CharacterTemp; tonccpy(&ss3CharacterTemp, (char*)ss3Save+getSS3CharacterOffset(id), 0x36); ss3CharacterTemp.poseSet = poseSet; tonccpy((char*)ss3Save+getSS3CharacterOffset(id), &ss3CharacterTemp, 0x36); } const char* readSS3ProfileName(u16 id) { u32 dlCharOffset = (saveRegion[2]==CFG_REGION_JPN ? 0x86F80 : 0x88C5C); if (id >= 0x0BB9) { // Downloaded character id -= 0x0BB9; for (int i = 0; i < 16; i++) { dlCharName[i] = ss3Save[(dlCharOffset + (0x2B4*id)) + i*2]; } return dlCharName; } return "???"; } void readSS3ProfileFile(u16 id, const char* filename) { FILE* profileData = fopen(filename, "rb"); if (!profileData) return; u32 dlCharOffset = (saveRegion[2]==CFG_REGION_JPN ? 0x86F80 : 0x88C5C); if (id >= 0x0BB9) { // Downloaded character id -= 0x0BB9; fread((char*)ss3Save+(dlCharOffset + (0x2B4*id)), 0x224, 1, profileData); } fclose(profileData); } void writeSS3ProfileFile(u16 id, const char* filename) { FILE* profileData = fopen(filename, "wb"); if (!profileData) return; u32 dlCharOffset = (saveRegion[2]==CFG_REGION_JPN ? 0x86F80 : 0x88C5C); if (id >= 0x0BB9) { // Downloaded character id -= 0x0BB9; fwrite((char*)ss3Save+(dlCharOffset + (0x2B4*id)), 0x224, 1, profileData); } fclose(profileData); } void readSS3Emblem(void) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x29A14 : 0x2ABB8); tonccpy(&emblemData, (char*)ss3Save+(offset), 0x804); } void writeSS3Emblem(void) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x29A14 : 0x2ABB8); tonccpy((char*)ss3Save+(offset), &emblemData, 0x804); } void writeSS3EmblemToSave(void) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x29A14 : 0x2ABB8); FILE* saveData = fopen(ss3SavePath, "rb+"); fseek(saveData, offset, SEEK_SET); fwrite((char*)ss3Save+(offset), 0x804, 1, saveData); fclose(saveData); ss3SaveModified = true; } void readSS3EmblemFile(const char* filename) { FILE* emblemData = fopen(filename, "rb"); if (!emblemData) return; u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x29A14 : 0x2ABB8); fread((char*)ss3Save+(offset), 0x804, 1, emblemData); fclose(emblemData); } void writeSS3EmblemFile(const char* filename) { FILE* emblemData = fopen(filename, "wb"); if (!emblemData) return; u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x29A14 : 0x2ABB8); fwrite((char*)ss3Save+(offset), 0x804, 1, emblemData); fclose(emblemData); } void readTempEmblemFile(const char* filename) { FILE* emblemDataFile = fopen(filename, "rb"); if (!emblemDataFile) return; fread(&emblemData, 0x804, 1, emblemDataFile); fclose(emblemDataFile); } u16 readSS3FashionOwnFlag(int id) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x11BB4 : 0x12D58); return *(u16*)((char*)ss3Save+(offset)+(id*sizeof(u16))); } void writeSS3FashionOwnFlag(int id, u16 flag) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x11BB4 : 0x12D58); toncset16((char*)ss3Save+(offset)+(id*sizeof(u16)), flag, 1); } u8 readSS3FashionOwnWardFlag(int id) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x11BB4 : 0x12D58); return *(u8*)((char*)ss3Save+(offset)+(id*sizeof(u16))); } void writeSS3FashionOwnWardFlag(int id, u8 flag) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x11BB4 : 0x12D58); toncset((char*)ss3Save+(offset)+(id*sizeof(u16)), flag, 1); } void writeSS3FashionOwnFlagsToSave(void) { u32 offset = (saveRegion[2]==CFG_REGION_JPN ? 0x11BB4 : 0x12D58); FILE* saveData = fopen(ss3SavePath, "rb+"); fseek(saveData, offset, SEEK_SET); fwrite(ss3Save+offset, 0x7918, 1, saveData); fclose(saveData); ss3SaveModified = true; } /* Style Savvy: Styling Star */ bool foundSS4Save(void) { Result res = FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_READ, 0); if (R_SUCCEEDED(res)) { FSFILE_Close(handle4); return true; } return false; } void readSS4Save(void) { if (ss4SaveRead) return; /*FILE* saveData = fopen(ss4SavePath, "rb"); fread(ss4Save, (int)sizeof(ss4Save), 1, saveData); fclose(saveData);*/ u32 bytesRead = 0; FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_READ, 0); FSFILE_Read(handle4, &bytesRead, 0, ss4Save, (u32)sizeof(ss4Save)); FSFILE_Close(handle4); // Get playable character's name for (int i = 0; i < 9; i++) { ss4PlayerName[i] = ss4Save[0x24370+(i*2)]; } ss4SaveRead = true; } void writeSS4Save(void) { /*FILE* saveData = fopen(ss4SavePath, "wb"); fwrite(ss4Save, (int)sizeof(ss4Save), 1, saveData); fclose(saveData);*/ u32 bytesWritten = 0; FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_WRITE, FS_WRITE_FLUSH); FSFILE_Write(handle4, &bytesWritten, 0, ss4Save, (u32)sizeof(ss4Save), 0); FSFILE_Close(handle4); //ss4SaveModified = true; } static u32 getSS4CharacterOffset(u16 id) { if (id == 0xBAE) { // Playable character return 0x2440A; } else if (id >= 0x0BB9) { // Downloaded character id -= 0x0BB9; return 0x81CEE + (0x1F8*id); } else if (id == 0x0B87) { // Unused/Hidden character return 0x8111E; } else if (id == 0x0B55) { // Unused/Hidden character return 0x80F26; } else if (id >= 0x0AF0 && id <= 0x0AF4) { // Unused/Hidden character id -= 0x0AF0; return 0x8054E + (0x1F8*id); } else if (id == 0x0A8D) { // Unused/Hidden character return 0x80356; } else if (id == 0x0A29 || id == 0x0A2A) { // Unused/Hidden character id -= 0x0A29; return 0x7FF66 + (0x1F8*id); } else if (id >= 0x09C5 && id <= 0x09C9) { // Unused/Hidden character id -= 0x09C5; return 0x7F58E + (0x1F8*id); } else if (id == 0x0961) { // Unused/Hidden character return 0x7F396; } else if (id >= 0x08FD && id <= 0x0901) { // Unused/Hidden character id -= 0x08FD; return 0x7E9BE + (0x1F8*id); } else if (id == 0x0899) { // Unused/Hidden character return 0x7E7C6; } else if (id >= 0x0835 && id <= 0x0852) { // Unused/Hidden character id -= 0x0835; return 0x7ACB6 + (0x1F8*id); } else if (id == 0x05DC || id == 0x05DD) { // Non-playable character id -= 0x05DC; return 0x7A8C6 + (0x1F8*id); } else if (id >= 0x044C && id <= 0x0469) { // Non-playable character id -= 0x044C; return 0x76DB6 + (0x1F8*id); } else if (id >= 0x041A && id <= 0x0437) { // Non-playable character id -= 0x041A; return 0x732A6 + (0x1F8*id); } else if (id >= 0x03E8 && id <= 0x0408) { // Non-playable character id -= 0x03E8; return 0x6F1AE + (0x1F8*id); } else if (id >= 0x0384 && id <= 0x038C) { // Non-playable character id -= 0x0384; return 0x6DFF6 + (0x1F8*id); } else if (id >= 0x0352 && id <= 0x036F) { // Non-playable character id -= 0x0352; return 0x6A4E6 + (0x1F8*id); } else if (id >= 0x0320 && id <= 0x033D) { // Non-playable character id -= 0x0320; return 0x669D6 + (0x1F8*id); } else if (id >= 0x02EE && id <= 0x030B) { // Non-playable character id -= 0x02EE; return 0x62EC6 + (0x1F8*id); } else if (id >= 0x02BC && id <= 0x02D9) { // Unused/Hidden character id -= 0x02BC; return 0x5F3B6 + (0x1F8*id); } else if (id >= 0x028A && id <= 0x02A7) { // Non-playable character id -= 0x028A; return 0x5B8A6 + (0x1F8*id); } else if (id >= 0x0258 && id <= 0x0275) { // Non-playable character id -= 0x0258; return 0x57D96 + (0x1F8*id); } else if (id >= 0x0226 && id <= 0x0243) { // Non-playable character id -= 0x0226; return 0x54286 + (0x1F8*id); } else if (id >= 0x01F4 && id <= 0x0211) { // Non-playable character id -= 0x01F4; return 0x50776 + (0x1F8*id); } else if (id >= 0x01C2 && id <= 0x01DF) { // Non-playable character id -= 0x01C2; return 0x4CC66 + (0x1F8*id); } else if (id >= 0x0190 && id <= 0x01AD) { // Non-playable character id -= 0x0190; return 0x49156 + (0x1F8*id); } else if (id >= 0x015E && id <= 0x017B) { // Non-playable character id -= 0x015E; return 0x45646 + (0x1F8*id); } else if (id >= 0x012C && id <= 0x0149) { // Non-playable character id -= 0x012C; return 0x41B36 + (0x1F8*id); } else if (id >= 0xFA && id <= 0x0117) { // Non-playable character id -= 0xFA; return 0x3E026 + (0x1F8*id); } else if (id >= 0xC8 && id <= 0xE5) { // Non-playable character id -= 0xC8; return 0x3A516 + (0x1F8*id); } else if (id >= 0x96 && id <= 0xB3) { // Non-playable character id -= 0x96; return 0x36A06 + (0x1F8*id); } else if (id >= 0x63 && id <= 0x81) { // Non-playable character id -= 0x63; return 0x32CFE + (0x1F8*id); } else { id--; // Non-playable character return 0x273EE + (0x1F8*id); } } static u32 getSS4MewtubeCharacterOffset(int video, int slot) { if (slot < 0) slot = 0; else if (slot > 5) slot = 5; switch (video) { case 0: // Open Plaza: Flying Shiny Day default: return 0x9BCDA + 0x40*slot; case 1: // Open Plaza: Ready Go!! return 0x9BE6A + 0x40*slot; case 2: // Outdoor Festival: Flying Shiny Day return 0x9BFFA + 0x40*slot; case 3: // Outdoor Festival: Ready Go!! return 0x9C18A + 0x40*slot; case 4: // Concert Hall: Higher Higher return 0x9C31A + 0x40*slot; case 5: // Concert Hall: To the Future return 0x9C4AA + 0x40*slot; case 6: // Charity Stage: Higher Higher return 0x9C63A + 0x40*slot; case 7: // Charity Stage: To the Future return 0x9C7CA + 0x40*slot; case 8: // Live Music Club: Wings return 0x9C95A + 0x40*slot; case 9: // Live Music Club: Beautiful return 0x9CAEA + 0x40*slot; case 10: // Celestial Hotel: Make Me Glow return 0x9CE0A + 0x40*slot; case 11: // Celestial Hotel: Glowing Moon return 0x9CF9A + 0x40*slot; case 12: // Alinatron On-Air: Fight For Your Style return 0x9D12A + 0x40*slot; case 13: // Promo Video: Twinkle Fantasia return 0x9D2BA + 0x40*slot; case 14: // Cinema: Maria return 0x9D44A + 0x40*slot; case 15: // Concert Hall: Dosukoi Koi Koi (Break It Down) return 0x9D5DA + 0x40*slot; case 16: // Concert Hall: Radiance return 0x9D76A + 0x40*slot; case 17: // Open Plaza: Ring a Ding return 0x9D8FA + 0x40*slot; case 18: // Open Plaza: Bravo return 0x9DA8A + 0x40*slot; } } void readSS4Character(u16 id) { tonccpy(&ss4CharacterData, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); } void readSS3CharacterToSS4(u16 id) { toncset(&ss4CharacterData, 0, sizeof(ss3to4character)); readSS3Character(id); // Convert the character int i = 0; // Eyes for (i = 0; i < SS3ToSS4EyeAmount; i++) { if (ss4CharacterData.eyes == SS3ToSS4EyeTable[i][0]) { ss4CharacterData.eyes = SS3ToSS4EyeTable[i][1]; break; } } // Mouth shape for (i = 0; i < SS3ToSS4MouthShapeAmount; i++) { if (ss4CharacterData.mouthShape == SS3ToSS4MouthShapeTable[i][0]) { ss4CharacterData.mouthShape = SS3ToSS4MouthShapeTable[i][1]; break; } } // Eyebrows for (i = 0; i < SS3ToSS4EyebrowAmount; i++) { if (ss4CharacterData.eyebrows == SS3ToSS4EyebrowTable[i][0]) { ss4CharacterData.eyebrows = SS3ToSS4EyebrowTable[i][1]; break; } } // Lipstick if (ss4CharacterData.lipstickColor != 0) { for (i = 0; i < SS3ToSS4LipstickAmount; i++) { if (ss4CharacterData.lipstickColor == SS3ToSS4LipstickTable[i][0]) { ss4CharacterData.lipstickColor = SS3ToSS4LipstickTable[i][1]; break; } } } // Mascara if (ss4CharacterData.mascaraColor != 0) { for (i = 0; i < SS3ToSS4MascaraAmount; i++) { if (ss4CharacterData.mascaraColor == SS3ToSS4MascaraTable[i][0]) { ss4CharacterData.mascaraColor = SS3ToSS4MascaraTable[i][1]; break; } } } // Eyeshadow if (ss4CharacterData.eyeshadowColor != 0) { for (i = 0; i < SS3ToSS4EyeshadowAmount; i++) { if (ss4CharacterData.eyeshadowColor == SS3ToSS4EyeshadowTable[i][0]) { ss4CharacterData.eyeshadowColor = SS3ToSS4EyeshadowTable[i][1]; break; } } } // Eyeliner if (ss4CharacterData.eyelinerColor != 0) { for (i = 0; i < SS3ToSS4EyelinerAmount; i++) { if (ss4CharacterData.eyelinerColor == SS3ToSS4EyelinerTable[i][0]) { ss4CharacterData.eyelinerColor = SS3ToSS4EyelinerTable[i][1]; break; } } } // Contacts if (ss4CharacterData.contactColor != 0) { for (i = 0; i < SS3ToSS4ContactAmount; i++) { if (ss4CharacterData.contactColor == SS3ToSS4ContactTable[i][0]) { ss4CharacterData.contactColor = SS3ToSS4ContactTable[i][1]; break; } } } // Blusher if (ss4CharacterData.blusherColor != 0) { for (i = 0; i < SS3ToSS4BlusherAmount; i++) { if (ss4CharacterData.blusherColor == SS3ToSS4BlusherTable[i][0]) { ss4CharacterData.blusherColor = SS3ToSS4BlusherTable[i][1]; break; } } } // Overlaying Eyebrows for (i = 0; i < SS3ToSS4EyebrowAmount; i++) { if (ss4CharacterData.eyebrowOverlay == SS3ToSS4EyebrowTable[i][0]) { ss4CharacterData.eyebrowOverlay = SS3ToSS4EyebrowTable[i][1]; break; } } // Hair style for (i = 0; i < SS3ToSS4HairStyleAmount; i++) { if (ss4CharacterData.hairStyle == SS3ToSS4HairStyleTable[i][0]) { ss4CharacterData.hairStyle = SS3ToSS4HairStyleTable[i][1]; break; } } // Remove data no longer used in Styling Star ss4CharacterData.nailColor = 0; ss4CharacterData.eyeliner = 0; ss4CharacterData.unknown1C = 0; ss4CharacterData.eyebrowColor = 0; // Replace fashion items removed in Styling Star // Inner/Top Hybrid if (ss4CharacterData.inner != 0) { for (i = 0; i < SS3ToSS4InnerTopAmount; i++) { if (ss4CharacterData.inner == SS3ToSS4InnerTopTable[i][0]) { ss4CharacterData.inner = SS3ToSS4InnerTopTable[i][1]; break; } } } // Top if (ss4CharacterData.top != 0) { bool topChanged = false; for (i = 0; i < SS3ToSS4InnerTopAmount; i++) { u16 top1 = ss4CharacterData.top; top1++; if (top1 == SS3ToSS4InnerTopTable[i][0]+1) { top1 = SS3ToSS4InnerTopTable[i][1]+1; topChanged = true; break; } } if (!topChanged) { for (i = 0; i < SS3ToSS4TopAmount; i++) { if (ss4CharacterData.top == SS3ToSS4TopTable[i][0]) { ss4CharacterData.top = SS3ToSS4TopTable[i][1]; break; } } } } // Skirt/Pants if (ss4CharacterData.skirtPants != 0) { for (i = 0; i < SS3ToSS4SkirtPantsAmount; i++) { if (ss4CharacterData.skirtPants == SS3ToSS4SkirtPantsTable[i][0]) { ss4CharacterData.skirtPants = SS3ToSS4SkirtPantsTable[i][1]; break; } } } // Hat if (ss4CharacterData.hat != 0) { for (i = 0; i < SS3ToSS4HatAmount; i++) { if (ss4CharacterData.hat == SS3ToSS4HatTable[i][0]) { ss4CharacterData.hat = SS3ToSS4HatTable[i][1]; break; } } } } void writeSS4Character(u16 id) { tonccpy((char*)ss4Save+getSS4CharacterOffset(id), &ss4CharacterData, 0x3E); } void writeSS4CharacterToSave(u16 id) { u32 bytesWritten = 0; FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_WRITE, FS_WRITE_FLUSH); FSFILE_Write(handle4, &bytesWritten, getSS4CharacterOffset(id), ss4Save+getSS4CharacterOffset(id), 0x3E, 0); FSFILE_Close(handle4); } u16 getSS4AssistantCharacterId(void) { return *(u16*)((char*)ss4Save+0x8BF96); } void writeSS4AssistantCharacterId(u16 id) { *(u16*)((char*)ss4Save+0x8BF96) = id; } void writeSS4AssistantCharacterToSave(void) { u32 bytesWritten = 0; FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_WRITE, FS_WRITE_FLUSH); FSFILE_Write(handle4, &bytesWritten, 0x8BF96, ss4Save+0x8BF96, 2, 0); FSFILE_Close(handle4); } void writeSS4MewtubeCharacter(int video, int slot) { tonccpy((char*)ss4Save+getSS4MewtubeCharacterOffset(video, slot), &ss4CharacterData, 0x3E); } void writeSS4MewtubeCharacterToSave(int video, int slot) { u32 bytesWritten = 0; FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_WRITE, FS_WRITE_FLUSH); FSFILE_Write(handle4, &bytesWritten, getSS4MewtubeCharacterOffset(video, slot)-2, ss4Save+getSS4MewtubeCharacterOffset(video, slot)-2, 0x40, 0); FSFILE_Close(handle4); } void revertSS4MewtubeCharacter(int video, int slot) { if (slot < 3) slot += 3; *(u16*)((char*)ss4Save+getSS4MewtubeCharacterOffset(video, slot)-2) = *(u16*)((char*)ss4Save+getSS4MewtubeCharacterOffset(video, slot-3)-2); tonccpy((char*)ss4Save+getSS4MewtubeCharacterOffset(video, slot), (char*)ss4Save+getSS4MewtubeCharacterOffset(video, slot-3), 0x3E); } bool existsSS4Character(u16 id) { if (id == 0 || id == 0xBAE) return true; u8 byte = *(u8*)((char*)ss4Save+getSS4CharacterOffset(id)+0x181); return (byte & 0xF0) == 0x40; } void readSS4CharacterFile(u16 id, const char* filename) { FILE* characterData = fopen(filename, "rb"); if (!characterData) return; fread((char*)ss4Save+getSS4CharacterOffset(id), 0x3E, 1, characterData); fclose(characterData); } void writeSS4CharacterFile(u16 id, const char* filename) { FILE* characterData = fopen(filename, "wb"); if (!characterData) return; fwrite((char*)ss4Save+getSS4CharacterOffset(id), 0x3E, 1, characterData); fclose(characterData); } u16 getSS4MewtubeCharacterId(int video, int slot) { return *(u16*)((char*)ss4Save+getSS4MewtubeCharacterOffset(video, slot)-2); } void writeSS4MewtubeCharacterId(u16 id, int video, int slot) { *(u16*)((char*)ss4Save+getSS4MewtubeCharacterOffset(video, slot)-2) = id; } bool getSS4CharacterGender(u16 id) { ss3to4character ss4CharacterGenderCheck; tonccpy(&ss4CharacterGenderCheck, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); if ((id == 0xBAE) && (strcmp(ss4PlayerName, "Robz") == 0) && (ss4CharacterGenderCheck.hairStyle == 0x6D)) { return true; // Robz is male, so return male } // true = male, false = female return (ss4CharacterGenderCheck.gender == 2); } bool getSS4CharacterGenderNoExceptions(u16 id) { ss3to4character ss4CharacterGenderCheck; tonccpy(&ss4CharacterGenderCheck, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); // true = male, false = female return (ss4CharacterGenderCheck.gender == 2); } static void changeSS4CharacterGenderToMale(u16 id) { ss3to4character ss4CharacterGenderSwap; tonccpy(&ss4CharacterGenderSwap, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); ss4CharacterGenderSwap.gender = 2; // Male int i = 0; // Workaround incompatible skin color for (i = 0; i < SS4ToSS3SkinAmount; i++) { if (ss4CharacterGenderSwap.skinColor == SS4ToSS3SkinTable[i][0]) { ss4CharacterGenderSwap.skinColor = SS4ToSS3SkinTable[i][1]; break; } } // Workaround incompatible face shape for (i = 0; i < SS4ToSS3FaceShapeAmount; i++) { if (ss4CharacterGenderSwap.faceShape == SS4ToSS3FaceShapeTable[i][0]) { ss4CharacterGenderSwap.faceShape = SS4ToSS3FaceShapeTable[i][1]; break; } } // Use male face shape set switch (ss4CharacterGenderSwap.faceShape) { case 3: ss4CharacterGenderSwap.faceShape = 4; break; case 1: ss4CharacterGenderSwap.faceShape = 5; break; case 2: ss4CharacterGenderSwap.faceShape = 6; break; } // Eyes for (i = 0; i < SS4FTMEyeAmount; i++) { if (ss4CharacterGenderSwap.eyes == SS4FTMEyeTable[i][0]) { ss4CharacterGenderSwap.eyes = SS4FTMEyeTable[i][1]; break; } } // Mouth shape for (i = 0; i < SS4FTMMouthShapeAmount; i++) { if (ss4CharacterGenderSwap.mouthShape == SS4FTMMouthShapeTable[i][0]) { ss4CharacterGenderSwap.mouthShape = SS4FTMMouthShapeTable[i][1]; break; } } // Eyebrows for (i = 0; i < SS4FTMEyebrowAmount; i++) { if (ss4CharacterGenderSwap.eyebrows == SS4FTMEyebrowTable[i][0]) { ss4CharacterGenderSwap.eyebrows = SS4FTMEyebrowTable[i][1]; break; } } // Overlaying Eyebrows for (i = 0; i < SS4FTMEyebrowAmount; i++) { if (ss4CharacterGenderSwap.eyebrowOverlay == SS4FTMEyebrowTable[i][0]) { ss4CharacterGenderSwap.eyebrowOverlay = SS4FTMEyebrowTable[i][1]; break; } } // Hair style for (i = 0; i < SS4FTMHairStyleAmount; i++) { if (ss4CharacterGenderSwap.hairStyle == SS4FTMHairStyleTable[i][0]) { ss4CharacterGenderSwap.hairStyle = SS4FTMHairStyleTable[i][1]; break; } } // Placeholder outfit ss4CharacterGenderSwap.inner = 0; ss4CharacterGenderSwap.top = 0x3365; ss4CharacterGenderSwap.outer = 0; ss4CharacterGenderSwap.necklaceScarfHeadphones = 0; ss4CharacterGenderSwap.gloves = 0; ss4CharacterGenderSwap.socks = 0; ss4CharacterGenderSwap.skirtPants = 0x37D5; ss4CharacterGenderSwap.shoes = 0x3B43; ss4CharacterGenderSwap.legWarmers = 0; ss4CharacterGenderSwap.hat = 0; ss4CharacterGenderSwap.glasses = 0; ss4CharacterGenderSwap.bag = 0; ss4CharacterGenderSwap.necklace = 0; ss4CharacterGenderSwap.watch = 0; ss4CharacterGenderSwap.earrings = 0; ss4CharacterGenderSwap.bowPosition = 0; tonccpy((char*)ss4Save+getSS4CharacterOffset(id), &ss4CharacterGenderSwap, 0x3E); } static void changeSS4CharacterGenderToFemale(u16 id) { ss3to4character ss4CharacterGenderSwap; tonccpy(&ss4CharacterGenderSwap, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); ss4CharacterGenderSwap.gender = 1; // Female int i = 0; // Workaround incompatible skin color for (i = 0; i < SS4ToSS3SkinAmount; i++) { if (ss4CharacterGenderSwap.skinColor == SS4ToSS3SkinTable[i][0]) { ss4CharacterGenderSwap.skinColor = SS4ToSS3SkinTable[i][1]; break; } } // Workaround incompatible face shape for (i = 0; i < SS4ToSS3FaceShapeAmount; i++) { if (ss4CharacterGenderSwap.faceShape == SS4ToSS3FaceShapeTable[i][0]) { ss4CharacterGenderSwap.faceShape = SS4ToSS3FaceShapeTable[i][1]; break; } } // Use female face shape set switch (ss4CharacterGenderSwap.faceShape) { case 4: ss4CharacterGenderSwap.faceShape = 3; break; case 5: ss4CharacterGenderSwap.faceShape = 1; break; case 6: ss4CharacterGenderSwap.faceShape = 2; break; } // Eyes for (i = 0; i < SS4MTFEyeAmount; i++) { if (ss4CharacterGenderSwap.eyes == SS4MTFEyeTable[i][0]) { ss4CharacterGenderSwap.eyes = SS4MTFEyeTable[i][1]; break; } } // Mouth shape for (i = 0; i < SS4MTFMouthShapeAmount; i++) { if (ss4CharacterGenderSwap.mouthShape == SS4MTFMouthShapeTable[i][0]) { ss4CharacterGenderSwap.mouthShape = SS4MTFMouthShapeTable[i][1]; break; } } // Eyebrows for (i = 0; i < SS4MTFEyebrowAmount; i++) { if (ss4CharacterGenderSwap.eyebrows == SS4MTFEyebrowTable[i][0]) { ss4CharacterGenderSwap.eyebrows = SS4MTFEyebrowTable[i][1]; break; } } // Overlaying Eyebrows for (i = 0; i < SS4MTFEyebrowAmount; i++) { if (ss4CharacterGenderSwap.eyebrowOverlay == SS4MTFEyebrowTable[i][0]) { ss4CharacterGenderSwap.eyebrowOverlay = SS4MTFEyebrowTable[i][1]; break; } } // Hair style for (i = 0; i < SS4MTFHairStyleAmount; i++) { if (ss4CharacterGenderSwap.hairStyle == SS4MTFHairStyleTable[i][0]) { ss4CharacterGenderSwap.hairStyle = SS4MTFHairStyleTable[i][1]; break; } } // Placeholder outfit ss4CharacterGenderSwap.inner = 0; ss4CharacterGenderSwap.top = 0x0BEA; ss4CharacterGenderSwap.outer = 0; ss4CharacterGenderSwap.necklaceScarfHeadphones = 0; ss4CharacterGenderSwap.gloves = 0; ss4CharacterGenderSwap.socks = 0; ss4CharacterGenderSwap.skirtPants = 0x1FAD; ss4CharacterGenderSwap.shoes = 0x1FBD; ss4CharacterGenderSwap.legWarmers = 0; ss4CharacterGenderSwap.hat = 0; ss4CharacterGenderSwap.glasses = 0; ss4CharacterGenderSwap.bag = 0; ss4CharacterGenderSwap.necklace = 0; ss4CharacterGenderSwap.watch = 0; ss4CharacterGenderSwap.earrings = 0; ss4CharacterGenderSwap.bowPosition = 0; tonccpy((char*)ss4Save+getSS4CharacterOffset(id), &ss4CharacterGenderSwap, 0x3E); } void changeSS4CharacterGender(u16 id) { getSS4CharacterGenderNoExceptions(id) ? changeSS4CharacterGenderToFemale(id) : changeSS4CharacterGenderToMale(id); } u8 readSS4CharacterHeight(u16 id) { ss3to4character ss4CharacterTemp; tonccpy(&ss4CharacterTemp, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); return ss4CharacterTemp.height; } void writeSS4CharacterHeight(u16 id, u8 height) { ss3to4character ss4CharacterTemp; tonccpy(&ss4CharacterTemp, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); ss4CharacterTemp.height = height; tonccpy((char*)ss4Save+getSS4CharacterOffset(id), &ss4CharacterTemp, 0x3E); } u8 readSS4CharacterPoseSet(u16 id) { ss3to4character ss4CharacterTemp; tonccpy(&ss4CharacterTemp, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); return ss4CharacterTemp.poseSet; } void writeSS4CharacterPoseSet(u16 id, u8 poseSet) { ss3to4character ss4CharacterTemp; tonccpy(&ss4CharacterTemp, (char*)ss4Save+getSS4CharacterOffset(id), 0x3E); ss4CharacterTemp.poseSet = poseSet; tonccpy((char*)ss4Save+getSS4CharacterOffset(id), &ss4CharacterTemp, 0x3E); } const char* readSS4ProfileName(u16 id) { if (id >= 0x0BB9) { // Downloaded character id -= 0x0BB9; for (int i = 0; i < 16; i++) { dlCharName[i] = ss4Save[(0x895BC + (0x150*id)) + i*2]; } return dlCharName; } return "???"; } void readSS4Emblem(int id) { switch (id) { case 0: tonccpy(&emblemData, (char*)ss4Save+(0x228FC), 0x804); break; case 1: tonccpy(&emblemData, (char*)ss4Save+(0x23100), 0x804); break; case 2: tonccpy(&emblemData, (char*)ss4Save+(0x23904), 0x804); break; } } void writeSS4Emblem(int id) { switch (id) { case 0: tonccpy((char*)ss4Save+(0x228FC), &emblemData, 0x804); break; case 1: tonccpy((char*)ss4Save+(0x23100), &emblemData, 0x804); break; case 2: tonccpy((char*)ss4Save+(0x23904), &emblemData, 0x804); break; } } void writeSS4EmblemToSave(int id) { u32 bytesWritten = 0; FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_WRITE, FS_WRITE_FLUSH); switch (id) { case 0: FSFILE_Write(handle4, &bytesWritten, 0x228FC, ss4Save+(0x228FC), 0x804, 0); break; case 1: FSFILE_Write(handle4, &bytesWritten, 0x23100, ss4Save+(0x23100), 0x804, 0); break; case 2: FSFILE_Write(handle4, &bytesWritten, 0x23904, ss4Save+(0x23904), 0x804, 0); break; } FSFILE_Close(handle4); } void readSS4EmblemFile(int id, const char* filename) { FILE* emblemData = fopen(filename, "rb"); if (!emblemData) return; switch (id) { case 0: fread((char*)ss4Save+(0x228FC), 0x804, 1, emblemData); break; case 1: fread((char*)ss4Save+(0x23100), 0x804, 1, emblemData); break; case 2: fread((char*)ss4Save+(0x23904), 0x804, 1, emblemData); break; } fclose(emblemData); } void writeSS4EmblemFile(int id, const char* filename) { FILE* emblemData = fopen(filename, "wb"); if (!emblemData) return; switch (id) { case 0: fwrite((char*)ss4Save+(0x228FC), 0x804, 1, emblemData); break; case 1: fwrite((char*)ss4Save+(0x23100), 0x804, 1, emblemData); break; case 2: fwrite((char*)ss4Save+(0x23904), 0x804, 1, emblemData); break; } fclose(emblemData); } u16 readSS4FashionOwnFlag(int id) { return *(u16*)((char*)ss4Save+0x10A1C+(id*sizeof(u16))); } void writeSS4FashionOwnFlag(int id, u16 flag) { toncset16((char*)ss4Save+0x10A1C+(id*sizeof(u16)), flag, 1); } u8 readSS4FashionOwnWardFlag(int id) { return *(u8*)((char*)ss4Save+0x10A1C+(id*sizeof(u16))); } void writeSS4FashionOwnWardFlag(int id, u8 flag) { toncset((char*)ss4Save+0x10A1C+(id*sizeof(u16)), flag, 1); } void writeSS4FashionOwnFlagsToSave(void) { u32 bytesWritten = 0; FSUSER_OpenFile(&handle4, archive4, fsMakePath(PATH_UTF16, (const void*)UTF8toUTF16(ss4SavePath).data()), FS_OPEN_WRITE, FS_WRITE_FLUSH); FSFILE_Write(handle4, &bytesWritten, 0x10A1C, ss4Save+(0x10A1C), 0xECC0, 0); FSFILE_Close(handle4); }