mirror of
https://github.com/suloku/pdrpse.git
synced 2026-08-26 18:44:24 -05:00
Initial commit for 0.1 version
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
build/
|
||||
*.3dsx
|
||||
*.exe
|
||||
*.elf
|
||||
*~
|
||||
179
Makefile
Normal file
179
Makefile
Normal file
@@ -0,0 +1,179 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITARM)/3ds_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
#
|
||||
# NO_SMDH: if set to anything, no SMDH file is generated.
|
||||
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
|
||||
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
|
||||
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
|
||||
# ICON is the filename of the icon (.png), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.png
|
||||
# - icon.png
|
||||
# - <libctru folder>/default_icon.png
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := $(notdir $(CURDIR))
|
||||
BUILD := build
|
||||
SOURCES := source
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
|
||||
APP_TITLE := PDR Pocket Save Editor
|
||||
APP_DESCRIPTION := A save editor for Pokemon Dream Radar
|
||||
APP_AUTHOR := suloku
|
||||
ICON :=
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
|
||||
|
||||
CFLAGS := -g -Wall -O2 -mword-relocations \
|
||||
-fomit-frame-pointer -ffast-math \
|
||||
$(ARCH)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lctru -lm
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(CTRULIB)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.png)
|
||||
ifneq (,$(findstring $(TARGET).png,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).png
|
||||
else
|
||||
ifneq (,$(findstring icon.png,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.png
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_SMDH)),)
|
||||
export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(NO_SMDH)),)
|
||||
$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh
|
||||
else
|
||||
$(OUTPUT).3dsx : $(OUTPUT).elf
|
||||
endif
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
# WARNING: This is not the right way to do this! TODO: Do it right!
|
||||
#---------------------------------------------------------------------------------
|
||||
%.vsh.o : %.vsh
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
|
||||
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
|
||||
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
|
||||
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
|
||||
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
|
||||
@rm ../$(notdir $<).shbin
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
34
README.md
34
README.md
@@ -1,2 +1,32 @@
|
||||
# pdrpse
|
||||
Pokémon Dream Radar Savegame Editor for 3DS
|
||||
# Pok<EFBFBD>mon Dream Radar Pocket Save Editor
|
||||
by suloku 2015
|
||||
|
||||
This is a very simple save editor for Pok<6F>mon Dream Radar, based on fylesystem.c and filesystem.h from meladroit's svdt, which is in turn based on ironhax installer by smea (aka sploit_installer).
|
||||
|
||||
This editor allows to modify current orbs (the that can be used to buy), total collected orbs (shown in the records screen).
|
||||
Also allows to modify the "current orb count for reward", which is the value that stores how many orbs were gathered since the last reward was received:
|
||||
|
||||
Retrieval Extension: Obtain a total of 200 Dream Orbs
|
||||
Eureka Extension A (Tornadus): Obtain a total of 400 Dream Orbs
|
||||
|
||||
Dowsing Extension: Obtain a total of 700 Dream Orbs, catch Tornadus
|
||||
Eureka Extension B (Thundurus): Obtain a total of 1500 Dream Orbs, catch Tornadus
|
||||
|
||||
Eureka Extension G (Landorus): Obtain a total of 3000 Dream Orbs, catch Thundurus
|
||||
|
||||
After the player catches Tornadus, Thundurs or Landorus, the "current orb count for reward" is reset to 0. This means that currently, to unlock all game content, one has to do the following:
|
||||
1.- Set "current orb count for reward" to at least 400
|
||||
2.- Enter the game, Retrieval and Eureka A extensions are received
|
||||
3.- Catch Tornadus, "current orb count for reward" is reset to 0.
|
||||
|
||||
4.- Set "current orb count for reward" to at least 1500
|
||||
5.- Enter the game, Dowsing and Eureka B extensions are received
|
||||
6.- Catch Thundurus, "current orb count for reward" is reset to 0.
|
||||
|
||||
7.- Set "current orb count for reward" to at least 3000
|
||||
8.- Enter the game, Eureka G extensions is received
|
||||
9.- After catching Landorus, the credits will roll and all left game content will be unlocked (simulator A, B and G will be received and gen IV extensions, if unlocked, will be available).
|
||||
|
||||
It also allows to unlock the geneartion IV extensions, which can normally only be unlocked by inserting a gen IV DS cartridge in the 3DS console, and to re-catch those legendaries so they can be transfered to another Black2/White2 cartridge.
|
||||
|
||||
See more information about the game at: http://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_Dream_Radar
|
||||
|
||||
BIN
pdrpse.smdh
Normal file
BIN
pdrpse.smdh
Normal file
Binary file not shown.
3
pdrpse.xml
Normal file
3
pdrpse.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<targets selectable="false">
|
||||
<title mediatype="1">00040000000ae100</title>
|
||||
</targets>
|
||||
310
source/filesystem.c
Normal file
310
source/filesystem.c
Normal file
@@ -0,0 +1,310 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "filesystem.h"
|
||||
|
||||
Handle saveGameFsHandle, sdmcFsHandle;
|
||||
FS_archive saveGameArchive, sdmcArchive;
|
||||
|
||||
typedef struct lsLine
|
||||
{
|
||||
FS_dirent thisLine;
|
||||
struct lsLine* nextLine;
|
||||
} lsLine;
|
||||
|
||||
typedef struct lsDir
|
||||
{
|
||||
struct lsLine* firstLine;
|
||||
struct lsDir* parentDir;
|
||||
} lsDir;
|
||||
|
||||
|
||||
// bypass handle list
|
||||
Result _srvGetServiceHandle(Handle* out, const char* name)
|
||||
{
|
||||
Result rc = 0;
|
||||
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = 0x50100;
|
||||
strcpy((char*) &cmdbuf[1], name);
|
||||
cmdbuf[3] = strlen(name);
|
||||
cmdbuf[4] = 0x0;
|
||||
|
||||
if((rc = svcSendSyncRequest(*srvGetSessionHandle())))return rc;
|
||||
|
||||
*out = cmdbuf[3];
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result filesystemInit()
|
||||
{
|
||||
Result ret;
|
||||
|
||||
ret = _srvGetServiceHandle(&saveGameFsHandle, "fs:USER");
|
||||
if(ret)return ret;
|
||||
|
||||
ret = FSUSER_Initialize(&saveGameFsHandle);
|
||||
if(ret)return ret;
|
||||
|
||||
ret = srvGetServiceHandle(&sdmcFsHandle, "fs:USER");
|
||||
if(ret)return ret;
|
||||
|
||||
saveGameArchive = (FS_archive){0x00000004, (FS_path){PATH_EMPTY, 1, (u8*)""}};
|
||||
ret = FSUSER_OpenArchive(&saveGameFsHandle, &saveGameArchive);
|
||||
|
||||
sdmcArchive = (FS_archive){0x00000009, (FS_path){PATH_EMPTY, 1, (u8*)""}};
|
||||
ret = FSUSER_OpenArchive(&sdmcFsHandle, &sdmcArchive);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result filesystemExit()
|
||||
{
|
||||
Result ret;
|
||||
|
||||
ret = FSUSER_CloseArchive(&saveGameFsHandle, &saveGameArchive);
|
||||
ret = FSUSER_CloseArchive(&sdmcFsHandle, &sdmcArchive);
|
||||
ret = svcCloseHandle(saveGameFsHandle);
|
||||
ret = svcCloseHandle(sdmcFsHandle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result filesystemSoftReset()
|
||||
{
|
||||
// exit and reinit without giving up those handles
|
||||
Result ret;
|
||||
|
||||
ret = FSUSER_CloseArchive(&saveGameFsHandle, &saveGameArchive);
|
||||
ret = FSUSER_CloseArchive(&sdmcFsHandle, &sdmcArchive);
|
||||
|
||||
saveGameArchive = (FS_archive){0x00000004, (FS_path){PATH_EMPTY, 1, (u8*)""}};
|
||||
ret = FSUSER_OpenArchive(&saveGameFsHandle, &saveGameArchive);
|
||||
|
||||
sdmcArchive = (FS_archive){0x00000009, (FS_path){PATH_EMPTY, 1, (u8*)""}};
|
||||
ret = FSUSER_OpenArchive(&sdmcFsHandle, &sdmcArchive);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result FSUSER_ControlArchive(Handle handle, FS_archive archive)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
u32 b1 = 0, b2 = 0;
|
||||
|
||||
cmdbuf[0]=0x080d0144;
|
||||
cmdbuf[1]=archive.handleLow;
|
||||
cmdbuf[2]=archive.handleHigh;
|
||||
cmdbuf[3]=0x0;
|
||||
cmdbuf[4]=0x1; //buffer1 size
|
||||
cmdbuf[5]=0x1; //buffer1 size
|
||||
cmdbuf[6]=0x1a;
|
||||
cmdbuf[7]=(u32)&b1;
|
||||
cmdbuf[8]=0x1c;
|
||||
cmdbuf[9]=(u32)&b2;
|
||||
|
||||
Result ret=0;
|
||||
if((ret=svcSendSyncRequest(handle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
/*Result FSUSER_GetMediaType(Handle handle, u8* mediatype)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=0x08680000;
|
||||
|
||||
Result ret=0;
|
||||
if((ret=svcSendSyncRequest(handle)))return ret;
|
||||
|
||||
if(mediatype)
|
||||
*mediatype = (u8)cmdbuf[2];
|
||||
|
||||
return cmdbuf[1];
|
||||
}*/
|
||||
|
||||
// let's add stuff from 3ds_hb_menu, just because
|
||||
Result loadFile(char* path, void* dst, FS_archive* archive, Handle* fsHandle, u64 maxSize)
|
||||
{
|
||||
// must malloc first! (and memset, if you'd like)
|
||||
if(!path || !dst || !archive)return -1;
|
||||
|
||||
u64 size;
|
||||
u32 bytesRead;
|
||||
Result ret;
|
||||
Handle fileHandle;
|
||||
|
||||
ret=FSUSER_OpenFile(fsHandle, &fileHandle, *archive, FS_makePath(PATH_CHAR, path), FS_OPEN_READ, FS_ATTRIBUTE_NONE);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
ret=FSFILE_GetSize(fileHandle, &size);
|
||||
if(ret!=0)goto loadFileExit;
|
||||
if(size>maxSize){ret=-2; goto loadFileExit;}
|
||||
|
||||
ret=FSFILE_Read(fileHandle, &bytesRead, 0x0, dst, size);
|
||||
if(ret!=0)goto loadFileExit;
|
||||
if(bytesRead<size){ret=-3; goto loadFileExit;}
|
||||
|
||||
loadFileExit:
|
||||
FSFILE_Close(fileHandle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// oh and let's add in a writeFile, because we kind of need that
|
||||
Result writeFile(char* path, u8* data, u32 size, FS_archive* archive, Handle* fsHandle)
|
||||
{
|
||||
if(!path || !data)return -1;
|
||||
|
||||
Handle outFileHandle;
|
||||
u32 bytesWritten;
|
||||
Result ret = 0;
|
||||
|
||||
ret = FSUSER_OpenFile(fsHandle, &outFileHandle, *archive, FS_makePath(PATH_CHAR, path), FS_OPEN_CREATE | FS_OPEN_WRITE, FS_ATTRIBUTE_NONE);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
ret = FSFILE_Write(outFileHandle, &bytesWritten, 0x0, data, size, 0x10001);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
ret = FSFILE_Close(outFileHandle);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
if(archive==&saveGameArchive)
|
||||
{
|
||||
//printf("calling ControlArchive\n");
|
||||
ret = FSUSER_ControlArchive(saveGameFsHandle, saveGameArchive);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// I'll try deleting! that's a good trick!
|
||||
Result deleteFile(char* path, FS_archive* archive, Handle* fsHandle)
|
||||
{
|
||||
if(!path || !archive)return -1;
|
||||
|
||||
Result ret = FSUSER_DeleteFile(fsHandle, *archive, FS_makePath(PATH_CHAR, path));
|
||||
if(ret!=0)return ret;
|
||||
|
||||
if(archive==&saveGameArchive)
|
||||
{
|
||||
//printf("\ncalling ControlArchive\n");
|
||||
ret = FSUSER_ControlArchive(saveGameFsHandle, saveGameArchive);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 sizeFile(char* path, FS_archive* archive, Handle* fsHandle)
|
||||
{
|
||||
if(!path || !archive)return -1;
|
||||
|
||||
u64 size = -1;
|
||||
Handle fileHandle;
|
||||
|
||||
Result ret=FSUSER_OpenFile(fsHandle, &fileHandle, *archive, FS_makePath(PATH_CHAR, path), FS_OPEN_READ, FS_ATTRIBUTE_NONE);
|
||||
if(ret!=0)return -1;
|
||||
|
||||
ret=FSFILE_GetSize(fileHandle, &size);
|
||||
if(ret!=0)return -1;
|
||||
|
||||
FSFILE_Close(fileHandle);
|
||||
return size;
|
||||
}
|
||||
|
||||
Result readBytesFromSaveFile(const char* filename, u64 offset, u8* buffer, u32 size)
|
||||
{
|
||||
Result ret;
|
||||
Handle fileHandle;
|
||||
|
||||
ret=FSUSER_OpenFile(&saveGameFsHandle, &fileHandle, saveGameArchive, FS_makePath(PATH_CHAR, filename), FS_OPEN_READ, FS_ATTRIBUTE_NONE);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
ret=FSFILE_Read(fileHandle, NULL, offset, buffer, size);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
FSFILE_Close(fileHandle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result writeBytesToSaveFile(const char* filename, u64 offset, u8* buffer, u32 size)
|
||||
{
|
||||
Result ret;
|
||||
Handle fileHandle;
|
||||
|
||||
ret=FSUSER_OpenFile(&saveGameFsHandle, &fileHandle, saveGameArchive, FS_makePath(PATH_CHAR, filename), FS_OPEN_WRITE | FS_OPEN_CREATE, FS_ATTRIBUTE_NONE);
|
||||
if(ret!=0)
|
||||
return ret;
|
||||
|
||||
ret=FSFILE_Write(fileHandle, NULL, offset, buffer, size, 0x10001);
|
||||
if(ret!=0)
|
||||
return ret;
|
||||
|
||||
FSFILE_Close(fileHandle);
|
||||
ret = FSUSER_ControlArchive(saveGameFsHandle, saveGameArchive);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result getSaveGameFileSize(const char* filename, u64* size)
|
||||
{
|
||||
Result ret;
|
||||
Handle fileHandle;
|
||||
|
||||
ret=FSUSER_OpenFile(&saveGameFsHandle, &fileHandle, saveGameArchive, FS_makePath(PATH_CHAR, filename), FS_OPEN_READ, FS_ATTRIBUTE_NONE);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
ret=FSFILE_GetSize(fileHandle, size);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
FSFILE_Close(fileHandle);
|
||||
|
||||
if(*size)
|
||||
return ret;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
Result doesFileNotExist(const char* filename, Handle* fsHandle, FS_archive archive)
|
||||
{
|
||||
Result ret;
|
||||
Handle fileHandle;
|
||||
u64 size;
|
||||
|
||||
ret=FSUSER_OpenFile(fsHandle, &fileHandle, archive, FS_makePath(PATH_CHAR, filename), FS_OPEN_READ, FS_ATTRIBUTE_NONE);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
ret=FSFILE_GetSize(fileHandle, &size);
|
||||
if(ret!=0)return ret;
|
||||
|
||||
FSFILE_Close(fileHandle);
|
||||
|
||||
if(size)
|
||||
return ret;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int file_exist(const char * filename)
|
||||
{
|
||||
FILE * pFile;
|
||||
long lSize;
|
||||
char * buffer;
|
||||
size_t result;
|
||||
|
||||
pFile = fopen ( filename , "rb" );
|
||||
if (pFile==NULL) return 0;
|
||||
fseek (pFile , 0 , SEEK_END);
|
||||
lSize = ftell (pFile);
|
||||
rewind (pFile);
|
||||
buffer = (char*) malloc (sizeof(char)*lSize);
|
||||
if (buffer == NULL) return 0;
|
||||
result = fread (buffer,1,lSize,pFile);
|
||||
if (result != lSize) return 0;
|
||||
fclose (pFile);
|
||||
free (buffer);
|
||||
if (lSize > 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
21
source/filesystem.h
Normal file
21
source/filesystem.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef FILESYSTEM_H
|
||||
#define FILESYSTEM_H
|
||||
|
||||
extern Handle saveGameFsHandle, sdmcFsHandle;
|
||||
extern FS_archive saveGameArchive, sdmcArchive;
|
||||
|
||||
Result filesystemInit();
|
||||
Result filesystemExit();
|
||||
Result filesystemSoftReset();
|
||||
Result FSUSER_ControlArchive(Handle handle, FS_archive archive);
|
||||
//Result FSUSER_GetMediaType(Handle handle, u8* mediatype);
|
||||
Result loadFile(char* path, void* dst, FS_archive* archive, Handle* fsHandle, u64 maxSize);
|
||||
Result writeFile(char* path, u8* data, u32 size, FS_archive* archive, Handle* fsHandle);
|
||||
Result deleteFile(char* path, FS_archive* archive, Handle* fsHandle);
|
||||
u64 sizeFile(char* path, FS_archive* archive, Handle* fsHandle);
|
||||
Result readBytesFromSaveFile(const char* filename, u64 offset, u8* buffer, u32 size);
|
||||
Result writeBytesToSaveFile(const char* filename, u64 offset, u8* buffer, u32 size);
|
||||
Result getSaveGameFileSize(const char* filename, u64* size);
|
||||
Result doesFileNotExist(const char* filename, Handle* fsHandle, FS_archive archive);
|
||||
int file_exist (const char *filename);
|
||||
#endif
|
||||
295
source/main.c
Normal file
295
source/main.c
Normal file
@@ -0,0 +1,295 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "text.h"
|
||||
|
||||
#define bitcheck(x) (number >> x) & 1
|
||||
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
|
||||
amInit();
|
||||
filesystemInit();
|
||||
|
||||
gfxInitDefault();
|
||||
//gfxSet3D(true); // uncomment if using stereoscopic 3D
|
||||
consoleInit(GFX_TOP, NULL);
|
||||
/*
|
||||
//u8 mediatype;
|
||||
u64 TID;
|
||||
//FSUSER_GetMediaType(&saveGameFsHandle,&mediatype);
|
||||
aptOpenSession();
|
||||
APT_GetProgramID(NULL, &TID);
|
||||
aptCloseSession();
|
||||
*/
|
||||
printf("Pokemon Dream Radar Pocket Save Editor v0.1\n");
|
||||
printf("------------------------------by suloku '15\n\n");
|
||||
|
||||
int exitnow = 0;
|
||||
|
||||
// Load savegame
|
||||
u64 size;
|
||||
u8* buffer = NULL;
|
||||
//Try to open savefile
|
||||
Result res = getSaveGameFileSize("/cygsavedata.dat",&size);
|
||||
if (res != 0 ){
|
||||
printf ("Can't open cygsavedata.dat\n");
|
||||
exitnow = 1;
|
||||
} else{
|
||||
buffer = (u8*)malloc(size);
|
||||
res = readBytesFromSaveFile("/cygsavedata.dat",0,buffer,size);
|
||||
if (res != 0 ){
|
||||
printf ("Failed to read cygsavedata.dat\n\n");
|
||||
exitnow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//Save is loaded in buffer
|
||||
|
||||
//Variables we'll modify
|
||||
u32 orbs_cash;
|
||||
u32 orbs_totalcol;
|
||||
u32 orbs_reward;
|
||||
u8 gen4ext;
|
||||
u16 gen4catch;
|
||||
|
||||
int save = 0;
|
||||
|
||||
// Main loop
|
||||
if (!exitnow){
|
||||
//Copy Data
|
||||
memcpy (&orbs_cash, buffer+0x68, sizeof(u32));
|
||||
memcpy (&orbs_totalcol, buffer+0x6C, sizeof(u32));
|
||||
memcpy (&orbs_reward, buffer+0x288, sizeof(u32));
|
||||
memcpy (&gen4ext, buffer+0x26E, sizeof(u8));
|
||||
memcpy (&gen4catch, buffer+0x272, sizeof(u16));
|
||||
int cursor = 0;
|
||||
while (aptMainLoop())
|
||||
{
|
||||
gspWaitForVBlank();
|
||||
hidScanInput();
|
||||
gotoxy(0,0);
|
||||
|
||||
printf("Pokemon Dream Radar Pocket Save Editor v0.1\n");
|
||||
printf("------------------------------by suloku '15\n\n");
|
||||
|
||||
printf ("\tOrbs Cash: %06lu \n", orbs_cash);
|
||||
printf ("\tTotal Collected Orbs: %06lu \n", orbs_totalcol);
|
||||
printf ("\tOrb count for next reward: %06lu \n", orbs_reward);
|
||||
|
||||
printf ("\nGen IV Extension: 0x%02X - 0x%04X\n", gen4ext, gen4catch);
|
||||
printf ("\tTemoral (Dialga): ");
|
||||
if ((gen4ext & 0x4) >1) printf("unlocked - ");
|
||||
else printf ("locked - ");
|
||||
if ((gen4catch & 0x10) >1) printf("catched \n");
|
||||
else printf ("uncatched\n");
|
||||
printf ("\tSpatial (Palkia): ");
|
||||
if ((gen4ext & 0x8) >1) printf("unlocked - ");
|
||||
else printf ("locked - ");
|
||||
if ((gen4catch & 0x20) >1) printf("catched \n");
|
||||
else printf ("uncatched\n");
|
||||
printf ("\tRenegade (Giratina): ");
|
||||
if ((gen4ext & 0x10) >1) printf("unlocked - ");
|
||||
else printf ("locked - ");
|
||||
if ((gen4catch & 0x40) >1) printf("catched \n");
|
||||
else printf ("uncatched\n");
|
||||
printf ("\tRainbow (Ho-Oh): ");
|
||||
if ((gen4ext & 0x20) >1) printf("unlocked - ");
|
||||
else printf ("locked - ");
|
||||
if ((gen4catch & 0x80) >1) printf("catched \n");
|
||||
else printf ("uncatched\n");
|
||||
printf ("\tDiving (Lugia): ");
|
||||
if ((gen4ext & 0x40) >1) printf("unlocked - ");
|
||||
else printf ("locked - ");
|
||||
if ((gen4catch & 0x100) >1) printf("catched \n");
|
||||
else printf ("uncatched\n");
|
||||
|
||||
printf("\n\n\nControls:\n");
|
||||
if (cursor < 3){
|
||||
printf("\tLEFT/RIGHT: +-100 \n");
|
||||
printf("\tLEFT/RIGHT (hold R): +-1 \n");
|
||||
printf("\tLEFT/RIGHT (hold L): +-1000 \n");
|
||||
}else{
|
||||
printf("\tA: toogle all gen IV extensions \n");
|
||||
printf("\tY: toogle gen IV extensions \n");
|
||||
printf("\tB: toogle gen IV as catched/uncatched\n");
|
||||
}
|
||||
|
||||
printf("\n\tX: unlock next reward\n");
|
||||
printf("\n\nPress START to exit\n");
|
||||
printf("Press SELECT to save & exit\n");
|
||||
|
||||
u32 kDown = hidKeysDown();
|
||||
u32 kHeld = hidKeysHeld();
|
||||
if (kDown & KEY_START)
|
||||
break; // break in order to return to hbmenu
|
||||
|
||||
if (kDown & KEY_SELECT){
|
||||
save = 1;
|
||||
break; // save and exit
|
||||
}
|
||||
|
||||
if (kDown & KEY_DOWN){
|
||||
cursor++;
|
||||
if (cursor > 7) cursor = 7;
|
||||
}
|
||||
if (kDown & KEY_UP){
|
||||
cursor--;
|
||||
if (cursor < 1) cursor = 0;
|
||||
}
|
||||
|
||||
switch (cursor){
|
||||
case 0:
|
||||
if (kDown & KEY_RIGHT && kHeld & KEY_R){
|
||||
orbs_cash++;
|
||||
} else if (kHeld & KEY_RIGHT && !(kHeld & (KEY_R|KEY_L))){
|
||||
orbs_cash+=100;
|
||||
} else if (kHeld & KEY_RIGHT && (kHeld & KEY_L)){
|
||||
orbs_cash+=1000;
|
||||
}
|
||||
if (orbs_cash > 999998) orbs_cash = 999999;
|
||||
if (kDown & KEY_LEFT && kHeld & KEY_R){
|
||||
orbs_cash--;
|
||||
} else if (kHeld & KEY_LEFT && !(kHeld & (KEY_R|KEY_L))){
|
||||
orbs_cash-=100;
|
||||
} else if (kHeld & KEY_LEFT && (kHeld & KEY_L)){
|
||||
orbs_cash-=1000;
|
||||
}
|
||||
if (orbs_cash < 1 || orbs_cash > 999999) orbs_cash = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (kDown & KEY_RIGHT && kHeld & KEY_R){
|
||||
orbs_totalcol++;
|
||||
} else if (kHeld & KEY_RIGHT && !(kHeld & (KEY_R|KEY_L))){
|
||||
orbs_totalcol+=100;
|
||||
} else if (kHeld & KEY_RIGHT && (kHeld & KEY_L)){
|
||||
orbs_totalcol+=1000;
|
||||
}
|
||||
if (orbs_totalcol > 999998) orbs_totalcol = 999999;
|
||||
if (kDown & KEY_LEFT && kHeld & KEY_R){
|
||||
orbs_totalcol--;
|
||||
} else if (kHeld & KEY_LEFT && !(kHeld & (KEY_R|KEY_L))){
|
||||
orbs_totalcol-=100;
|
||||
} else if (kHeld & KEY_LEFT && (kHeld & KEY_L)){
|
||||
orbs_totalcol-=1000;
|
||||
}
|
||||
if (orbs_totalcol < 1 || orbs_totalcol > 999999) orbs_totalcol = 0;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (kDown & KEY_RIGHT && kHeld & KEY_R){
|
||||
orbs_reward++;
|
||||
} else if (kHeld & KEY_RIGHT && !(kHeld & (KEY_R|KEY_L))){
|
||||
orbs_reward+=100;
|
||||
} else if (kHeld & KEY_RIGHT && (kHeld & KEY_L)){
|
||||
orbs_reward+=1000;
|
||||
}
|
||||
if (orbs_reward > 999998) orbs_reward = 999999;
|
||||
if (kDown & KEY_LEFT && kHeld & KEY_R){
|
||||
orbs_reward--;
|
||||
} else if (kHeld & KEY_LEFT && !(kHeld & (KEY_R|KEY_L))){
|
||||
orbs_reward-=100;
|
||||
} else if (kHeld & KEY_LEFT && (kHeld & KEY_L)){
|
||||
orbs_reward-=1000;
|
||||
}
|
||||
if (orbs_reward < 1 || orbs_reward > 999999) orbs_reward = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (kDown & KEY_X){
|
||||
orbs_reward = 3000;
|
||||
}
|
||||
if (kDown & KEY_A){
|
||||
//Disable if there's one enabled
|
||||
if (gen4ext & 0x7C){
|
||||
gen4ext &= ~0x7C;
|
||||
//And disable catched flags
|
||||
gen4catch &= ~0x10;
|
||||
gen4catch &= ~0x20;
|
||||
gen4catch &= ~0x40;
|
||||
gen4catch &= ~0x80;
|
||||
gen4catch &= ~0x100;
|
||||
}else //enable all
|
||||
gen4ext |= 0x7C;
|
||||
}
|
||||
if (kDown & KEY_Y){
|
||||
if (cursor == 3) gen4ext ^= 0x4;
|
||||
if (cursor == 4) gen4ext ^= 0x8;
|
||||
if (cursor == 5) gen4ext ^= 0x10;
|
||||
if (cursor == 6) gen4ext ^= 0x20;
|
||||
if (cursor == 7) gen4ext ^= 0x40;
|
||||
//Disable catched if unlocked
|
||||
if (!(gen4ext & 0x4)) gen4catch &= ~0x10;
|
||||
if (!(gen4ext & 0x8)) gen4catch &= ~0x20;
|
||||
if (!(gen4ext & 0x10)) gen4catch &= ~0x40;
|
||||
if (!(gen4ext & 0x20)) gen4catch &= ~0x80;
|
||||
if (!(gen4ext & 0x40)) gen4catch &= ~0x100;
|
||||
|
||||
}
|
||||
if (kDown & KEY_B){
|
||||
if (gen4ext & 0x4 && cursor == 3) gen4catch ^= 0x10;
|
||||
if (gen4ext & 0x8 && cursor == 4) gen4catch ^= 0x20;
|
||||
if (gen4ext & 0x10 && cursor == 5) gen4catch ^= 0x40;
|
||||
if (gen4ext & 0x20 && cursor == 6) gen4catch ^= 0x80;
|
||||
if (gen4ext & 0x40 && cursor == 7) gen4catch ^= 0x100;
|
||||
}
|
||||
|
||||
gotoxy(0, 3); printf (" ");
|
||||
gotoxy(0, 4); printf (" ");
|
||||
gotoxy(0, 5); printf (" ");
|
||||
gotoxy(0, 8); printf (" ");
|
||||
gotoxy(0, 9); printf (" ");
|
||||
gotoxy(0, 10); printf (" ");
|
||||
gotoxy(0, 11); printf (" ");
|
||||
gotoxy(0, 12); printf (" ");
|
||||
if (cursor < 3)
|
||||
gotoxy(0, 3+cursor);
|
||||
else if (cursor > 2)
|
||||
gotoxy(0, 3+cursor+2);
|
||||
printf(">>");
|
||||
|
||||
//if (kHeld || kDown) consoleClear();
|
||||
// Flush and swap framebuffers
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
}
|
||||
}else{
|
||||
printf("\nPress START to exit.\n");
|
||||
while(aptMainLoop()){
|
||||
gspWaitForVBlank();
|
||||
hidScanInput();
|
||||
|
||||
u32 kDown = hidKeysDown();
|
||||
if (kDown & KEY_START)
|
||||
break; // break in order to return to hbmenu
|
||||
|
||||
// Flush and swap framebuffers
|
||||
gfxFlushBuffers();
|
||||
gfxSwapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
if (save){
|
||||
//set data to buffer
|
||||
memcpy (buffer+0x68, &orbs_cash, sizeof(u32));
|
||||
memcpy (buffer+0x6C, &orbs_totalcol, sizeof(u32));
|
||||
memcpy (buffer+0x288, &orbs_reward, sizeof(u32));
|
||||
memcpy (buffer+0x26E, &gen4ext, sizeof(u8));
|
||||
memcpy (buffer+0x272, &gen4catch, sizeof(u16));
|
||||
// Save savegame
|
||||
res = writeBytesToSaveFile("/cygsavedata.dat", 0, buffer, size);
|
||||
}
|
||||
|
||||
if (buffer != NULL) free(buffer);
|
||||
|
||||
filesystemExit();
|
||||
amExit();
|
||||
gfxExit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
77
source/text.c
Normal file
77
source/text.c
Normal file
@@ -0,0 +1,77 @@
|
||||
// some text routines from 3dsfindskitten
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "text.h"
|
||||
|
||||
void gotoxy(int x, int y)
|
||||
{
|
||||
// in other words, move to row y, column x
|
||||
// (both zero-indexed!)
|
||||
printf("\x1b[0m");
|
||||
printf("\x1b[%d;%dH",y,x);
|
||||
}
|
||||
|
||||
void textcolour(enum colour c)
|
||||
{
|
||||
printf("\x1b[0m");
|
||||
if(c>>3) // i.e. if normal intensity
|
||||
{
|
||||
printf("\x1b[3%d;1m",c%8);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\x1b[3%dm",c%8);
|
||||
}
|
||||
}
|
||||
|
||||
int lastSpace(char *tocut)
|
||||
{
|
||||
char *lastSpace;
|
||||
lastSpace = strrchr(tocut,' ');
|
||||
if(lastSpace)
|
||||
{
|
||||
return (int)(lastSpace-tocut);
|
||||
} else { return -1; }
|
||||
}
|
||||
|
||||
void wordwrap(char *towrap, int width)
|
||||
{
|
||||
int idx = 0;
|
||||
int i, lastSpc;
|
||||
char* buffer = (char*)malloc(width+1);
|
||||
memset(buffer,0,width+1);
|
||||
do
|
||||
{
|
||||
strncpy(buffer,towrap+idx,width);
|
||||
if(strlen(buffer)<width)
|
||||
{
|
||||
printf(buffer);
|
||||
putchar(' ');
|
||||
break;
|
||||
}
|
||||
if(towrap[idx+width]==' ')
|
||||
{
|
||||
printf(buffer);
|
||||
idx = idx + width;
|
||||
} else {
|
||||
lastSpc = lastSpace(buffer);
|
||||
if (lastSpc>0)
|
||||
{
|
||||
for(i=0;i<lastSpc;i++)
|
||||
{
|
||||
putchar(buffer[i]);
|
||||
idx++;
|
||||
}
|
||||
putchar('\n');
|
||||
} else {
|
||||
for(i=0;i<width-1;i++)
|
||||
{
|
||||
putchar(buffer[i]);
|
||||
}
|
||||
printf("- ");
|
||||
idx = idx + width - 1;
|
||||
}
|
||||
}
|
||||
}while (strlen(buffer)==width);
|
||||
}
|
||||
15
source/text.h
Normal file
15
source/text.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#define TOP_WIDTH 50 // text columns
|
||||
#define BOTTOM_WIDTH 40 // text columns
|
||||
#define WIDTH BOTTOM_WIDTH
|
||||
#define HEIGHT 30 // text rows
|
||||
|
||||
enum colour
|
||||
{
|
||||
BLACK, RED, GREEN, BROWN, INDIGO, PURPLE, TEAL, GREY,
|
||||
DARKGREY, SALMON, NEONGREEN,YELLOW, BLUE, MAGENTA, CYAN, WHITE
|
||||
}; // notice that 0-7 are normal intensity, 8-15 are bold intensity
|
||||
|
||||
void gotoxy(int x, int y);
|
||||
void textcolour(enum colour c);
|
||||
int lastSpace(char *tocut);
|
||||
void wordwrap(char *towrap, int width);
|
||||
Reference in New Issue
Block a user