Test Styling Star save reading/writing

This commit is contained in:
RocketRobz 2019-11-14 22:17:59 -07:00
parent afcd476ee2
commit fda330ea0a
5 changed files with 315 additions and 1 deletions

43
include/tonccpy.h Normal file
View File

@ -0,0 +1,43 @@
//# Stuff you may not have yet.
#ifndef TONCCPY_H
#define TONCCPY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <3ds.h>
typedef unsigned int uint;
#define BIT_MASK(len) ( (1<<(len))-1 )
static inline u32 quad8(u8 x) { x |= x<<8; return x | x<<16; }
//# Declarations and inlines.
void tonccpy(void *dst, const void *src, uint size);
void __toncset(void *dst, u32 fill, uint size);
static inline void toncset(void *dst, u8 src, uint size);
static inline void toncset16(void *dst, u16 src, uint size);
static inline void toncset32(void *dst, u32 src, uint size);
//! VRAM-safe memset, byte version. Size in bytes.
static inline void toncset(void *dst, u8 src, uint size)
{ __toncset(dst, quad8(src), size); }
//! VRAM-safe memset, halfword version. Size in hwords.
static inline void toncset16(void *dst, u16 src, uint size)
{ __toncset(dst, src|src<<16, size*2); }
//! VRAM-safe memset, word version. Size in words.
static inline void toncset32(void *dst, u32 src, uint size)
{ __toncset(dst, src, size*4); }
#ifdef __cplusplus
}
#endif
#endif

View File

@ -6,6 +6,7 @@
#include <sys/stat.h>
#include "gui.hpp"
#include "savedata.h"
#define CONFIG_3D_SLIDERSTATE (*(float *)0x1FF81080)
@ -84,6 +85,7 @@ int main()
//titleshot = title1shot;
int highlightedGame = 0;
bool saveWritten = false;
int fadealpha = 255;
int fadecolor = 0;
@ -227,6 +229,19 @@ int main()
if (fadealpha > 0) Draw_Rect(0, 0, 400, 240, C2D_Color32(fadecolor, fadecolor, fadecolor, fadealpha)); // Fade in/out effect
Draw_EndFrame();
if (highlightedGame == 3 && !saveWritten) {
readSS4Save();
readSS4Character(0);
if (ss4CharacterData.gender == 1) {
ss4CharacterData.gender = 2; // Male
} else {
ss4CharacterData.gender = 1; // Female
}
writeSS4Character(0);
writeSS4Save();
saveWritten = true;
}
if(!fadein) {
if(hDown & KEY_B){
screenmodebuffer = SCREEN_MODE_GAME_SELECT;
@ -240,7 +255,7 @@ int main()
bg_yPos -= 0.2;
if(bg_yPos <= -136) bg_yPos = 0.0f;
if (fadein == true) {
if (fadein) {
fadealpha -= 6;
if (fadealpha < 0) {
fadealpha = 0;
@ -254,6 +269,9 @@ int main()
if (fadealpha > 255) {
fadealpha = 255;
screenmode = screenmodebuffer;
if(screenmode == SCREEN_MODE_CHARACTER_SELECT) {
saveWritten = false;
}
fadein = true;
fadeout = false;
}

43
source/savedata.cpp Normal file
View File

@ -0,0 +1,43 @@
#include <3ds.h>
#include <stdio.h>
#include <cstring>
#include "savedata.h"
#include "tonccpy.h"
ss3to4character ss4CharacterData;
char ss3Save[0x174000];
char ss4Save[0xF0000];
void readSS4Save(void) {
FILE* saveData = fopen("sdmc:/3ds/Checkpoint/extdata/0x01C25 Style Savvy Styling Star/SavvyManager/savedata.dat", "rb");
fread(ss4Save, (int)sizeof(ss4Save), 1, saveData);
fclose(saveData);
}
void writeSS4Save(void) {
FILE* saveData = fopen("sdmc:/3ds/Checkpoint/extdata/0x01C25 Style Savvy Styling Star/SavvyManager/savedata.dat", "wb");
fwrite(ss4Save, (int)sizeof(ss4Save), 1, saveData);
fclose(saveData);
}
void readSS4Character(u16 id) {
if (id == 0) {
// Playable character
tonccpy(&ss4CharacterData, (char*)ss4Save+(0x2440A), 0x3E);
} else {
// Non-playable character
tonccpy(&ss4CharacterData, (char*)ss4Save+(0x273EE + (0x1F8*id)), 0x3E);
}
}
void writeSS4Character(u16 id) {
if (id == 0) {
// Playable character
tonccpy((char*)ss4Save+(0x2440A), &ss4CharacterData, 0x3E);
} else {
// Non-playable character
tonccpy((char*)ss4Save+(0x273EE + (0x1F8*id)), &ss4CharacterData, 0x3E);
}
}

74
source/savedata.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef SAVEDATA_H
#define SAVEDATA_H
#ifdef __cplusplus
extern "C" {
#endif
#include <3ds.h>
typedef struct ss3to4character {
u8 gender; // Gender (01=Female, 02=Male)
u8 height; // Height (00=Character is invisible)
u8 poseSet; // Pose set (01=Normal, 02=Cute, 03=Bold)
u8 skinColor;
u8 faceShape; // Face shape (03=Left, 01=Mid, 02=Right)
u8 eyes;
u8 mouthShape;
u8 eyebrows;
u8 faceMole; // Face mole (Female), Facial hair (Male)
u8 freckles; // Unknown for Styling Star
u8 mascaraColor;
u8 unknownC;
u8 unknownD;
u8 eyeMakeupColor;
u8 unknownF;
u8 mascaraLength;
u8 unknown11;
u8 lipShine;
u8 eyeColor;
u8 eyebrowOverlay;
u8 hairStyle;
u8 hairFringe;
u8 hairColorMain;
u8 hairColorHighlights;
u8 expessFreckles; // Show expressions for Fashion Forward, or freckles for Styling Star
u8 nailColor;
u8 eyeliner; // Eyeliner (00=Normal, 01=Double)
u8 unknown1C;
u16 inner;
u16 top; // Top/Dress/Yukatas (Female), Yukatas/Dungarees (Male)
u16 outer;
u16 necklaceScarf; // Necklace/Scarf
u16 gloves;
u16 socks; // Socks/Leggings/Tights
u16 skirtPants; // Skirt/Pants
u16 shoes;
u16 unknown2E;
u16 hat;
u16 glasses;
u16 bow;
u16 unknown36;
u16 unknown38;
u16 unknown3A;
u8 bowPosition;
u8 unknown3D;
} ss3to4character;
extern ss3to4character ss4CharacterData;
extern char ss3Save[0x174000];
extern char ss4Save[0xF0000];
extern void readSS4Save(void);
extern void writeSS4Save(void);
extern void readSS4Character(u16 id);
extern void writeSS4Character(u16 id);
#ifdef __cplusplus
}
#endif
#endif // SAVEDATA_H

136
source/tonccpy.c Normal file
View File

@ -0,0 +1,136 @@
#include "tonccpy.h"
//# tonccpy.c
//! VRAM-safe cpy.
/*! This version mimics memcpy in functionality, with
the benefit of working for VRAM as well. It is also
slightly faster than the original memcpy, but faster
implementations can be made.
\param dst Destination pointer.
\param src Source pointer.
\param size Fill-length in bytes.
\note The pointers and size need not be word-aligned.
*/
void tonccpy(void *dst, const void *src, uint size)
{
if(size==0 || dst==0 || src==0)
return;
uint count;
u16 *dst16; // hword destination
u8 *src8; // byte source
// Ideal case: copy by 4x words. Leaves tail for later.
if( ((u32)src|(u32)dst)%4==0 && size>=4)
{
u32 *src32= (u32*)src, *dst32= (u32*)dst;
count= size/4;
uint tmp= count&3;
count /= 4;
// Duff's Device, good friend!
switch(tmp) {
do { *dst32++ = *src32++;
case 3: *dst32++ = *src32++;
case 2: *dst32++ = *src32++;
case 1: *dst32++ = *src32++;
case 0: ; } while(count--);
}
// Check for tail
size &= 3;
if(size == 0)
return;
src8= (u8*)src32;
dst16= (u16*)dst32;
}
else // Unaligned.
{
uint dstOfs= (u32)dst&1;
src8= (u8*)src;
dst16= (u16*)(dst-dstOfs);
// Head: 1 byte.
if(dstOfs != 0)
{
*dst16= (*dst16 & 0xFF) | *src8++<<8;
dst16++;
if(--size==0)
return;
}
}
// Unaligned main: copy by 2x byte.
count= size/2;
while(count--)
{
*dst16++ = src8[0] | src8[1]<<8;
src8 += 2;
}
// Tail: 1 byte.
if(size&1)
*dst16= (*dst16 &~ 0xFF) | *src8;
}
//# toncset.c
//! VRAM-safe memset, internal routine.
/*! This version mimics memset in functionality, with
the benefit of working for VRAM as well. It is also
slightly faster than the original memset.
\param dst Destination pointer.
\param fill Word to fill with.
\param size Fill-length in bytes.
\note The \a dst pointer and \a size need not be
word-aligned. In the case of unaligned fills, \a fill
will be masked off to match the situation.
*/
void __toncset(void *dst, u32 fill, uint size)
{
if(size==0 || dst==0)
return;
uint left= (u32)dst&3;
u32 *dst32= (u32*)(dst-left);
u32 count, mask;
// Unaligned head.
if(left != 0)
{
// Adjust for very small stint.
if(left+size<4)
{
mask= BIT_MASK(size*8)<<(left*8);
*dst32= (*dst32 &~ mask) | (fill & mask);
return;
}
mask= BIT_MASK(left*8);
*dst32= (*dst32 & mask) | (fill&~mask);
dst32++;
size -= 4-left;
}
// Main stint.
count= size/4;
uint tmp= count&3;
count /= 4;
switch(tmp) {
do { *dst32++ = fill;
case 3: *dst32++ = fill;
case 2: *dst32++ = fill;
case 1: *dst32++ = fill;
case 0: ; } while(count--);
}
// Tail
size &= 3;
if(size)
{
mask= BIT_MASK(size*8);
*dst32= (*dst32 &~ mask) | (fill & mask);
}
}