Compare commits

...

39 Commits
1.1.8 ... main

Author SHA1 Message Date
Lorenzooone
11bf35dfce Add libnds2 basic support 2024-11-12 04:59:58 +01:00
Lorenzooone
652e30f888 Remove alignment assumption 2024-09-08 06:47:11 +02:00
Lorenzooone
4aca1adaef Add option to mantain data for Event Pokémon (Mew/Celebi) 2024-08-29 15:05:09 +02:00
Lorenzooone
cff5d3a96c Fix issue with bad Center detection for RS 2024-05-30 01:15:54 +02:00
Lorenzooone
37bf016e8e Use single method for nature calculations 2024-05-01 17:33:40 +02:00
Lorenzooone
10cdba19fe Add forgotten nature normalization 2024-05-01 17:13:38 +02:00
Lorenzooone
4b96c30fee Add decompression ifdef to prevent OOB reads (disabled by default) 2024-03-17 15:41:13 +01:00
Lorenzooone
133f5a37ff Handle un-aligned decompression start or end 2024-03-17 15:05:52 +01:00
Lorenzooone
75fb2859c1 Introduce overrun protection for decompression 2024-03-17 14:21:28 +01:00
Lorenzooone
401767e16a Implement alignment fix option 2024-03-13 19:40:11 +01:00
Lorenzooone
b7c3bb550f Change ifdef and use itcm on NDS 2024-03-13 18:47:03 +01:00
Lorenzooone
6730a50457 Significantly improve speed of LZ77 decompression for NDS build 2024-03-13 17:36:09 +01:00
Lorenzooone
23510710dd Update dockerfile agbabi 2023-12-29 04:07:59 +01:00
Lorenzooone
2a5efee9ec Implement clock advancing when the battery is fine 2023-12-29 03:35:41 +01:00
Lorenzooone
1970dad8a8 Prevent bad RS OT ID 2023-12-28 05:01:08 +01:00
Lorenzooone
53cb31d84a Add Channel conversion (unused) 2023-12-28 04:53:05 +01:00
Lorenzooone
b5ae450131 Implement OT name preservation for Gen 1 and 2 using Markings 2023-12-27 04:28:06 +01:00
Lorenzooone
c97e951ac2 Prevent Colo/XD protag from being female 2023-12-25 23:28:45 +01:00
Lorenzooone
9e8887ca72 Improve delays for saving 2023-11-30 20:52:03 +01:00
Lorenzooone
c3ee0e7ed9 Improve worst case saving speeds 2023-11-30 12:22:23 +01:00
Lorenzooone
2a3bd9b97f Implement Multiboot through GBA cable as well 2023-11-09 07:06:07 +01:00
Lorenzooone
571490d1aa Add out folder to gitignore 2023-10-12 17:52:32 +02:00
Lorenzooone
a43cb36f69 Create separate builders for GBA and NDS 2023-10-12 17:45:58 +02:00
Lorenzooone
597a4da1f8 Merge branch 'Gronis-main' 2023-10-12 02:02:13 +02:00
Robin Grönberg
7b4d8ee2a3 Lock versions of deps in Dockerfile. 2023-09-22 22:18:01 +02:00
Robin Grönberg
746378de6b Update README build instructions. 2023-09-22 22:02:27 +02:00
Robin Grönberg
6b0752bf9d Add NDS support to Dockerfile. 2023-09-18 02:27:39 +02:00
Robin Grönberg
e314b40efa Add Dockerfile for multiplatform build. 2023-09-16 20:42:42 +02:00
Lorenzooone
012b6e89c6 Fix build process 2023-09-15 21:31:07 +02:00
Lorenzooone
97bb4f0d26 Better separate GBA and NDS 2023-09-14 23:38:13 +02:00
Lorenzooone
f3499c1803 Optimize printing for size 2023-09-14 23:30:20 +02:00
Lorenzooone
40fe49bf82 Reduce size with LTO, needs testing 2023-09-14 22:45:55 +02:00
Lorenzooone
b24341a877 Do not use GBAROM on DSi 2023-09-14 21:31:43 +02:00
Lorenzooone
e9a15640db Add base for 80 FPS code for NDS 2023-09-12 15:04:15 +02:00
Lorenzooone
892d586af0 Use helper for SIO read/write 2023-08-14 16:07:22 +02:00
Lorenzooone
1fdee3d5cd Fix text tables 2023-08-14 15:11:28 +02:00
Lorenzooone
d230e487c1 Fix bad Max PPs for Gen1/2 2023-07-16 02:30:11 +02:00
Lorenzooone
5f6927b0ad Remove extra byte from mail data preamble 2023-07-10 16:15:40 +02:00
Lorenzooone
cd982c0fa7 Add special case for Pokerus from Ruby/Sapphire 2023-07-08 01:17:57 +02:00
82 changed files with 1621 additions and 335 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
build/
out/
*.elf
*.nds
*.NDS

View File

@ -31,11 +31,11 @@ ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -Wstrict-overflow=5 -Wextra\
-Wpointer-arith -Wpedantic -Wcast-qual -Wswitch-default\
-Wstrict-prototypes -Wmissing-prototypes\
-Wmissing-prototypes\
-Wshadow -Wwrite-strings -save-temps -Os -s\
-mcpu=arm7tdmi -mtune=arm7tdmi\
-fomit-frame-pointer\
-ffast-math \
-mcpu=arm7tdmi -mtune=arm7tdmi -masm-syntax-unified\
-fomit-frame-pointer -flto=auto \
-ffast-math -D__GBA__\
-fno-tree-loop-distribute-patterns \
$(ARCH)

View File

@ -28,9 +28,9 @@ SDIMAGE := image.bin
SOURCEDIRS := source
INCLUDEDIRS := include
GFXDIRS := graphics
GFXDIRS :=
BINDIRS := data
AUDIODIRS := audio
AUDIODIRS :=
NITROFATDIR :=
# Defines passed to all files
@ -101,7 +101,7 @@ SOURCES_CPP := $(shell find -L $(SOURCEDIRS) -name "*.cpp")
# Compiler and linker flags
# -------------------------
DEFINES += -D__NDS__ -DARM9
DEFINES += -D__NDS__ -DARM9 -D__BLOCKSDS__
ARCH := -march=armv5te -mtune=arm946e-s
@ -127,7 +127,7 @@ CFLAGS += -std=gnu11 $(WARNFLAGS) $(DEFINES) $(ARCH) \
-Wall -Wstrict-overflow=5 -Wextra\
-Wpointer-arith -Wpedantic -Wcast-qual -Wswitch-default\
-Wstrict-prototypes -Wmissing-prototypes\
-Wshadow -Wwrite-strings \
-Wshadow -Wwrite-strings -masm-syntax-unified\
-ffunction-sections -fdata-sections \
-fomit-frame-pointer

132
Makefile.arm9libnds2 Normal file
View File

@ -0,0 +1,132 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_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
# INCLUDES is a list of directories containing extra header files
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build_ds
SOURCES := gfx source data
INCLUDES := include $(BUILD)
NAME_MAKEFILE := Makefile.arm9
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv5te -mtune=arm946e-s -mthumb
CFLAGS := -g -Wall\
-Wstrict-overflow=5 -Wextra\
-Wpointer-arith -Wpedantic -Wcast-qual -Wswitch-default\
-Wmissing-prototypes\
-Wshadow -Wwrite-strings -save-temps -Os -s\
-masm-syntax-unified\
-fomit-frame-pointer -flto=auto \
-ffast-math \
-fno-tree-loop-distribute-patterns \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lnds9 -lagbabi
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS) $(LIBAGBABI)
#---------------------------------------------------------------------------------
# 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 VPATH := $(foreach dir,$(SOURCES),$(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,$(SOURCES),$(notdir $(wildcard $(dir)/*.bin)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(BINFILES:.bin=.bin.o) \
$(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)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/$(NAME_MAKEFILE)
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(TARGET).ds.gba
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).nds : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -34,6 +34,7 @@ The "Act as" option allows one to choose whether the console will act as the mai
- Trading across Generations is a lossy operation. As such, some information (like ribbons) will be lost!!!
- You will not be able to trade Pokémon which did not exist in the target games.
- These include: Unown ? and !, all Shiny Unown but I and V, certain Female Shiny Pokémon, Pokémon holding Mail.
- When trading, markings may be applied to Pokémon from Gen 1 or Gen 2 games to preserve some data regarding the OT. Editing the markings may cause data loss.
### Clock Settings
In the Settings inside of the Main Menu, the Clock Settings will be available if you're playing Pokémon Ruby/Sapphire/Emerald.
@ -66,6 +67,7 @@ Inside the Cheats menu, you will find Special options which can be useful for va
- "Cross-Gen Evo." can be used to allow evolution of Pokémon which would not evolve in the target generation (A Scyther holding Metal Coat from Gen 1 will evolve with this option enabled).
- "Tradeless Evo." can be used to execute trade evolutions without a link cable.
- "Undistr. Events" can be used to make it so Celebi and Mew from Gen 1 and Gen 2 games will not be Japanese (but they will be illegal).
- "Event Pokémon" can be used to make it so Celebi and Mew from Gen 1 and Gen 2 games will not replace OT data (but they will be illegal).
- "Fast Hatch Eggs" when enabled reduces the steps incoming eggs will need in order to hatch.
- "Give Pokérus to Party", can be used to fix the fact that it's impossible to get Pokérus in Pokémon Fire Red/Leaf Green.
@ -83,3 +85,8 @@ Everything else, and the programming code, is governed by the MIT license.
## Example
[This is a Video showing how to use the homebrew](https://youtu.be/3-EKe_lQREY).
## Building
Docker allows easily building without having to install the dependencies.
- To build for the GBA, while in the root of the project, run: `docker run --rm -it -v ${PWD}:/home/builder/pokemon_gen3_to_genx lorenzooone/pokemon_gen3_to_genx:gba_builder`
- To build for the NDS, while in the root of the project, run: `docker run --rm -it -v ${PWD}:/home/builder/pokemon_gen3_to_genx lorenzooone/pokemon_gen3_to_genx:nds_builder`

Binary file not shown.

View File

@ -0,0 +1,2 @@
.aEP&
£P@göP»NP@€†„<E280A0>“ŽP‡P†ˆˆP<CB86>‡P‰€ŠP<C5A0>€ €‡P‰€ŠP<C5A0>‡P‰€ˆŒ„P<E2809E>€€™”P†€˜P‰€<E280B0>€”P†€˜P‰ <20>”P†€˜P<CB9C>ˆ<10>”„P†€˜P‰<04>”„P„†ˆP†€˜P‰Ž‡<C5BD>P<EFBFBD>$†€˜P‰”€<E2809D>P<EFBFBD>€†€˜P<CB9C>ˆ<EFBFBD><CB86>ŽP†„<E2809E>P€‡P‰€ †ˆŽP€‡PˆˆP<CB86>”Ž•ŽP†ŽƒP‡ˆŽP“†ŽƒP‰”ˆ<CB86>†”€ƒŽP€‡P€†®«£Pƒ€<C692>ˆ ‰€ŠP<C5A0>€Œ„P<E2809E> ‰€ŠP<C5A0><E28093>‰€ˆŒ„P<E2809E>”„•Ž€‰„€<E2809E>P<EFBFBD>ŽŒœP‰Ž‡<C5BD>P<EFBFBD>€Œ„P ‰Ž‡<C5BD>P<EFBFBD><E28093>‰”€<E2809D>P<EFBFBD>”„•Ž€ŽŽP‡ˆŽP“Ž€ŽŽP<C5BD>€ŽŽPƒ<10>€”P<E280B9>ŽŒœP<C593><08>ˆ<EFBFBD><CB86>ŽP<C5BD>”Ž•Ž<10>€“€PŠ€ŒŽ<C592>„ƒP€‡P‰€„ƒP‡€P<E282AC>„†ˆP‰„€<E2809E>PމŽP€‡P‰€€ŽŽP€‡P†Ž“P€‡P‰€ ‡€P<E282AC>€”Pˆ•„Pƒ€<C692>ˆˆ•„PŠ€ŒŽ¨«¡¤±P“‡ŽŒ ˜ŽP€‡P˜ŽP

View File

@ -0,0 +1 @@
 <07><><EFBFBD>P<EFBFBD> <09><>P<> <0B><>P,< <0B><><EFBFBD>P, <0B><>P,<<1B><>P<EFBFBD><50><02><><EFBFBD><EFBFBD>P<EFBFBD><02><><EFBFBD>P <0B><02><08>P <0B><02><><19>P<EFBFBD><02><><EFBFBD> P <02><>P<><50>

Binary file not shown.

View File

@ -0,0 +1,51 @@
gPPPPPPPPœÃ
x¾PPœÃ
x
>PPœÃ
xùPP ôœ>PPPP>ªEPPPP>ª™PPPPï.²PPPPîÏ.²PP%/5PPPP  <09>
gPPPPܲPPPPö <09>
cPPPP¤æœPPPPlæœPPPP 8PPPPˆˆPPPPPP
gPPPPPP
g ÅPPPPïïPPPPPPé ÞÃPPPPÊaœPPPPÊaEAæÆPPPPPPÆ yPPPP
g òPPPPÜòPPPP<04>Ñ.&PPM&PPPPPPÏEáõPPPÏE>:PPÏE mPPPPÏEáïPPPÏE>PPÏE ‡PPPP¯¯PPPPPP
hcPPPPPPdJ §ŸPP:ž §ŸPP
:@PPPPPP
: y@PPPPîPPPPPPaîPPPPPP¡÷ÝPPPPOÅïPPPPÃ
cécÆ ôÃJPPPP ôÃí ÞPP < þPPPPPP:>PPPP`§ÙPPPPÚ Þ> PP:+PPPPPP
3c"PPMà ôöPPaöPPPPPPa €PPPPPPêh.PPPP`PPPPPPy`PPPPPP߬œPPPP&*¬œPP ¬œPPPP œcPPPP<07>6ÃPPPP
ÄbPPPPPPË »“PPPP©“PPPP{ò“PPPP<04>Ù
gPPPPL÷PPPPL÷ ÞPP5«
xPPPP ô>PPPPïFPPPPˆ>PPPPlˆ>PPPP
'Ï ˆPPPP?FPPPPßPPPPPPßÅPPPP :ŸPPPPPPéî :ŸPP ô >PPPP..PPPPPP. Þ> PPPPPPPPéOPPPP*
œPPPP*²PPPPïßPPPPPP ô3ïPPPPM JPPPPMLJ ÞPP
 ¢PPPPPPJ ¶PPPPM>
aPPPPM>
PPPP yÖPPPPPP ‡ yÖPPPPŽ>>hPP5PPPPPPÆÃ>PPPP:cPPPPPP ˆ>PPPP ¦ˆ>PPPPcÓPP
«&“PPPPKÌPPPPJPPPPJPP¤ PPPP :¡>PPPPà €PPPPPPˆ>PPPP  PPPPPPŽEÃPPPPcEÃPPPP < PPPPPP5 < PPPP·>PPÆ MJ ˆPPF£gPPPPJà yPPPPÃPPPPéJPPPPF§FPPPPª·œÊPP + ˆþJPP§î ‡PPPPÃJPPÃ
aÃJPP~ ˆ™PPPPœJœPPPPÎÌEPPPP
gƒõPP.J <09>PPPP
*>OPPPPÏ:œ ÞPPÏJ ˆPPPP ňPPPPPP ň
:JPP
a §ÃPPPP±HPPPP
a>ÞPPPPƒõPPPPPP ôœîPPPP̨PPPPPPe¨PPPPPPa:¨PPPPÂ÷PPPPPPÂPPPPPPPP  :> ˆPPœ>
aPP~ÏbPPJ )žPPPPF§ )žPPMéœüPP>Æ :PPPP>4œPPµ yþÙŸï>áPPPPÙï>PPPP.L.PPPPß.ûPPPPé`ÙPPPPé`ÈPPPP
œ+PPPPÆ>ÆJ yþîPPPPÊòPPPPÓ ŸPPPPPP
gòPPPPPP¯PPPPPPPP
:
:@PPPP ´4
gPPPP ´4 íPPPPwœ ìPPPPwœ ì PP~>
aPPPP  PPPPÌPPPPPPÆ3 :PPPPFAPPPPPPFA>PPPPï&<04>PPPP5ˆ>PPPP » » :PPPP. :PPPPPP :PPPPœ úPPPP
xj÷PPPP
xÌPPPP5ª>PPPPL ôPPPPPP© PPPPPPJœPPPPMÑ €PPPPÏþLPPPPß ‡PPPP«LFPPPPÈ“PPPPPPFªKPPPP €E €PPPP
g <PPPPPPŽ <PPPPPPM PPPP«Ãœ%PP ¶ ¶PPPPMPPPPPP§ËMPP ÙPPPP
v¿PPPPPPÜÜ&PPPP
Œà yþJ
'
:ÏPPPPÄ&ePPPPEePPPPPPF§F§PPF§ 3M  >PPPP~ >PPPP :º
£PPPPÑîPPPPPPë
'«PPd>öEPPH ˆžPPPP«µæPPPPdPPPPPP
<EFBFBD>PPPPPP ‡EÃPPPP : :>PPPP :> PPPP
*>OøPPPÃ €PPPPJPPPPè €PPPP
'ÃPPÃPPPPé €EPPF§aPPPPÐ š yPPPP
x
gjJPPÜ :PPPPØ §œPPPPJœ OPPPPÖöÃJPP²ÃJPPF²ÃJPP²ÆPPPP ÆæPPPPìéaPPPP gPPPPPPPPËPPPPPPPP gPPPPPPPP gPPPPPPPP

View File

@ -0,0 +1 @@
°売P<EFBFBD>遭P猿㍾P剛<EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
槍ケ€仲P園P剛<EFBFBD>

View File

@ -0,0 +1 @@
宙虚яP橿月

View File

@ -0,0 +1 @@
<EFBFBD>給事P€仲P園P剛<EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD>泣P鉛笈ы

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
宙虚яPム壕

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD>ォ」Pム壕щ

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
暢ォ。、アP島詞

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD>

View File

@ -0,0 +1 @@
綜鋳傘€仲P<EFBFBD><EFBFBD>P鵠歯傘

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD>€給傘€仲P<EFBFBD><EFBFBD>P鵠歯傘

View File

@ -0,0 +1 @@
<1B>P<EFBFBD><50><EFBFBD> P ⑪P,<

View File

@ -0,0 +1 @@
P<>

View File

@ -0,0 +1 @@
<07><><EFBFBD>P<EFBFBD><08>P <0B><>P,<

View File

@ -0,0 +1 @@
ァャP鞄輝 ュャ⑰,

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><19>P<EFBFBD>

View File

@ -0,0 +1 @@
<ィ絮鞄輝 ュャ⑰,

View File

@ -0,0 +1,2 @@
aEP&
£P

View File

@ -0,0 +1 @@
g<04>NP

View File

@ -0,0 +1 @@
€剩輝<EFBFBD>遭P鉛€恒鵠<EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
資傘㊧綜P梼

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1,38 @@
################################################################################
### Build agbabi ###
################################################################################
FROM debian:stable-slim as agbabi
RUN apt-get update && apt-get install -y build-essential cmake gcc-arm-none-eabi git
RUN git clone https://github.com/felixjones/agbabi && \
cd agbabi && \
git checkout 2adf1e6c01f9d4acd6f8e728892c5e18aae5332e && \
cmake -S . -DCMAKE_TOOLCHAIN_FILE=cross/agb.cmake -DCMAKE_BUILD_TYPE=MinSizeRel -B build && \
cmake --build build && \
cmake --install build
###############################################################################
### NDS Builder ###
###############################################################################
FROM skylyrac/blocksds:slim-latest as ds-build
RUN mkdir -p /home/builder/pokemon_gen3_to_genx
RUN mkdir -p /home/builder/building
RUN chown -R ubuntu:ubuntu /home/builder
COPY --from=agbabi /usr/local/ /opt/agbabi/
ENV LIBAGBABI=/opt/agbabi
WORKDIR /home/builder/building
USER ubuntu
CMD /home/builder/pokemon_gen3_to_genx/docker-scripts/docker_build_nds
###############################################################################
### GBA Builder ###
###############################################################################
FROM devkitpro/devkitarm as gba-build
RUN useradd builder -m
RUN mkdir -p /home/builder/pokemon_gen3_to_genx
RUN mkdir -p /home/builder/building
RUN chown -R builder:builder /home/builder
COPY --from=agbabi /usr/local/ /opt/agbabi/
ENV LIBAGBABI=/opt/agbabi
WORKDIR /home/builder/building
USER builder
CMD /home/builder/pokemon_gen3_to_genx/docker-scripts/docker_build_gba

View File

@ -0,0 +1,3 @@
#!/bin/bash
docker image rm lorenzooone/pokemon_gen3_to_genx:gba_builder
docker build --target gba-build . -t lorenzooone/pokemon_gen3_to_genx:gba_builder

View File

@ -0,0 +1,3 @@
#!/bin/bash
docker image rm lorenzooone/pokemon_gen3_to_genx:nds_builder
docker build --target ds-build . -t lorenzooone/pokemon_gen3_to_genx:nds_builder

11
docker-scripts/docker_build_gba Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
cp -R /home/builder/pokemon_gen3_to_genx/. .
make clean
make 2>&1 >/dev/null | grep ^$(pwd);
mkdir -p /home/builder/pokemon_gen3_to_genx/out
cp building_mb.gba /home/builder/pokemon_gen3_to_genx/out/pokemon_gen3_to_genx_mb.gba

11
docker-scripts/docker_build_nds Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
cp -R /home/builder/pokemon_gen3_to_genx/. .
make -f Makefile.arm9 clean
make -f Makefile.arm9 2>&1 >/dev/null | grep ^$(pwd);
mkdir -p /home/builder/pokemon_gen3_to_genx/out
cp Pokemon_Gen3_to_GenX.nds /home/builder/pokemon_gen3_to_genx/out/pokemon_gen3_to_genx.nds

View File

@ -1,25 +1,27 @@
#ifndef BASE_INCLUDE__
#define BASE_INCLUDE__
#ifndef __NDS__
#ifdef __GBA__
// GBA defines and all
#include <gba.h>
#include "useful_qualifiers.h"
#define SCANLINES 0xE4
#define ROM 0x8000000
ALWAYS_INLINE MAX_OPTIMIZE void __set_next_vcount_interrupt_gba(int scanline) {
REG_DISPSTAT = (REG_DISPSTAT &0xFF) | (scanline<<8);
REG_DISPSTAT = (REG_DISPSTAT & 0xFF) | (scanline<<8);
}
ALWAYS_INLINE MAX_OPTIMIZE int __get_next_vcount_interrupt(void) {
return REG_DISPSTAT >> 8;
u16 reg_val = REG_DISPSTAT;
return reg_val >> 8;
}
#define __set_next_vcount_interrupt(x) __set_next_vcount_interrupt_gba(x)
#define SCANLINE_IRQ_BIT LCDC_VCNT
#define REG_WAITCNT *(vu16*)(REG_BASE + 0x204) // Wait state Control
#define SRAM_READING_VALID_WAITCYCLES 3
#define SRAM_ACCESS_CYCLES 9
#define NON_SRAM_MASK 0xFFFC
#define BASE_WAITCNT_VAL 0x4314
#define TIMEOUT_INCREASE 0
#define OVRAM_START ((uintptr_t)OBJ_BASE_ADR)
#define TILE_1D_MAP 0
#define ACTIVATE_SCREEN_HW 0
@ -28,31 +30,33 @@ ALWAYS_INLINE MAX_OPTIMIZE int __get_next_vcount_interrupt(void) {
#define VRAM_0 VRAM
#define HAS_SIO
#define CLOCK_SPEED 16777216
#define SCANLINES 0xE4
#define SAME_ON_BOTH_SCREENS 0
#ifndef __GBA__
#define __GBA__
#endif
#define CONSOLE_LETTER 'G'
#else
#endif
#ifdef __NDS__
// NDS defines and all
#include <nds.h>
#include "useful_qualifiers.h"
#include "decompress.h"
#define SCANLINES 0x107
#define ROM GBAROM
ALWAYS_INLINE MAX_OPTIMIZE int __get_next_vcount_interrupt(void) {
return (REG_DISPSTAT >> 8) | ((REG_DISPSTAT & 0x80) << 1);
u16 reg_val = REG_DISPSTAT;
return (reg_val >> 8) | ((reg_val & 0x80) << 1);
}
ALWAYS_INLINE MAX_OPTIMIZE void __reset_vcount(void) {
REG_VCOUNT = (REG_VCOUNT & 0xFE00) | (SCANLINES - 2);
}
#define __set_next_vcount_interrupt(x) SetYtrigger(x)
#define SCANLINE_IRQ_BIT DISP_YTRIGGER_IRQ
#define REG_WAITCNT REG_EXMEMCNT // Wait state Control
#define SRAM_READING_VALID_WAITCYCLES 3
#define SRAM_ACCESS_CYCLES (2 * 18)
#define NON_SRAM_MASK 0xFFFC
#define EXMEMCNT_MASK_SLOT2_CLOCKRATE (3<<5)
#define EXMEMCNT_SLOT2_CLOCKRATE_1 (1<<5)
#define BASE_WAITCNT_VAL EXMEMCNT_SLOT2_CLOCKRATE_1
#define TIMEOUT_INCREASE 2
#define BASE_WAITCNT_VAL 0x0014
#define OVRAM_START ((uintptr_t)SPRITE_GFX)
#define OVRAM_START_SUB ((uintptr_t)SPRITE_GFX_SUB)
#define OBJ_ON DISPLAY_SPR_ACTIVE
@ -66,7 +70,6 @@ ALWAYS_INLINE MAX_OPTIMIZE int __get_next_vcount_interrupt(void) {
#define ARM7_CLOCK_SPEED 33554432
#define ARM7_GBA_CLOCK_SPEED 16777216
#define CLOCK_SPEED ARM9_CLOCK_SPEED
#define SCANLINES 0x107
#define SAME_ON_BOTH_SCREENS 1
#define CONSOLE_LETTER 'D'
@ -82,10 +85,29 @@ typedef struct {
#define Div(x, y) swiDivide(x, y)
#define DivMod(x, y) swiRemainder(x, y)
#define Sqrt(x) swiSqrt(x)
#define LZ77UnCompWram(x, y) swiDecompressLZSSWram(x, y)
#define LZ77UnCompWram(x, y) swi_LZ77UnCompWrite8bit(x, y)
#ifdef __BLOCKSDS__
#define CpuFastSet(x, y, z) swiFastCopy(x, y, z)
#define VBlankIntrWait() swiWaitForVBlank()
#define Halt() CP15_WaitForInterrupt()
#else
static void CpuFastSet(volatile const void*, volatile void*, volatile int);
static void Halt(void);
ALWAYS_INLINE MAX_OPTIMIZE void CpuFastSet(volatile const void* source, volatile void* dest, volatile int flags)
{
register uint32_t src asm("r0") = (uint32_t)source;
register uint32_t dst asm("r1") = (uint32_t)dest;
register uint32_t flg asm("r2") = (uint32_t)flags;
register uint32_t after_destroyed asm("r3");
asm volatile(
"swi 0xC;" : "=r"(src), "=r"(dst), "=r"(flg) :
"r"(src), "r"(dst), "r"(flg), "r"(after_destroyed) :
);
}
ALWAYS_INLINE void Halt() {__asm__("swi 0x6");}
#endif
#define VBlankIntrWait() swiWaitForVBlank()
#define DIV_SWI_VAL "0x09"
#endif

View File

@ -32,6 +32,7 @@ void set_default_settings(void);
void set_sys_language(u8);
void set_target_int_language(u8);
void set_conversion_colo_xd(u8);
void set_prioritize_ot_gender(u8);
void set_default_conversion_game(u8);
void set_gen1_everstone(u8);
void set_allow_cross_gen_evos(u8);
@ -39,6 +40,7 @@ void set_single_colour(u8, u8, u8);
void set_evolve_without_trade(u8);
void set_allow_undistributed_events(u8);
void set_fast_hatch_eggs(u8);
void set_event_info_replacement(u8);
void increase_egg_met_location(void);
void decrease_egg_met_location(void);
u8 set_applied_ball(u16);
@ -46,6 +48,7 @@ u8 get_sys_language(void);
u8 get_target_int_language(void);
u8 get_filtered_target_int_language(void);
u8 get_conversion_colo_xd(void);
u8 get_prioritize_ot_gender(void);
u8 get_default_conversion_game(void);
u16 get_full_colour(u8);
u8 get_single_colour(u8, u8);
@ -56,6 +59,7 @@ u8 get_allow_undistributed_events(void);
u8 get_fast_hatch_eggs(void);
u8 get_egg_met_location(void);
u16 get_applied_ball(void);
u8 get_event_info_replacement(void);
const struct version_t* get_version(void);
#endif

1
include/decompress.h Normal file
View File

@ -0,0 +1 @@
#ifndef _DCMPRSS_HEADER_ #define _DCMPRSS_HEADER_ extern int swi_LZ77UnCompWrite16bit(const void *source, void *destination); extern int swi_LZ77UnCompWrite8bit(const void *source, void *destination); #endif

10
include/delays.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef DELAYS__
#define DELAYS__
#define CLOCK_CYCLES_PER_MS(x) ((((x) * ((uint64_t)CLOCK_SPEED)) + 999) / 1000)
#define CLOCK_CYCLES_PER_MUS(x) ((((x) * ((uint64_t)CLOCK_SPEED)) + 999999) / 1000000)
void delay_cycles(u32);
void delay_cycles_until(u32, vu8*, u8, u8);
#endif

View File

@ -24,5 +24,6 @@ u8 get_pokemon_gender_kind_gen2(u8, u8, u8);
const u8* get_pokemon_name_gen2_gen3_enc(int, u8, u8);
const u8* get_pokemon_name_gen2(int, u8, u8, u8*);
const u8* get_default_trainer_name_gen2(u8, u8*);
const u8* get_actual_ot_name(const u8*, u8, u8, u8);
#endif

View File

@ -11,6 +11,8 @@ void enable_rtc_reset(struct clock_events_t*);
void disable_rtc_reset(struct clock_events_t*);
u8 is_rtc_reset_enabled(struct clock_events_t*);
u8 is_daily_update_safe(struct game_data_t*, struct clock_events_t*, struct saved_time_t*);
u8 has_init_succeded(void);
u8 update_base_time(void);
void init_rtc_time(void);
void run_daily_update(struct game_data_t*, struct clock_events_t*, struct saved_time_t*, u8);
u8 is_daytime(struct clock_events_t*, struct saved_time_t*);

View File

@ -12,7 +12,7 @@ void alter_nature(struct gen3_mon_data_unenc*, u8);
void set_alter_data(struct gen3_mon_data_unenc*, struct alternative_data_gen3*);
void preload_if_fixable(struct gen3_mon_data_unenc*);
void convert_trainer_name_gen3_to_gen12(u8*, u8*, u8, u8);
void convert_trainer_name_gen3_to_gen12(u8*, u8*, u8, u8, u8);
void convert_trainer_name_gen12_to_gen3(u8*, u8*, u8, u8, u8);
u8 gen3_to_gen2(struct gen2_mon*, struct gen3_mon_data_unenc*, u32);

View File

@ -7,6 +7,7 @@
#define CANCEL_INFO 0xFF
#define CANCEL_TRADING 0xFF
#define CANCEL_IV_FIX 0xFF
#define CANCEL_MULTIBOOT 0xFF
#define EXIT_EVOLUTION 0xFF
#define DENIED_LEARNING 0xFF
#define EXIT_BASE_SETTINGS 0xFF
@ -16,18 +17,19 @@
#define EXIT_CLOCK_WARNING_SETTINGS 0xFF
#define EXIT_COLOURS_SETTINGS 0xFF
#define DO_NOT_FORGET_MOVE 0xFF
#define CANCEL_TRADE_START 0xFF
#define CANCEL_TRADE_OPTIONS 0xFF
#define CANCEL_NATURE 0xFF
#define ENTER_COLOUR_MENU 1
#define ENTER_CLOCK_MENU 2
#define ENTER_CHEATS_MENU 3
#define ENTER_GEN12_MENU 4
#define ENTER_LEARN_MENU 1
#define CONFIRM_IV_FIX 1
#define CANCEL_NATURE 0xFF
#define CONFIRM_MULTIBOOT 0x35
#define CONFIRM_NATURE 3
#define INC_NATURE 1
#define DEC_NATURE 2
#define CANCEL_TRADE_START 0xFF
#define CANCEL_TRADE_OPTIONS 0xFF
#define OFFER_INFO_DISPLAY 0x12
#define START_MULTIBOOT 0x49
#define START_PRINT_READ_INFO 0x57
@ -38,6 +40,7 @@
#define PAGES_TOTAL 5
#define FIRST_PAGE 1
u8 handle_input_multiboot_settings(u16, u8*, u8*);
u8 handle_input_multiboot_menu(u16);
u8 handle_input_learnable_message_moves_menu(u16, u8*);
u8 handle_input_learnable_moves_menu(u16, u8*);

View File

@ -21,6 +21,7 @@ void print_set_nature(u8, struct gen3_mon_data_unenc*);
void print_iv_fix(struct gen3_mon_data_unenc*);
void print_pokemon_pages(u8, u8, struct gen3_mon_data_unenc*, u8);
void print_main_menu(u8, u8, u8, u8, struct game_data_t*, struct game_data_priv_t*);
void print_multiboot_settings(u8, u8);
void print_multiboot_mid_process(u8);
void print_multiboot(enum MULTIBOOT_RESULTS);
void print_start_trade(void);
@ -40,6 +41,7 @@ void print_colour_settings_menu(u8);
void print_evolution_menu(struct gen3_mon_data_unenc*, u16, u8, u8);
void print_evolution_window(struct gen3_mon_data_unenc*);
void print_cheats_menu(u8);
void print_clock_variable_menu(struct clock_events_t*, struct saved_time_t*, u8);
void print_clock_menu(struct clock_events_t*, struct saved_time_t*, u8);
void print_warning_when_clock_changed(void);
void print_load_warnings(struct game_data_t*, struct game_data_priv_t*);

View File

@ -3,8 +3,8 @@
#define MULTIBOOT_MAX_SIZE 0x3FF40
enum MULTIBOOT_RESULTS {MB_SUCCESS, MB_NO_INIT_SYNC, MB_WRONG_ANSWER, MB_HEADER_ISSUE, MB_SWI_FAILURE};
enum MULTIBOOT_RESULTS {MB_SUCCESS, MB_NO_INIT_SYNC, MB_WRONG_ANSWER, MB_HEADER_ISSUE, MB_PALETTE_FAILURE, MB_SWI_FAILURE};
enum MULTIBOOT_RESULTS multiboot_normal(u16*, u16*);
enum MULTIBOOT_RESULTS multiboot_normal(u16*, u16*, int);
#endif

View File

@ -156,6 +156,7 @@
#define GEN2_EGG 253
#define GEN2_NO_MON 255
#define GEN12_MAX_MOVE_PP 40
#define CELEBI_AGATE_OT_ID 31121
@ -173,6 +174,10 @@
#define ROAMER_ENCOUNTER 2
#define UNOWN_ENCOUNTER 3
#define SPECIAL_NAME_MARKS_VALUE 0xF
//#define ALLOW_KOREAN
#define NUM_LANGUAGES 8
#define NUM_POKEMON_NAME_LANGUAGES 4
#define FIRST_VALID_LANGUAGE 1
@ -185,6 +190,11 @@
#define GERMAN_LANGUAGE 5
#define KOREAN_LANGUAGE 6
#define SPANISH_LANGUAGE 7
#ifdef ALLOW_KOREAN
#define ALL_LANGUAGES ((1 << JAPANESE_LANGUAGE) | (1 << ENGLISH_LANGUAGE) | (1 << FRENCH_LANGUAGE) | (1 << ITALIAN_LANGUAGE) | (1 << GERMAN_LANGUAGE) | (1 << KOREAN_LANGUAGE) | (1 << SPANISH_LANGUAGE))
#else
#define ALL_LANGUAGES ((1 << JAPANESE_LANGUAGE) | (1 << ENGLISH_LANGUAGE) | (1 << FRENCH_LANGUAGE) | (1 << ITALIAN_LANGUAGE) | (1 << GERMAN_LANGUAGE) | (1 << SPANISH_LANGUAGE))
#endif
#define GET_LANGUAGE_IS_JAPANESE(x) ((x) == JAPANESE_LANGUAGE)
#define GET_LANGUAGE_NICKNAME_LIMIT(x) (GET_LANGUAGE_IS_JAPANESE(x) ? NICKNAME_JP_GEN3_SIZE : NICKNAME_GEN3_SIZE)
@ -321,11 +331,13 @@ struct gen3_mon {
u8 is_bad_egg : 1;
u8 has_species : 1;
u8 use_egg_name : 1;
u8 unused : 5;
u8 block_box_rs : 1;
u8 unused : 4;
u8 ot_name[OT_NAME_GEN3_MAX_SIZE];
u8 marks;
u8 marks : 4;
u8 unused2 : 4;
u16 checksum;
u16 unk;
u16 unused3;
u32 enc_data[ENC_DATA_SIZE>>2];
u32 status;
u8 level;

View File

@ -10,15 +10,19 @@ void generate_unown_shiny_info_letter_preloaded(u8, u8, u16, u32*, u32*);
void generate_unown_info(u8, u16, u16, u32*, u32*);
void generate_unown_info_letter_preloaded(u8, u16, u8, u16, u32*, u32*);
void generate_static_shiny_info(u8, u16, u32*, u32*);
void generate_generic_genderless_shadow_shiny_info_colo(u8, u16, u32*, u32*, u8*);
void generate_static_info(u8, u16, u16, u32*, u32*);
void generate_generic_genderless_shadow_shiny_info_colo(u8, u16, u32*, u32*, u8*);
void generate_generic_genderless_shadow_info_colo(u8, u16, u16, u32*, u32*, u8*);
void generate_generic_genderless_shadow_info_xd(u8, u8, u16, u16, u32*, u32*, u8*);
void generate_egg_shiny_info(u8, u8, u16, u16, u8, u32*, u32*);
void generate_egg_info(u8, u8, u16, u16, u8, u32*, u32*);
void generate_channel_shiny_info(u8, u32*, u32*, u16*, u8*, u8*);
void generate_channel_info(u8, u16, u32*, u32*, u16*, u8*, u8*);
u32 generate_ot(u16, u8*);
u8 are_colo_valid_tid_sid(u16, u16);
u8 are_rs_valid_tid_sid(u16, u16);
void convert_roamer_to_colo_info(u8, u16, u8, u8, u16, u32*, u32*, u8*);
void convert_shiny_roamer_to_colo_info(u8, u8, u8, u16, u32*, u32*, u8*);
#endif

View File

@ -7,12 +7,16 @@
#define SIO_MASTER 1
#define SIO_SLAVE 0
#define MAX_NUM_SLAVES 3
#define SIO_DEFAULT_VALUE 0xFE
void init_sio_normal(int, int);
void init_sio_multi(int);
int sio_normal(int, int, int, u8*);
void sio_normal_prepare_irq_slave(int);
int timed_sio_normal_master(int, int, int);
void timed_sio_multi_master(int, int, u16*);
void sio_handle_irq_slave(int);
void sio_stop_irq_slave(void);
int sio_read(u8);

View File

@ -12,7 +12,7 @@
#define DEFAULT_FILLER 0
#define USELESS_SYNC_BYTES 6
#define USELESS_SYNC_BYTES 5
#define USELESS_SYNC_VALUE 0x20
#define NUM_SIZES 4

View File

@ -3,6 +3,7 @@
#define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
#define ALWAYS_INLINE __attribute__((always_inline)) static inline
#define NO_INLINE __attribute__((noinline))
#define MAX_OPTIMIZE __attribute__((optimize(3)))
#ifndef PACKED
#define PACKED __attribute__((packed))

View File

@ -14,6 +14,7 @@
#define DEFAULT_SYS_LANGUAGE ENGLISH_LANGUAGE
#define DEFAULT_TARGET_INT_LANGUAGE UNKNOWN_LANGUAGE
#define DEFAULT_CONVERSION_COLO_XD 1
#define DEFAULT_PRIORITIZE_OT_GENDER 1
#define DEFAULT_DEFAULT_CONVERSION_GAME FR_VERSION_ID
#define DEFAULT_GEN1_EVERSTONE 0
#define DEFAULT_ALLOW_CROSS_GEN_EVOS 0
@ -21,6 +22,7 @@
#define DEFAULT_ALLOW_UNDISTRIBUTED_EVENTS 0
#define DEFAULT_FAST_HATCH_EGGS 0
#define DEFAULT_BALL POKEBALL_ID
#define DEFAULT_EVENT_INFO_REPLACEMENT 1
void sanitize_egg_met_location(void);
const u8* get_valid_egg_met_locs(void);
@ -28,6 +30,7 @@ const u8* get_valid_egg_met_locs(void);
static u8 sys_language;
static u8 target_int_language;
static u8 conversion_colo_xd;
static u8 prioritize_ot_gender;
static u8 default_conversion_game;
static u8 default_colours[NUM_COLOURS][NUM_SUB_COLOURS];
static u8 gen1_everstone;
@ -38,14 +41,16 @@ static u8 fast_hatch_eggs;
static u16 applied_ball;
static u8 egg_met_location;
static u8 first_set_egg_met_location;
static u8 event_info_replacement;
const struct version_t version = { .main_version = 1, .sub_version = 1, .revision_version = 8, .revision_letter = CONSOLE_LETTER};
const struct version_t version = { .main_version = 1, .sub_version = 1, .revision_version = 14, .revision_letter = CONSOLE_LETTER};
const u8* egg_valid_met_locations[NUMBER_OF_GAMES+FIRST_VERSION_ID] = {valid_egg_locations_rs_bin, valid_egg_locations_rs_bin, valid_egg_locations_rs_bin, valid_egg_locations_e_bin, valid_egg_locations_frlg_bin, valid_egg_locations_frlg_bin};
void set_default_settings() {
set_sys_language(DEFAULT_SYS_LANGUAGE);
set_target_int_language(DEFAULT_TARGET_INT_LANGUAGE);
set_conversion_colo_xd(DEFAULT_CONVERSION_COLO_XD);
set_prioritize_ot_gender(DEFAULT_PRIORITIZE_OT_GENDER);
first_set_egg_met_location = 1;
set_default_conversion_game(DEFAULT_DEFAULT_CONVERSION_GAME);
for(size_t i = 0; i < NUM_COLOURS; i++)
@ -57,6 +62,7 @@ void set_default_settings() {
set_allow_undistributed_events(DEFAULT_ALLOW_UNDISTRIBUTED_EVENTS);
set_fast_hatch_eggs(DEFAULT_FAST_HATCH_EGGS);
set_applied_ball(DEFAULT_BALL);
set_event_info_replacement(DEFAULT_EVENT_INFO_REPLACEMENT);
}
const u8* get_valid_egg_met_locs() {
@ -103,6 +109,10 @@ void set_conversion_colo_xd(u8 new_val) {
conversion_colo_xd = new_val;
}
void set_prioritize_ot_gender(u8 new_val) {
prioritize_ot_gender = new_val;
}
void set_default_conversion_game(u8 new_val) {
if((new_val < FIRST_VERSION_ID) || (new_val == ((u8)(FIRST_VERSION_ID-1))))
new_val = NUMBER_OF_GAMES-1+FIRST_VERSION_ID;
@ -132,6 +142,10 @@ void set_fast_hatch_eggs(u8 new_val) {
fast_hatch_eggs = new_val;
}
void set_event_info_replacement(u8 new_val) {
event_info_replacement = new_val;
}
void increase_egg_met_location() {
const u8* valid_met_locs = get_valid_egg_met_locs();
u8 base_val = egg_met_location;
@ -202,6 +216,10 @@ u8 get_conversion_colo_xd() {
return conversion_colo_xd;
}
u8 get_prioritize_ot_gender() {
return prioritize_ot_gender;
}
u8 get_default_conversion_game() {
return default_conversion_game;
}
@ -248,6 +266,10 @@ u16 get_applied_ball() {
return applied_ball;
}
u8 get_event_info_replacement() {
return event_info_replacement;
}
const struct version_t* get_version() {
return &version;
}

253
source/decompress.s Normal file
View File

@ -0,0 +1,253 @@
@-------------------------------------------------------------
@ Original code by fleroviux, distributed under the MIT License:
@ Link: https://github.com/Cult-of-GBA/BIOS
@ Copyright 2020 - 2021 DenSinH fleroviux
@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@-------------------------------------------------------------
@ Speed optimizations by Lorenzooone - 2024
@ 8bit version not included because the optimized 16bit version is faster.
@ Works fine even with 1 as the window offset (fixes LZ77 VRAM bug).
@-------------------------------------------------------------
.arm
.align
.global swi_LZ77UnCompWrite16bit
.global swi_LZ77UnCompWrite8bit
.type swi_LZ77UnCompWrite16bit,function
.type swi_LZ77UnCompWrite8bit,function
#ifdef __NDS__
.section .itcm, "ax", %progbits
#else
.section .iwram, "ax", %progbits
#endif
@ALIGNMENT_FIX has an impact of around 0.25% on performance, but it prevents
@alignment warnings (which wouldn't affect real hardware).
#define ALIGNMENT_FIX
@OVERRUN_PROTECTION has an impact of around 0.9% on performance, but it
@prevents overrunning the buffer by up to 2 extra bytes if the compressed data
@has issues. Apparently, the regular BIOS functions lack any kind of overrun
@protection. So instead of potentially writing 2 extra bytes, they could
@write way more...
#define OVERRUN_PROTECTION
@PREVENT_OOB_READS has an impact of around 2% on performance. It prevents
@the LZ77 window from going to an address before the initial destination one.
@Such LZ77 data is badly formed, and this shouldn't be enabled at all
@unless you don't trust the data coming in...
@#define PREVENT_OOB_READS
swi_LZ77UnCompWrite16bit:
swi_LZ77UnCompWrite8bit:
stmfd sp!, {r3 - r8}
@ Read header word:
@ bit0-3: reserved
@ bit4-7: compressed type (1 for LZ77)
@ bit8-31: size of compressed data
ldrb r2, [r0, #0]
lsr r2, r2, #4
@ Stop if this isn't LZ77
cmp r2, #1
bne .lz77_16bit_end
@ Don't make any assumption about initial alignment to
@ read the size of the data
ldrb r2, [r0, #1]
ldrb r3, [r0, #2]
lsl r3, r3, #8
orr r2, r2, r3
ldrb r3, [r0, #3]
add r0, r0, #4
lsl r3, r3, #16
orrs r2, r2, r3
@ ignore zero-length decompression requests
beq .lz77_16bit_end
@ Cover un-aligned destination
tst r1, #1
ldrneb r7, [r1, #-1]
#ifdef PREVENT_OOB_READS
@ Store the initial address in r8
movs r8, r1
#endif
.lz77_16bit_loop:
@ read encoder byte, shift to MSB for easier access.
ldrb r3, [r0], #1
orr r3, #0x01000000
.lz77_16bit_encoder_loop:
tst r3, #0x80
bne .lz77_16bit_copy_window
.lz77_16bit_copy_byte:
@ copy byte from current source to current destination
ldrb r4, [r0], #1
tst r1, #1
moveq r7, r4
orrne r7, r4, lsl #8
strneh r7, [r1, #-1]
add r1, #1
@ check if decompressed length has been reached.
subs r2, #1
beq .lz77_16bit_done
@ read next encoder or process next block
lsls r3, #1
bcc .lz77_16bit_encoder_loop
@ read encoder byte, shift to MSB for easier access.
ldrb r3, [r0], #1
orr r3, #0x01000000
tst r3, #0x80
beq .lz77_16bit_copy_byte
.lz77_16bit_copy_window:
@ read window tuple {displacement, size}
ldrb r4, [r0], #1
ldrb r5, [r0], #1
@ r5 = window displacement
orr r5, r5, r4, lsl #8
bic r5, #0xF000
add r5, #1
@ r4 = window size
lsr r4, #4
add r4, #3
cmp r4, r2
movgt r4, r2
subs r2, r4
subs r5, r1, r5
#ifdef PREVENT_OOB_READS
subs r6, r5, r8
cmp r6, #0
blt .lz77_16bit_done
#endif
@ About 50% of the time, the two addresses will be aligned. Abuse this...
eor r6, r1, r5
tst r6, #1
bne .lz77_16bit_copy_window_not_aligned_check
tst r1, #1
beq .lz77_optimized_16bit_copy_window_pre_loop
ldrb r6, [r5], #1
orr r7, r6, lsl #8
#ifdef ALIGNMENT_FIX
subs r1, #1
strh r7, [r1], #2
#else
strh r7, [r1], #1
#endif
subs r4, #1
.lz77_optimized_16bit_copy_window_pre_loop:
#ifdef OVERRUN_PROTECTION
cmp r4, #1
ble .lz77_optimized_16bit_copy_window_after_loop
#endif
.lz77_optimized_16bit_copy_window_loop:
ldrh r6, [r5], #2
strh r6, [r1], #2
subs r4, #2
cmp r4, #1
bgt .lz77_optimized_16bit_copy_window_loop
.lz77_optimized_16bit_copy_window_after_loop:
@ copy byte from window to current destination
ldreqb r7, [r5]
addeq r1, #1
@ check if decompressed length has been reached
cmp r2, #0
beq .lz77_16bit_done
@ read next encoder or process next block
lsls r3, #1
bcc .lz77_16bit_encoder_loop
b .lz77_16bit_loop
.lz77_16bit_copy_window_not_aligned_check:
subs r1, #1
cmp r1, r5
beq .set_previous_byte
tst r5, #1
ldrneb r7, [r5], #1
addne r1, #1
subne r4, #1
#ifdef OVERRUN_PROTECTION
cmp r4, #1
ble .lz77_16bit_copy_window_not_aligned_after_loop
#endif
.lz77_16bit_copy_window_not_aligned_loop:
ldrh r6, [r5], #2
orr r7, r6, lsl #8
strh r7, [r1], #2
lsr r7, #16
subs r4, #2
cmp r4, #1
bgt .lz77_16bit_copy_window_not_aligned_loop
.lz77_16bit_copy_window_not_aligned_after_loop:
@ copy byte from window to current destination
ldreqb r6, [r5]
orreq r7, r6, lsl #8
streqh r7, [r1], #1
add r1, #1
@ check if decompressed length has been reached
cmp r2, #0
beq .lz77_16bit_done
@ read next encoder or process next block
lsls r3, #1
bcc .lz77_16bit_encoder_loop
b .lz77_16bit_loop
.set_previous_byte:
tst r1, #1
beq .got_byte_in_r7
ldrb r7, [r1], #1
movs r6, r7
orr r7, r6, lsl #8
b .pre_set_loop
.got_byte_in_r7:
movs r6, r7
orr r7, r6, lsl #8
strh r7, [r1], #2
subs r4, #1
.pre_set_loop:
#ifdef OVERRUN_PROTECTION
cmp r4, #1
ble .set_after_loop
#endif
.set_loop:
strh r7, [r1], #2
subs r4, #2
cmp r4, #1
bgt .set_loop
.set_after_loop:
@ copy byte from window to current destination
lsreq r7, #8
addeq r1, #1
@ check if decompressed length has been reached
cmp r2, #0
beq .lz77_16bit_done
@ read next encoder or process next block
lsls r3, #1
bcc .lz77_16bit_encoder_loop
b .lz77_16bit_loop
.lz77_16bit_done:
@ Cover un-aligned end
tst r1, #1
ldrneb r6, [r1]
orrne r7, r6, lsl #8
strneh r7, [r1, #-1]
.lz77_16bit_end:
ldmfd sp!, {r3 - r8}
bx lr

35
source/delays.c Normal file
View File

@ -0,0 +1,35 @@
#include "base_include.h"
#include <stddef.h>
#include "useful_qualifiers.h"
#include "timing_basic.h"
#include "delays.h"
#ifdef __GBA__
#define NUM_CYCLES_PER_ITER 4
#define NUM_CYCLES_PER_ITER_CHECK 8
#else
#define NUM_CYCLES_PER_ITER 4
#define NUM_CYCLES_PER_ITER_CHECK 14
#endif
NO_INLINE IWRAM_CODE void delay_cycles(u32 num_cycles) {
num_cycles = (num_cycles + NUM_CYCLES_PER_ITER - 1 + (NUM_CYCLES_PER_ITER / 2)) / NUM_CYCLES_PER_ITER;
__asm__ volatile (
"L1%=: subs %[wait], #1;"
"bne L1%=;"
: [wait] "+l" (num_cycles)
);
}
NO_INLINE IWRAM_CODE void delay_cycles_until(u32 num_cycles, vu8* data, u8 wanted, u8 cycles_per_load) {
num_cycles = (num_cycles + (NUM_CYCLES_PER_ITER_CHECK + cycles_per_load) - 1 + ((NUM_CYCLES_PER_ITER_CHECK + cycles_per_load) / 2)) / (NUM_CYCLES_PER_ITER_CHECK + cycles_per_load);
__asm__ volatile (
"L1%=: ldrb r3, [%[data], #0];"
"cmp r3, %[wanted];"
"beq L2%=;"
"subs %[wait], #1;"
"bne L1%=;"
"L2%=:;"
: [wait] "+l" (num_cycles) : [data]"l"(data), [wanted]"l"(wanted) : "r3"
);
}

View File

@ -9,6 +9,8 @@
#include "pokemon_gender_bin.h"
#include "pokemon_stats_gen1_bin.h"
#include "pokemon_stats_bin.h"
#include "default_names_int_gen_i_ii_bin.h"
#include "default_names_jpn_gen_i_ii_bin.h"
const u8* set_buffer_with_gen2(const u8*, u8, u8*);
u16 get_stat_exp_contribution(u16);
@ -153,9 +155,7 @@ u8 is_pokerus_strain_valid_gen2(u8 pokerus_byte) {
u8 get_pokerus_strain_max_days_gen2(u8 pokerus_byte) {
if(!is_pokerus_strain_valid_gen2(pokerus_byte))
return 0;
if(!(pokerus_byte >> 4))
return 1;
return (((pokerus_byte >> 4) - 1) & 3) + 1;
return ((pokerus_byte >> 4) & 3) + 1;
}
u8 are_pokerus_days_valid_gen2(u8 pokerus_byte) {
@ -230,6 +230,43 @@ const u8* get_default_trainer_name_gen2(u8 language, u8* buffer) {
return set_buffer_with_gen2(get_default_trainer_name(language), language, buffer);
}
const u8* get_actual_ot_name(const u8* gen2_ot_name, u8 is_jp, u8 terminator_stop, u8 language_target) {
const u8* names_list = default_names_int_gen_i_ii_bin;
if(is_jp)
names_list = default_names_jpn_gen_i_ii_bin;
u8 names_size = names_list[0] - 1;
u8 num_entries = names_list[1];
u16 curr_pos = 2;
u8 found = 0;
for(int i = 0; i < num_entries; i++) {
int diff = 0;
for(int j = 0; j < names_size; j++) {
diff = gen2_ot_name[j] - names_list[curr_pos + j];
if(diff != 0)
break;
if(terminator_stop && (gen2_ot_name[j] == GEN2_EOL))
break;
}
if(diff == 0) {
if((language_target == 0) || (names_list[curr_pos + names_size] & (1 << language_target))) {
found = 1;
break;
}
}
// Use the fact that the list is sorted
if(diff < 0)
break;
curr_pos += names_size + 1;
}
if(!found)
return NULL;
return &names_list[curr_pos];
}
u8 get_pokemon_gender_gen2(u8 index, u8 atk_ivs, u8 is_egg, u8 curr_gen) {
u8 gender_kind = get_pokemon_gender_kind_gen2(index, is_egg, curr_gen);
switch(gender_kind){

View File

@ -144,6 +144,7 @@ const u16 berry_trees_pos[NUM_MAIN_GAME_ID] = {0x688, 0, 0x71C};
const u16 daily_show_thresholds[TOTAL_DAILY_SHOW_VARS] = {100, 50, 100, 20, 20, 20, 30};
static u32 time_events_rng_seed;
#endif
static u8 init_successful;
u8 has_rtc_events(struct game_identity* game_id) {
if(game_id->game_main_version == RS_MAIN_GAME_CODE)
@ -196,51 +197,76 @@ void change_tide(struct clock_events_t* clock_events, struct saved_time_t* extra
increase_clock(extra_time, 0xFFFF, 0, 0, 0, 0);
}
u8 has_init_succeded() {
return init_successful;
}
u8 update_base_time() {
#if ACTIVE_RTC_FUNCTIONS
__agbabi_datetime_t datetime = __agbabi_rtc_datetime();
u16 year = bcd_decode(datetime[0], 1);
u8 month = bcd_decode(datetime[0] >> 8, 1);
u8 day = bcd_decode(datetime[0] >> 16, 1);
u8 hour = bcd_decode(datetime[1], 1);
u8 minute = bcd_decode(datetime[1] >> 8, 1);
u8 second = bcd_decode(datetime[1] >> 16, 1);
u8 error_out = 0;
if(year == ((u16)ERROR_OUT_BCD))
error_out = 1;
if((month == ((u8)ERROR_OUT_BCD)) || (month == 0) || (month > NUM_MONTHS))
error_out = 1;
// There is no checking for overflows here, normally... :/
u8 checking_month = 0;
if((month > 0) && (month <= NUM_MONTHS))
checking_month = month - 1;
u8 max_day = num_days_per_month[checking_month];
if((month == LEAP_YEAR_EXTRA_DAY_MONTH) && is_leap_year(year))
max_day++;
// What if the day is 0? And if it's the max_day?! :/
if((day == ((u8)ERROR_OUT_BCD)) || (day > max_day))
error_out = 1;
// What if the hour is 0? And if it's MAX_HOURS?! :/
if((hour == ((u8)ERROR_OUT_BCD)) || (hour > MAX_HOURS))
error_out = 1;
// What if the minute is 0? And if it's MAX_MINUTES?! :/
if((minute == ((u8)ERROR_OUT_BCD)) || (minute > MAX_MINUTES))
error_out = 1;
// What if the second is 0? And if it's MAX_SECONDS?! :/
if((second == ((u8)ERROR_OUT_BCD)) || (second > MAX_SECONDS))
error_out = 1;
if(!error_out) {
u16 final_days = get_num_days(year, month, day);
u8 final_hours = hour;
u8 final_minutes = minute;
u8 final_seconds = second;
u8 updated = 0;
if(base_rtc_time.d != final_days)
updated = 1;
if(base_rtc_time.h != final_hours)
updated = 1;
if(base_rtc_time.m != final_minutes)
updated = 1;
if(base_rtc_time.s != final_seconds)
updated = 1;
base_rtc_time.d = final_days;
base_rtc_time.h = final_hours;
base_rtc_time.m = final_minutes;
base_rtc_time.s = final_seconds;
return 1 + updated;
}
#endif
return 0;
}
void init_rtc_time() {
base_rtc_time.d = 1;
base_rtc_time.h = 0;
base_rtc_time.m = 0;
base_rtc_time.s = 0;
init_successful = 0;
#if ACTIVE_RTC_FUNCTIONS
if(!__agbabi_rtc_init()) {
__agbabi_datetime_t datetime = __agbabi_rtc_datetime();
u16 year = bcd_decode(datetime[0], 1);
u8 month = bcd_decode(datetime[0] >> 8, 1);
u8 day = bcd_decode(datetime[0] >> 16, 1);
u8 hour = bcd_decode(datetime[1], 1);
u8 minute = bcd_decode(datetime[1] >> 8, 1);
u8 second = bcd_decode(datetime[1] >> 16, 1);
u8 error_out = 0;
if(year == ((u16)ERROR_OUT_BCD))
error_out = 1;
if((month == ((u8)ERROR_OUT_BCD)) || (month == 0) || (month > NUM_MONTHS))
error_out = 1;
// There is no checking for overflows here, normally... :/
u8 checking_month = 0;
if((month > 0) && (month <= NUM_MONTHS))
checking_month = month - 1;
u8 max_day = num_days_per_month[checking_month];
if((month == LEAP_YEAR_EXTRA_DAY_MONTH) && is_leap_year(year))
max_day++;
// What if the day is 0? And if it's the max_day?! :/
if((day == ((u8)ERROR_OUT_BCD)) || (day > max_day))
error_out = 1;
// What if the hour is 0? And if it's MAX_HOURS?! :/
if((hour == ((u8)ERROR_OUT_BCD)) || (hour > MAX_HOURS))
error_out = 1;
// What if the minute is 0? And if it's MAX_MINUTES?! :/
if((minute == ((u8)ERROR_OUT_BCD)) || (minute > MAX_MINUTES))
error_out = 1;
// What if the second is 0? And if it's MAX_SECONDS?! :/
if((second == ((u8)ERROR_OUT_BCD)) || (second > MAX_SECONDS))
error_out = 1;
if(!error_out) {
base_rtc_time.d = get_num_days(year, month, day);
base_rtc_time.h = hour;
base_rtc_time.m = minute;
base_rtc_time.s = second;
}
}
if((!__agbabi_rtc_init()) && update_base_time())
init_successful = 1;
#endif
}
@ -426,8 +452,8 @@ void run_daily_update(struct game_data_t* game_data, struct clock_events_t* cloc
#else
void run_daily_update(struct game_data_t* game_data, struct clock_events_t* clock_events, struct saved_time_t* extra_time, u8 UNUSED(is_game_cleared)) {
#endif
if(has_rtc_events(&game_data->game_identifier))
init_rtc_time();
if(has_rtc_events(&game_data->game_identifier) && has_init_succeded())
update_base_time();
swap_time(&clock_events->saved_time);
u16 d = clock_events->saved_time.d;
add_time(&clock_events->saved_time, extra_time, &clock_events->saved_time);
@ -488,8 +514,8 @@ void wipe_clock(struct clock_events_t* clock_events) {
}
u8 is_daily_update_safe(struct game_data_t* game_data, struct clock_events_t* clock_events, struct saved_time_t* extra_time) {
if(has_rtc_events(&game_data->game_identifier))
init_rtc_time();
if(has_rtc_events(&game_data->game_identifier) && has_init_succeded())
update_base_time();
swap_time(&clock_events->saved_time);
struct saved_time_t tmp;
u16 days_increase = clock_events->saved_time.d;

View File

@ -527,8 +527,10 @@ void read_party(int slot, struct game_data_t* game_data, struct game_data_priv_t
game_data_priv->game_is_suspended = 0;
}
if(section_id == SECTION_LOCATION_ID)
if(section_id == SECTION_LOCATION_ID) {
game_data_priv->curr_map = read_short_save((slot * SAVE_SLOT_SIZE) + (i * SECTION_SIZE) + LOCATION_POS);
game_data_priv->curr_map = ((game_data_priv->curr_map & 0xFF) << 8) | ((game_data_priv->curr_map & 0xFF00) >> 8);
}
if(section_id == SECTION_BASE_DEX_ID) {
game_data_priv->nat_dex_magic = read_byte_save((slot * SAVE_SLOT_SIZE) + (i * SECTION_SIZE) + nat_dex_magic_pos[game_id]);
@ -823,14 +825,18 @@ IWRAM_CODE u8 has_cartridge_been_removed(){
ALWAYS_INLINE void start_gen3_save_data_transfer() {
#ifdef __NDS__
#ifdef __BLOCKSDS__
disableSleep();
#endif
#endif
}
ALWAYS_INLINE void end_gen3_save_data_transfer() {
#ifdef __NDS__
#ifdef __BLOCKSDS__
enableSleep();
#endif
#endif
}
u8 read_gen_3_data(struct game_data_t* game_data, struct game_data_priv_t* game_data_priv){

View File

@ -9,7 +9,6 @@
#include "rng.h"
#include "pid_iv_tid.h"
#include "fast_pokemon_methods.h"
#include "optimized_swi.h"
#include "useful_qualifiers.h"
#include <stddef.h>
@ -75,7 +74,7 @@ void convert_strings_of_gen3_generic(struct gen3_mon*, u16, u8*, u8*, u8, u8, u8
void convert_strings_of_gen12(struct gen3_mon*, u8, u8*, u8*, u8, u8);
void special_convert_strings_distribution(struct gen3_mon*, u16);
u8 text_handling_gen12_to_gen3(struct gen3_mon*, u16, u16, u8, u8*, u8*, u8, u8);
void set_language_gen12_to_gen3(struct gen3_mon*, u16, u8, u8*, u8);
void set_language_gen12_to_gen3(struct gen3_mon*, u16, u8, const u8*, const u8*, u8);
void sanitize_ot_name_gen3_to_gen12(u8*, u8*, u8, u8);
void sanitize_ot_name_gen12_to_gen3(u8*, u8*, u8);
void clean_name_gen12(u8*, u8);
@ -205,9 +204,10 @@ u8 convert_moves_of_gen3(struct gen3_mon_attacks* attacks, u8 pp_bonuses, u8* mo
if(!found) {
u8 bonus_pp = (pp_bonuses>>(2*i))&3;
u8 base_pp = get_pp_of_move(move, bonus_pp, last_valid_move);
// Limit the PP to its maximum of 61
if(base_pp > 61)
base_pp = 61;
// Limit the PP to the real maximum
u8 max_gen12_move_pps = GEN12_MAX_MOVE_PP + (((GEN12_MAX_MOVE_PP / 5) - 1) * bonus_pp);
if(base_pp >= max_gen12_move_pps)
base_pp = max_gen12_move_pps;
base_pp |= (bonus_pp << 6);
pps[used_slots] = base_pp;
moves[used_slots++] = move;
@ -287,7 +287,7 @@ void convert_exp_nature_of_gen3(struct gen3_mon* src, struct gen3_mon_growth* gr
u8 nature = get_nature(src->pid);
// Nature handling
u8 exp_nature = DivMod(exp, NUM_NATURES);
u8 exp_nature = get_nature(exp);
if(exp_nature > nature)
nature += NUM_NATURES;
exp += nature - exp_nature;
@ -337,7 +337,7 @@ u8 get_exp_nature(struct gen3_mon* dst, struct gen3_mon_growth* growth, u8 level
s32 exp = get_proper_exp_from_gen12(mon_index, level, is_egg, given_exp);
// Save nature in experience, like the Gen I-VII conversion
u8 nature = SWI_DivMod(exp, NUM_NATURES);
u8 nature = get_nature(exp);
// Store exp and level
dst->level = level;
@ -551,6 +551,10 @@ void preload_if_fixable(struct gen3_mon_data_unenc* data_src) {
data_src->fixed_ivs.ot_id = generate_ot(data_src->src->ot_id & 0xFFFF, data_src->src->ot_name);
data_src->fix_has_altered_ot = 1;
}
if(data_src->misc.origins_info >> 15) {
data_src->fixed_ivs.origins_info &= ~(1 << 15);
data_src->fix_has_altered_ot = 1;
}
u8 wanted_nature = get_nature(data_src->src->pid);
u32 ot_id = data_src->fixed_ivs.ot_id;
u8 is_shiny = is_shiny_gen3_raw(data_src, ot_id);
@ -603,7 +607,7 @@ void alter_nature(struct gen3_mon_data_unenc* data_src, u8 wanted_nature) {
return;
// Normalize nature
SWI_DivMod(wanted_nature, NUM_NATURES);
wanted_nature = get_nature(wanted_nature);
if(wanted_nature == get_nature(data_src->src->pid))
return;
@ -635,7 +639,7 @@ void alter_nature(struct gen3_mon_data_unenc* data_src, u8 wanted_nature) {
switch(encounter_type) {
case STATIC_ENCOUNTER:
case ROAMER_ENCOUNTER:
if(species == CELEBI_SPECIES) {
if(get_event_info_replacement() && (species == CELEBI_SPECIES)) {
generate_generic_genderless_shadow_info_xd(wanted_nature, 0, wanted_ivs, tsv, pid_ptr, ivs_ptr, ability_ptr);
is_ability_set = 1;
}
@ -693,6 +697,9 @@ void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_data_unenc* data_ds
u8 trainer_game_version = id_to_version(&trainer_data->game_identifier);
u8 trainer_gender = trainer_data->trainer_gender;
// Normalize nature
wanted_nature = get_nature(wanted_nature);
// Handle eggs separately
u32 ot_id = dst->ot_id;
if(is_egg)
@ -722,7 +729,7 @@ void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_data_unenc* data_ds
switch(encounter_type) {
case STATIC_ENCOUNTER:
valid_balls = VALID_POKEBALL_NO_EGG;
if(species == CELEBI_SPECIES) {
if(get_event_info_replacement() && (species == CELEBI_SPECIES)) {
valid_balls = VALID_POKEBALL_CELEBI;
chosen_version = R_VERSION_ID;
generate_generic_genderless_shadow_info_xd(wanted_nature, 0, wanted_ivs, tsv, &dst->pid, &ivs, &ability);
@ -731,11 +738,12 @@ void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_data_unenc* data_ds
}
else if(!is_shiny) {
// Prefer Colosseum/XD encounter, if possible
if(get_conversion_colo_xd() && is_static_in_xd(species) && are_colo_valid_tid_sid(ot_id & 0xFFFF, ot_id >> 0x10)) {
if(get_conversion_colo_xd() && is_static_in_xd(species) && are_colo_valid_tid_sid(ot_id & 0xFFFF, ot_id >> 0x10) && ((ot_gender == 0) || (!get_prioritize_ot_gender()))) {
chosen_version = COLOSSEUM_CODE;
generate_generic_genderless_shadow_info_xd(wanted_nature, has_prev_check_tsv_in_xd(species), wanted_ivs, tsv, &dst->pid, &ivs, &ability);
misc->ribbons |= COLO_RIBBON_VALUE;
is_ability_set = 1;
ot_gender = 0;
data_dst->learnable_moves = (const struct learnset_data_mon_moves*)get_learnset_for_species((const u16*)learnset_static_xd_bin, species);
}
else
@ -749,7 +757,7 @@ void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_data_unenc* data_ds
case ROAMER_ENCOUNTER:
valid_balls = VALID_POKEBALL_NO_EGG;
// Prefer Colosseum/XD encounter, if possible
if(get_conversion_colo_xd() && are_colo_valid_tid_sid(ot_id & 0xFFFF, ot_id >> 0x10)) {
if(get_conversion_colo_xd() && are_colo_valid_tid_sid(ot_id & 0xFFFF, ot_id >> 0x10) && ((ot_gender == 0) || (!get_prioritize_ot_gender()))) {
chosen_version = COLOSSEUM_CODE;
if(!is_shiny)
generate_generic_genderless_shadow_info_colo(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs, &ability);
@ -757,6 +765,7 @@ void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_data_unenc* data_ds
generate_generic_genderless_shadow_shiny_info_colo(wanted_nature, tsv, &dst->pid, &ivs, &ability);
misc->ribbons |= COLO_RIBBON_VALUE;
is_ability_set = 1;
ot_gender = 0;
}
else {
if(!is_shiny)
@ -902,7 +911,7 @@ void sanitize_ot_name_gen12_to_gen3(u8* src, u8* dst, u8 language) {
sanitize_name_gen12_to_gen3(src, dst, get_default_trainer_name(language), gen2_name_cap, gen3_ot_name_cap);
}
void convert_trainer_name_gen3_to_gen12(u8* src, u8* dst, u8 src_language, u8 dst_language) {
void convert_trainer_name_gen3_to_gen12(u8* src, u8* dst, u8 src_language, u8 dst_language, u8 marks) {
u8 is_jp_gen3 = GET_LANGUAGE_IS_JAPANESE(src_language);
u8 is_jp_target = GET_LANGUAGE_IS_JAPANESE(dst_language);
@ -924,6 +933,26 @@ void convert_trainer_name_gen3_to_gen12(u8* src, u8* dst, u8 src_language, u8 ds
// Do some sanitization
sanitize_ot_name_gen3_to_gen12(src, dst, src_language, dst_language);
// Apply special OT Name handling with special markings value
if(marks == SPECIAL_NAME_MARKS_VALUE) {
const u8* special_name = get_actual_ot_name(dst, is_jp_target, 1, src_language);
if(special_name) {
for(size_t i = 0; i < gen12_ot_name_size; i++)
dst[i] = special_name[i];
return;
}
marks = 0;
}
// Apply special OT Name handling and 0 out certain parts of the name
if(marks > gen12_ot_name_size)
marks = 0;
size_t pos_zeros = text_gen2_size(dst, gen12_ot_name_cap) + 1;
if(marks > pos_zeros)
pos_zeros = marks;
for(; pos_zeros < gen12_ot_name_size; pos_zeros++)
dst[pos_zeros] = 0;
}
void convert_trainer_name_gen12_to_gen3(u8* src, u8* dst, u8 src_is_jp, u8 dst_language, u8 max_size) {
@ -987,7 +1016,7 @@ void convert_strings_of_gen3_generic(struct gen3_mon* src, u16 species, u8* ot_n
text_gen2_replace(nickname, gen12_nickname_cap, GEN2_DOT, GEN1_DOT);
*/
convert_trainer_name_gen3_to_gen12(src->ot_name, ot_name, src->language, target_language);
convert_trainer_name_gen3_to_gen12(src->ot_name, ot_name, src->language, target_language, src->marks);
}
void convert_strings_of_gen3(struct gen3_mon* src, u16 species, u8* ot_name, u8* ot_name_jp, u8* nickname, u8* nickname_jp, u8 is_egg, u8 is_gen2) {
@ -1264,21 +1293,54 @@ void clean_name_gen12(u8* name, u8 is_jp) {
text_gen2_replace(name, gen2_name_cap, GEN1_DOT, GEN2_DOT);
}
void set_language_gen12_to_gen3(struct gen3_mon* dst, u16 species, u8 is_egg, u8* nickname, u8 is_jp) {
void set_language_gen12_to_gen3(struct gen3_mon* dst, u16 species, u8 is_egg, const u8* ot_name, const u8* nickname, u8 is_jp) {
u8 gen2_buffer[STRING_GEN2_MAX_SIZE];
u8 int_language = get_filtered_target_int_language();
u32 possible_languages = ALL_LANGUAGES & (~(1 << JAPANESE_LANGUAGE));
u8 gen12_ot_name_size = STRING_GEN2_INT_SIZE;
if(is_jp) {
possible_languages = (1 << JAPANESE_LANGUAGE);
gen12_ot_name_size = STRING_GEN2_JP_SIZE;
}
const u8* special_name = get_actual_ot_name(ot_name, is_jp, 0, 0);
// Abuse markings to store info about the Gen 1/2 OT Name's trailing bytes
if(special_name != NULL) {
possible_languages &= special_name[gen12_ot_name_size];
dst->marks = SPECIAL_NAME_MARKS_VALUE;
}
else {
size_t end_eol = gen12_ot_name_size;
for(; end_eol > 0; end_eol--) {
if(ot_name[end_eol - 1] == GEN2_EOL)
break;
}
dst->marks = end_eol;
}
// Fix possible bad language filtering (Korean)
if(!possible_languages) {
possible_languages = ALL_LANGUAGES & (~(1 << JAPANESE_LANGUAGE));
dst->marks = 0;
}
if((!is_jp) && (get_target_int_language() == UNKNOWN_LANGUAGE)) {
u32 found_languages = 0;
for(size_t i = FIRST_INTERNATIONAL_VALID_LANGUAGE; i < NUM_LANGUAGES; i++)
if(text_gen2_is_same(nickname, get_pokemon_name_gen2(species, is_egg, i, gen2_buffer), STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP))
found_languages |= 1<<i;
if(found_languages && (!(found_languages & (1<<int_language))))
for(size_t i = FIRST_INTERNATIONAL_VALID_LANGUAGE; i < NUM_LANGUAGES; i++)
if(found_languages & (1<<i)) {
int_language = i;
break;
}
found_languages |= 1 << i;
// OT Name has priority
if(possible_languages & found_languages)
possible_languages &= found_languages;
}
if((!is_jp) && (!(possible_languages & (1 << int_language)))) {
for(size_t i = FIRST_INTERNATIONAL_VALID_LANGUAGE; i < NUM_LANGUAGES; i++)
if(possible_languages & (1 << i)) {
int_language = i;
break;
}
}
if(is_jp)
@ -1286,7 +1348,7 @@ void set_language_gen12_to_gen3(struct gen3_mon* dst, u16 species, u8 is_egg, u8
else
dst->language = int_language;
if((species == MEW_SPECIES) || (species == CELEBI_SPECIES)) {
if(get_event_info_replacement() && ((species == MEW_SPECIES) || (species == CELEBI_SPECIES))) {
if((!get_allow_undistributed_events()) || is_jp)
dst->language = JAPANESE_LANGUAGE;
else
@ -1302,10 +1364,10 @@ u8 text_handling_gen12_to_gen3(struct gen3_mon* dst, u16 species, u16 swapped_ot
clean_name_gen12(nickname, is_jp);
// Handle language
set_language_gen12_to_gen3(dst, species, is_egg, nickname, is_jp);
set_language_gen12_to_gen3(dst, species, is_egg, ot_name, nickname, is_jp);
// Specially handle Celebi's event
if((species == CELEBI_SPECIES) && (!is_egg)) {
if(get_event_info_replacement() && (species == CELEBI_SPECIES) && (!is_egg)) {
dst->ot_id = CELEBI_AGATE_OT_ID;
special_convert_strings_distribution(dst, species);
return no_restrictions;

View File

@ -28,7 +28,9 @@ void convert_3bpp_forward_even(const u8*, u32*, size_t);
MAX_OPTIMIZE void load_pokemon_sprite_gfx(const u32* src, u32* dst, u8 is_3bpp, u8 zero_fill, u8 index, u8* colors){
u32 zero = 0;
u32 buffer[BUFFER_SIZE];
CpuFastSet(&zero, buffer, BUFFER_SIZE|CPUFASTSET_FILL);
LZ77UnCompWram(src, buffer);
size_t processed_size = TOTAL_POKEMON_SPRITE_SIZE;

View File

@ -7,6 +7,24 @@
#include "useful_qualifiers.h"
#include "config_settings.h"
u8 handle_input_multiboot_settings(u16 keys, u8* is_normal, u8* update) {
if(keys & KEY_A)
return CONFIRM_MULTIBOOT;
if(keys & KEY_B)
return CANCEL_MULTIBOOT;
if(*is_normal && (keys & KEY_RIGHT)) {
*is_normal = 0;
*update = 1;
}
else if((!(*is_normal)) && (keys & KEY_LEFT)) {
*is_normal = 1;
*update = 1;
}
return 0;
}
u8 handle_input_multiboot_menu(u16 keys) {
if(keys & KEY_A)
return 1;
@ -489,7 +507,7 @@ u8 handle_input_gen12_settings_menu(u16 keys, u8* cursor_y_pos, u8* update) {
switch(*cursor_y_pos) {
case 0:
if(keys & KEY_UP)
*cursor_y_pos = 6;
*cursor_y_pos = 7;
else if(keys & KEY_DOWN)
*cursor_y_pos += 1;
else if((keys & KEY_RIGHT) || (keys & KEY_A)) {
@ -531,11 +549,21 @@ u8 handle_input_gen12_settings_menu(u16 keys, u8* cursor_y_pos, u8* update) {
else if(keys & KEY_DOWN)
*cursor_y_pos += 1;
else if((keys & KEY_RIGHT) || (keys & KEY_A) || (keys & KEY_LEFT)) {
set_gen1_everstone(!get_gen1_everstone());
set_prioritize_ot_gender(!get_prioritize_ot_gender());
*update = 1;
}
break;
case 4:
if(keys & KEY_UP)
*cursor_y_pos -= 1;
else if(keys & KEY_DOWN)
*cursor_y_pos += 1;
else if((keys & KEY_RIGHT) || (keys & KEY_A) || (keys & KEY_LEFT)) {
set_gen1_everstone(!get_gen1_everstone());
*update = 1;
}
break;
case 5:
if(keys & KEY_UP)
*cursor_y_pos -= 1;
else if(keys & KEY_DOWN)
@ -553,7 +581,7 @@ u8 handle_input_gen12_settings_menu(u16 keys, u8* cursor_y_pos, u8* update) {
*update = 1;
}
break;
case 5:
case 6:
if(keys & KEY_UP)
*cursor_y_pos -= 1;
else if(keys & KEY_DOWN)
@ -567,7 +595,7 @@ u8 handle_input_gen12_settings_menu(u16 keys, u8* cursor_y_pos, u8* update) {
*update = 1;
}
break;
case 6:
case 7:
if(keys & KEY_UP)
*cursor_y_pos -= 1;
else if(keys & KEY_DOWN)
@ -687,7 +715,7 @@ u8 handle_input_cheats_menu(u16 keys, u8* cursor_y_pos, u8* update) {
switch(*cursor_y_pos) {
case 0:
if(keys & KEY_UP)
*cursor_y_pos = 4;
*cursor_y_pos = 5;
else if(keys & KEY_DOWN)
*cursor_y_pos += 1;
else if((keys & KEY_RIGHT) || (keys & KEY_A) || (keys & KEY_LEFT)) {
@ -721,11 +749,21 @@ u8 handle_input_cheats_menu(u16 keys, u8* cursor_y_pos, u8* update) {
else if(keys & KEY_DOWN)
*cursor_y_pos += 1;
else if((keys & KEY_RIGHT) || (keys & KEY_A) || (keys & KEY_LEFT)) {
set_fast_hatch_eggs(!get_fast_hatch_eggs());
set_event_info_replacement(!get_event_info_replacement());
*update = 1;
}
break;
case 4:
if(keys & KEY_UP)
*cursor_y_pos -= 1;
else if(keys & KEY_DOWN)
*cursor_y_pos += 1;
else if((keys & KEY_RIGHT) || (keys & KEY_A) || (keys & KEY_LEFT)) {
set_fast_hatch_eggs(!get_fast_hatch_eggs());
*update = 1;
}
break;
case 5:
if(keys & KEY_A)
return 1;
else if(keys & KEY_UP)
@ -854,8 +892,11 @@ u8 handle_input_clock_menu(u16 keys, struct clock_events_t* clock_events, struct
}
break;
case BOTTOM_Y_CURSOR_CLOCK_SETTINGS_MENU_VALUE:
if(keys & KEY_A)
return 1;
if(keys & KEY_A) {
if((time_change->d != 0) || (time_change->h != 0) || (time_change->m != 0) || (time_change->s != 0))
return 1;
return EXIT_CLOCK_SETTINGS;
}
else if(keys & KEY_UP)
*cursor_y_pos = 9;
else if(keys & KEY_DOWN)

View File

@ -108,7 +108,7 @@ void complete_save_menu(struct game_data_t*, struct game_data_priv_t*, u8, u8);
void complete_cartridge_loading(struct game_data_t*, struct game_data_priv_t*, u8, u8, u8, u8*);
int main(void);
enum STATE {MAIN_MENU, MULTIBOOT, TRADING_MENU, INFO_MENU, START_TRADE, WAITING_DATA, TRADE_OPTIONS, NATURE_SETTING, OFFER_MENU, TRADING_ANIMATION, OFFER_INFO_MENU, IV_FIX_MENU, LEARNABLE_MOVES_MESSAGE, LEARNABLE_MOVES_MESSAGE_MENU, LEARNABLE_MOVES_MENU, SWAP_CARTRIDGE_MENU, BASE_SETTINGS_MENU, COLOURS_SETTINGS_MENU, CLOCK_SETTINGS_MENU, CHEATS_MENU, EVOLUTION_MENU, WARNINGS_WHEN_LOADING, WARNING_WHEN_ADVANCING_CLOCK, PRINT_READ_INFO, GEN12_SETTINGS_MENU};
enum STATE {MAIN_MENU, MULTIBOOT, TRADING_MENU, INFO_MENU, START_TRADE, WAITING_DATA, TRADE_OPTIONS, NATURE_SETTING, OFFER_MENU, TRADING_ANIMATION, OFFER_INFO_MENU, IV_FIX_MENU, LEARNABLE_MOVES_MESSAGE, LEARNABLE_MOVES_MESSAGE_MENU, LEARNABLE_MOVES_MENU, SWAP_CARTRIDGE_MENU, BASE_SETTINGS_MENU, COLOURS_SETTINGS_MENU, CLOCK_SETTINGS_MENU, CHEATS_MENU, EVOLUTION_MENU, WARNINGS_WHEN_LOADING, WARNING_WHEN_ADVANCING_CLOCK, PRINT_READ_INFO, GEN12_SETTINGS_MENU, MULTIBOOT_SETTINGS_MENU};
enum STATE curr_state;
u32 counter = 0;
u32 input_counter = 0;
@ -129,6 +129,10 @@ IWRAM_CODE void vblank_update_function() {
// Handle trading animation
if(curr_state == TRADING_ANIMATION)
advance_trade_animation();
#ifdef __NDS__
// Increase FPS on NDS
//__reset_vcount();
#endif
#ifdef HAS_SIO
// Handle slave communications
if((REG_SIOCNT & SIO_IRQ) && (!(REG_SIOCNT & SIO_START)))
@ -642,10 +646,13 @@ void clock_settings_menu_init(struct game_data_priv_t* game_data_priv, struct sa
set_screen(BASE_SCREEN);
disable_all_screens_but_current();
disable_all_cursors();
if(reset_time)
if(reset_time) {
wipe_time(time_change);
init_rtc_time();
}
print_clock_menu(&game_data_priv->clock_events, time_change, 1);
enable_screen(BASE_SCREEN);
enable_screen(BASE_SCREEN + 1);
*cursor_y_pos = 0;
update_cursor_base_x(BASE_X_CURSOR_CLOCK_SETTINGS_MENU);
cursor_update_clock_settings_menu(*cursor_y_pos);
@ -707,6 +714,9 @@ void prepare_crash_screen(enum CRASH_REASONS reason) {
print_crash(reason);
enable_screen(CRASH_WINDOW_SCREEN);
prepare_flush();
#if defined(__NDS__) && (!defined(__BLOCKSDS__))
pmMainLoop();
#endif
}
void crash_on_cartridge_removed() {
@ -752,8 +762,15 @@ void complete_save_menu(struct game_data_t* game_data, struct game_data_priv_t*
void complete_cartridge_loading(struct game_data_t* game_data, struct game_data_priv_t* game_data_priv, u8 target, u8 region, u8 master, u8* cursor_y_pos) {
init_game_data(game_data);
get_game_id(&game_data->game_identifier);
read_gen_3_data(game_data, game_data_priv);
u8 can_check_cart = 1;
#ifdef __NDS__
if(isDSiMode())
can_check_cart = 0;
#endif
if(can_check_cart) {
get_game_id(&game_data->game_identifier);
read_gen_3_data(game_data, game_data_priv);
}
prepare_main_options(game_data, game_data_priv);
if((!get_valid_options_main()) || (!loaded_data_has_warnings(game_data, game_data_priv)))
main_menu_init(game_data, game_data_priv, target, region, master, cursor_y_pos);
@ -766,6 +783,10 @@ int main(void)
#ifdef __GBA__
RegisterRamReset(RESET_SIO|RESET_SOUND|RESET_OTHER);
disable_all_irqs();
#else
#ifndef __BLOCKSDS__
gbacartOpen();
#endif
#endif
curr_state = MAIN_MENU;
counter = 0;
@ -806,6 +827,7 @@ int main(void)
u8 returned_val;
u8 move_go_on = 0;
u8 update = 0;
u8 is_normal = 1;
u8 target = 1;
u8 region = 0;
u8 master = 0;
@ -832,10 +854,13 @@ int main(void)
//PRINT_FUNCTION("\n\n0x\x0D: 0x\x0D\n", REG_MEMORY_CONTROLLER_ADDR, 8, REG_MEMORY_CONTROLLER, 8);
scanKeys();
keys = keysDown();
while(1) {
do {
#if defined(__NDS__) && (!defined(__BLOCKSDS__))
pmMainLoop();
#endif
prepare_flush();
VBlankIntrWait();
scanKeys();
@ -987,6 +1012,9 @@ int main(void)
}
}
break;
case CLOCK_SETTINGS_MENU:
print_clock_variable_menu(&game_data_priv.clock_events, &time_change, 0);
break;
default:
break;
}
@ -999,14 +1027,10 @@ int main(void)
print_main_menu(update, target, region, master, &game_data[0], &game_data_priv);
cursor_update_main_menu(cursor_y_pos);
if(returned_val == START_MULTIBOOT) {
curr_state = MULTIBOOT;
#ifdef HAS_SIO
sio_stop_irq_slave();
irqDisable(IRQ_SERIAL);
#endif
curr_state = MULTIBOOT_SETTINGS_MENU;
is_normal = 1;
disable_cursor();
init_save_data();
print_multiboot(multiboot_normal((u16*)EWRAM, (u16*)(EWRAM + MULTIBOOT_MAX_SIZE)));
print_multiboot_settings(is_normal, 1);
}
if(returned_val == START_PRINT_READ_INFO) {
curr_state = PRINT_READ_INFO;
@ -1077,6 +1101,22 @@ int main(void)
else
print_pokemon_pages(returned_val, submenu_cursor_y_pos != prev_val, &game_data[submenu_cursor_y_pos].party_3_undec[*party_selected_mons[submenu_cursor_y_pos]], curr_page);
break;
case MULTIBOOT_SETTINGS_MENU:
returned_val = handle_input_multiboot_settings(keys, &is_normal, &update);
if(returned_val == CONFIRM_MULTIBOOT) {
curr_state = MULTIBOOT;
#ifdef HAS_SIO
sio_stop_irq_slave();
irqDisable(IRQ_SERIAL);
#endif
init_save_data();
print_multiboot(multiboot_normal((u16*)EWRAM, (u16*)(EWRAM + MULTIBOOT_MAX_SIZE), is_normal));
}
else if(returned_val == CANCEL_MULTIBOOT)
main_menu_init(&game_data[0], &game_data_priv, target, region, master, &cursor_y_pos);
else
print_multiboot_settings(is_normal, update);
break;
case MULTIBOOT:
if(handle_input_multiboot_menu(keys)) {
loading_print_screen();

View File

@ -450,18 +450,28 @@ void print_gen12_settings_menu(u8 update) {
default_reset_screen();
PRINT_FUNCTION("\n Target Language: <\x01>\n\n", get_language_string(get_target_int_language()));
PRINT_FUNCTION(" Convert to: <\x01>\n\n", game_strings[get_default_conversion_game()]);
PRINT_FUNCTION(" Prioritize Colo/XD:");
if(get_conversion_colo_xd())
PRINT_FUNCTION(" Prioritize Colo/XD: <True>\n\n");
PRINT_FUNCTION(" <True>\n\n");
else
PRINT_FUNCTION(" Prioritize Colo/XD: <False>\n\n");
PRINT_FUNCTION(" <False>\n\n");
PRINT_FUNCTION(" Preserve OT Gender:");
if(get_prioritize_ot_gender())
PRINT_FUNCTION(" <True>\n\n");
else
PRINT_FUNCTION(" <False>\n\n");
PRINT_FUNCTION(" Gen 1 Everstone: ");
if(get_gen1_everstone())
PRINT_FUNCTION(" Gen 1 Everstone: <Enabled>\n\n");
PRINT_FUNCTION("<Enabled>\n\n");
else
PRINT_FUNCTION(" Gen 1 Everstone: <Disabled>\n\n");
PRINT_FUNCTION("<Disabled>\n\n");
PRINT_FUNCTION(" Caught in: <\x01 Ball>\n\n", get_pokeball_base_name_gen3_pure(get_applied_ball()));
PRINT_FUNCTION(" Hatched at: <\x0B> +/- 1\n\n", get_egg_met_location(), 3);
PRINT_FUNCTION(" Hatched at: <\x0B> +/- 10\n\n\n", get_egg_met_location(), 3);
PRINT_FUNCTION("Hatched at: \x01\n\n", get_met_location_name_gen3_pure(get_egg_met_location(), get_default_conversion_game()));
PRINT_FUNCTION(" Hatched at: ");
PRINT_FUNCTION("<\x0B> +/- 1\n\n", get_egg_met_location(), 3);
PRINT_FUNCTION(" Hatched at: ");
PRINT_FUNCTION("<\x0B> +/- 10\n\n", get_egg_met_location(), 3);
PRINT_FUNCTION("Hatched at: ");
PRINT_FUNCTION("\x01", get_met_location_name_gen3_pure(get_egg_met_location(), get_default_conversion_game()));
print_bottom_info();
}
@ -507,32 +517,58 @@ void print_base_settings_menu(struct game_identity* game_identifier, u8 is_loade
PRINT_FUNCTION("V.\x03.\x03.\x03\x02", version->main_version, version->sub_version, version->revision_version, version->revision_letter);
}
void print_clock_menu(struct clock_events_t* clock_events, struct saved_time_t* time_change, u8 update) {
if(!update)
void print_clock_variable_menu(struct clock_events_t* clock_events, struct saved_time_t* time_change, u8 force_print) {
u8 update_value = 0;
if(has_init_succeded())
update_value = update_base_time();
if((update_value != 2) && (!force_print))
return;
init_rtc_time();
struct saved_time_t base_time;
struct saved_time_t new_time;
get_clean_time(&clock_events->saved_time, &base_time);
get_increased_time(&clock_events->saved_time, time_change, &new_time);
default_reset_screen();
u8 old_screen = get_screen_num();
set_screen(old_screen + 1);
reset_screen(BLANK_FILL);
set_text_y(1);
set_text_x(8);
if(is_daytime(clock_events, time_change))
PRINT_FUNCTION("\n Time: <Day>\n\n");
PRINT_FUNCTION("<Day>\n\n");
else
PRINT_FUNCTION("\n Time: <Night>\n\n");
PRINT_FUNCTION("<Night>\n\n");
set_text_x(19);
if(is_high_tide(clock_events, time_change))
PRINT_FUNCTION(" Shoal Cave Tide: <High>\n\n");
PRINT_FUNCTION("<High>");
else
PRINT_FUNCTION(" Shoal Cave Tide: <Low>\n\n");
PRINT_FUNCTION("<Low>");
set_text_y(Y_LIMIT-6);
set_text_x(11);
PRINT_FUNCTION("\x0B-\x0B:\x0B:\x0B\n", base_time.d, 5, base_time.h, 2, base_time.m, 2, base_time.s, 2);
set_text_x(11);
PRINT_FUNCTION("\x0B-\x0B:\x0B:\x0B\n", new_time.d, 5, new_time.h, 2, new_time.m, 2, new_time.s, 2);
set_screen(old_screen);
}
void print_clock_menu(struct clock_events_t* clock_events, struct saved_time_t* time_change, u8 update) {
if(!update)
return;
default_reset_screen();
PRINT_FUNCTION("\n Time: \n\n");
PRINT_FUNCTION(" Shoal Cave Tide: \n\n");
u8 curr_y = get_text_y();
PRINT_FUNCTION(" Clock Reset Menu: ");
if(is_rtc_reset_enabled(clock_events))
PRINT_FUNCTION(" Clock Reset Menu: <Enabled>");
PRINT_FUNCTION("<Enabled>");
else
PRINT_FUNCTION(" Clock Reset Menu: <Disabled>");
PRINT_FUNCTION("<Disabled>");
set_text_y(curr_y+2);
PRINT_FUNCTION(" Days Increase: <\x0B>\n", time_change->d, 5);
@ -542,14 +578,15 @@ void print_clock_menu(struct clock_events_t* clock_events, struct saved_time_t*
set_text_y(Y_LIMIT-8);
PRINT_FUNCTION(" Save and Exit\n\n");
PRINT_FUNCTION("Base Time: \x0B-\x0B:\x0B:\x0B\n", base_time.d, 5, base_time.h, 2, base_time.m, 2, base_time.s, 2);
PRINT_FUNCTION("New Time: \x0B-\x0B:\x0B:\x0B\n", new_time.d, 5, new_time.h, 2, new_time.m, 2, new_time.s, 2);
set_text_y(Y_LIMIT-4);
PRINT_FUNCTION("Base Time:\n");
PRINT_FUNCTION("New Time:\n");
PRINT_FUNCTION("Issues may arise when changing");
set_text_y(Y_LIMIT-3);
PRINT_FUNCTION("the time of a Working Battery.");
set_text_y(Y_LIMIT-1);
PRINT_FUNCTION("B: Exit Without Saving");
print_clock_variable_menu(clock_events, time_change, 1);
}
void print_cheats_menu(u8 update) {
@ -557,22 +594,31 @@ void print_cheats_menu(u8 update) {
return;
default_reset_screen();
PRINT_FUNCTION("\n Cross-Gen Evo.:");
if(get_allow_cross_gen_evos())
PRINT_FUNCTION("\n Cross-Gen Evo.: <Enabled>\n\n");
PRINT_FUNCTION(" <Enabled>\n\n");
else
PRINT_FUNCTION("\n Cross-Gen Evo.: <Disabled>\n\n");
PRINT_FUNCTION(" <Disabled>\n\n");
PRINT_FUNCTION(" Tradeless Evo.:");
if(get_evolve_without_trade())
PRINT_FUNCTION(" Tradeless Evo.: <Enabled>\n\n");
PRINT_FUNCTION(" <Enabled>\n\n");
else
PRINT_FUNCTION(" Tradeless Evo.: <Disabled>\n\n");
PRINT_FUNCTION(" <Disabled>\n\n");
PRINT_FUNCTION(" Undistr. Events:");
if(get_allow_undistributed_events())
PRINT_FUNCTION(" Undistr. Events: <Enabled>\n\n");
PRINT_FUNCTION(" <Enabled>\n\n");
else
PRINT_FUNCTION(" Undistr. Events: <Disabled>\n\n");
PRINT_FUNCTION(" <Disabled>\n\n");
PRINT_FUNCTION(" Event Pok\xE9mon:");
if(get_event_info_replacement())
PRINT_FUNCTION(" <Legit Data>\n\n");
else
PRINT_FUNCTION(" <Keep Data>\n\n");
PRINT_FUNCTION(" Fast Hatch Eggs:");
if(get_fast_hatch_eggs())
PRINT_FUNCTION(" Fast Hatch Eggs: <Enabled>\n\n");
PRINT_FUNCTION(" <Enabled>\n\n");
else
PRINT_FUNCTION(" Fast Hatch Eggs: <Disabled>\n\n");
PRINT_FUNCTION(" <Disabled>\n\n");
PRINT_FUNCTION(" Give Pok\xE9rus to Party\n\n");
print_bottom_info();
@ -768,8 +814,10 @@ void print_basic_alter_conf_data(struct gen3_mon_data_unenc* mon, struct alterna
PRINT_FUNCTION(" \x09\x02", calc_stats_gen3_raw_alternative(mon, altered, i), 4, get_nature_symbol(altered->pid, i));
PRINT_FUNCTION(" \x09 \x09", get_ivs_gen3(&mon->misc, i), 3, get_ivs_gen3_pure(altered->ivs, i), 3);
}
PRINT_FUNCTION("\n\nOld Hidden Power: \x01 \x03", get_hidden_power_type_name_gen3(&mon->misc), get_hidden_power_power_gen3(&mon->misc));
PRINT_FUNCTION("\nNew Hidden Power: \x01 \x03", get_hidden_power_type_name_gen3_pure(altered->ivs), get_hidden_power_power_gen3_pure(altered->ivs));
PRINT_FUNCTION("\n\nOld ");
PRINT_FUNCTION("Hidden Power: \x01 \x03", get_hidden_power_type_name_gen3(&mon->misc), get_hidden_power_power_gen3(&mon->misc));
PRINT_FUNCTION("\nNew ");
PRINT_FUNCTION("Hidden Power: \x01 \x03", get_hidden_power_type_name_gen3_pure(altered->ivs), get_hidden_power_power_gen3_pure(altered->ivs));
}
void print_set_nature(u8 load_sprites, struct gen3_mon_data_unenc* mon) {
@ -1211,28 +1259,31 @@ void print_main_menu(u8 update, u8 curr_gen, u8 is_jp, u8 is_master, struct game
set_text_y(1);
set_text_x(MAIN_MENU_DISTANCE_FROM_BORDER);
curr_gen = options[curr_gen];
PRINT_FUNCTION("Target: ");
if(get_number_of_higher_ordered_options(options, curr_gen, TOTAL_GENS) > 0 && get_number_of_lower_ordered_options(options, curr_gen, TOTAL_GENS) > 0)
PRINT_FUNCTION("Target: <\x01>", target_strings[curr_gen-1]);
PRINT_FUNCTION("<\x01>", target_strings[curr_gen-1]);
else if(get_number_of_higher_ordered_options(options, curr_gen, TOTAL_GENS) > 0)
PRINT_FUNCTION("Target: \x01>", target_strings[curr_gen-1]);
PRINT_FUNCTION(" \x01>", target_strings[curr_gen-1]);
else if(get_number_of_lower_ordered_options(options, curr_gen, TOTAL_GENS) > 0)
PRINT_FUNCTION("Target: <\x01", target_strings[curr_gen-1]);
PRINT_FUNCTION("<\x01", target_strings[curr_gen-1]);
else
PRINT_FUNCTION("Target: \x01", target_strings[curr_gen-1]);
PRINT_FUNCTION(" \x01", target_strings[curr_gen-1]);
set_text_y(3);
set_text_x(MAIN_MENU_DISTANCE_FROM_BORDER);
if(curr_gen < 3) {
PRINT_FUNCTION("Target Region: ");
if(!is_jp)
PRINT_FUNCTION("Target Region: \x01>", region_strings[0]);
PRINT_FUNCTION(" \x01>", region_strings[0]);
else
PRINT_FUNCTION("Target Region: <\x01", region_strings[1]);
PRINT_FUNCTION("<\x01", region_strings[1]);
}
set_text_y(5);
set_text_x(MAIN_MENU_DISTANCE_FROM_BORDER);
PRINT_FUNCTION("Act as: ");
if(!is_master)
PRINT_FUNCTION("Act as: \x01>", actor_strings[1]);
PRINT_FUNCTION(" \x01>", actor_strings[1]);
else
PRINT_FUNCTION("Act as: <\x01", actor_strings[0]);
PRINT_FUNCTION("<\x01", actor_strings[0]);
set_text_y(7);
set_text_x(MAIN_MENU_DISTANCE_FROM_BORDER);
PRINT_FUNCTION("Start Trade");
@ -1256,6 +1307,20 @@ void print_main_menu(u8 update, u8 curr_gen, u8 is_jp, u8 is_master, struct game
}
}
void print_multiboot_settings(u8 is_normal, u8 update) {
if(!update)
return;
default_reset_screen();
PRINT_FUNCTION("\nCable type: ");
if(is_normal)
PRINT_FUNCTION(" GBC> (Fast)");
else
PRINT_FUNCTION("<GBA (Slow)");
set_text_y(Y_LIMIT-1);
PRINT_FUNCTION("A: Start - B: Go Back");
}
void print_multiboot_mid_process(u8 initial_handshake) {
default_reset_screen();
PRINT_FUNCTION("\nInitiating handshake!\n");

View File

@ -6,45 +6,62 @@
#include "timing_basic.h"
#include "useful_qualifiers.h"
#define MAX_PALETTE_ATTEMPTS 128
#define MULTIBOOT_WAIT_TIME_NS 36000
#define MULTIBOOT_VCOUNTWAIT (((MULTIBOOT_WAIT_TIME_NS/NS_PER_SCANLINE) + ((MULTIBOOT_WAIT_TIME_NS%NS_PER_SCANLINE) == 0 ? 0 : 1))+1)
int multiboot_normal_send(int);
void multiboot_send(int, int, u16*);
int multiboot_normal_send(int data) {
#ifndef HAS_SIO
void multiboot_send(int UNUSED(data), int UNUSED(is_normal), u16* UNUSED(out_buffer)) {
#else
void multiboot_send(int data, int is_normal, u16* out_buffer) {
// Only this part of REG_SIODATA32 is used during setup.
// The rest is handled by SWI $25
return timed_sio_normal_master(data, SIO_32, MULTIBOOT_VCOUNTWAIT) >> 0x10;
for(int i = 0; i < MAX_NUM_SLAVES; i++)
out_buffer[i] = 0;
if(is_normal)
out_buffer[0] = timed_sio_normal_master(data, SIO_32, MULTIBOOT_VCOUNTWAIT) >> 0x10;
else
timed_sio_multi_master(data, MULTIBOOT_VCOUNTWAIT, out_buffer);
#endif
}
#ifdef HAS_SIO
enum MULTIBOOT_RESULTS multiboot_normal (u16* data, u16* end) {
#ifndef HAS_SIO
enum MULTIBOOT_RESULTS multiboot_normal (u16* UNUSED(data), u16* UNUSED(end), int UNUSED(is_normal)) {
#else
enum MULTIBOOT_RESULTS multiboot_normal (u16* UNUSED(data), u16* UNUSED(end)) {
#endif
#ifdef HAS_SIO
int response;
enum MULTIBOOT_RESULTS multiboot_normal (u16* data, u16* end, int is_normal) {
u16 response[MAX_NUM_SLAVES];
u8 clientMask = 0;
u8 client_bit;
int attempts, sends, halves;
u8 answer, handshake;
u8 answers[MAX_NUM_SLAVES] = {0xFF, 0xFF, 0xFF};
u8 handshake;
u8 sendMask;
u8 attempt_counter;
const u8 palette = 0x81;
const int paletteCmd = 0x6300 | palette;
enum MULTIBOOT_MODES mb_mode = MODE32_NORMAL;
MultiBootParam mp;
if(!is_normal)
mb_mode = MODE16_MULTI;
init_sio_normal(SIO_MASTER, SIO_32);
if(is_normal)
init_sio_normal(SIO_MASTER, SIO_32);
else
init_sio_multi(SIO_MASTER);
print_multiboot_mid_process(0);
prepare_flush();
for(attempts = 0; attempts < 128; attempts++) {
for(sends = 0; sends < 16; sends++) {
response = multiboot_normal_send(0x6200);
multiboot_send(0x6200, is_normal, response);
if((response & 0xfff0) == 0x7200) {
clientMask = (response & 0xf);
if(clientMask)
break;
}
for(int i = 0; i < MAX_NUM_SLAVES; i++)
if((response[i] & 0xFFF0) == 0x7200) {
clientMask |= response[i];
}
}
if(clientMask)
@ -58,46 +75,85 @@ enum MULTIBOOT_RESULTS multiboot_normal (u16* UNUSED(data), u16* UNUSED(end)) {
}
clientMask &= 0xF;
response = multiboot_normal_send(0x6100 | clientMask);
if(response != (0x7200 | clientMask))
return MB_WRONG_ANSWER;
multiboot_send(0x6100 | clientMask, is_normal, response);
for(int i = 0; i < MAX_NUM_SLAVES; i++) {
client_bit = 1 << (i + 1);
for(halves = 0; halves < 0x60; ++halves)
if(multiboot_normal_send(*data++) != ((0x60 - halves) << 8 | clientMask))
return MB_HEADER_ISSUE;
if ((clientMask & client_bit) && (response[i] != (0x7200 | client_bit)))
return MB_WRONG_ANSWER;
}
response = multiboot_normal_send(0x6200);
if(response != (clientMask))
return MB_WRONG_ANSWER;
for(halves = 0; halves < 0x60; ++halves) {
multiboot_send(*data++, is_normal, response);
for(int i = 0; i < MAX_NUM_SLAVES; i++) {
client_bit = 1 << (i + 1);
response = multiboot_normal_send(0x6200 | clientMask);
if(response != (0x7200 | clientMask))
return MB_WRONG_ANSWER;
if ((clientMask & client_bit) && (response[i] != (((0x60 - halves) << 8) | client_bit)))
return MB_HEADER_ISSUE;
}
}
while((response & 0xFF00) != 0x7300)
response = multiboot_normal_send(paletteCmd);
multiboot_send(0x6200, is_normal, response);
for(int i = 0; i < MAX_NUM_SLAVES; i++) {
client_bit = 1 << (i + 1);
answer = response&0xFF;
handshake = 0x11 + 0xFF + 0xFF + answer;
if ((clientMask & client_bit) && (response[i] != client_bit))
return MB_WRONG_ANSWER;
}
response = multiboot_normal_send(0x6400 | handshake);
if((response & 0xFF00) != 0x7300)
return MB_WRONG_ANSWER;
multiboot_send(0x6200 | clientMask, is_normal, response);
for(int i = 0; i < MAX_NUM_SLAVES; i++) {
client_bit = 1 << (i + 1);
if ((clientMask & client_bit) && (response[i] != (0x7200 | client_bit)))
return MB_WRONG_ANSWER;
}
sendMask = clientMask;
attempt_counter = 0;
while(sendMask) {
multiboot_send(0x6300 | palette, is_normal, response);
for(int i = 0; i < MAX_NUM_SLAVES; i++) {
client_bit = 1 << (i + 1);
if ((clientMask & client_bit) && ((response[i] & 0xFF00) == 0x7300)) {
answers[i] = response[i] & 0xFF;
sendMask &= ~client_bit;
}
}
attempt_counter++;
if((attempt_counter == MAX_PALETTE_ATTEMPTS) && sendMask)
return MB_PALETTE_FAILURE;
}
handshake = 0x11;
for(int i = 0; i < MAX_NUM_SLAVES; i++)
handshake += answers[i];
multiboot_send(0x6400 | handshake, is_normal, response);
for(int i = 0; i < MAX_NUM_SLAVES; i++) {
client_bit = 1 << (i + 1);
if ((clientMask & client_bit) && ((response[i] & 0xFF00) != 0x7300))
return MB_WRONG_ANSWER;
}
print_multiboot_mid_process(1);
prepare_flush();
VBlankIntrWait();
mp.handshake_data = handshake;
mp.client_data[0] = answer;
mp.client_data[1] = 0xFF;
mp.client_data[2] = 0xFF;
for(int i = 0; i < MAX_NUM_SLAVES; i++)
mp.client_data[i] = answers[i];
mp.palette_data = palette;
mp.client_bit = clientMask;
mp.boot_srcp = (u8*)data;
mp.boot_endp = (u8*)end;
if(MultiBoot(&mp, MODE32_NORMAL))
if(MultiBoot(&mp, mb_mode))
return MB_SWI_FAILURE;
#endif

View File

@ -926,13 +926,14 @@ void recalc_stats_gen3(struct gen3_mon_data_unenc* data_dst, struct gen3_mon* ds
u8 is_pokerus_strain_valid_gen3(u8 pokerus_byte) {
if(!pokerus_byte)
return 1;
if(!((pokerus_byte >> 4) & 7))
return 0;
// Ruby and Sapphire can have Pokerus strains 0 and 8
//if(!((pokerus_byte >> 4) & 7))
// return 0;
return 1;
}
u8 get_pokerus_strain_max_days_gen3(u8 pokerus_byte) {
if(!((pokerus_byte >> 4) & 7))
if(!is_pokerus_strain_valid_gen3(pokerus_byte))
return 0;
return ((pokerus_byte >> 4) & 3) + 1;
}

View File

@ -44,6 +44,9 @@
#define COLO_MOD_PART 0x12D96
#define COLO_DIV_PART 0x2732
#define CHANNEL_SEED_SPACE_SIZE (1 << (32 - 4))
#define CHANNEL_SEED_MASK (CHANNEL_SEED_SPACE_SIZE - 1)
#define STATIC_IV_MASK (((0xF<<10) | (0xF<<5))<<(16+1))
#define NUM_SEEDS 0x10000
@ -70,6 +73,11 @@ void _generate_egg_info(u8, u16, u16, u8, u8, u32*, u32*, u32);
void _generate_egg_shiny_info(u8, u16, u8, u8, u32*, u32*, u32);
void _convert_roamer_to_colo_info(u8, u16, u8, u8, u16, u32*, u32*, u8*, u32);
void _generate_generic_genderless_info(u8, u16, u16, u32*, u32*, u8*, u32, genderless_generator_functions_t);
static u8 validate_channel_pattern_seed(u32);
static u8 validate_channel_seed(u32);
void _generate_channel_info(u8, u16, u32*, u32*, u32, u16*, u8*, u8*);
static u8 is_shiny_channel_valid_seed(u32, u16, u16, u8, u32*, u32*, u16*, u8*, u8*);
void _generate_channel_shiny_info(u8, u32*, u32*, u32, u16*, u8*, u8*);
u8 _generator_static_info(u16, u16, u8, u16, u32*, u32*, u8*);
u8 _generator_generic_shadow_info_colo(u16, u16, u8, u16, u32*, u32*, u8*);
u8 _generator_generic_shadow_info_xd(u16, u16, u8, u16, u32*, u32*, u8*);
@ -299,6 +307,11 @@ u8 are_colo_valid_tid_sid(u16 tid, u16 sid) {
return (get_seed_colo(possible_seeds, tid, sid) > 0) ? 1 : 0;
}
u8 are_rs_valid_tid_sid(u16 tid, u16 sid) {
u32 possible_seeds[3];
return (get_seed_gba3(possible_seeds, sid, tid) > 0) ? 1 : 0;
}
u32 generate_ot(u16 tid, u8* name) {
// Worst case: ANY
// This should NOT be random...
@ -321,7 +334,7 @@ u32 generate_ot(u16 tid, u8* name) {
seed = get_next_seed(seed);
sid = seed >> 0x10;
}
while(is_bad_tsv(sid^tid) && (!are_colo_valid_tid_sid(tid, sid)));
while(is_bad_tsv(sid^tid) && (!are_colo_valid_tid_sid(tid, sid)) && (!are_rs_valid_tid_sid(tid, sid)));
return (sid << 0x10) | tid;
}
@ -609,6 +622,213 @@ void _generate_generic_genderless_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv
*dst_ivs = 0;
}
// Adapted from: https://github.com/Admiral-Fish/PokeFinder/blob/master/Source/Core/Gen3/Searchers/GameCubeSearcher.cpp
ALWAYS_INLINE u8 validate_channel_pattern_seed(u32 base_pattern_seed) {
u8 target = base_pattern_seed >> 30;
if(target == 0)
return 0;
u8 mask = 1 << target;
while ((mask & 14) != 14) {
base_pattern_seed = get_prev_seed_colo(base_pattern_seed);
u8 num = base_pattern_seed >> 30;
if (num == target)
return 0;
mask |= 1 << num;
}
return 1;
}
// Adapted from: https://github.com/Admiral-Fish/PokeFinder/blob/master/Source/Core/Gen3/Searchers/GameCubeSearcher.cpp
ALWAYS_INLINE u8 validate_channel_seed(u32 origin_seed) {
u32 first_seed = get_prev_seed_colo(origin_seed);
u32 second_seed = get_prev_seed_colo(first_seed);
u32 third_seed = get_prev_seed_colo(second_seed);
u16 num1 = first_seed >> 16;
u16 num2 = second_seed >> 16;
u16 num3 = third_seed >> 16;
u32 six_seed = get_prev_seed_colo(get_prev_seed_colo(get_prev_seed_colo(third_seed)));
u32 seven_seed = get_prev_seed_colo(six_seed);
// 8 advances
if((num3 > 0x4000) && (num2 > 0x547a) && validate_channel_pattern_seed(get_prev_seed_colo(seven_seed)))
return 1;
// 7 advances
if((num2 > 0x4000) && (num1 <= 0x547a) && validate_channel_pattern_seed(seven_seed))
return 1;
// 6 advances
if((num1 <= 0x4000) && validate_channel_pattern_seed(six_seed))
return 1;
return 0;
}
IWRAM_CODE MAX_OPTIMIZE void _generate_channel_info(u8 wanted_nature, u16 wanted_ivs, u32* dst_pid, u32* dst_ivs, u32 start_seed, u16* dst_sid, u8* dst_gender, u8* dst_game) {
// Very slow code to convert to a Channel mon (not actually used)
u8 base_atk_ivs = ((wanted_ivs>>4) & 0xF)<<1;
u8 base_def_ivs = ((wanted_ivs) & 0xF)<<1;
u8 base_spe_ivs = ((wanted_ivs>>12) & 0xF)<<1;
u8 base_spa_ivs = ((wanted_ivs>>8) & 0xF)<<1;
u32 rng_base_seed = start_seed & CHANNEL_SEED_MASK;
int increase = 1;
if(start_seed & CHANNEL_SEED_SPACE_SIZE)
increase = -1;
// Iter the free bits for attack
for(size_t i = 0; i < CHANNEL_SEED_SPACE_SIZE; i++) {
u32 atk_seed = (base_atk_ivs << 28) | rng_base_seed;
rng_base_seed = (rng_base_seed + increase) & CHANNEL_SEED_MASK;
u8 atk_iv = atk_seed >> 27;
u32 curr_seed = get_next_seed_colo(atk_seed);
u8 def_iv = curr_seed >> 27;
if((def_iv & (0xF << 1)) != base_def_ivs)
continue;
curr_seed = get_next_seed_colo(curr_seed);
u8 spe_iv = curr_seed >> 27;
if((spe_iv & (0xF << 1)) != base_spe_ivs)
continue;
curr_seed = get_next_seed_colo(curr_seed);
u8 spa_iv = curr_seed >> 27;
curr_seed = get_next_seed_colo(curr_seed);
u8 spd_iv = curr_seed >> 27;
if((((spa_iv + spd_iv) >> 1) & (0xF << 1)) != base_spa_ivs)
continue;
curr_seed = get_prev_seed_colo(atk_seed);
u8 hp_iv = curr_seed >> 27;
curr_seed = get_prev_seed_colo(curr_seed);
u8 gender = curr_seed >> 31;
curr_seed = get_prev_seed_colo(curr_seed);
u8 game = curr_seed >> 31;
curr_seed = get_prev_seed_colo(curr_seed);
//u8 berry = curr_seed >> 31;
curr_seed = get_prev_seed_colo(curr_seed);
u16 low = curr_seed >> 16;
curr_seed = get_prev_seed_colo(curr_seed);
u16 high = curr_seed >> 16;
curr_seed = get_prev_seed_colo(curr_seed);
u16 sid = curr_seed >> 16;
const u16 tid = 40122;
if(tid ^ sid ^ high ^ (low < 8))
high ^= 0x8000;
u32 pid = (high << 16) | low;
if((tid ^ sid ^ high ^ low) < 8)
continue;
u8 nature = get_nature_fast(pid);
if(nature != wanted_nature)
continue;
if(validate_channel_seed(get_prev_seed_colo(curr_seed))) {
*dst_pid = pid;
*dst_sid = sid;
*dst_gender = gender;
*dst_game = game;
*dst_ivs = (hp_iv << 0) | (atk_iv << 5) | (def_iv << 10) | (spe_iv << 15) | (spa_iv << 20) | (spd_iv << 25);
return;
}
}
*dst_pid = 0;
*dst_sid = 0;
*dst_gender = 0;
*dst_game = 0;
*dst_ivs = 0;
}
void generate_channel_info(u8 wanted_nature, u16 wanted_ivs, u32* dst_pid, u32* dst_ivs, u16* dst_sid, u8* dst_gender, u8* dst_game) {
_generate_channel_info(wanted_nature, wanted_ivs, dst_pid, dst_ivs, get_rng(), dst_sid, dst_gender, dst_game);
}
ALWAYS_INLINE u8 is_shiny_channel_valid_seed(u32 sid_seed, u16 high, u16 low, u8 is_forward, u32* dst_pid, u32* dst_ivs, u16* dst_sid, u8* dst_gender, u8* dst_game) {
const u16 tid = 40122;
u16 sid = sid_seed >> 16;
u32 pid = (high << 16) | low;
if(is_forward && (tid ^ sid ^ high ^ (low < 8)))
return 0;
if((!is_forward) && (!(tid ^ sid ^ (high ^ 0x8000) ^ (low < 8))))
return 0;
if((tid ^ sid ^ high ^ low) >= 8)
return 0;
if(validate_channel_seed(get_prev_seed_colo(sid_seed))) {
*dst_pid = pid;
*dst_sid = sid;
u32 curr_seed = get_next_seed_colo(get_next_seed_colo(get_next_seed_colo(sid_seed)));
//u8 berry = curr_seed >> 31;
curr_seed = get_next_seed_colo(curr_seed);
u8 game = curr_seed >> 31;
curr_seed = get_next_seed_colo(curr_seed);
u8 gender = curr_seed >> 31;
curr_seed = get_next_seed_colo(curr_seed);
u8 hp_iv = curr_seed >> 27;
curr_seed = get_next_seed_colo(curr_seed);
u8 atk_iv = curr_seed >> 27;
curr_seed = get_next_seed_colo(curr_seed);
u8 def_iv = curr_seed >> 27;
curr_seed = get_next_seed_colo(curr_seed);
u8 spe_iv = curr_seed >> 27;
curr_seed = get_next_seed_colo(curr_seed);
u8 spa_iv = curr_seed >> 27;
curr_seed = get_next_seed_colo(curr_seed);
u8 spd_iv = curr_seed >> 27;
*dst_gender = gender;
*dst_game = game;
*dst_ivs = (hp_iv << 0) | (atk_iv << 5) | (def_iv << 10) | (spe_iv << 15) | (spa_iv << 20) | (spd_iv << 25);
return 1;
}
return 0;
}
IWRAM_CODE MAX_OPTIMIZE void _generate_channel_shiny_info(u8 wanted_nature, u32* dst_pid, u32* dst_ivs, u32 start_seed, u16* dst_sid, u8* dst_gender, u8* dst_game) {
// Code to convert to a shiny Channel mon (not actually used)
u32 pid = start_seed;
u8 nature = get_nature_fast(pid);
u8 nature_diff = wanted_nature - nature;
if(nature > wanted_nature)
nature_diff = wanted_nature - nature + NUM_NATURES;
pid += nature_diff;
if(pid < NUM_NATURES)
pid = wanted_nature;
u32 start_pid = pid;
do {
u16 high = pid >> 16;
u16 low = pid & 0xFFFF;
u32 possible_seeds[4];
u8 num_found = 0;
num_found = get_seed_colo(possible_seeds, high, low);
for(size_t i = 0; i < num_found; i++)
if(is_shiny_channel_valid_seed(possible_seeds[i], high, low, 1, dst_pid, dst_ivs, dst_sid, dst_gender, dst_game))
return;
num_found = get_seed_colo(possible_seeds, high ^ 0x8000, low);
for(size_t i = 0; i < num_found; i++)
if(is_shiny_channel_valid_seed(possible_seeds[i], high, low, 0, dst_pid, dst_ivs, dst_sid, dst_gender, dst_game))
return;
pid += NUM_NATURES;
if(pid < NUM_NATURES)
pid = wanted_nature;
} while(pid != start_pid);
*dst_pid = 0;
*dst_sid = 0;
*dst_gender = 0;
*dst_game = 0;
*dst_ivs = 0;
}
void generate_channel_shiny_info(u8 wanted_nature, u32* dst_pid, u32* dst_ivs, u16* dst_sid, u8* dst_gender, u8* dst_game) {
_generate_channel_shiny_info(wanted_nature, dst_pid, dst_ivs, get_rng(), dst_sid, dst_gender, dst_game);
}
u8 _generator_static_info(u16 first, u16 second, u8 wanted_nature, u16 tsv, u32* dst_pid, u32* dst_ivs, u8* UNUSED(dst_ability)) {
u32 possible_seeds[3*2*2];
u8 num_found = get_reverse_masked_ivs_gba3(possible_seeds, second, first);
@ -1112,7 +1332,8 @@ void worst_case_conversion_tester(vu32* counter) {
u32 curr_counter = *counter;
u32 max_counter = 0;
u32 pid, ivs;
u8 ability;
u16 sid;
u8 ability, game, gender;
VBlankIntrWait();
curr_counter = *counter;
@ -1204,5 +1425,23 @@ void worst_case_conversion_tester(vu32* counter) {
max_counter = ((*counter)-curr_counter);
PRINT_FUNCTION("Max time conv s: 0x\x04\n", max_counter);
VBlankIntrWait();
curr_counter = *counter;
_generate_channel_info(4, 0xFFFF, &pid, &ivs, 0, &sid, &gender, &game);
max_counter = ((*counter)-curr_counter);
PRINT_FUNCTION("Random time c p: 0x\x04\n", max_counter);
VBlankIntrWait();
curr_counter = *counter;
_generate_channel_shiny_info(4, &pid, &ivs, 0, &sid, &gender, &game);
max_counter = ((*counter)-curr_counter);
PRINT_FUNCTION("Random time c s: 0x\x04\n", max_counter);
#endif
}

View File

@ -188,6 +188,13 @@ void init_text_system() {
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
REG_DISPCNT_SUB = 0 | TILE_1D_MAP | ACTIVATE_SCREEN_HW;
#endif
#ifdef __NDS__
vramSetBankA(VRAM_A_MAIN_BG);
vramSetBankB(VRAM_B_MAIN_SPRITE);
vramSetBankC(VRAM_C_SUB_BG);
vramSetBankD(VRAM_D_SUB_SPRITE);
#endif
screens_flush = 0;
for(int i = 0; i < TOTAL_BG; i++) {
enabled_screen[i] = 0;

View File

@ -3,6 +3,7 @@
#include <stddef.h>
#include "useful_qualifiers.h"
#include "timing_basic.h"
#include "delays.h"
#define IS_FLASH 1
#define SAVE_POS SRAM
@ -14,8 +15,9 @@
#define FLASH_TERM_CMD *((vu8*)(SAVE_POS+0x5555)) = 0xF0;
#define FLASH_ENTER_MAN_CMD BASE_FLASH_CMD *((vu8*)(SAVE_POS+0x5555)) = 0x90;
#define FLASH_EXIT_MAN_CMD BASE_FLASH_CMD FLASH_TERM_CMD FLASH_TERM_CMD
#define TIMEOUT (50000*(((CLOCK_SPEED + GBA_CLOCK_SPEED - 1)/GBA_CLOCK_SPEED) + TIMEOUT_INCREASE))
#define ERASE_TIMEOUT (TIMEOUT)
#define ID_TIMEOUT_CYCLES CLOCK_CYCLES_PER_MS(28)
#define TIMEOUT_CYCLES CLOCK_CYCLES_PER_MS(10)
#define ERASE_TIMEOUT_CYCLES CLOCK_CYCLES_PER_MS(2000)
#define ERASED_BYTE 0xFF
#define BANK_SIZE 0x10000
#define NUM_BANKS 2
@ -31,30 +33,31 @@
#define BANK_LIMIT (NUM_BANKS * BANK_SIZE)
#endif
uintptr_t bank_check(uintptr_t);
static uintptr_t bank_check(uintptr_t);
static size_t sanitize_save_size(uintptr_t, size_t);
static u8 read_direct_single_byte_save(uintptr_t);
static void write_direct_single_byte_save(uintptr_t, u8);
u8 current_bank;
u8 is_macronix;
IWRAM_CODE void init_bank(){
IWRAM_CODE void init_bank() {
REG_WAITCNT &= NON_SRAM_MASK;
REG_WAITCNT |= SRAM_READING_VALID_WAITCYCLES;
current_bank = NUM_BANKS;
is_macronix = 0;
#if IS_FLASH
FLASH_ENTER_MAN_CMD
for(vu32 j = 0; j < TIMEOUT; j++);
delay_cycles(ID_TIMEOUT_CYCLES);
u8 man_id = *((vu8*)SAVE_POS);
if((man_id == MACRONIX_MAN_ID) || (man_id == SANYO_MAN_ID) || (man_id == DEFAULT_MAN_ID))
is_macronix = 1;
FLASH_EXIT_MAN_CMD
for(vu32 j = 0; j < TIMEOUT; j++);
delay_cycles(ID_TIMEOUT_CYCLES);
#endif
}
IWRAM_CODE uintptr_t bank_check(uintptr_t address){
IWRAM_CODE uintptr_t bank_check(uintptr_t address) {
address %= (NUM_BANKS * BANK_SIZE);
#if IS_FLASH
u8 bank = address / BANK_SIZE;
@ -84,7 +87,7 @@ IWRAM_CODE void erase_sector(uintptr_t address) {
save_data[address+(SECTOR_SIZE-1)-j] = ERASED_BYTE;
#endif
for(vu32 j = 0; j < ERASE_TIMEOUT; j++);
delay_cycles_until(ERASE_TIMEOUT_CYCLES, &save_data[address], 0xFF, SRAM_ACCESS_CYCLES);
failed = 0;
for(size_t j = 0; j < SECTOR_SIZE; j++)
@ -108,109 +111,116 @@ IWRAM_CODE void write_direct_single_byte_save(uintptr_t address, u8 data) {
FLASH_WRITE_CMD
#endif
save_data[address] = data;
for(vu32 j = 0; (j < TIMEOUT) && (save_data[address] != data); j++);
delay_cycles_until(TIMEOUT_CYCLES, &save_data[address], data, SRAM_ACCESS_CYCLES);
if(is_macronix && (save_data[address] != data))
FLASH_TERM_CMD
}
}
IWRAM_CODE u8 read_byte_save(uintptr_t address){
IWRAM_CODE u8 read_byte_save(uintptr_t address) {
address = bank_check(address);
return read_direct_single_byte_save(address);
}
IWRAM_CODE void write_byte_save(uintptr_t address, u8 data){
IWRAM_CODE u16 read_short_save(uintptr_t address) {
u16 data_out = 0;
copy_save_to_ram(address, (u8*)&data_out, sizeof(u16));
return data_out;
}
IWRAM_CODE u32 read_int_save(uintptr_t address) {
u32 data_out = 0;
copy_save_to_ram(address, (u8*)&data_out, sizeof(u32));
return data_out;
}
IWRAM_CODE void write_byte_save(uintptr_t address, u8 data) {
address = bank_check(address);
write_direct_single_byte_save(address, data);
}
IWRAM_CODE u32 read_int_save(uintptr_t address){
IWRAM_CODE void write_short_save(uintptr_t address, u16 data) {
u16 data_in = data;
copy_ram_to_save((u8*)&data_in, address, sizeof(u16));
}
IWRAM_CODE void write_int_save(uintptr_t address, u32 data) {
u32 data_in = data;
copy_ram_to_save((u8*)&data_in, address, sizeof(u32));
}
IWRAM_CODE size_t sanitize_save_size(uintptr_t address, size_t size) {
address %= NUM_BANKS * BANK_SIZE;
if((address + size) > (NUM_BANKS * BANK_SIZE))
size = (NUM_BANKS * BANK_SIZE) - address;
return size;
}
IWRAM_CODE void copy_save_to_ram(uintptr_t address, u8* destination, size_t size) {
// Sanitize size
size = sanitize_save_size(address, size);
address = bank_check(address);
u32 data_out = 0;
if((address + sizeof(u32)) > BANK_LIMIT) {
for(size_t i = 0; i < sizeof(u32); i++)
data_out += read_byte_save(address + i) << (i*8);
}
else {
for(size_t i = 0; i < sizeof(u32); i++)
data_out += read_direct_single_byte_save(address + i) << (i*8);
}
return data_out;
}
size_t num_banks = (address + size + BANK_SIZE - 1) / BANK_SIZE;
for(size_t n = 0; n < num_banks; n++) {
size_t inner_size = size;
if(n != (num_banks - 1))
inner_size = BANK_SIZE - address;
IWRAM_CODE u16 read_short_save(uintptr_t address){
address = bank_check(address);
u16 data_out = 0;
if((address + sizeof(u16)) > BANK_LIMIT) {
for(size_t i = 0; i < sizeof(u16); i++)
data_out += read_byte_save(address + i) << (i*8);
}
else {
for(size_t i = 0; i < sizeof(u16); i++)
data_out += read_direct_single_byte_save(address + i) << (i*8);
}
return data_out;
}
for(size_t i = 0; i < inner_size; i++)
destination[i] = read_direct_single_byte_save(address + i);
IWRAM_CODE void write_int_save(uintptr_t address, u32 data){
address = bank_check(address);
if((address + sizeof(u32)) > BANK_LIMIT) {
for(size_t i = 0; i < sizeof(u32); i++)
write_byte_save(address + i, (data >> (i*8)) & 0xFF);
}
else {
for(size_t i = 0; i < sizeof(u32); i++)
write_direct_single_byte_save(address + i, (data >> (i*8)) & 0xFF);
if(n != (num_banks - 1)) {
address = bank_check(address + inner_size);
destination += inner_size;
size -= inner_size;
}
}
}
IWRAM_CODE void write_short_save(uintptr_t address, u16 data){
address = bank_check(address);
if((address + sizeof(u16)) > BANK_LIMIT) {
for(size_t i = 0; i < sizeof(u16); i++)
write_byte_save(address + i, (data >> (i*8)) & 0xFF);
}
else {
for(size_t i = 0; i < sizeof(u16); i++)
write_direct_single_byte_save(address + i, (data >> (i*8)) & 0xFF);
}
}
IWRAM_CODE void copy_ram_to_save(u8* base_address, uintptr_t save_address, size_t size) {
// Sanitize size
size = sanitize_save_size(save_address, size);
IWRAM_CODE void copy_save_to_ram(uintptr_t base_address, u8* new_address, size_t size){
base_address = bank_check(base_address);
if((base_address + size) > BANK_LIMIT) {
for(size_t i = 0; i < size; i++)
new_address[i] = read_byte_save(base_address + i);
}
else {
for(size_t i = 0; i < size; i++)
new_address[i] = read_direct_single_byte_save(base_address + i);
}
}
IWRAM_CODE void copy_ram_to_save(u8* base_address, uintptr_t save_address, size_t size){
save_address = bank_check(save_address);
if((save_address + size) > BANK_LIMIT) {
for(size_t i = 0; i < size; i++)
write_byte_save(save_address + i, base_address[i]);
}
else {
for(size_t i = 0; i < size; i++)
size_t num_banks = (save_address + size + BANK_SIZE - 1) / BANK_SIZE;
for(size_t n = 0; n < num_banks; n++) {
size_t inner_size = size;
if(n != (num_banks - 1))
inner_size = BANK_SIZE - save_address;
for(size_t i = 0; i < inner_size; i++)
write_direct_single_byte_save(save_address + i, base_address[i]);
if(n != (num_banks - 1)) {
save_address = bank_check(save_address + inner_size);
base_address += inner_size;
size -= inner_size;
}
}
}
IWRAM_CODE u8 is_save_correct(u8* base_address, uintptr_t save_address, size_t size) {
// Sanitize size
size = sanitize_save_size(save_address, size);
save_address = bank_check(save_address);
if((save_address + size) > BANK_LIMIT) {
for(size_t i = 0; i < size; i++)
if(read_byte_save(save_address + i) != base_address[i])
return 0;
}
else {
for(size_t i = 0; i < size; i++)
size_t num_banks = (save_address + size + BANK_SIZE - 1) / BANK_SIZE;
for(size_t n = 0; n < num_banks; n++) {
size_t inner_size = size;
if(n != (num_banks - 1))
inner_size = BANK_SIZE - save_address;
for(size_t i = 0; i < inner_size; i++)
if(read_direct_single_byte_save(save_address + i) != base_address[i])
return 0;
if(n != (num_banks - 1)) {
save_address = bank_check(save_address + inner_size);
base_address += inner_size;
size -= inner_size;
}
}
return 1;
}

View File

@ -6,33 +6,46 @@
void sio_normal_inner_slave(void);
u8 sio_normal_inner_master(void);
void sio_write(u32);
void timed_wait_master(int);
#ifdef HAS_SIO
IWRAM_CODE int timed_sio_normal_master(int data, int is_32, int vCountWait) {
IWRAM_CODE void timed_wait_master(int vCountWait) {
u8 curr_vcount, target_vcount;
if(is_32)
REG_SIODATA32 = data;
else
REG_SIODATA8 = (data & 0xFF);
// - Wait at least 36 us between sends (this is a bit more, but it works)
curr_vcount = REG_VCOUNT;
target_vcount = curr_vcount + vCountWait;
if(target_vcount >= SCANLINES)
target_vcount -= SCANLINES;
while (target_vcount != REG_VCOUNT);
// - Set Start flag.
REG_SIOCNT |= SIO_START;
// - Wait for IRQ (or for Start bit to become zero).
while (REG_SIOCNT & SIO_START);
}
IWRAM_CODE int timed_sio_normal_master(int data, int is_32, int vCountWait) {
sio_write(data);
timed_wait_master(vCountWait);
// - Process received data.
if(is_32)
return REG_SIODATA32;
else
return (REG_SIODATA8 & 0xFF);
return sio_read(is_32);
}
IWRAM_CODE void timed_sio_multi_master(int data, int vCountWait, u16* out_buff) {
if(REG_SIOCNT & SIO_RDY)
return;
REG_SIOMLT_SEND = (data & 0xFFFF);
timed_wait_master(vCountWait);
// - Process received data.
for(int i = 0; i < MAX_NUM_SLAVES; i++)
out_buff[i] = *((&REG_SIOMULTI1) + i);
}
IWRAM_CODE void sio_normal_inner_slave() {
@ -54,8 +67,7 @@ IWRAM_CODE void sio_normal_inner_slave() {
IWRAM_CODE MAX_OPTIMIZE void sio_handle_irq_slave(int next_data) {
REG_SIOCNT |= SIO_SO_HIGH;
REG_SIODATA32 = next_data;
REG_SIODATA8 = next_data;
sio_write(next_data);
REG_SIOCNT &= ~(SIO_START | SIO_SO_HIGH);
// - Set Start=1 and SO=1 (SO=HIGH indicates not ready, applied after transfer).
@ -67,12 +79,17 @@ IWRAM_CODE MAX_OPTIMIZE void sio_handle_irq_slave(int next_data) {
}
IWRAM_CODE MAX_OPTIMIZE int sio_read(u8 is_32) {
u32 data = REG_SIODATA8;
u32 data = (REG_SIODATA8 & 0xFF);
if(is_32)
data = REG_SIODATA32;
return data;
}
IWRAM_CODE MAX_OPTIMIZE void sio_write(u32 data) {
REG_SIODATA32 = data;
REG_SIODATA8 = (data & 0xFF);
}
IWRAM_CODE void sio_stop_irq_slave() {
REG_SIOCNT &= ~SIO_SO_HIGH;
REG_SIOCNT &= ~SIO_IRQ;
@ -80,9 +97,8 @@ IWRAM_CODE void sio_stop_irq_slave() {
IWRAM_CODE void sio_normal_prepare_irq_slave(int data) {
// - Initialize data which is to be sent to master.
REG_SIODATA32 = data;
REG_SIODATA8 = (data & 0xFF);
sio_write(data);
REG_SIOCNT |= SIO_IRQ;
// - Set Start=0 and SO=0 (SO=LOW indicates that slave is (almost) ready).
@ -97,8 +113,8 @@ IWRAM_CODE void sio_normal_prepare_irq_slave(int data) {
IWRAM_CODE MAX_OPTIMIZE u32 sio_send_if_ready_master(u32 data, u8 is_32, u8* success) {
// - Wait for SI to become LOW (slave ready). (Check timeout here!)
REG_SIODATA32 = data;
REG_SIODATA8 = (data & 0xFF);
sio_write(data);
if (!(REG_SIOCNT & SIO_RDY)) {
// - Set Start flag.
REG_SIOCNT |= SIO_START;
@ -113,8 +129,8 @@ IWRAM_CODE MAX_OPTIMIZE u32 sio_send_if_ready_master(u32 data, u8 is_32, u8* suc
IWRAM_CODE MAX_OPTIMIZE u32 sio_send_master(u32 data, u8 is_32) {
// - Wait for SI to become LOW (slave ready). (Check timeout here!)
REG_SIODATA32 = data;
REG_SIODATA8 = (data & 0xFF);
sio_write(data);
// - Set Start flag.
REG_SIOCNT |= SIO_START;
// - Wait for IRQ (or for Start bit to become zero).
@ -141,7 +157,7 @@ IWRAM_CODE u8 sio_normal_inner_master() {
IWRAM_CODE void init_sio_normal(int is_master, int is_32) {
u16 sio_cnt_val = 0;
if(is_32)
sio_cnt_val |= SIO_32BIT;
else
@ -151,28 +167,33 @@ IWRAM_CODE void init_sio_normal(int is_master, int is_32) {
sio_cnt_val |= SIO_CLK_INT;
else
sio_cnt_val |= SIO_SO_HIGH;
REG_RCNT = R_NORMAL;
REG_SIOCNT = sio_cnt_val;
}
IWRAM_CODE void init_sio_multi(int is_master) {
u16 sio_cnt_val = SIO_MULTI | SIO_57600;
if(is_master)
sio_cnt_val |= SIO_CLK_INT;
else
sio_cnt_val |= SIO_SO_HIGH;
REG_RCNT = R_MULTI;
REG_SIOCNT = sio_cnt_val;
}
IWRAM_CODE int sio_normal(int data, int is_master, int is_32, u8* success) {
// - Initialize data which is to be sent to master.
if(is_32)
REG_SIODATA32 = data;
else
REG_SIODATA8 = (data & 0xFF);
sio_write(data);
if(is_master)
*success = sio_normal_inner_master();
else
sio_normal_inner_slave();
// - Process received data.
if(is_32)
return REG_SIODATA32;
else
return (REG_SIODATA8 & 0xFF);
return sio_read(is_32);
}
#endif

View File

@ -144,12 +144,13 @@ void load_names_gen12(struct game_data_t* game_data, struct gen2_party* party_2,
if(is_jp)
language = JAPANESE_LANGUAGE;
convert_trainer_name_gen3_to_gen12(game_data->trainer_name, trainer_name, game_data->game_identifier.language, language);
convert_trainer_name_gen3_to_gen12(game_data->trainer_name, trainer_name, game_data->game_identifier.language, language, 0);
for(size_t i = 0; i < size; i++)
if((trainer_name[i] == NO_ACTION_BYTE) || (trainer_name[i] == (NO_ACTION_BYTE-1)))
trainer_name[i] = NO_ACTION_BYTE-2;
trainer_name[size-1] = GEN2_EOL;
u8 text_size = text_gen2_size(trainer_name, size-1);
trainer_name[text_size] = GEN2_EOL;
if(!curr_gen)
return;
@ -174,9 +175,11 @@ void load_names_gen12(struct game_data_t* game_data, struct gen2_party* party_2,
src_nickname = party_1->mons[i].nickname;
}
copy_bytes(src_ot_name, ot_names, size, 0, i*size);
ot_names[(i*size)+size-1] = GEN2_EOL;
text_size = text_gen2_size(&ot_names[i*size], size-1);
ot_names[(i*size)+text_size] = GEN2_EOL;
copy_bytes(src_nickname, nicknames, size, 0, i*size);
nicknames[(i*size)+size-1] = GEN2_EOL;
text_size = text_gen2_size(&nicknames[i*size], size-1);
nicknames[(i*size)+text_size] = GEN2_EOL;
}
}

View File

@ -167,7 +167,7 @@ void sanitize_name_general_to_general(const u8* src, u8* dst, const u8* default_
size_t question_marks_count = question_marks_count_dst - question_marks_count_src;
if(question_marks_count_src > question_marks_count_dst)
question_marks_count = 0;
if((question_marks_count >= (text_general_size(dst, dst_size, dst_terminator) >> 1)) || (!text_general_size(dst, dst_size, dst_terminator)))
if((question_marks_count >= ((text_general_size(dst, dst_size, dst_terminator) + 1) >> 1)) || (!text_general_size(dst, dst_size, dst_terminator)))
text_general_copy(default_name, dst, dst_size, dst_size, dst_terminator);
}