diff --git a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml index 4564bad007..e06d7a2f5d 100644 --- a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml +++ b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml @@ -43,17 +43,15 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.13.3 (Latest release) + - 1.14.0 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.13.4 + - 1.13.3 - 1.13.2 - 1.13.1 - 1.13.0 - - 1.12.3 - - 1.12.2 - - 1.12.1 - - 1.12.0 - - pre-1.12.0 + - pre-1.13.0 validations: required: true - type: input diff --git a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml index 8ee1d1cc17..38f171b721 100644 --- a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml +++ b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml @@ -43,17 +43,15 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.13.3 (Latest release) + - 1.14.0 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.13.4 + - 1.13.3 - 1.13.2 - 1.13.1 - 1.13.0 - - 1.12.3 - - 1.12.2 - - 1.12.1 - - 1.12.0 - - pre-1.12.0 + - pre-1.13.0 validations: required: true - type: input diff --git a/.github/ISSUE_TEMPLATE/04_other_errors.yaml b/.github/ISSUE_TEMPLATE/04_other_errors.yaml index 5791967807..b1ba4c3897 100644 --- a/.github/ISSUE_TEMPLATE/04_other_errors.yaml +++ b/.github/ISSUE_TEMPLATE/04_other_errors.yaml @@ -43,17 +43,15 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.13.3 (Latest release) + - 1.14.0 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.13.4 + - 1.13.3 - 1.13.2 - 1.13.1 - 1.13.0 - - 1.12.3 - - 1.12.2 - - 1.12.1 - - 1.12.0 - - pre-1.12.0 + - pre-1.13.0 validations: required: true - type: input diff --git a/Makefile b/Makefile index fa2420e105..ccfe64dcf4 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,32 @@ +GAME_VERSION ?= EMERALD +TITLE ?= POKEMON EMER +GAME_CODE ?= BPEE +BUILD_NAME ?= emerald +MAP_VERSION ?= emerald + +ifeq (firered,$(MAKECMDGOALS)) + GAME_VERSION := FIRERED + TITLE := POKEMON FIRE + GAME_CODE := BPRE + BUILD_NAME := firered + MAP_VERSION := firered +else +ifeq (leafgreen,$(MAKECMDGOALS)) + GAME_VERSION := LEAFGREEN + TITLE := POKEMON LEAF + GAME_CODE := BPGE + BUILD_NAME := leafgreen + MAP_VERSION := firered +endif +endif + # GBA rom header -TITLE := POKEMON EMER -GAME_CODE := BPEE MAKER_CODE := 01 REVISION := 0 KEEP_TEMPS ?= 0 # `File name`.gba -FILE_NAME := pokeemerald +FILE_NAME := poke$(BUILD_NAME) BUILD_DIR := build # Compares the ROM to a checksum of the original - only makes sense using when non-modern @@ -21,6 +41,9 @@ UNUSED_ERROR ?= 0 DEBUG ?= 0 # Adds -flto flag, which increases link time but results in a more efficient binary (especially in audio processing) LTO ?= 0 +# Makes an optimized build for release, also enabling NDEBUG macro and disabling other debugging features +# Enables LTO by default, but can be changed in the config.mk file +RELEASE ?= 0 ifeq (compare,$(MAKECMDGOALS)) COMPARE := 1 @@ -31,6 +54,11 @@ endif ifeq (debug,$(MAKECMDGOALS)) DEBUG := 1 endif +ifneq (,$(filter release tidyrelease,$(MAKECMDGOALS))) + RELEASE := 1 +endif + +include config.mk # Default make rule all: rom @@ -62,10 +90,15 @@ endif CPP := $(PREFIX)cpp +ifeq ($(RELEASE),1) + FILE_NAME := $(FILE_NAME)-release +endif + ROM_NAME := $(FILE_NAME).gba -OBJ_DIR_NAME := $(BUILD_DIR)/modern -OBJ_DIR_NAME_TEST := $(BUILD_DIR)/modern-test -OBJ_DIR_NAME_DEBUG := $(BUILD_DIR)/modern-debug +OBJ_DIR_NAME := $(BUILD_DIR)/$(BUILD_NAME) +OBJ_DIR_NAME_TEST := $(BUILD_DIR)/$(BUILD_NAME)-test +OBJ_DIR_NAME_DEBUG := $(BUILD_DIR)/$(BUILD_NAME)-debug +OBJ_DIR_NAME_RELEASE := $(BUILD_DIR)/$(BUILD_NAME)-release ELF_NAME := $(ROM_NAME:.gba=.elf) MAP_NAME := $(ROM_NAME:.gba=.map) @@ -85,6 +118,9 @@ endif ifeq ($(DEBUG),1) OBJ_DIR := $(OBJ_DIR_NAME_DEBUG) endif +ifeq ($(RELEASE),1) + OBJ_DIR := $(OBJ_DIR_NAME_RELEASE) +endif ELF := $(ROM:.gba=.elf) MAP := $(ROM:.gba=.map) SYM := $(ROM:.gba=.sym) @@ -108,7 +144,7 @@ TEST_BUILDDIR = $(OBJ_DIR)/$(TEST_SUBDIR) SHELL := bash -o pipefail # Set flags for tools -ASFLAGS := -mcpu=arm7tdmi -march=armv4t -meabi=5 --defsym MODERN=1 +ASFLAGS := -mcpu=arm7tdmi -march=armv4t -meabi=5 --defsym MODERN=1 --defsym $(GAME_VERSION)=1 INCLUDE_DIRS := include INCLUDE_CPP_ARGS := $(INCLUDE_DIRS:%=-iquote %) @@ -119,7 +155,13 @@ O_LEVEL ?= g else O_LEVEL ?= 2 endif -CPPFLAGS := $(INCLUDE_CPP_ARGS) -Wno-trigraphs -DMODERN=1 -DTESTING=$(TEST) -std=gnu17 +CPPFLAGS := $(INCLUDE_CPP_ARGS) -Wno-trigraphs -DMODERN=1 -DTESTING=$(TEST) -D$(GAME_VERSION) -std=gnu17 +ifeq ($(RELEASE),1) + override CPPFLAGS += -DRELEASE + ifeq ($(USE_LTO_ON_RELEASE),1) + LTO := 1 + endif +endif ARMCC := $(PREFIX)gcc PATH_ARMCC := PATH="$(PATH)" $(ARMCC) CC1 := $(shell $(PATH_ARMCC) --print-prog-name=cc1) -quiet @@ -199,7 +241,7 @@ MISC_TOOL_DIR := $(TOOLS_DIR)/misc AUTO_GEN_TARGETS += $(INCLUDE_DIRS)/constants/script_commands.h $(DATA_SRC_SUBDIR)/wild_encounters.h: $(DATA_SRC_SUBDIR)/wild_encounters.json $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py $(INCLUDE_DIRS)/config/overworld.h $(INCLUDE_DIRS)/config/dexnav.h - python3 $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py > $@ + python3 $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py $(INCLUDE_DIRS)/constants/script_commands.h: $(MISC_TOOL_DIR)/make_scr_cmd_constants.py $(DATA_ASM_SUBDIR)/script_cmd_table.inc python3 $(MISC_TOOL_DIR)/make_scr_cmd_constants.py @@ -220,8 +262,8 @@ MAKEFLAGS += --no-print-directory # Delete files that weren't built properly .DELETE_ON_ERROR: -RULES_NO_SCAN += libagbsyscall clean clean-assets tidy tidymodern tidycheck generated clean-generated -.PHONY: all rom agbcc modern compare check debug +RULES_NO_SCAN += libagbsyscall clean clean-assets tidy tidymodern tidycheck tidyrelease generated clean-generated +.PHONY: all rom agbcc modern compare check debug release .PHONY: $(RULES_NO_SCAN) infoshell = $(foreach line, $(shell $1 | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line)))) @@ -248,7 +290,7 @@ ifeq ($(SETUP_PREREQS),1) $(error Errors occurred while building tools. See error messages above for more details) endif # Oh and also generate mapjson sources before we use `SCANINC`. - $(foreach line, $(shell $(MAKE) generated | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line)))) + $(foreach line, $(shell $(MAKE) MAP_VERSION=$(MAP_VERSION) generated | sed "s/ /__SPACE__/g"), $(info $(subst __SPACE__, ,$(line)))) ifneq ($(.SHELLSTATUS),0) $(error Errors occurred while generating map-related sources. See error messages above for more details) endif @@ -292,6 +334,7 @@ $(shell mkdir -p $(SUBDIRS)) modern: all compare: all debug: all +release: all # Uncomment the next line, and then comment the 4 lines after it to reenable agbcc. #agbcc: all agbcc: @@ -340,7 +383,7 @@ clean-assets: find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' -o -iname '*.smol' -o -iname '*.fastSmol' -o -iname '*.smolTM' -o -iname '*.rl' -o -iname '*.latfont' -o -iname '*.hwjpnfont' -o -iname '*.fwjpnfont' \) -exec rm {} + find $(DATA_ASM_SUBDIR)/maps \( -iname 'connections.inc' -o -iname 'events.inc' -o -iname 'header.inc' \) -exec rm {} + -tidy: tidymodern tidycheck tidydebug +tidy: tidymodern tidycheck tidydebug tidyrelease tidymodern: rm -f $(ROM_NAME) $(ELF_NAME) $(MAP_NAME) @@ -353,6 +396,14 @@ tidycheck: tidydebug: rm -rf $(DEBUG_OBJ_DIR_NAME) +tidyrelease: +ifeq ($(RELEASE),1) + rm -f $(ROM_NAME) $(ELF_NAME) $(MAP_NAME) +else # Manually remove the release files on clean/tidy + rm -f $(FILE_NAME)-release.gba $(FILE_NAME)-release.elf $(FILE_NAME)-release.map +endif + rm -rf $(OBJ_DIR_NAME_RELEASE) + # Other rules include graphics_file_rules.mk include map_data_rules.mk @@ -449,7 +500,7 @@ ifneq ($(NODEP),1) endif $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.s $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $< @@ -459,7 +510,7 @@ ifneq ($(NODEP),1) endif $(DATA_ASM_BUILDDIR)/%.o: $(DATA_ASM_SUBDIR)/%.s - $(PREPROC) $< charmap.txt | $(CPP) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) $(INCLUDE_SCANINC_ARGS) - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I "" $< @@ -518,6 +569,9 @@ $(ROM): $(ELF) $(OBJCOPY) -O binary $< $@ $(FIX) $@ -p --silent +emerald: all +firered: all +leafgreen: all # Symbol file (`make syms`) $(SYM): $(ELF) $(OBJDUMP) -t $< | sort -u | grep -E "^0[2389]" | $(PERL) -p -e 's/^(\w{8}) (\w).{6} \S+\t(\w{8}) (\S+)$$/\1 \2 \3 \4/g' > $@ diff --git a/README.md b/README.md index 2389dfe26a..65db8463d9 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you use **`pokeemerald-expansion`**, please credit **RHH (Rom Hacking Hideout)**. Optionally, include the version number for clarity. ``` -Based off RHH's pokeemerald-expansion 1.13.3 https://github.com/rh-hideout/pokeemerald-expansion/ +Based off RHH's pokeemerald-expansion 1.14.0 https://github.com/rh-hideout/pokeemerald-expansion/ ``` Please consider [crediting all contributors](CREDITS.md) involved in the project! diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a9584dcef6..7eb3b9d064 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -9,11 +9,11 @@ .2byte \move .endm - .macro attackstring + .macro printattackstring .byte 0x2 .endm - .macro ppreduce + .macro unused_0x3 .byte 0x3 .endm @@ -45,14 +45,16 @@ .byte 0xa .endm - .macro healthbarupdate battler:req + .macro healthbarupdate battler:req updateState:req .byte 0xb .byte \battler + .byte \updateState .endm - .macro datahpupdate battler:req + .macro datahpupdate battler:req updateState:req .byte 0xc .byte \battler + .byte \updateState .endm .macro critmessage @@ -363,9 +365,8 @@ .byte 0x3a .endm - .macro absorbhealthbarupdate battler:req + .macro isdmgblockedbydisguise .byte 0x3b - .byte \battler .endm .macro return @@ -678,10 +679,8 @@ .byte 0x75 .endm - .macro various battler:req, id:req + .macro unused_0x78 .byte 0x76 - .byte \battler - .byte \id .endm .macro setprotectlike @@ -701,10 +700,10 @@ .4byte \jumpInstr .endm - .macro tryhealhalfhealth failInstr:req, battler:req + .macro tryhealhalfhealth battler:req, failInstr:req .byte 0x7b - .4byte \failInstr .byte \battler + .4byte \failInstr .endm .macro trymirrormove @@ -729,14 +728,12 @@ .byte \mode .endm - .macro trysetrest failInstr:req + .macro trysetrest .byte 0x81 - .4byte \failInstr .endm - .macro jumpifnotfirstturn jumpInstr:req + .macro unused_0x82 .byte 0x82 - .4byte \jumpInstr .endm .macro unused_0x83 @@ -753,9 +750,8 @@ .byte \id .endm - .macro stockpiletobasedamage failInstr:req + .macro stockpiletobasedamage .byte 0x86 - .4byte \failInstr .endm .macro stockpiletohpheal failInstr:req @@ -767,7 +763,7 @@ callnative BS_RemoveStockpileCounters .endm - .macro setdrainedhp + .macro unused_0x88 .byte 0x88 .endm @@ -882,7 +878,7 @@ .4byte \failInstr .endm - .macro metronome + .macro setcalledmove .byte 0x9e .endm @@ -943,7 +939,7 @@ .4byte \failInstr .endm - .macro trysetdestinybondtohappen + .macro unused_0xab .byte 0xab .endm @@ -1019,8 +1015,10 @@ .4byte \jumpInstr .endm - .macro tryrestorehpberry + .macro tryactivateitem battler:req, flag:req .byte 0xbb + .byte \battler + .byte \flag .endm .macro halvehp failInstr:req @@ -1050,9 +1048,8 @@ .byte 0xc2 .endm - .macro trysetfutureattack failInstr:req + .macro setfutureattack .byte 0xc3 - .4byte \failInstr .endm .macro trydobeatup endInstr:req, failInstr:req @@ -1102,7 +1099,7 @@ .byte 0xca .endm - .macro setcharge battler:req + .macro unused_0xcb battler:req .byte 0xcb .byte \battler .endm @@ -1229,10 +1226,8 @@ .4byte \jumpInstr .endm - .macro jumpifnotcurrentmoveargtype battler:req, failInstr:req + .macro unused_0xE4 .byte 0xe4 - .byte \battler - .4byte \failInstr .endm .macro pickup @@ -1302,7 +1297,7 @@ .byte 0xf3 .endm - .macro subattackerhpbydmg + .macro unused_0xf4 .byte 0xf4 .endm @@ -1348,7 +1343,7 @@ .byte \trigger .endm - .macro tryworryseed failInstr:req + .macro tryoverwriteability failInstr:req .byte 0xfe .4byte \failInstr .endm @@ -1383,17 +1378,6 @@ .4byte \failInstr .endm - .macro jumpifcantfling battler:req, jumpInstr:req - callnative BS_JumpIfCantFling - .byte \battler - .4byte \jumpInstr - .endm - - .macro itemstatchangeeffects battler:req - callnative BS_RunStatChangeItems - .byte \battler - .endm - .macro allyswitchswapbattlers callnative BS_AllySwitchSwapBattler .endm @@ -1444,26 +1428,17 @@ .4byte \failInstr .endm - .macro setglaiverush - callnative BS_SetGlaiveRush - .endm - .macro setpledge jumpInstr:req callnative BS_SetPledge .4byte \jumpInstr .endm - .macro setpledgestatus battler:req sidestatus:req + .macro setpledgestatus battler:req, sidestatus:req callnative BS_SetPledgeStatus .byte \battler .4byte \sidestatus .endm - .macro trycopycat failInstr:req - callnative BS_TryCopycat - .4byte \failInstr - .endm - .macro setzeffect callnative BS_SetZEffect .endm @@ -1646,14 +1621,6 @@ .4byte \failInstr .endm - .macro tryupdaterecoiltracker - callnative BS_TryUpdateRecoilTracker - .endm - - .macro tryupdateleaderscresttracker - callnative BS_TryUpdateLeadersCrestTracker - .endm - .macro trytidyup clear:req, jumpInstr:req callnative BS_TryTidyUp .byte \clear @@ -1789,6 +1756,10 @@ .2byte \flags .endm + .macro clearspecialstatuses + callnative BS_ClearSpecialStatuses + .endm + .macro clearmoveresultflags flags:req callnative BS_ClearMoveResultFlags .2byte \flags @@ -1811,11 +1782,8 @@ .4byte \jumpInstr .endm - .macro jumpiflastuseditemholdeffect holdEffect:req, secondaryId:req, jumpInstr:req - callnative BS_JumpIfLastUsedItemHoldEffect - .byte \holdEffect - .2byte \secondaryId - .4byte \jumpInstr + .macro tryflingholdeffect + callnative BS_TryFlingHoldEffect .endm .macro swapsidestatuses @@ -2178,16 +2146,6 @@ .4byte \failInstr .endm - .macro suckerpunchcheck failInstr:req - callnative BS_SuckerPunchCheck - .4byte \failInstr - .endm - - .macro setsimplebeam failInstr:req - callnative BS_SetSimpleBeam - .4byte \failInstr - .endm - .macro tryentrainment failInstr:req callnative BS_TryEntrainment .4byte \failInstr @@ -2201,11 +2159,6 @@ callnative BS_InvertStatStages .endm - .macro trymefirst failInstr:req - callnative BS_TryMeFirst - .4byte \failInstr - .endm - .macro tryelectrify failInstr:req callnative BS_TryElectrify .4byte \failInstr @@ -2222,11 +2175,6 @@ .byte \case_ .endm - .macro trylastresort failInstr:req - callnative BS_TryLastResort - .4byte \failInstr - .endm - .macro tryautotomize failInstr:req callnative BS_TryAutotomize .4byte \failInstr @@ -2415,20 +2363,11 @@ .4byte \failInstr .endm - .macro checkpoltergeist failInstr:req - callnative BS_CheckPoltergeist + .macro setpoltergeistmessage failInstr:req + callnative BS_SetPoltergeistMessage .4byte \failInstr .endm - .macro trynoretreat failInstr:req - callnative BS_TryNoRetreat - .4byte \failInstr - .endm - - .macro curecertainstatuses - callnative BS_CureCertainStatuses - .endm - .macro tryresetnegativestatstages callnative BS_TryResetNegativeStatStages .endm diff --git a/asm/macros/event.inc b/asm/macros/event.inc index 6e08a3cdff..6abaeff265 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -2332,6 +2332,11 @@ callnative ScriptSetDoubleBattleFlag, requests_effects=1 .endm + @ Stop using the ORAS dowsing machine. + .macro stoporasdowsing + callnative EndORASDowsing + .endm + @ ============================ @ @ FAKE RTC MACROS @ Will only function if OW_USE_FAKE_RTC is true. If it has any additional requirements, it will be listed accordingly. @@ -2674,8 +2679,34 @@ .2byte \battlePartner .endm + @ Manually buffer a string as the speaker's name for namebox. + @ The next shown message/msgbox will include a namebox, if the provided string is not NULL. + @ An SP_NAME_* constant can also be used, it'll take the name from gSpeakerNamesTable instead. + .macro setspeaker name:req + callnative SetSpeaker + .4byte \name + .endm + @ VS Seeker .macro vsseeker_rematchid rematchId:req callnative NativeVsSeekerRematchId, requests_effects=1 .2byte \rematchId .endm + + @ Sets the move relearner state + .macro setmoverelearnerstate state:req + callnative ScrCmd_setmoverelearnerstate, requests_effects=1 + .2byte \state + .endm + + @ Retrieves the move relearner state and stores it in the specified var + .macro getmoverelearnerstate varId:req + callnative ScrCmd_getmoverelearnerstate, requests_effects=1 + .4byte \varId + .endm + + @ Execute script if bag has TMs and/or HMs + .macro istmrelearneractive destination:req + callnative ScrCmd_istmrelearneractive, requests_effects=1 + .4byte \destination + .endm diff --git a/charmap.txt b/charmap.txt index 83f2cf602b..dd2123f8f9 100644 --- a/charmap.txt +++ b/charmap.txt @@ -459,6 +459,13 @@ JPN = FC 15 ENG = FC 16 PAUSE_MUSIC = FC 17 RESUME_MUSIC = FC 18 +SPEAKER = FC 19 + +@ Speaker names, the order must be matching with include/constants/speaker_names.h +NAME_NONE = 00 +NAME_MOM = 01 +NAME_PLAYER = 02 +NAME_COUNT = 03 @ fonts diff --git a/config.mk b/config.mk new file mode 100644 index 0000000000..7360c158ef --- /dev/null +++ b/config.mk @@ -0,0 +1,2 @@ +# Enable LTO when making a release build. Disable by setting to 0. +USE_LTO_ON_RELEASE ?= 1 diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index b546558daa..2118d14c4b 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -3361,6 +3361,7 @@ gBattleAnimMove_AquaJet:: visible ANIM_ATTACKER clearmonbg ANIM_DEF_PARTNER blendoff + setarg 7, 0x1000 end gBattleAnimMove_AttackOrder:: @@ -31083,6 +31084,17 @@ gBattleAnimStatus_Nightmare:: clearmonbg ANIM_DEF_PARTNER end +gBattleAnimStatus_Frostbite:: + playsewithpan SE_M_ICY_WIND, 0 + loadspritegfx ANIM_TAG_ICE_CRYSTALS + monbg ANIM_DEF_PARTNER + splitbgprio ANIM_TARGET + call IceCrystalEffectShort + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, F_PAL_TARGET, 5, 7, 0, RGB(0, 20, 31) + waitforvisualfinish + clearmonbg ANIM_DEF_PARTNER + end + gBattleAnimGeneral_StatsChange:: createvisualtask AnimTask_StatsChange, 5 waitforvisualfinish diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 777481ac5e..8754ed053c 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -23,8 +23,6 @@ BattleScript_EffectFickleBeam:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE ficklebeamdamagecalculation goto BattleScript_HitFromCritCalc @@ -81,19 +79,14 @@ BattleScript_LowerAtkSpAtkEnd: BattleScript_EffectSpicyExtract:: attackcanceler jumpifsubstituteblocks BattleScript_ButItFailed - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_SpicyExtract_CheckShouldSkipAttackAnim jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_SpicyExtract_CheckShouldSkipAttackAnim goto BattleScript_ButItFailed BattleScript_SpicyExtract_CheckShouldSkipAttackAnim: jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0, BattleScript_SpicyExtract_RaiseAtk - attackstring - ppreduce - bicword gHitMarker, HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT goto BattleScript_SpicyExtract_SkipAttackAnim BattleScript_SpicyExtract_RaiseAtk: - attackstring - ppreduce attackanimation waitanimation BattleScript_SpicyExtract_SkipAttackAnim: @@ -111,9 +104,7 @@ BattleScript_EffectSpicyExtract_End: BattleScript_EffectTidyUp:: attackcanceler - attackstring pause B_WAIT_TIME_MED - ppreduce waitstate saveattacker savetarget @@ -132,26 +123,18 @@ BattleScript_EffectTidyUpDoMoveAnimation:: restoretarget goto BattleScript_EffectDragonDanceFromStatUp -BattleScript_EffectUpperHand:: - attackcanceler - tryupperhand BattleScript_FailedFromAtkString - goto BattleScript_HitFromAccCheck - BattleScript_EffectShedTail:: attackcanceler - attackstring - ppreduce waitstate jumpifvolatile BS_ATTACKER, VOLATILE_SUBSTITUTE, BattleScript_AlreadyHasSubstitute jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_ButItFailed jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailed setsubstitute jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SUBSTITUTE_FAILED, BattleScript_SubstituteString - orword gHitMarker, HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_SHEDITSTAIL waitmessage B_WAIT_TIME_LONG moveendto MOVEEND_ATTACKER_VISIBLE @@ -169,14 +152,11 @@ BattleScript_EffectPsychicNoise:: BattleScript_EffectFilletAway:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_FilletAwayTryAttack jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_FilletAwayTryAttack jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_ButItFailed BattleScript_FilletAwayTryAttack:: halvehp BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation setstatchanger STAT_ATK, 2, FALSE @@ -195,14 +175,12 @@ BattleScript_FilletAwayTrySpeed:: waitmessage B_WAIT_TIME_LONG BattleScript_FilletAwayEnd:: clearmoveresultflags MOVE_RESULT_NO_EFFECT - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE goto BattleScript_MoveEnd BattleScript_EffectDoodle:: attackcanceler - attackstring - ppreduce trycopyability BS_ATTACKER, BattleScript_ButItFailed saveattacker attackanimation @@ -212,10 +190,8 @@ BattleScript_EffectDoodle:: BattleScript_EffectDoodle_CopyAbility: trycopyability BS_ATTACKER, BattleScript_EffectDoodleMoveEnd BattleScript_EffectDoodle_AfterCopy: -.if B_ABILITY_POP_UP == TRUE copybyte gBattlerAbility, gBattlerAttacker call BattleScript_AbilityPopUpOverwriteThenNormal -.endif recordability BS_ATTACKER printstring STRINGID_PKMNCOPIEDFOE waitmessage B_WAIT_TIME_LONG @@ -231,7 +207,7 @@ BattleScript_EffectDoodleMoveEnd: BattleScript_EffectGlaiveRush:: call BattleScript_EffectHit_Ret jumpifmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_TryFaintMon - setglaiverush + setvolatile BS_ATTACKER, VOLATILE_GLAIVE_RUSH, 2 goto BattleScript_TryFaintMon BattleScript_SyrupBombActivates:: @@ -253,7 +229,6 @@ BattleScript_EffectChillyReception:: printstring STRINGID_PKMNTELLCHILLINGRECEPTIONJOKE waitmessage B_WAIT_TIME_LONG attackcanceler - ppreduce jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_SUN_PRIMAL, BattleScript_EffectChillyReceptionBlockedByPrimalSun jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_RAIN_PRIMAL, BattleScript_EffectChillyReceptionBlockedByPrimalRain jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_STRONG_WINDS, BattleScript_EffectChillyReceptionBlockedByStrongWinds @@ -266,7 +241,6 @@ BattleScript_EffectChillyReception:: call BattleScript_MoveWeatherChangeRet goto BattleScript_MoveSwitch BattleScript_EffectChillyReceptionPlayAnimation: - attackstring attackanimation waitanimation return @@ -283,8 +257,8 @@ BattleScript_EffectChillyReceptionBlockedByStrongWinds: call BattleScript_MysteriousAirCurrentBlowsOnRet goto BattleScript_MoveSwitch BattleScript_EffectChillyReceptionTrySwitchWeatherFailed: - jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_FailedFromAtkString - jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_FailedFromAtkString + jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_ButItFailed + jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailed call BattleScript_EffectChillyReceptionPlayAnimation return @@ -337,9 +311,7 @@ BattleScript_MoveSwitchOpenPartyScreenReturnWithNoAnim: BattleScript_EffectPledge:: attackcanceler setpledge BattleScript_HitFromAccCheck - attackstring pause B_WAIT_TIME_MED - ppreduce printstring STRINGID_WAITINGFORPARTNERSMOVE waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -410,26 +382,17 @@ BattleScript_MoveEffectSaltCure:: BattleScript_SaltCureExtraDamage:: playanimation BS_ATTACKER, B_ANIM_SALT_CURE_DAMAGE, NULL waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_TARGETISHURTBYSALTCURE waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER - tryrestorehpberry + tryactivateitem BS_ATTACKER, ACTIVATION_ON_HP_THRESHOLD end2 -BattleScript_HurtTarget_NoString: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - return - BattleScript_EffectCorrosiveGas:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifsubstituteblocks BattleScript_CorrosiveGasFail jumpifcantloseitem BS_TARGET, BattleScript_CorrosiveGasFail attackanimation @@ -450,8 +413,6 @@ BattleScript_CorrosiveGasFail: BattleScript_EffectTakeHeart:: attackcanceler - attackstring - ppreduce curestatuswithmove BattleScript_CalmMindTryToRaiseStats attackanimation waitanimation @@ -464,8 +425,6 @@ BattleScript_EffectTakeHeart:: BattleScript_EffectRevivalBlessing:: attackcanceler - attackstring - ppreduce tryrevivalblessing BattleScript_ButItFailed attackanimation waitanimation @@ -498,8 +457,6 @@ BattleScript_SpikesActivates:: BattleScript_EffectAttackUpUserAlly:: jumpifnoally BS_ATTACKER, BattleScript_EffectAttackUp attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_NOT_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_EffectAttackUpUserAlly_Works jumpifstat BS_ATTACKER_PARTNER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed BattleScript_EffectAttackUpUserAlly_Works: @@ -517,7 +474,7 @@ BattleScript_EffectAttackUpUserAlly_TryAlly_: jumpifblockedbysoundproof BS_ATTACKER_PARTNER, BattleScript_EffectAttackUpUserAlly_TryAllyBlocked setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectAttackUpUserAlly_End - jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectAttackUpUserAlly_AllyString + jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectAttackUpUserAlly_AllyString pause B_WAIT_TIME_SHORTEST printstring STRINGID_TARGETSTATWONTGOHIGHER waitmessage B_WAIT_TIME_LONG @@ -536,8 +493,6 @@ BattleScript_EffectAttackUpUserAlly_TryAllyBlocked: BattleScript_EffectTeatime:: attackcanceler - attackstring - ppreduce jumpifteanoberry BattleScript_ButItFailed @ at least one battler is affected attackanimation @@ -548,10 +503,8 @@ BattleScript_TeatimeLoop: jumpifelectricabilityaffected BS_TARGET, ABILITY_VOLT_ABSORB, BattleScript_Teatimesorb jumpifelectricabilityaffected BS_TARGET, ABILITY_MOTOR_DRIVE, BattleScript_Teatimemotor jumpifteainvulnerable BS_TARGET, BattleScript_Teatimevul @ in semi-invulnerable state OR held item is not a Berry - orword gHitMarker, HITMARKER_DISABLE_ANIMATION | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE setbyte sBERRY_OVERRIDE, TRUE @ override the requirements for eating berries consumeberry BS_TARGET, TRUE @ consume the berry, then restore the item from changedItems - bicword gHitMarker, HITMARKER_DISABLE_ANIMATION | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE setbyte sBERRY_OVERRIDE, FALSE removeitem BS_TARGET moveendto MOVEEND_NEXT_TARGET @@ -566,8 +519,8 @@ BattleScript_Teatimevul: BattleScript_Teatimesorb: call BattleScript_AbilityPopUpTarget tryhealquarterhealth BS_TARGET, BattleScript_Teatimesorb_end - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_Teatimesorb_end: @@ -652,17 +605,13 @@ BattleScript_ShellTrapSetUp:: BattleScript_EffectShellTrap:: attackcanceler jumpifshelltrap BS_ATTACKER, BattleScript_HitFromAccCheck - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT, BattleScript_MoveEnd - ppreduce printstring STRINGID_SHELLTRAPDIDNTWORK waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd BattleScript_EffectCourtChange:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE swapsidestatuses attackanimation waitanimation @@ -686,9 +635,7 @@ BattleScript_BeakBlastBurn:: BattleScript_EffectSkyDrop:: attackcanceler jumpifvolatile BS_ATTACKER, VOLATILE_MULTIPLETURNS, BattleScript_SkyDropTurn2 - ppreduce - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifsubstituteblocks BattleScript_ButItFailed jumpiftargetally BattleScript_ButItFailed jumpifunder200 BattleScript_SkyDropWork @@ -703,7 +650,6 @@ BattleScript_SkyDropWork: goto BattleScript_MoveEnd BattleScript_SkyDropTurn2: call BattleScript_TwoTurnMovesSecondTurnRet - attackstring clearskydrop BattleScript_SkyDropChangedTarget jumpiftype BS_TARGET, TYPE_FLYING, BattleScript_SkyDropFlyingType goto BattleScript_HitFromCritCalc @@ -733,14 +679,11 @@ BattleScript_SkyDropFlyingAlreadyConfused: BattleScript_EffectFling:: attackcanceler - jumpifcantfling BS_ATTACKER, BattleScript_FailedFromAtkString setlastuseditem BS_ATTACKER accuracycheck BattleScript_FlingMissed, ACC_CURR_MOVE - attackstring pause B_WAIT_TIME_SHORT printstring STRINGID_PKMNFLUNG waitmessage B_WAIT_TIME_SHORT - ppreduce critcalc damagecalc adjustdamage @@ -750,28 +693,22 @@ BattleScript_EffectFling:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_MED resultmessage waitmessage B_WAIT_TIME_MED jumpiflastuseditemberry BattleScript_EffectFlingConsumeBerry - jumpifability BS_TARGET, ABILITY_SHIELD_DUST, BattleScript_FlingBlockedByShieldDust - jumpiflastuseditemholdeffect HOLD_EFFECT_FLAME_ORB, 0, BattleScript_FlingFlameOrb - jumpiflastuseditemholdeffect HOLD_EFFECT_FLINCH, 0, BattleScript_FlingFlinch - jumpiflastuseditemholdeffect HOLD_EFFECT_LIGHT_BALL, 0, BattleScript_FlingLightBall - jumpiflastuseditemholdeffect HOLD_EFFECT_MENTAL_HERB, 0, BattleScript_FlingMentalHerb - jumpiflastuseditemholdeffect HOLD_EFFECT_TYPE_POWER, TYPE_POISON, BattleScript_FlingPoisonBarb - jumpiflastuseditemholdeffect HOLD_EFFECT_TOXIC_ORB, 0, BattleScript_FlingToxicOrb - jumpiflastuseditemholdeffect HOLD_EFFECT_WHITE_HERB, 0, BattleScript_FlingWhiteHerb + tryflingholdeffect goto BattleScript_FlingEnd + BattleScript_EffectFlingConsumeBerry: savebattleritem battleritemtolastuseditem setbyte sBERRY_OVERRIDE, 1 @ override the requirements for eating berries orword gHitMarker, HITMARKER_DISABLE_ANIMATION - consumeberry BS_TARGET, TRUE + consumeberry BS_TARGET, FALSE bicword gHitMarker, HITMARKER_DISABLE_ANIMATION setbyte sBERRY_OVERRIDE, 0 restorebattleritem @@ -782,76 +719,31 @@ BattleScript_FlingEnd: BattleScript_FlingFailConsumeItem:: removeitem BS_ATTACKER - goto BattleScript_FailedFromAtkString + goto BattleScript_ButItFailed BattleScript_FlingBlockedByShieldDust:: printstring STRINGID_ITEMWASUSEDUP waitmessage B_WAIT_TIME_LONG goto BattleScript_FlingEnd -BattleScript_FlingFlameOrb: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_BURN - goto BattleScript_FlingEnd -BattleScript_FlingFlinch: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_FLINCH - goto BattleScript_FlingEnd -BattleScript_FlingLightBall: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_PARALYSIS - goto BattleScript_FlingEnd -BattleScript_FlingMentalHerb: - curecertainstatuses - saveattacker - copybyte gBattlerAttacker, gBattlerTarget - playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, NULL - printfromtable gMentalHerbCureStringIds - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_ATTACKER - restoreattacker - goto BattleScript_FlingEnd -BattleScript_FlingPoisonBarb: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_POISON - goto BattleScript_FlingEnd -BattleScript_FlingToxicOrb: - seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_TOXIC - goto BattleScript_FlingEnd -BattleScript_FlingWhiteHerb: - tryresetnegativestatstages - swapattackerwithtarget - printstring STRINGID_PKMNSTATUSNORMAL - waitmessage B_WAIT_TIME_MED - swapattackerwithtarget - goto BattleScript_FlingEnd - BattleScript_FlingMissed: removeitem BS_ATTACKER - attackstring - ppreduce goto BattleScript_MoveMissedPause -BattleScript_EffectAuraWheel:: @ Aura Wheel can only be used by Morpeko - jumpifspecies SPECIES_MORPEKO_FULL_BELLY, BattleScript_EffectHit - jumpifspecies SPECIES_MORPEKO_HANGRY, BattleScript_EffectHit - goto BattleScript_PokemonCantUseTheMove - BattleScript_EffectClangorousSoul:: attackcanceler - attackstring - ppreduce cutonethirdhpandraisestats BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_BIDE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE call BattleScript_AllStatsUp goto BattleScript_MoveEnd BattleScript_EffectOctolock:: attackcanceler - jumpifsubstituteblocks BattleScript_FailedFromAtkString - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + jumpifsubstituteblocks BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE trysetoctolock BattleScript_ButItFailed attackanimation waitanimation @@ -874,21 +766,17 @@ BattleScript_OctlockTurnDmgEnd: BattleScript_EffectPoltergeist:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - checkpoltergeist BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE + setpoltergeistmessage BattleScript_ButItFailed printstring STRINGID_ABOUTTOUSEPOLTERGEIST waitmessage B_WAIT_TIME_LONG goto BattleScript_HitFromCritCalc BattleScript_EffectTarShot:: attackcanceler - jumpifsubstituteblocks BattleScript_FailedFromAtkString - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - cantarshotwork BattleScript_FailedFromAtkString - attackstring - ppreduce + jumpifsubstituteblocks BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE + cantarshotwork BattleScript_ButItFailed setstatchanger STAT_SPEED, 1, TRUE attackanimation waitanimation @@ -903,10 +791,9 @@ BattleScript_TryTarShot: BattleScript_EffectNoRetreat:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - trynoretreat BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE + jumpifvolatile BS_TARGET, VOLATILE_NO_RETREAT, BattleScript_ButItFailed + setvolatile BS_TARGET, VOLATILE_NO_RETREAT attackanimation waitanimation call BattleScript_AllStatsUp @@ -963,9 +850,6 @@ BattleScript_MoveEffectLightScreen:: BattleScript_EffectStuffCheeks:: attackcanceler - attackstring - ppreduce - jumpifnotberry BS_ATTACKER, BattleScript_ButItFailed attackanimation waitanimation setbyte sBERRY_OVERRIDE, 1 @@ -983,9 +867,7 @@ BattleScript_StuffCheeksEnd: BattleScript_EffectDecorate:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_ATK, 12, BattleScript_DecorateBoost jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_SPATK, 12, BattleScript_DecorateBoost goto BattleScript_ButItFailed @@ -1007,8 +889,6 @@ BattleScript_DecorateBoostSpAtk: BattleScript_EffectCoaching:: attackcanceler - attackstring - ppreduce jumpifnoally BS_ATTACKER, BattleScript_ButItFailed copybyte gBattlerTarget, gBattlerAttacker setallytonexttarget EffectCoaching_CheckAllyStats @@ -1036,8 +916,6 @@ BattleScript_CoachingBoostDef: BattleScript_EffectJungleHealing:: attackcanceler - attackstring - ppreduce jumpifteamhealthy BattleScript_ButItFailed attackanimation waitanimation @@ -1046,9 +924,8 @@ BattleScript_EffectJungleHealing:: JungleHealing_RestoreTargetHealth: copybyte gBattlerAttacker, gBattlerTarget tryhealquarterhealth BS_TARGET, BattleScript_JungleHealing_TryCureStatus - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_JungleHealing_TryCureStatus: @@ -1068,8 +945,6 @@ BattleScript_JungleHealingTryRestoreAlly: BattleScript_EffectLifeDew:: attackcanceler - attackstring - ppreduce jumpiffullhp BS_ATTACKER, BattleScript_EffectLifeDewCheckPartner copybyte gBattlerTarget, gBattlerAttacker attackanimation @@ -1091,19 +966,16 @@ BattleScript_EffectLifeDewCheckPartner: setallytonexttarget BattleScript_EffectLifeDewNextTarget BattleScript_EffectLifeDewHealing: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE tryhealquarterhealth BS_TARGET, BattleScript_EffectLifeDewEnd - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG return BattleScript_EffectAllySwitch:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE tryallyswitch BattleScript_ButItFailed attackanimation waitanimation @@ -1115,9 +987,7 @@ BattleScript_EffectAllySwitch:: BattleScript_EffectFairyLock:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE trysetfairylock BattleScript_ButItFailed attackanimation waitanimation @@ -1125,14 +995,6 @@ BattleScript_EffectFairyLock:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_FailIfNotArgType:: - attackcanceler - attackstring - ppreduce - jumpifnotcurrentmoveargtype BS_ATTACKER, BattleScript_ButItFailed - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - goto BattleScript_HitFromCritCalc - BattleScript_RemoveFireType:: printstring STRINGID_ATTACKERLOSTFIRETYPE waitmessage B_WAIT_TIME_LONG @@ -1155,8 +1017,6 @@ BattleScript_DefDown_Ret: BattleScript_EffectPurify:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_PurifyWorks goto BattleScript_ButItFailed @@ -1167,16 +1027,14 @@ BattleScript_PurifyWorks: updatestatusicon BS_TARGET printstring STRINGID_ATTACKERCUREDTARGETSTATUS waitmessage B_WAIT_TIME_LONG - tryhealhalfhealth BattleScript_AlreadyAtFullHp, BS_ATTACKER + tryhealhalfhealth BS_ATTACKER, BattleScript_AlreadyAtFullHp goto BattleScript_RestoreHp BattleScript_EffectStrengthSap:: setstatchanger STAT_ATK, 1, TRUE attackcanceler - jumpifsubstituteblocks BattleScript_FailedFromAtkString - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + jumpifsubstituteblocks BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_ATK, MIN_STAT_STAGE, BattleScript_StrengthSapTryLower pause B_WAIT_TIME_SHORT statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_MoveEnd @@ -1190,7 +1048,7 @@ BattleScript_StrengthSapAnimation: attackanimation waitanimation statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_StrengthSapHp - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_StrengthSapHp + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_StrengthSapHp printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG @ Drain HP without lowering a stat @@ -1200,10 +1058,9 @@ BattleScript_StrengthSapHp: jumpiffullhp BS_ATTACKER, BattleScript_MoveEnd BattleScript_StrengthSapManipulateDmg: manipulatedamage DMG_BIG_ROOT - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE jumpifability BS_TARGET, ABILITY_LIQUID_OOZE, BattleScript_StrengthSapLiquidOoze - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNENERGYDRAINED waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -1211,15 +1068,15 @@ BattleScript_StrengthSapLiquidOoze: call BattleScript_AbilityPopUpTarget manipulatedamage DMG_CHANGE_SIGN setbyte cMULTISTRING_CHOOSER, B_MSG_ABSORB_OOZE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printfromtable gAbsorbDrainStringIds waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER goto BattleScript_MoveEnd BattleScript_StrengthSapMustLower: statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_MoveEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_MoveEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_MoveEnd goto BattleScript_StrengthSapAnimation BattleScript_MoveEffectIncinerate:: @@ -1252,8 +1109,6 @@ BattleScript_CoreEnforcerRet: BattleScript_EffectLaserFocus:: attackcanceler - attackstring - ppreduce trysetvolatile BS_ATTACKER, VOLATILE_LASER_FOCUS, BattleScript_ButItFailed attackanimation waitanimation @@ -1268,19 +1123,19 @@ BattleScript_VCreateStatLoss:: BattleScript_VCreateStatAnim: setstatchanger STAT_DEF, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_CERTAIN, BattleScript_VCreateTrySpDef, BIT_SPDEF | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_VCreateTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VCreateTrySpDef printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VCreateTrySpDef: setstatchanger STAT_SPDEF, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_CERTAIN, BattleScript_VCreateTrySpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_VCreateTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VCreateTrySpeed printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VCreateTrySpeed: setstatchanger STAT_SPEED, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_CERTAIN, BattleScript_VCreateStatLossRet - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_VCreateStatLossRet + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VCreateStatLossRet printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VCreateStatLossRet: @@ -1300,9 +1155,7 @@ BattleScript_SpectralThiefSteal:: BattleScript_EffectSpectralThief:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE typecalc tryspectralthiefsteal BattleScript_SpectralThiefSteal BattleScript_EffectSpectralThiefFromDamage: @@ -1316,12 +1169,10 @@ BattleScript_EffectSpectralThiefFromDamage: BattleScript_EffectPartingShot:: attackcanceler - attackstring - ppreduce jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_EffectPartingShotTryAtk jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPATK, MIN_STAT_STAGE, BattleScript_CantLowerMultipleStats BattleScript_EffectPartingShotTryAtk: - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE attackanimation waitanimation setstatchanger STAT_ATK, 1, TRUE @@ -1339,9 +1190,7 @@ BattleScript_EffectPartingShotSwitch: BattleScript_EffectPowder:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, NO_ACC_CALC_CHECK_LOCK_ON jumpifvolatile BS_TARGET, VOLATILE_POWDER, BattleScript_ButItFailed setvolatile BS_TARGET, VOLATILE_POWDER attackanimation @@ -1352,8 +1201,6 @@ BattleScript_EffectPowder:: BattleScript_EffectAromaticMist:: attackcanceler - attackstring - ppreduce jumpifbyteequal gBattlerTarget, gBattlerAttacker, BattleScript_ButItFailed jumpiftargetally BattleScript_EffectAromaticMistWorks goto BattleScript_ButItFailed @@ -1375,8 +1222,6 @@ BattleScript_EffectAromaticMistWontGoHigher: BattleScript_EffectMagneticFlux:: attackcanceler - attackstring - ppreduce setbyte gBattleCommunication, 0 BattleScript_EffectMagneticFluxStart: jumpifability BS_TARGET, ABILITY_MINUS, BattleScript_EffectMagneticFluxCheckStats @@ -1392,14 +1237,14 @@ BattleScript_EffectMagneticFluxTryDef: BattleScript_EffectMagneticFluxSkipAnim: setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectMagneticFluxTrySpDef, BIT_SPDEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectMagneticFluxTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectMagneticFluxTrySpDef addbyte gBattleCommunication, 1 printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectMagneticFluxTrySpDef: setstatchanger STAT_SPDEF, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectMagneticFluxLoop - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectMagneticFluxLoop + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectMagneticFluxLoop addbyte gBattleCommunication, 1 printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG @@ -1412,8 +1257,6 @@ BattleScript_EffectMagneticFluxEnd: BattleScript_EffectGearUp:: attackcanceler - attackstring - ppreduce setbyte gBattleCommunication, 0 BattleScript_EffectGearUpStart: jumpifability BS_TARGET, ABILITY_MINUS, BattleScript_EffectGearUpCheckStats @@ -1429,14 +1272,14 @@ BattleScript_EffectGearUpTryAtk: BattleScript_EffectGearUpSkipAnim: setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectGearUpTrySpAtk, BIT_SPATK - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectGearUpTrySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectGearUpTrySpAtk addbyte gBattleCommunication, 1 printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectGearUpTrySpAtk: setstatchanger STAT_SPATK, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectGearUpLoop - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectGearUpLoop + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectGearUpLoop addbyte gBattleCommunication, 1 printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG @@ -1450,10 +1293,8 @@ BattleScript_EffectGearUpEnd: BattleScript_EffectAcupressure:: attackcanceler jumpifbyteequal gBattlerTarget, gBattlerAttacker, BattleScript_EffectAcupressureTry - jumpifvolatile BS_TARGET, VOLATILE_SUBSTITUTE, BattleScript_PrintMoveMissed + jumpifvolatile BS_TARGET, VOLATILE_SUBSTITUTE, BattleScript_MoveMissedPause BattleScript_EffectAcupressureTry: - attackstring - ppreduce tryacupressure BattleScript_ButItFailed attackanimation waitanimation @@ -1469,9 +1310,7 @@ BattleScript_MoveEffectFeint:: BattleScript_EffectThirdType:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE trythirdtype BattleScript_ButItFailed attackanimation waitanimation @@ -1481,8 +1320,6 @@ BattleScript_EffectThirdType:: BattleScript_EffectFlowerShield:: attackcanceler - attackstring - ppreduce savetarget selectfirstvalidtarget BattleScript_FlowerShieldIsAnyValidTarget: @@ -1501,8 +1338,8 @@ BattleScript_FlowerShieldLoop: BattleScript_FlowerShieldLoop2: setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_FlowerShieldMoveTargetEnd - jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_FlowerShieldDoAnim - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_EMPTY, BattleScript_FlowerShieldMoveTargetEnd + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_FlowerShieldDoAnim + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_FlowerShieldMoveTargetEnd pause 21 goto BattleScript_FlowerShieldString BattleScript_FlowerShieldDoAnim: @@ -1516,13 +1353,11 @@ BattleScript_FlowerShieldMoveTargetEnd: moveendto MOVEEND_NEXT_TARGET jumpifnexttargetvalid BattleScript_FlowerShieldLoop restoretarget - moveendfrom MOVEEND_ITEM_EFFECTS_ATTACKER + moveendfrom MOVEEND_ITEM_EFFECTS_ATTACKER_1 end BattleScript_EffectRototiller:: attackcanceler - attackstring - ppreduce getrototillertargets BattleScript_ButItFailed @ at least one battler is affected attackanimation @@ -1537,13 +1372,13 @@ BattleScript_RototillerCheckAffected: jumpifnotrototilleraffected BattleScript_RototillerNoEffect setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_RototillerTrySpAtk, BIT_SPATK - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_RototillerTrySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_RototillerTrySpAtk printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_RototillerTrySpAtk:: setstatchanger STAT_SPATK, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_RototillerMoveTargetEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_RototillerMoveTargetEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_RototillerMoveTargetEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_RototillerMoveTargetEnd: @@ -1567,23 +1402,20 @@ BattleScript_RototillerNoEffect: BattleScript_EffectBestow:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, NO_ACC_CALC_CHECK_LOCK_ON jumpifsubstituteblocks BattleScript_ButItFailed trybestow BattleScript_ButItFailed attackanimation waitanimation printstring STRINGID_BESTOWITEMGIVING waitmessage B_WAIT_TIME_LONG + tryactivateitem BS_TARGET, ACTIVATION_ON_USABLE_AGAIN trysymbiosis BS_ATTACKER goto BattleScript_MoveEnd BattleScript_EffectAfterYou:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE tryafteryou BattleScript_ButItFailed attackanimation waitanimation @@ -1594,17 +1426,14 @@ BattleScript_EffectAfterYou:: BattleScript_MoveEffectFlameBurst:: printstring STRINGID_BURSTINGFLAMESHIT waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE tryfaintmon BS_SCRIPTING return BattleScript_EffectPowerTrick:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE powertrick attackanimation waitanimation @@ -1614,9 +1443,7 @@ BattleScript_EffectPowerTrick:: BattleScript_EffectPsychoShift:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifstatus BS_ATTACKER, STATUS1_ANY, BattleScript_EffectPsychoShiftCanWork goto BattleScript_ButItFailed BattleScript_EffectPsychoShiftCanWork: @@ -1638,9 +1465,7 @@ BattleScript_EffectPsychoShiftCanWork: BattleScript_EffectSynchronoise:: attackcanceler - attackstring pause B_WAIT_TIME_MED - ppreduce trysynchronoise BattleScript_MoveEnd accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE goto BattleScript_HitFromCritCalc @@ -1669,14 +1494,12 @@ BattleScript_EffectDefog:: jumpifsubstituteblocks BattleScript_DefogIfCanClearHazards jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_EVASION, MIN_STAT_STAGE, BattleScript_DefogWorks BattleScript_DefogIfCanClearHazards: - trydefog FALSE, BattleScript_FailedFromAtkString + trydefog FALSE, BattleScript_ButItFailed BattleScript_DefogWorks: - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_DefogTryHazardsWithAnim - jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_DefogDoAnim - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_DefogTryHazardsWithAnim + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_DefogDoAnim + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_DefogTryHazardsWithAnim pause B_WAIT_TIME_SHORT goto BattleScript_DefogPrintString BattleScript_DefogDoAnim:: @@ -1702,23 +1525,9 @@ BattleScript_MoveEffectDefog:: restoreattacker return -BattleScript_EffectCopycat:: - attackcanceler - attackstring - pause 5 - trycopycat BattleScript_CopycatFail - attackanimation - waitanimation - jumptocalledmove TRUE -BattleScript_CopycatFail: - ppreduce - goto BattleScript_ButItFailed - BattleScript_EffectInstruct:: attackcanceler - attackstring - ppreduce - pause 5 + pause B_WAIT_TIME_SHORT tryinstruct BattleScript_ButItFailed attackanimation waitanimation @@ -1731,10 +1540,8 @@ BattleScript_EffectInstruct:: BattleScript_EffectAutotomize:: setstatchanger STAT_SPEED, 2, FALSE attackcanceler - attackstring - ppreduce statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_AutotomizeWeightLoss - jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_AutotomizeAttackAnim + jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_AutotomizeAttackAnim pause B_WAIT_TIME_SHORT goto BattleScript_AutotomizePrintString BattleScript_AutotomizeAttackAnim:: @@ -1753,8 +1560,8 @@ BattleScript_AutotomizeWeightLoss:: BattleScript_FinalGambit:: setatkhptozero - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return @@ -1772,17 +1579,15 @@ BattleScript_HitSwitchTargetForceRandomSwitchFailed: BattleScript_EffectToxicThread:: setstatchanger STAT_SPEED, 1, TRUE attackcanceler - jumpifsubstituteblocks BattleScript_FailedFromAtkString + jumpifsubstituteblocks BattleScript_ButItFailed checknonvolatiletrigger MOVE_EFFECT_POISON, BattleScript_EffectStatDownFromAccCheck - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE attackanimation waitanimation setstatchanger STAT_SPEED, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_ToxicThreadTryPsn - jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_ToxicThreadDoAnim - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_ToxicThreadTryPsn + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ToxicThreadDoAnim + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_ToxicThreadTryPsn pause B_WAIT_TIME_SHORT goto BattleScript_ToxicThreadPrintString BattleScript_ToxicThreadDoAnim:: @@ -1796,8 +1601,6 @@ BattleScript_ToxicThreadTryPsn:: BattleScript_EffectVenomDrench:: attackcanceler - attackstring - ppreduce jumpifstatus BS_TARGET, STATUS1_PSN_ANY, BattleScript_EffectVenomDrenchCanBeUsed goto BattleScript_ButItFailed BattleScript_EffectVenomDrenchCanBeUsed: @@ -1810,19 +1613,19 @@ BattleScript_VenomDrenchDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_VenomDrenchTryLowerSpAtk, BIT_SPATK | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_VenomDrenchTryLowerSpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VenomDrenchTryLowerSpAtk printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VenomDrenchTryLowerSpAtk:: setstatchanger STAT_SPATK, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_VenomDrenchTryLowerSpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_VenomDrenchTryLowerSpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VenomDrenchTryLowerSpeed printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VenomDrenchTryLowerSpeed:: setstatchanger STAT_SPEED, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_VenomDrenchEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_VenomDrenchEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VenomDrenchEnd printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VenomDrenchEnd:: @@ -1830,8 +1633,6 @@ BattleScript_VenomDrenchEnd:: BattleScript_EffectNobleRoar:: attackcanceler - attackstring - ppreduce jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_NobleRoarDoMoveAnim jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPATK, MIN_STAT_STAGE, BattleScript_CantLowerMultipleStats BattleScript_NobleRoarDoMoveAnim:: @@ -1840,13 +1641,13 @@ BattleScript_NobleRoarDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_NobleRoarTryLowerSpAtk, BIT_SPATK - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_NobleRoarTryLowerSpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_NobleRoarTryLowerSpAtk printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_NobleRoarTryLowerSpAtk:: setstatchanger STAT_SPATK, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_NobleRoarEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_NobleRoarEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_NobleRoarEnd printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_NobleRoarEnd:: @@ -1854,8 +1655,6 @@ BattleScript_NobleRoarEnd:: BattleScript_EffectShellSmash:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_ShellSmashTryDef jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_ShellSmashTryDef jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPEED, MAX_STAT_STAGE, BattleScript_ShellSmashTryDef @@ -1866,48 +1665,38 @@ BattleScript_ShellSmashTryDef:: waitanimation setstatchanger STAT_DEF, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_CERTAIN, BattleScript_ShellSmashTrySpDef, BIT_SPDEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShellSmashTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ShellSmashTrySpDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShellSmashTrySpDef: setstatchanger STAT_SPDEF, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_CERTAIN, BattleScript_ShellSmashTryAttack - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShellSmashTryAttack + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ShellSmashTryAttack printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShellSmashTryAttack: setstatchanger STAT_ATK, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_ShellSmashTrySpAtk, BIT_SPATK | BIT_SPEED, - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShellSmashTrySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ShellSmashTrySpAtk printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShellSmashTrySpAtk: setstatchanger STAT_SPATK, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_ShellSmashTrySpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShellSmashTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ShellSmashTrySpeed printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShellSmashTrySpeed: setstatchanger STAT_SPEED, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_ShellSmashEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShellSmashEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ShellSmashEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShellSmashEnd: goto BattleScript_MoveEnd -BattleScript_EffectLastResort:: - attackcanceler - attackstring - ppreduce - trylastresort BattleScript_ButItFailed - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - goto BattleScript_HitFromCritCalc - BattleScript_EffectGrowth:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_GrowthDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPATK, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats BattleScript_GrowthDoMoveAnim:: @@ -1920,7 +1709,7 @@ BattleScript_GrowthAtk2: setstatchanger STAT_ATK, 2, FALSE BattleScript_GrowthAtk: statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_GrowthTrySpAtk, BIT_SPATK - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_GrowthTrySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_GrowthTrySpAtk printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_GrowthTrySpAtk:: @@ -1931,7 +1720,7 @@ BattleScript_GrowthSpAtk2: setstatchanger STAT_SPATK, 2, FALSE BattleScript_GrowthSpAtk: statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_GrowthEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_GrowthEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_GrowthEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_GrowthEnd: @@ -1939,9 +1728,7 @@ BattleScript_GrowthEnd: BattleScript_EffectSoak:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifability BS_TARGET, ABILITY_MULTITYPE, BattleScript_ButItFailed jumpifability BS_TARGET, ABILITY_RKS_SYSTEM, BattleScript_ButItFailed jumpifsubstituteblocks BattleScript_ButItFailed @@ -1954,9 +1741,7 @@ BattleScript_EffectSoak:: BattleScript_EffectReflectType:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE tryreflecttype BattleScript_ButItFailed attackanimation waitanimation @@ -1966,9 +1751,7 @@ BattleScript_EffectReflectType:: BattleScript_EffectElectrify:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE tryelectrify BattleScript_ButItFailed attackanimation waitanimation @@ -1978,8 +1761,6 @@ BattleScript_EffectElectrify:: BattleScript_EffectShiftGear:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPEED, MAX_STAT_STAGE, BattleScript_ShiftGearDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats BattleScript_ShiftGearDoMoveAnim: @@ -1992,13 +1773,13 @@ BattleScript_ShiftGearSpeedBy1: setstatchanger STAT_SPEED, 1, FALSE BattleScript_ShiftGearDoSpeed: statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_ShiftGearTryAtk, BIT_ATK - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShiftGearTryAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ShiftGearTryAtk printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShiftGearTryAtk: setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_ShiftGearEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_ShiftGearEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_ShiftGearEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_ShiftGearEnd: @@ -2006,8 +1787,6 @@ BattleScript_ShiftGearEnd: BattleScript_EffectCoil:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_CoilDoMoveAnim jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_DEF, MAX_STAT_STAGE, BattleScript_CoilDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_ACC, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats @@ -2016,19 +1795,19 @@ BattleScript_CoilDoMoveAnim: waitanimation setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CoilTryDef, BIT_DEF | BIT_ACC - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CoilTryDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CoilTryDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CoilTryDef: setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CoilTryAcc, BIT_ACC - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CoilTryAcc + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CoilTryAcc printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CoilTryAcc: setstatchanger STAT_ACC, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CoilEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CoilEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CoilEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CoilEnd: @@ -2036,8 +1815,6 @@ BattleScript_CoilEnd: BattleScript_EffectQuiverDance:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_QuiverDanceDoMoveAnim jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPDEF, MAX_STAT_STAGE, BattleScript_QuiverDanceDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats @@ -2046,19 +1823,19 @@ BattleScript_QuiverDanceDoMoveAnim:: waitanimation setstatchanger STAT_SPATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_QuiverDanceTrySpDef, BIT_SPDEF | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_QuiverDanceTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_QuiverDanceTrySpDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_QuiverDanceTrySpDef:: setstatchanger STAT_SPDEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_QuiverDanceTrySpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_QuiverDanceTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_QuiverDanceTrySpeed printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_QuiverDanceTrySpeed:: setstatchanger STAT_SPEED, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_QuiverDanceEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_QuiverDanceEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_QuiverDanceEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_QuiverDanceEnd:: @@ -2066,8 +1843,6 @@ BattleScript_QuiverDanceEnd:: BattleScript_EffectVictoryDance:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_VictoryDanceDoMoveAnim jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_DEF, MAX_STAT_STAGE, BattleScript_VictoryDanceDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats @@ -2076,36 +1851,26 @@ BattleScript_VictoryDanceDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_VictoryDanceTryDef, BIT_DEF | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_VictoryDanceTryDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VictoryDanceTryDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VictoryDanceTryDef:: setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_VictoryDanceTrySpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_VictoryDanceTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VictoryDanceTrySpeed printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VictoryDanceTrySpeed:: setstatchanger STAT_SPEED, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_VictoryDanceEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_VictoryDanceEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_VictoryDanceEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_VictoryDanceEnd:: goto BattleScript_MoveEnd -BattleScript_EffectMeFirst:: - attackcanceler - attackstring - trymefirst BattleScript_FailedFromPpReduce - attackanimation - waitanimation - jumptocalledmove TRUE - BattleScript_EffectAttackSpAttackUp:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_AttackSpAttackUpDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPATK, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats BattleScript_AttackSpAttackUpDoMoveAnim:: @@ -2113,13 +1878,13 @@ BattleScript_AttackSpAttackUpDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_AttackSpAttackUpTrySpAtk, BIT_SPATK - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_AttackSpAttackUpTrySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_AttackSpAttackUpTrySpAtk printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_AttackSpAttackUpTrySpAtk:: setstatchanger STAT_SPATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_AttackSpAttackUpEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_AttackSpAttackUpEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_AttackSpAttackUpEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_AttackSpAttackUpEnd: @@ -2127,8 +1892,6 @@ BattleScript_AttackSpAttackUpEnd: BattleScript_EffectAttackAccUp:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_AttackAccUpDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_ACC, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats BattleScript_AttackAccUpDoMoveAnim:: @@ -2136,13 +1899,13 @@ BattleScript_AttackAccUpDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_AttackAccUpTryAcc, BIT_ACC - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_AttackAccUpTryAcc + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_AttackAccUpTryAcc printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_AttackAccUpTryAcc:: setstatchanger STAT_ACC, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_AttackAccUpEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_AttackAccUpEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_AttackAccUpEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_AttackAccUpEnd: @@ -2153,8 +1916,6 @@ BattleScript_EffectGrassyTerrain:: BattleScript_EffectElectricTerrain:: BattleScript_EffectPsychicTerrain:: attackcanceler - attackstring - ppreduce setterrain BattleScript_ButItFailed attackanimation waitanimation @@ -2166,8 +1927,6 @@ BattleScript_EffectPsychicTerrain:: BattleScript_EffectTopsyTurvy:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_ATK, 6, BattleScript_EffectTopsyTurvyWorks jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_DEF, 6, BattleScript_EffectTopsyTurvyWorks @@ -2186,9 +1945,7 @@ BattleScript_EffectTopsyTurvyWorks: BattleScript_EffectIonDeluge:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE orword gFieldStatuses, STATUS_FIELD_ION_DELUGE attackanimation waitanimation @@ -2198,9 +1955,7 @@ BattleScript_EffectIonDeluge:: BattleScript_EffectQuash:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE tryquash BattleScript_ButItFailed attackanimation waitanimation @@ -2210,8 +1965,6 @@ BattleScript_EffectQuash:: BattleScript_EffectHealPulse:: attackcanceler - attackstring - ppreduce jumpifvolatile BS_ATTACKER, VOLATILE_HEAL_BLOCK, BattleScript_MoveUsedHealBlockPrevents @ stops pollen puff jumpifvolatile BS_TARGET, VOLATILE_HEAL_BLOCK, BattleScript_MoveUsedHealBlockPrevents accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON @@ -2219,21 +1972,19 @@ BattleScript_EffectHealPulse:: tryhealpulse BattleScript_AlreadyAtFullHp attackanimation waitanimation - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd BattleScript_EffectEntrainment:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE tryentrainment BattleScript_ButItFailed attackanimation waitanimation - setlastusedability + switchinabilities BS_TARGET printstring STRINGID_PKMNACQUIREDABILITY waitmessage B_WAIT_TIME_LONG trytoclearprimalweather @@ -2242,37 +1993,8 @@ BattleScript_EffectEntrainment:: tryendneutralizinggas goto BattleScript_MoveEnd -BattleScript_EffectSimpleBeam:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - setsimplebeam BattleScript_ButItFailed - attackanimation - waitanimation -.if B_ABILITY_POP_UP == TRUE - copybyte gBattlerAbility, gBattlerTarget - call BattleScript_AbilityPopUpOverwriteThenNormal -.endif - recordability BS_TARGET - printstring STRINGID_PKMNACQUIREDSIMPLE - waitmessage B_WAIT_TIME_LONG - trytoclearprimalweather - tryrevertweatherform - flushtextbox - tryendneutralizinggas - goto BattleScript_MoveEnd - -BattleScript_EffectSuckerPunch:: - attackcanceler - suckerpunchcheck BattleScript_FailedFromAtkString - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - goto BattleScript_HitFromAtkString - BattleScript_EffectLuckyChant:: attackcanceler - attackstring - ppreduce setluckychant BattleScript_ButItFailed attackanimation waitanimation @@ -2282,10 +2004,8 @@ BattleScript_EffectLuckyChant:: BattleScript_EffectMetalBurst:: attackcanceler - metalburstdamagecalculator BattleScript_FailedFromAtkString - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + metalburstdamagecalculator BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE typecalc clearmoveresultflags MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE adjustdamage @@ -2293,9 +2013,7 @@ BattleScript_EffectMetalBurst:: BattleScript_EffectHealingWish:: attackcanceler - jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_FailedFromAtkString - attackstring - ppreduce + jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailed attackanimation waitanimation instanthpdrop @@ -2338,8 +2056,8 @@ BattleScript_EffectHealingWishRestore: waitanimation dmgtomaxattackerhp manipulatedamage DMG_CHANGE_SIGN - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE clearstatus waitstate updatestatusicon BS_ATTACKER @@ -2348,18 +2066,14 @@ BattleScript_EffectHealingWishRestore: waitmessage B_WAIT_TIME_LONG return -BattleScript_EffectWorrySeed:: +BattleScript_EffectOverwriteAbility:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - tryworryseed BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE + tryoverwriteability BattleScript_ButItFailed attackanimation waitanimation -.if B_ABILITY_POP_UP == TRUE copybyte gBattlerAbility, gBattlerTarget call BattleScript_AbilityPopUpOverwriteThenNormal -.endif recordability BS_TARGET printstring STRINGID_PKMNACQUIREDABILITY waitmessage B_WAIT_TIME_LONG @@ -2371,8 +2085,6 @@ BattleScript_EffectWorrySeed:: BattleScript_EffectPowerSplit:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON averagestats STAT_ATK averagestats STAT_SPATK @@ -2384,8 +2096,6 @@ BattleScript_EffectPowerSplit:: BattleScript_EffectGuardSplit:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON averagestats STAT_DEF averagestats STAT_SPDEF @@ -2397,8 +2107,6 @@ BattleScript_EffectGuardSplit:: BattleScript_EffectHeartSwap:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON swapstatstages STAT_ATK swapstatstages STAT_DEF @@ -2415,8 +2123,6 @@ BattleScript_EffectHeartSwap:: BattleScript_EffectPowerSwap:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON swapstatstages STAT_ATK swapstatstages STAT_SPATK @@ -2428,8 +2134,6 @@ BattleScript_EffectPowerSwap:: BattleScript_EffectGuardSwap:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON swapstatstages STAT_DEF swapstatstages STAT_SPDEF @@ -2441,8 +2145,6 @@ BattleScript_EffectGuardSwap:: BattleScript_EffectSpeedSwap:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON swapstats STAT_SPEED attackanimation @@ -2453,9 +2155,7 @@ BattleScript_EffectSpeedSwap:: BattleScript_EffectTelekinesis:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, NO_ACC_CALC_CHECK_LOCK_ON settelekinesis BattleScript_ButItFailed attackanimation waitanimation @@ -2465,8 +2165,6 @@ BattleScript_EffectTelekinesis:: BattleScript_EffectStealthRock:: attackcanceler - attackstring - ppreduce setstealthrock BattleScript_ButItFailed attackanimation waitanimation @@ -2476,8 +2174,6 @@ BattleScript_EffectStealthRock:: BattleScript_EffectStickyWeb:: attackcanceler - attackstring - ppreduce setstickyweb BattleScript_ButItFailed attackanimation waitanimation @@ -2487,9 +2183,7 @@ BattleScript_EffectStickyWeb:: BattleScript_EffectGastroAcid:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifvolatile BS_TARGET, VOLATILE_GASTRO_ACID, BattleScript_ButItFailed setgastroacid BattleScript_ButItFailed attackanimation @@ -2504,8 +2198,6 @@ BattleScript_EffectGastroAcid:: BattleScript_EffectToxicSpikes:: attackcanceler - attackstring - ppreduce settoxicspikes BattleScript_ButItFailed attackanimation waitanimation @@ -2515,8 +2207,6 @@ BattleScript_EffectToxicSpikes:: BattleScript_EffectMagnetRise:: attackcanceler - attackstring - ppreduce jumpifvolatile BS_ATTACKER, VOLATILE_ROOT, BattleScript_ButItFailed jumpifvolatile BS_ATTACKER, VOLATILE_SMACK_DOWN, BattleScript_ButItFailed trysetvolatile BS_ATTACKER, VOLATILE_MAGNET_RISE, BattleScript_ButItFailed @@ -2528,8 +2218,6 @@ BattleScript_EffectMagnetRise:: BattleScript_EffectTrickRoom:: attackcanceler - attackstring - ppreduce setroom attackanimation waitanimation @@ -2554,8 +2242,6 @@ BattleScript_RoomServiceLoop_NextBattler: BattleScript_EffectWonderRoom:: BattleScript_EffectMagicRoom:: attackcanceler - attackstring - ppreduce setroom attackanimation waitanimation @@ -2565,8 +2251,6 @@ BattleScript_EffectMagicRoom:: BattleScript_EffectAquaRing:: attackcanceler - attackstring - ppreduce setvolatile BS_ATTACKER, VOLATILE_AQUA_RING attackanimation waitanimation @@ -2576,9 +2260,7 @@ BattleScript_EffectAquaRing:: BattleScript_EffectEmbargo:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE setembargo BattleScript_ButItFailed attackanimation waitanimation @@ -2588,8 +2270,6 @@ BattleScript_EffectEmbargo:: BattleScript_EffectTailwind:: attackcanceler - attackstring - ppreduce settailwind BattleScript_ButItFailed attackanimation waitanimation @@ -2618,26 +2298,23 @@ BattleScript_TryTailwindAbilitiesLoop_WindRider: BattleScript_TryTailwindAbilitiesLoop_WindPower: call BattleScript_AbilityPopUp - setcharge BS_TARGET + setvolatile BS_TARGET, VOLATILE_CHARGE_TIMER, 2 printstring STRINGID_BEINGHITCHARGEDPKMNWITHPOWER waitmessage B_WAIT_TIME_LONG goto BattleScript_TryTailwindAbilitiesLoop_Increment BattleScript_EffectMiracleEye:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE setvolatile BS_TARGET, VOLATILE_MIRACLE_EYE goto BattleScript_IdentifiedFoe + BattleScript_EffectGravity:: call BattleScript_EffectGravityInternal goto BattleScript_MoveEnd BattleScript_EffectGravityInternal: attackcanceler - attackstring - ppreduce setgravity BattleScript_ButItFailed attackanimation waitanimation @@ -2664,29 +2341,23 @@ BattleScript_GravityLoopEnd: BattleScript_EffectRoost:: attackcanceler - attackstring - ppreduce - tryhealhalfhealth BattleScript_AlreadyAtFullHp, BS_TARGET + tryhealhalfhealth BS_TARGET, BattleScript_AlreadyAtFullHp setroost goto BattleScript_PresentHealTarget BattleScript_EffectCaptivate:: setstatchanger STAT_SPATK, 2, TRUE attackcanceler - attackstring - ppreduce jumpifsubstituteblocks BattleScript_ButItFailed jumpifcaptivateaffected BattleScript_CaptivateCheckAcc goto BattleScript_ButItFailed BattleScript_CaptivateCheckAcc: accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE - goto BattleScript_StatDownFromAttackString + goto BattleScript_EffectStatDownFromStatBuffChange BattleScript_EffectHealBlock:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects sethealblock BattleScript_ButItFailed attackanimation @@ -2705,8 +2376,6 @@ BattleScript_HitEscapeSwitch: BattleScript_EffectPlaceholder:: attackcanceler - attackstring - ppreduce pause 5 printstring STRINGID_NOTDONEYET goto BattleScript_MoveEnd @@ -2714,10 +2383,7 @@ BattleScript_EffectPlaceholder:: BattleScript_EffectHit:: attackcanceler BattleScript_HitFromAccCheck:: - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE -BattleScript_HitFromAtkString:: - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE BattleScript_HitFromCritCalc:: critcalc damagecalc @@ -2733,9 +2399,7 @@ BattleScript_MoveEnd:: BattleScript_EffectHit_Ret:: attackcanceler BattleScript_EffectHit_RetFromAccCheck:: - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE BattleScript_EffectHit_RetFromCritCalc:: critcalc damagecalc @@ -2746,8 +2410,8 @@ BattleScript_Hit_RetFromAtkAnimation:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_LONG resultmessage @@ -2757,8 +2421,6 @@ BattleScript_Hit_RetFromAtkAnimation:: BattleScript_EffectNaturalGift:: attackcanceler - attackstring - ppreduce jumpifnotberry BS_ATTACKER, BattleScript_ButItFailed jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailed jumpifability BS_ATTACKER, ABILITY_KLUTZ, BattleScript_ButItFailed @@ -2768,9 +2430,6 @@ BattleScript_EffectNaturalGift:: BattleScript_MakeMoveMissed:: setmoveresultflags MOVE_RESULT_MISSED -BattleScript_PrintMoveMissed:: - attackstring - ppreduce BattleScript_MoveMissedPause:: pause B_WAIT_TIME_SHORT BattleScript_MoveMissed:: @@ -2788,7 +2447,7 @@ BattleScript_TerrainPreventsEnd2:: BattleScript_ImmunityProtectedEnd2:: call BattleScript_AbilityPopUp pause B_WAIT_TIME_SHORT - printfromtable gStatusPreventionStringIds + printstring STRINGID_ITDOESNTAFFECT waitmessage B_WAIT_TIME_LONG end2 @@ -2842,14 +2501,6 @@ BattleScript_AromaVeilProtects: setmoveresultflags MOVE_RESULT_FAILED goto BattleScript_MoveEnd -BattleScript_PastelVeilProtects: - pause B_WAIT_TIME_SHORT - call BattleScript_AbilityPopUp - printstring STRINGID_PASTELVEILPROTECTED - waitmessage B_WAIT_TIME_LONG - setmoveresultflags MOVE_RESULT_FAILED - goto BattleScript_MoveEnd - BattleScript_AbilityProtectsDoesntAffectRet:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp @@ -2862,7 +2513,7 @@ BattleScript_AbilityProtectsDoesntAffect:: setmoveresultflags MOVE_RESULT_FAILED goto BattleScript_MoveEnd -BattleScript_InsomniaProtects: +BattleScript_InsomniaProtects:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printstring STRINGID_PKMNSTAYEDAWAKEUSING @@ -2891,24 +2542,21 @@ BattleScript_EffectAbsorbLiquidOoze:: goto BattleScript_EffectAbsorb BattleScript_EffectAbsorb:: - absorbhealthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printfromtable gAbsorbDrainStringIds waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER - bicword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_PASSIVE_HP_UPDATE BattleScript_EffectAbsorbRet: return BattleScript_EffectExplosion:: attackcanceler - attackstring - ppreduce tryexplosion setatkhptozero waitstate jumpiffainted BS_TARGET, TRUE, BattleScript_MoveEnd - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE goto BattleScript_HitFromCritCalc BattleScript_FaintAttackerForExplosion:: @@ -2916,9 +2564,8 @@ BattleScript_FaintAttackerForExplosion:: return BattleScript_MaxHp50Recoil:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return @@ -2929,17 +2576,6 @@ BattleScript_EffectDreamEater:: jumpifability BS_TARGET, ABILITY_COMATOSE, BattleScript_HitFromAccCheck goto BattleScript_DoesntAffectTargetAtkString -BattleScript_EffectMirrorMove:: - attackcanceler - attackstring - pause B_WAIT_TIME_LONG - trymirrormove - ppreduce - setmoveresultflags MOVE_RESULT_FAILED - printstring STRINGID_MIRRORMOVEFAILED - waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd - BattleScript_EffectAttackUp:: setstatchanger STAT_ATK, 1, FALSE goto BattleScript_EffectStatUp @@ -2969,10 +2605,8 @@ BattleScript_EffectEvasionUp:: BattleScript_EffectStatUp:: attackcanceler BattleScript_EffectStatUpAfterAtkCanceler:: - attackstring - ppreduce statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_StatUpEnd - jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_StatUpAttackAnim + jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_StatUpAttackAnim pause B_WAIT_TIME_SHORT goto BattleScript_StatUpPrintString BattleScript_StatUpAttackAnim:: @@ -3019,16 +2653,13 @@ BattleScript_EffectEvasionDown:: setstatchanger STAT_EVASION, 1, TRUE BattleScript_EffectStatDown: attackcanceler - jumpifsubstituteblocks BattleScript_FailedFromAtkString + jumpifsubstituteblocks BattleScript_ButItFailed BattleScript_EffectStatDownFromAccCheck: - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE -BattleScript_StatDownFromAttackString: - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE BattleScript_EffectStatDownFromStatBuffChange: statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_StatDownEnd - jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_StatDownDoAnim - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_StatDownEnd + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_StatDownDoAnim + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_StatDownEnd pause B_WAIT_TIME_SHORT goto BattleScript_StatDownPrintString BattleScript_StatDownDoAnim:: @@ -3048,7 +2679,7 @@ BattleScript_MirrorArmorReflect:: jumpifvolatile BS_ATTACKER, VOLATILE_SUBSTITUTE, BattleScript_MirrorArmorDoesntAffect BattleScript_MirrorArmorReflectStatLoss: statbuffchange BS_ATTACKER, STAT_CHANGE_MIRROR_ARMOR | STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_MirrorArmorReflectEnd - jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_MirrorArmorReflectPrintString + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_MirrorArmorReflectPrintString goto BattleScript_MirrorArmorReflectWontFall BattleScript_MirrorArmorReflectPrintString: printfromtable gStatDownStringIds @@ -3082,8 +2713,6 @@ BattleScript_StatDown:: BattleScript_EffectHaze:: attackcanceler - attackstring - ppreduce attackanimation waitanimation normalisebuffs @@ -3093,8 +2722,6 @@ BattleScript_EffectHaze:: BattleScript_EffectBide:: attackcanceler - attackstring - ppreduce attackanimation waitanimation setbide @@ -3102,8 +2729,6 @@ BattleScript_EffectBide:: BattleScript_EffectRoar:: attackcanceler - attackstring - ppreduce jumpifroarfails BattleScript_ButItFailed jumpifcommanderactive BattleScript_ButItFailed jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_ButItFailed @@ -3134,8 +2759,6 @@ BattleScript_ScaleShot:: BattleScript_EffectConversion:: attackcanceler - attackstring - ppreduce tryconversiontypechange BattleScript_ButItFailed attackanimation waitanimation @@ -3145,15 +2768,12 @@ BattleScript_EffectConversion:: BattleScript_EffectRestoreHp:: attackcanceler - attackstring - ppreduce - tryhealhalfhealth BattleScript_AlreadyAtFullHp, BS_ATTACKER + tryhealhalfhealth BS_ATTACKER, BattleScript_AlreadyAtFullHp attackanimation waitanimation BattleScript_RestoreHp: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -3167,29 +2787,20 @@ BattleScript_AlreadyPoisoned:: BattleScript_ImmunityProtected:: call BattleScript_AbilityPopUp - pause B_WAIT_TIME_SHORT - printfromtable gStatusPreventionStringIds - waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + goto BattleScript_DoesntAffectTargetAtkString BattleScript_EffectAuroraVeil:: attackcanceler - attackstring - ppreduce setauroraveil goto BattleScript_PrintReflectLightScreenSafeguardString BattleScript_EffectLightScreen:: attackcanceler - attackstring - ppreduce setlightscreen goto BattleScript_PrintReflectLightScreenSafeguardString BattleScript_EffectRest:: attackcanceler - attackstring - ppreduce jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_RestIsAlreadyAsleep jumpifability BS_ATTACKER, ABILITY_COMATOSE, BattleScript_RestIsAlreadyAsleep jumpifuproarwakes BattleScript_RestCantSleep @@ -3197,7 +2808,7 @@ BattleScript_EffectRest:: jumpifability BS_TARGET, ABILITY_VITAL_SPIRIT, BattleScript_InsomniaProtects jumpifability BS_ATTACKER, ABILITY_PURIFYING_SALT, BattleScript_InsomniaProtects jumpifabilitypreventsrest BS_TARGET, BattleScript_AbilityPreventsRest - trysetrest BattleScript_AlreadyAtFullHp + trysetrest pause B_WAIT_TIME_SHORT printfromtable gRestUsedStringIds waitmessage B_WAIT_TIME_LONG @@ -3226,12 +2837,9 @@ BattleScript_AbilityPreventsRest:: BattleScript_EffectOHKO:: attackcanceler - attackstring - ppreduce typecalc jumpifmovehadnoeffect BattleScript_HitFromAtkAnimation tryKO BattleScript_KOFail - trysetdestinybondtohappen goto BattleScript_HitFromAtkAnimation BattleScript_KOFail:: pause B_WAIT_TIME_LONG @@ -3243,16 +2851,14 @@ BattleScript_RecoilIfMiss:: printstring STRINGID_PKMNCRASHED waitmessage B_WAIT_TIME_LONG jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_RecoilEnd - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER +BattleScript_RecoilEnd: return BattleScript_EffectMist:: attackcanceler - attackstring - ppreduce setmist attackanimation waitanimation @@ -3262,8 +2868,6 @@ BattleScript_EffectMist:: BattleScript_EffectFocusEnergy:: attackcanceler - attackstring - ppreduce jumpifvolatile BS_ATTACKER, VOLATILE_DRAGON_CHEER, BattleScript_ButItFailed jumpifvolatile BS_ATTACKER, VOLATILE_FOCUS_ENERGY, BattleScript_ButItFailed setfocusenergy BS_TARGET @@ -3275,8 +2879,6 @@ BattleScript_EffectFocusEnergy:: BattleScript_EffectConfuse:: attackcanceler - attackstring - ppreduce jumpifability BS_TARGET, ABILITY_OWN_TEMPO, BattleScript_OwnTempoPrevents jumpifsubstituteblocks BattleScript_ButItFailed jumpifvolatile BS_TARGET, VOLATILE_CONFUSION, BattleScript_AlreadyConfused @@ -3335,8 +2937,6 @@ BattleScript_EffectEvasionUp2:: BattleScript_EffectTransform:: attackcanceler - attackstring - ppreduce trytoclearprimalweather tryrevertweatherform flushtextbox @@ -3379,8 +2979,6 @@ BattleScript_EffectEvasionDown2:: BattleScript_EffectReflect:: attackcanceler - attackstring - ppreduce setreflect BattleScript_PrintReflectLightScreenSafeguardString:: attackanimation @@ -3415,8 +3013,6 @@ BattleScript_PowerHerbActivation: BattleScript_EffectTwoTurnsAttack:: jumpifvolatile BS_ATTACKER, VOLATILE_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_ATTACKSTRING_PRINTED, BattleScript_EffectHit @ if it's not the first hit tryfiretwoturnmovewithoutcharging BS_ATTACKER, BattleScript_EffectHit @ e.g. Solar Beam call BattleScript_FirstChargingTurn tryfiretwoturnmoveaftercharging BS_ATTACKER, BattleScript_TwoTurnMovesSecondTurn @ e.g. Electro Shot @@ -3425,7 +3021,6 @@ BattleScript_EffectTwoTurnsAttack:: BattleScript_EffectGeomancy:: jumpifvolatile BS_ATTACKER, VOLATILE_MULTIPLETURNS, BattleScript_GeomancySecondTurn - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_GeomancySecondTurn call BattleScript_FirstChargingTurn jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd call BattleScript_PowerHerbActivation @@ -3433,8 +3028,6 @@ BattleScript_GeomancySecondTurn: attackcanceler setbyte sB_ANIM_TURN, 1 clearvolatile BS_ATTACKER, VOLATILE_MULTIPLETURNS - orword gHitMarker, HITMARKER_NO_PPDEDUCT - attackstring jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_GeomancyDoMoveAnim jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPDEF, MAX_STAT_STAGE, BattleScript_GeomancyDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats @@ -3443,19 +3036,19 @@ BattleScript_GeomancyDoMoveAnim:: waitanimation setstatchanger STAT_SPATK, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_GeomancyTrySpDef, BIT_SPDEF | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_GeomancyTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_GeomancyTrySpDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_GeomancyTrySpDef:: setstatchanger STAT_SPDEF, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_GeomancyTrySpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_GeomancyTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_GeomancyTrySpeed printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_GeomancyTrySpeed:: setstatchanger STAT_SPEED, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_GeomancyEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_GeomancyEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_GeomancyEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_GeomancyEnd:: @@ -3463,13 +3056,7 @@ BattleScript_GeomancyEnd:: BattleScript_FirstChargingTurn:: attackcanceler -@ before Gen 5, charge moves did not print an attack string on the charge turn -.if B_UPDATED_MOVE_DATA >= GEN_5 - flushtextbox - attackstring waitmessage B_WAIT_TIME_LONG -.endif - ppreduce BattleScript_FirstChargingTurnAfterAttackString: setsemiinvulnerablebit @ only for moves with EFFECT_SEMI_INVULNERABLE/EFFECT_SKY_DROP setchargingturn @@ -3482,17 +3069,12 @@ BattleScript_TwoTurnMovesSecondPowerHerbActivates: trygulpmissile @ Edge case for Cramorant ability Gulp Missile BattleScript_FromTwoTurnMovesSecondTurnRet: call BattleScript_TwoTurnMovesSecondTurnRet - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE -@ before Gen 5, charge moves did not print an attack string on the charge turn -.if B_UPDATED_MOVE_DATA < GEN_5 - attackstring -.endif + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE goto BattleScript_HitFromCritCalc BattleScript_TwoTurnMovesSecondTurn:: attackcanceler call BattleScript_TwoTurnMovesSecondTurnRet - orword gHitMarker, HITMARKER_NO_PPDEDUCT goto BattleScript_HitFromAccCheck BattleScript_TwoTurnMovesSecondTurnRet: @@ -3504,17 +3086,14 @@ BattleScript_TwoTurnMovesSecondTurnRet: BattleScript_EffectSubstitute:: attackcanceler - ppreduce - attackstring waitstate jumpifvolatile BS_ATTACKER, VOLATILE_SUBSTITUTE, BattleScript_AlreadyHasSubstitute setsubstitute jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SUBSTITUTE_FAILED, BattleScript_SubstituteString - orword gHitMarker, HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE BattleScript_SubstituteString:: pause B_WAIT_TIME_SHORT printfromtable gSubstituteUsedStringIds @@ -3536,15 +3115,13 @@ BattleScript_EffectRage:: attackcanceler accuracycheck BattleScript_RageMiss, ACC_CURR_MOVE seteffectprimary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_RAGE - goto BattleScript_HitFromAtkString + goto BattleScript_HitFromCritCalc BattleScript_RageMiss:: clearvolatile BS_ATTACKER, VOLATILE_RAGE - goto BattleScript_PrintMoveMissed + goto BattleScript_MoveMissedPause BattleScript_EffectMimic:: attackcanceler - attackstring - ppreduce jumpifsubstituteblocks BattleScript_ButItFailed accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON mimicattackcopy BattleScript_ButItFailed @@ -3554,19 +3131,9 @@ BattleScript_EffectMimic:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectMetronome:: - attackcanceler - attackstring - pause B_WAIT_TIME_SHORT - attackanimation - waitanimation - metronome - BattleScript_EffectLeechSeed:: attackcanceler - attackstring pause B_WAIT_TIME_SHORT - ppreduce jumpifsubstituteblocks BattleScript_ButItFailed accuracycheck BattleScript_DoLeechSeed, ACC_CURR_MOVE BattleScript_DoLeechSeed:: @@ -3579,8 +3146,6 @@ BattleScript_DoLeechSeed:: BattleScript_EffectDoNothing:: attackcanceler - attackstring - ppreduce attackanimation waitanimation incrementgamestat GAME_STAT_USED_SPLASH @@ -3590,8 +3155,6 @@ BattleScript_EffectDoNothing:: BattleScript_EffectHoldHands:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifbyteequal gBattlerTarget, gBattlerAttacker, BattleScript_ButItFailed attackanimation @@ -3600,8 +3163,6 @@ BattleScript_EffectHoldHands:: BattleScript_EffectCelebrate:: attackcanceler - attackstring - ppreduce attackanimation waitanimation printstring STRINGID_CELEBRATEMESSAGE @@ -3610,8 +3171,6 @@ BattleScript_EffectCelebrate:: BattleScript_EffectHappyHour:: attackcanceler - attackstring - ppreduce attackanimation waitanimation seteffectprimary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_HAPPY_HOUR @@ -3619,8 +3178,6 @@ BattleScript_EffectHappyHour:: BattleScript_EffectDisable:: attackcanceler - attackstring - ppreduce jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE disablelastusedattack BattleScript_ButItFailed @@ -3632,10 +3189,8 @@ BattleScript_EffectDisable:: BattleScript_EffectCounter:: attackcanceler - counterdamagecalculator BattleScript_FailedFromAtkString - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + counterdamagecalculator BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE typecalc clearmoveresultflags MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE adjustdamage @@ -3643,9 +3198,7 @@ BattleScript_EffectCounter:: BattleScript_EffectEncore:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects trysetencore BattleScript_ButItFailed attackanimation @@ -3656,43 +3209,30 @@ BattleScript_EffectEncore:: BattleScript_EffectPainSplit:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON painsplitdmgcalc BattleScript_ButItFailed attackanimation waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_SHAREDPAIN waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd BattleScript_EffectSnore:: attackcanceler - jumpifability BS_ATTACKER, ABILITY_COMATOSE, BattleScript_SnoreIsAsleep - jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_SnoreIsAsleep - attackstring - ppreduce - goto BattleScript_ButItFailed -BattleScript_SnoreIsAsleep:: jumpifhalfword CMP_EQUAL, gChosenMove, MOVE_SLEEP_TALK, BattleScript_DoSnore printstring STRINGID_PKMNFASTASLEEP waitmessage B_WAIT_TIME_LONG statusanimation BS_ATTACKER BattleScript_DoSnore:: - attackstring - ppreduce accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE goto BattleScript_HitFromCritCalc BattleScript_EffectConversion2:: attackcanceler - attackstring - ppreduce settypetorandomresistance BattleScript_ButItFailed attackanimation waitanimation @@ -3702,8 +3242,6 @@ BattleScript_EffectConversion2:: BattleScript_EffectLockOn:: attackcanceler - attackstring - ppreduce jumpifsubstituteblocks BattleScript_ButItFailed accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE setalwayshitflag @@ -3715,8 +3253,6 @@ BattleScript_EffectLockOn:: BattleScript_EffectSketch:: attackcanceler - attackstring - ppreduce copymovepermanently BattleScript_ButItFailed attackanimation waitanimation @@ -3724,33 +3260,9 @@ BattleScript_EffectSketch:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectSleepTalk:: - attackcanceler - jumpifability BS_ATTACKER, ABILITY_COMATOSE, BattleScript_SleepTalkIsAsleep - jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_SleepTalkIsAsleep - attackstring - ppreduce - goto BattleScript_ButItFailed -BattleScript_SleepTalkIsAsleep:: - printstring STRINGID_PKMNFASTASLEEP - waitmessage B_WAIT_TIME_LONG - statusanimation BS_ATTACKER - attackstring - ppreduce - orword gHitMarker, HITMARKER_NO_PPDEDUCT - trychoosesleeptalkmove BattleScript_SleepTalkUsingMove - pause B_WAIT_TIME_LONG - goto BattleScript_ButItFailed -BattleScript_SleepTalkUsingMove:: - attackanimation - waitanimation - jumptocalledmove TRUE - BattleScript_EffectDestinyBond:: attackcanceler - attackstring - ppreduce - trysetdestinybond BattleScript_ButItFailed + setvolatile BS_ATTACKER, VOLATILE_DESTINY_BOND, 2 attackanimation waitanimation printstring STRINGID_PKMNTRYINGTOTAKEFOE @@ -3764,8 +3276,6 @@ BattleScript_MoveEffectEerieSpell:: BattleScript_EffectSpite:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE tryspiteppreduce BattleScript_ButItFailed attackanimation @@ -3777,8 +3287,6 @@ BattleScript_EffectSpite:: @ TODO: Simplfy script BattleScript_EffectHealBell:: attackcanceler - attackstring - ppreduce attackanimation waitanimation healpartystatus @@ -3811,8 +3319,6 @@ BattleScript_MoveEffectAromatherapy:: BattleScript_EffectMeanLook:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifvolatile BS_TARGET, VOLATILE_ESCAPE_PREVENTION, BattleScript_ButItFailed jumpifsubstituteblocks BattleScript_ButItFailed @@ -3828,8 +3334,6 @@ BattleScript_EffectMeanLook:: BattleScript_EffectNightmare:: attackcanceler - attackstring - ppreduce jumpifsubstituteblocks BattleScript_ButItFailed jumpifvolatile BS_TARGET, VOLATILE_NIGHTMARE, BattleScript_ButItFailed jumpifstatus BS_TARGET, STATUS1_SLEEP, BattleScript_NightmareWorked @@ -3857,8 +3361,6 @@ BattleScript_EffectCurse:: jumpiftype BS_ATTACKER, TYPE_GHOST, BattleScript_GhostCurse attackcanceler jumpiftype BS_ATTACKER, TYPE_GHOST, BattleScript_DoGhostCurse - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_GREATER_THAN, STAT_SPEED, MIN_STAT_STAGE, BattleScript_CurseTrySpeed jumpifstat BS_ATTACKER, CMP_NOT_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_CurseTrySpeed jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_DEF, MAX_STAT_STAGE, BattleScript_ButItFailed @@ -3888,32 +3390,21 @@ BattleScript_GhostCurse:: getmovetarget BattleScript_DoGhostCurse:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON cursetarget BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE setbyte sB_ANIM_TURN, 0 attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNLAIDCURSE waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER goto BattleScript_MoveEnd -BattleScript_EffectMatBlock:: - attackcanceler - jumpifnotfirstturn BattleScript_FailedFromAtkString - goto BattleScript_ProtectLikeAtkString - BattleScript_EffectProtect:: BattleScript_EffectEndure:: attackcanceler -BattleScript_ProtectLikeAtkString: - attackstring - ppreduce setprotectlike attackanimation waitanimation @@ -3923,9 +3414,7 @@ BattleScript_ProtectLikeAtkString: BattleScript_EffectSpikes:: attackcanceler - trysetspikes BattleScript_FailedFromAtkString - attackstring - ppreduce + trysetspikes BattleScript_ButItFailed attackanimation waitanimation printstring STRINGID_SPIKESSCATTERED @@ -3934,8 +3423,6 @@ BattleScript_EffectSpikes:: BattleScript_EffectForesight:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifvolatile BS_TARGET, VOLATILE_FORESIGHT, BattleScript_ButItFailed setvolatile BS_TARGET, VOLATILE_FORESIGHT @@ -3948,8 +3435,6 @@ BattleScript_IdentifiedFoe: BattleScript_EffectPerishSong:: attackcanceler - attackstring - ppreduce trysetperishsong BattleScript_ButItFailed savetarget attackanimation @@ -3979,17 +3464,13 @@ BattleScript_PerishSongNotAffected: BattleScript_EffectSandstorm:: attackcanceler - attackstring - ppreduce call BattleScript_CheckPrimalWeather setfieldweather BATTLE_WEATHER_SANDSTORM goto BattleScript_MoveWeatherChange BattleScript_EffectRollout:: attackcanceler - attackstring jumpifvolatile BS_ATTACKER, VOLATILE_MULTIPLETURNS, BattleScript_RolloutCheckAccuracy - ppreduce BattleScript_RolloutCheckAccuracy:: accuracycheck BattleScript_RolloutHit, ACC_CURR_MOVE BattleScript_RolloutHit:: @@ -4000,15 +3481,13 @@ BattleScript_RolloutHit:: BattleScript_EffectSwagger:: attackcanceler jumpifsubstituteblocks BattleScript_MakeMoveMissed - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifconfusedandstatmaxed STAT_ATK, BattleScript_ButItFailed attackanimation waitanimation setstatchanger STAT_ATK, 2, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_SwaggerTryConfuse - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_SwaggerTryConfuse + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_SwaggerTryConfuse printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_SwaggerTryConfuse: @@ -4019,8 +3498,6 @@ BattleScript_SwaggerTryConfuse: BattleScript_EffectFuryCutter:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_FuryCutterHit, ACC_CURR_MOVE BattleScript_FuryCutterHit: handlefurycutter @@ -4057,8 +3534,6 @@ BattleScript_TryDestinyKnotAttacker: BattleScript_EffectAttract:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects tryinfatuating BattleScript_ButItFailed @@ -4071,36 +3546,26 @@ BattleScript_EffectAttract:: BattleScript_EffectPresent:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE typecalc presentdamagecalculation BattleScript_EffectSafeguard:: attackcanceler - attackstring - ppreduce setsafeguard goto BattleScript_PrintReflectLightScreenSafeguardString BattleScript_EffectMagnitude:: - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT, BattleScript_EffectMagnitudeTarget attackcanceler - attackstring - ppreduce magnitudedamagecalculation pause B_WAIT_TIME_SHORT printstring STRINGID_MAGNITUDESTRENGTH waitmessage B_WAIT_TIME_LONG -BattleScript_EffectMagnitudeTarget: accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE goto BattleScript_HitFromCritCalc BattleScript_EffectBatonPass:: attackcanceler - attackstring - ppreduce jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_ButItFailed jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailed attackanimation @@ -4126,15 +3591,11 @@ BattleScript_EffectSynthesis:: BattleScript_EffectMoonlight:: BattleScript_EffectShoreUp:: attackcanceler - attackstring - ppreduce recoverbasedonsunlight BattleScript_AlreadyAtFullHp goto BattleScript_PresentHealTarget BattleScript_EffectRainDance:: attackcanceler - attackstring - ppreduce call BattleScript_CheckPrimalWeather setfieldweather BATTLE_WEATHER_RAIN BattleScript_MoveWeatherChange:: @@ -4151,8 +3612,6 @@ BattleScript_MoveWeatherChangeRet:: BattleScript_EffectSunnyDay:: attackcanceler - attackstring - ppreduce call BattleScript_CheckPrimalWeather setfieldweather BATTLE_WEATHER_SUN goto BattleScript_MoveWeatherChange @@ -4227,15 +3686,12 @@ BattleScript_BlockedByPrimalWeatherRet:: BattleScript_EffectBellyDrum:: attackcanceler - attackstring - ppreduce jumpifstatignorecontrary BS_ATTACKER, CMP_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_ButItFailed halvehp BattleScript_ButItFailed - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE attackanimation waitanimation - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE setstatchanger STAT_ATK, MAX_STAT_STAGE, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_MoveEnd printstring STRINGID_PKMNCUTHPMAXEDATTACK @@ -4244,8 +3700,6 @@ BattleScript_EffectBellyDrum:: BattleScript_EffectPsychUp:: attackcanceler - attackstring - ppreduce copyfoestats attackanimation waitanimation @@ -4255,10 +3709,8 @@ BattleScript_EffectPsychUp:: BattleScript_EffectMirrorCoat:: attackcanceler - mirrorcoatdamagecalculator BattleScript_FailedFromAtkString - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + mirrorcoatdamagecalculator BattleScript_ButItFailed + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE typecalc clearmoveresultflags MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE adjustdamage @@ -4266,9 +3718,7 @@ BattleScript_EffectMirrorCoat:: BattleScript_EffectFutureSight:: attackcanceler - attackstring - ppreduce - trysetfutureattack BattleScript_ButItFailed + setfutureattack attackanimation waitanimation printfromtable gFutureMoveUsedStringIds @@ -4284,8 +3734,6 @@ BattleScript_EffectTeleportGen7:: jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_FailedFromAtkCanceler BattleScript_DoEffectTeleport:: attackcanceler - attackstring - ppreduce isrunningimpossible jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FORBIDDEN, BattleScript_ButItFailed jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FAILURE, BattleScript_PrintAbilityMadeIneffective @@ -4302,22 +3750,18 @@ BattleScript_EffectBeatUp:: BattleScript_EffectBeatUpGen3: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE pause B_WAIT_TIME_SHORT - ppreduce trydobeatup BattleScript_MoveEnd, BattleScript_ButItFailed printstring STRINGID_PKMNATTACK goto BattleScript_HitFromCritCalc BattleScript_EffectDefenseCurl:: attackcanceler - attackstring - ppreduce setvolatile BS_TARGET, VOLATILE_DEFENSE_CURL setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_DefenseCurlDoStatUpAnim - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_StatUpPrintString + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_StatUpPrintString attackanimation waitanimation BattleScript_DefenseCurlDoStatUpAnim:: @@ -4325,15 +3769,12 @@ BattleScript_DefenseCurlDoStatUpAnim:: BattleScript_EffectSoftboiled:: attackcanceler - attackstring - ppreduce - tryhealhalfhealth BattleScript_AlreadyAtFullHp, BS_TARGET + tryhealhalfhealth BS_TARGET, BattleScript_AlreadyAtFullHp BattleScript_PresentHealTarget:: attackanimation waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -4344,17 +3785,8 @@ BattleScript_AlreadyAtFullHp:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectFirstTurnOnly:: - attackcanceler - jumpifnotfirstturn BattleScript_FailedFromAtkString - goto BattleScript_EffectHit - BattleScript_FailedFromAtkCanceler:: attackcanceler -BattleScript_FailedFromAtkString:: - attackstring -BattleScript_FailedFromPpReduce:: - ppreduce BattleScript_ButItFailed:: pause B_WAIT_TIME_SHORT setmoveresultflags MOVE_RESULT_FAILED @@ -4386,23 +3818,12 @@ BattleScript_NotAffectedAbilityPopUp:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectUproar:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - jumpifvolatile BS_ATTACKER, VOLATILE_MULTIPLETURNS, BattleScript_UproarHit - ppreduce -BattleScript_UproarHit:: - goto BattleScript_HitFromCritCalc - BattleScript_EffectStockpile:: attackcanceler - attackstring - ppreduce stockpile 0 attackanimation waitanimation - printfromtable gStockpileUsedStringIds + printstring STRINGID_PKMNSTOCKPILED waitmessage B_WAIT_TIME_LONG .if B_STOCKPILE_RAISES_DEFS < GEN_4 goto BattleScript_EffectStockpileEnd @@ -4413,13 +3834,13 @@ BattleScript_EffectStockpile:: BattleScript_EffectStockpileDef: setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectStockpileSpDef, BIT_SPDEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectStockpileSpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectStockpileSpDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectStockpileSpDef:: setstatchanger STAT_SPDEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectStockpileEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectStockpileEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectStockpileEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectStockpileEnd: @@ -4444,67 +3865,42 @@ BattleScript_StockpileStatChangeDown_Ret: BattleScript_EffectSpitUp:: attackcanceler jumpifbyte CMP_EQUAL, cMISS_TYPE, B_MSG_PROTECTED, BattleScript_SpitUpFailProtect - attackstring - ppreduce - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE damagecalc adjustdamage - stockpiletobasedamage BattleScript_SpitUpFail + stockpiletobasedamage call BattleScript_Hit_RetFromAtkAnimation tryfaintmon BS_TARGET removestockpilecounters - goto BattleScript_SpitUpEnd -BattleScript_SpitUpFail:: - checkparentalbondcounter 2, BattleScript_SpitUpEnd - pause B_WAIT_TIME_SHORT - printstring STRINGID_FAILEDTOSPITUP - waitmessage B_WAIT_TIME_LONG -BattleScript_SpitUpEnd: goto BattleScript_MoveEnd BattleScript_SpitUpFailProtect:: - attackstring - ppreduce pause B_WAIT_TIME_LONG - stockpiletobasedamage BattleScript_SpitUpFail + stockpiletobasedamage resultmessage waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd BattleScript_EffectSwallow:: attackcanceler - attackstring - ppreduce - stockpiletohpheal BattleScript_SwallowFail + stockpiletohpheal BattleScript_ButItFailed attackanimation waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG removestockpilecounters goto BattleScript_MoveEnd - -BattleScript_SwallowFail:: - pause B_WAIT_TIME_SHORT - printfromtable gSwallowFailStringIds - waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd - BattleScript_EffectHail:: attackcanceler - attackstring - ppreduce call BattleScript_CheckPrimalWeather setfieldweather BATTLE_WEATHER_HAIL goto BattleScript_MoveWeatherChange BattleScript_EffectTorment:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects settorment BattleScript_ButItFailed @@ -4517,15 +3913,13 @@ BattleScript_EffectTorment:: BattleScript_EffectFlatter:: attackcanceler jumpifsubstituteblocks BattleScript_MakeMoveMissed - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifconfusedandstatmaxed STAT_SPATK, BattleScript_ButItFailed attackanimation waitanimation setstatchanger STAT_SPATK, 1, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_FlatterTryConfuse - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_FlatterTryConfuse + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_FlatterTryConfuse printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_FlatterTryConfuse:: @@ -4541,8 +3935,6 @@ BattleScript_EffectDarkVoid:: .endif BattleScript_EffectNonVolatileStatus:: attackcanceler - attackstring - ppreduce trynonvolatilestatus accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE attackanimation @@ -4563,8 +3955,6 @@ BattleScript_AlreadyBurned:: BattleScript_EffectMemento:: attackcanceler jumpifbyte CMP_EQUAL, cMISS_TYPE, B_MSG_PROTECTED, BattleScript_MementoTargetProtect - attackstring - ppreduce trymemento BattleScript_ButItFailed setatkhptozero attackanimation @@ -4572,15 +3962,15 @@ BattleScript_EffectMemento:: jumpifsubstituteblocks BattleScript_EffectMementoPrintNoEffect setstatchanger STAT_ATK, 2, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectMementoTrySpAtk, BIT_SPATK -@ Greater than B_MSG_DEFENDER_STAT_FELL is checking if the stat cannot decrease - jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_FELL, BattleScript_EffectMementoTrySpAtk +@ Greater than B_MSG_DEFENDER_STAT_CHANGED is checking if the stat cannot decrease + jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_CHANGED, BattleScript_EffectMementoTrySpAtk printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectMementoTrySpAtk: setstatchanger STAT_SPATK, 2, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectMementoTryFaint -@ Greater than B_MSG_DEFENDER_STAT_FELL is checking if the stat cannot decrease - jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_FELL, BattleScript_EffectMementoTryFaint +@ Greater than B_MSG_DEFENDER_STAT_CHANGED is checking if the stat cannot decrease + jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_CHANGED, BattleScript_EffectMementoTryFaint printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectMementoTryFaint: @@ -4592,8 +3982,6 @@ BattleScript_EffectMementoPrintNoEffect: goto BattleScript_EffectMementoTryFaint @ If the target is protected there's no need to check the target's stats or animate, the user will just faint BattleScript_MementoTargetProtect: - attackstring - ppreduce trymemento BattleScript_MementoTargetProtectEnd BattleScript_MementoTargetProtectEnd: setatkhptozero @@ -4607,18 +3995,12 @@ BattleScript_MementoTargetProtectEnd: BattleScript_EffectFocusPunch:: attackcanceler jumpifnodamage BattleScript_HitFromAccCheck - ppreduce printstring STRINGID_PKMNLOSTFOCUS waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd BattleScript_EffectFollowMe:: attackcanceler - attackstring - ppreduce - .if B_UPDATED_MOVE_DATA >= GEN_8 - jumpifnotbattletype BATTLE_TYPE_DOUBLE, BattleScript_ButItFailed - .endif setforcedtarget attackanimation waitanimation @@ -4626,26 +4008,15 @@ BattleScript_EffectFollowMe:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectNaturePower:: - attackcanceler - attackstring - pause B_WAIT_TIME_SHORT - callenvironmentattack - printstring STRINGID_NATUREPOWERTURNEDINTO - waitmessage B_WAIT_TIME_LONG - return - BattleScript_EffectCharge:: attackcanceler - attackstring - ppreduce - setcharge BS_ATTACKER + setvolatile BS_ATTACKER, VOLATILE_CHARGE_TIMER, 2 attackanimation waitanimation .if B_CHARGE_SPDEF_RAISE >= GEN_5 setstatchanger STAT_SPDEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectChargeString - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectChargeString + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectChargeString printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectChargeString: @@ -4656,8 +4027,6 @@ BattleScript_EffectChargeString: BattleScript_EffectTaunt:: attackcanceler - attackstring - ppreduce jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE settaunt BattleScript_ButItFailed @@ -4669,8 +4038,6 @@ BattleScript_EffectTaunt:: BattleScript_EffectHelpingHand:: attackcanceler - attackstring - ppreduce trysethelpinghand BattleScript_ButItFailed attackanimation waitanimation @@ -4680,8 +4047,6 @@ BattleScript_EffectHelpingHand:: BattleScript_EffectTrick:: attackcanceler - attackstring - ppreduce jumpifsubstituteblocks BattleScript_ButItFailed accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE tryswapitems BattleScript_ButItFailed @@ -4695,16 +4060,12 @@ BattleScript_EffectTrick:: BattleScript_EffectRolePlay:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON trycopyability BS_ATTACKER, BattleScript_ButItFailed attackanimation waitanimation -.if B_ABILITY_POP_UP == TRUE copybyte gBattlerAbility, gBattlerAttacker call BattleScript_AbilityPopUpOverwriteThenNormal -.endif recordability BS_ATTACKER printstring STRINGID_PKMNCOPIEDFOE waitmessage B_WAIT_TIME_LONG @@ -4713,25 +4074,13 @@ BattleScript_EffectRolePlay:: BattleScript_EffectWish:: attackcanceler - attackstring - ppreduce trywish BattleScript_ButItFailed attackanimation waitanimation goto BattleScript_MoveEnd -BattleScript_EffectAssist:: - attackcanceler - attackstring - assistattackselect BattleScript_FailedFromPpReduce - attackanimation - waitanimation - jumptocalledmove TRUE - BattleScript_EffectIngrain:: attackcanceler - attackstring - ppreduce trysetvolatile BS_ATTACKER, VOLATILE_ROOT, BattleScript_ButItFailed attackanimation waitanimation @@ -4741,9 +4090,7 @@ BattleScript_EffectIngrain:: BattleScript_EffectMagicCoat:: attackcanceler - trysetmagiccoat BattleScript_FailedFromAtkString - attackstring - ppreduce + trysetmagiccoat BattleScript_ButItFailed attackanimation waitanimation printstring STRINGID_PKMNSHROUDEDITSELF @@ -4752,8 +4099,6 @@ BattleScript_EffectMagicCoat:: BattleScript_EffectRecycle:: attackcanceler - attackstring - ppreduce tryrecycleitem BattleScript_ButItFailed attackanimation waitanimation @@ -4763,9 +4108,7 @@ BattleScript_EffectRecycle:: BattleScript_EffectBrickBreak:: attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE typecalc removescreens critcalc @@ -4784,8 +4127,8 @@ BattleScript_BrickBreakDoHit:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_LONG resultmessage @@ -4796,8 +4139,6 @@ BattleScript_BrickBreakDoHit:: BattleScript_EffectYawn:: attackcanceler - attackstring - ppreduce trynonvolatilestatus accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON setyawn BattleScript_ButItFailed @@ -4821,8 +4162,6 @@ BattleScript_PrintAbilityMadeIneffective:: BattleScript_EffectEndeavor:: attackcanceler - attackstring - ppreduce setdamagetohealthdifference BattleScript_ButItFailed accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE typecalc @@ -4833,20 +4172,16 @@ BattleScript_EffectEndeavor:: BattleScript_EffectSkillSwap:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON tryswapabilities BattleScript_ButItFailed attackanimation waitanimation jumpiftargetally BattleScript_EffectSkillSwap_AfterAbilityPopUp -.if B_ABILITY_POP_UP == TRUE copybyte gBattlerAbility, gBattlerAttacker call BattleScript_AbilityPopUpOverwriteThenNormal copybyte gBattlerAbility, gBattlerTarget copyhword sABILITY_OVERWRITE, gLastUsedAbility call BattleScript_AbilityPopUpOverwriteThenNormal -.endif BattleScript_EffectSkillSwap_AfterAbilityPopUp: recordability BS_ATTACKER recordability BS_TARGET @@ -4860,8 +4195,6 @@ BattleScript_EffectSkillSwap_AfterAbilityPopUp: BattleScript_EffectImprison:: attackcanceler - attackstring - ppreduce tryimprison BattleScript_ButItFailed attackanimation waitanimation @@ -4871,8 +4204,6 @@ BattleScript_EffectImprison:: BattleScript_EffectRefresh:: attackcanceler - attackstring - ppreduce curestatuswithmove BattleScript_ButItFailed attackanimation waitanimation @@ -4883,9 +4214,8 @@ BattleScript_EffectRefresh:: BattleScript_EffectGrudge:: attackcanceler - attackstring - ppreduce - trysetvolatile BS_ATTACKER, VOLATILE_GRUDGE, BattleScript_ButItFailed + jumpifvolatile BS_ATTACKER, VOLATILE_GRUDGE, BattleScript_ButItFailed + setvolatile BS_ATTACKER, VOLATILE_GRUDGE, 2 attackanimation waitanimation printstring STRINGID_PKMNWANTSGRUDGE @@ -4894,9 +4224,7 @@ BattleScript_EffectGrudge:: BattleScript_EffectSnatch:: attackcanceler - trysetsnatch BattleScript_FailedFromAtkString - attackstring - ppreduce + trysetsnatch BattleScript_ButItFailed attackanimation waitanimation pause B_WAIT_TIME_SHORT @@ -4912,8 +4240,6 @@ BattleScript_EffectStruggle:: BattleScript_EffectMudSport:: BattleScript_EffectWaterSport:: attackcanceler - attackstring - ppreduce settypebasedhalvers BattleScript_ButItFailed attackanimation waitanimation @@ -4923,8 +4249,6 @@ BattleScript_EffectWaterSport:: BattleScript_EffectTickle:: attackcanceler - attackstring - ppreduce jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_TickleDoMoveAnim jumpifstat BS_TARGET, CMP_EQUAL, STAT_DEF, MIN_STAT_STAGE, BattleScript_CantLowerMultipleStats BattleScript_TickleDoMoveAnim:: @@ -4933,13 +4257,13 @@ BattleScript_TickleDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_TickleTryLowerDef, BIT_DEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_TickleTryLowerDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_TickleTryLowerDef printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_TickleTryLowerDef:: setstatchanger STAT_DEF, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_TickleEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_TickleEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_TickleEnd printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_TickleEnd:: @@ -4954,8 +4278,6 @@ BattleScript_CantLowerMultipleStats:: BattleScript_EffectCosmicPower:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_DEF, MAX_STAT_STAGE, BattleScript_CosmicPowerDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPDEF, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats BattleScript_CosmicPowerDoMoveAnim:: @@ -4963,13 +4285,13 @@ BattleScript_CosmicPowerDoMoveAnim:: waitanimation setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CosmicPowerTrySpDef, BIT_SPDEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CosmicPowerTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CosmicPowerTrySpDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CosmicPowerTrySpDef:: setstatchanger STAT_SPDEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CosmicPowerEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CosmicPowerEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CosmicPowerEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CosmicPowerEnd:: @@ -4977,8 +4299,6 @@ BattleScript_CosmicPowerEnd:: BattleScript_EffectBulkUp:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_BulkUpDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_DEF, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats BattleScript_BulkUpDoMoveAnim:: @@ -4986,13 +4306,13 @@ BattleScript_BulkUpDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_BulkUpTryDef, BIT_DEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_BulkUpTryDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_BulkUpTryDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_BulkUpTryDef:: setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_BulkUpEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_BulkUpEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_BulkUpEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_BulkUpEnd:: @@ -5000,8 +4320,6 @@ BattleScript_BulkUpEnd:: BattleScript_EffectCalmMind:: attackcanceler - attackstring - ppreduce BattleScript_CalmMindTryToRaiseStats:: jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_CalmMindDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPDEF, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats @@ -5011,13 +4329,13 @@ BattleScript_CalmMindDoMoveAnim:: BattleScript_CalmMindStatRaise:: setstatchanger STAT_SPATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CalmMindTrySpDef, BIT_SPDEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CalmMindTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CalmMindTrySpDef printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CalmMindTrySpDef:: setstatchanger STAT_SPDEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CalmMindEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CalmMindEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CalmMindEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CalmMindEnd:: @@ -5032,8 +4350,6 @@ BattleScript_CantRaiseMultipleStats:: BattleScript_EffectDragonDance:: attackcanceler - attackstring - ppreduce BattleScript_EffectDragonDanceFromStatUp:: jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_DragonDanceDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats @@ -5042,13 +4358,13 @@ BattleScript_DragonDanceDoMoveAnim:: waitanimation setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_DragonDanceTrySpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DragonDanceTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_DragonDanceTrySpeed printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_DragonDanceTrySpeed:: setstatchanger STAT_SPEED, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_DragonDanceEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DragonDanceEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_DragonDanceEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_DragonDanceEnd:: @@ -5056,8 +4372,6 @@ BattleScript_DragonDanceEnd:: BattleScript_EffectCamouflage:: attackcanceler - attackstring - ppreduce settypetoenvironment BattleScript_ButItFailed attackanimation waitanimation @@ -5065,39 +4379,22 @@ BattleScript_EffectCamouflage:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_FaintAttacker:: - tryillusionoff BS_ATTACKER +BattleScript_FaintBattler:: + tryillusionoff BS_FAINTED tryactivategulpmissile - playfaintcry BS_ATTACKER + playfaintcry BS_FAINTED pause B_WAIT_TIME_LONG - dofaintanimation BS_ATTACKER - printstring STRINGID_ATTACKERFAINTED - cleareffectsonfaint BS_ATTACKER + dofaintanimation BS_FAINTED + copybyte sBATTLER, gBattlerFainted @ for message + printstring STRINGID_BATTLERFAINTED + cleareffectsonfaint BS_FAINTED trytoclearprimalweather tryrevertweatherform flushtextbox waitanimation - tryactivatereceiver BS_ATTACKER + tryactivatereceiver BS_FAINTED tryactivatesoulheart - trytrainerslidemsgfirstoff BS_ATTACKER - return - -BattleScript_FaintTarget:: - tryillusionoff BS_TARGET - tryactivategulpmissile - tryupdateleaderscresttracker - playfaintcry BS_TARGET - pause B_WAIT_TIME_LONG - dofaintanimation BS_TARGET - printstring STRINGID_TARGETFAINTED - cleareffectsonfaint BS_TARGET - trytoclearprimalweather - tryrevertweatherform - flushtextbox - waitanimation - tryactivatereceiver BS_TARGET - tryactivatesoulheart - trytrainerslidemsgfirstoff BS_TARGET + trytrainerslidemsgfirstoff BS_FAINTED return BattleScript_GiveExp:: @@ -5500,11 +4797,11 @@ BattleScript_FogEnded_Ret:: BattleScript_IceBodyHeal:: call BattleScript_AbilityPopUp playanimation BS_ATTACKER, B_ANIM_SIMPLE_HEAL - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_ICEBODYHPGAIN waitmessage B_WAIT_TIME_LONG - end3 + end2 BattleScript_OverworldStatusStarts:: printfromtable gStartingStatusStringIds @@ -5568,7 +4865,7 @@ BattleScript_MagicRoomEnds:: setbyte gBattlerTarget, 0 BattleScript_MagicRoomHealingItemsLoop: copyarraywithindex gBattlerAttacker, gBattlerByTurnOrder, gBattlerTarget, 1 - tryrestorehpberry + tryactivateitem BS_ATTACKER, ACTIVATION_ON_USABLE_AGAIN addbyte gBattlerTarget, 1 jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_MagicRoomHealingItemsLoop end2 @@ -5630,9 +4927,8 @@ BattleScript_LeechSeedTurnDrainHealBlockEnd2: BattleScript_LeechSeedTurnDrainRecovery:: call BattleScript_LeechSeedTurnDrain BattleScript_LeechSeedTurnDrainGainHp: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printfromtable gLeechSeedStringIds waitmessage B_WAIT_TIME_LONG tryfaintmon BS_TARGET @@ -5640,8 +4936,8 @@ BattleScript_LeechSeedTurnDrainGainHp: BattleScript_LeechSeedTurnDrain: playanimation BS_ATTACKER, B_ANIM_LEECH_SEED_DRAIN, sB_ANIM_ARG1 - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return @@ -5666,8 +4962,8 @@ BattleScript_BideAttack:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE resultmessage waitmessage B_WAIT_TIME_LONG tryfaintmon BS_TARGET @@ -5726,13 +5022,13 @@ BattleScript_WeaknessPolicyAtk: waitanimation setstatchanger STAT_ATK, 2, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_WeaknessPolicySpAtk, BIT_SPATK - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_WeaknessPolicySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_WeaknessPolicySpAtk printstring STRINGID_USINGITEMSTATOFPKMNROSE waitmessage B_WAIT_TIME_LONG BattleScript_WeaknessPolicySpAtk: setstatchanger STAT_SPATK, 2, FALSE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_WeaknessPolicyRemoveItem - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_WeaknessPolicyRemoveItem + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_WeaknessPolicyRemoveItem printstring STRINGID_USINGITEMSTATOFPKMNROSE waitmessage B_WAIT_TIME_LONG BattleScript_WeaknessPolicyRemoveItem: @@ -5743,7 +5039,7 @@ BattleScript_WeaknessPolicyEnd: BattleScript_TargetItemStatRaise:: copybyte sBATTLER, gBattlerTarget statbuffchange BS_TARGET, STAT_CHANGE_ONLY_CHECKING, BattleScript_TargetItemStatRaiseRemoveItemRet - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_TargetItemStatRaiseRemoveItemRet + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_TargetItemStatRaiseRemoveItemRet playanimation BS_TARGET, B_ANIM_HELD_ITEM_EFFECT waitanimation statbuffchange BS_TARGET, 0, BattleScript_TargetItemStatRaiseRemoveItemRet @@ -5756,7 +5052,7 @@ BattleScript_TargetItemStatRaiseRemoveItemRet: BattleScript_AttackerItemStatRaise:: copybyte sBATTLER, gBattlerAttacker statbuffchange BS_ATTACKER, STAT_CHANGE_ONLY_CHECKING, BattleScript_AttackerItemStatRaiseRet - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_AttackerItemStatRaiseRet + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_AttackerItemStatRaiseRet playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT waitanimation statbuffchange BS_ATTACKER, 0, BattleScript_AttackerItemStatRaiseRet @@ -5815,16 +5111,14 @@ BattleScript_EncoredNoMore:: BattleScript_DestinyBondTakesLife:: printstring STRINGID_PKMNTOOKFOE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER return BattleScript_DmgHazardsOnAttacker:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_ATTACKER tryfaintmon_spikes BS_ATTACKER, BattleScript_DmgHazardsOnAttackerFainted @@ -5837,9 +5131,8 @@ BattleScript_DmgHazardsOnAttackerFainted:: goto BattleScript_HandleFaintedMon BattleScript_DmgHazardsOnTarget:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_TARGET tryfaintmon_spikes BS_TARGET, BattleScript_DmgHazardsOnTargetFainted @@ -5852,9 +5145,8 @@ BattleScript_DmgHazardsOnTargetFainted:: goto BattleScript_HandleFaintedMon BattleScript_DmgHazardsOnBattlerScripting:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_SCRIPTING tryfaintmon_spikes BS_SCRIPTING, BattleScript_DmgHazardsOnBattlerScriptingFainted @@ -5867,9 +5159,8 @@ BattleScript_DmgHazardsOnBattlerScriptingFainted:: goto BattleScript_HandleFaintedMon BattleScript_DmgHazardsOnFaintedBattler:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_FAINTED - datahpupdate BS_FAINTED + healthbarupdate BS_FAINTED, PASSIVE_HP_UPDATE + datahpupdate BS_FAINTED, PASSIVE_HP_UPDATE call BattleScript_PrintHurtByDmgHazards tryfaintmon BS_FAINTED tryfaintmon_spikes BS_FAINTED, BattleScript_DmgHazardsOnFaintedBattlerFainted @@ -5916,7 +5207,7 @@ BattleScript_StickyWebOnSwitchIn:: waitmessage B_WAIT_TIME_LONG jumpifability BS_TARGET, ABILITY_MIRROR_ARMOR, BattleScript_MirrorArmorReflectStickyWeb statbuffchange BS_TARGET, STAT_CHANGE_CHECK_PREVENTION | STAT_CHANGE_ALLOW_PTR, BattleScript_StickyWebOnSwitchInEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_StickyWebOnSwitchInEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_StickyWebOnSwitchInEnd printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_StickyWebOnSwitchInEnd: @@ -5928,9 +5219,8 @@ BattleScript_StickyWebOnSwitchInEnd: BattleScript_PerishSongTakesLife:: printstring STRINGID_PKMNPERISHCOUNTFELL waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER end2 @@ -5938,20 +5228,18 @@ BattleScript_PerishBodyActivates:: call BattleScript_AbilityPopUp printstring STRINGID_PKMNSWILLPERISHIN3TURNS waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE return BattleScript_GulpMissileGorging:: call BattleScript_AbilityPopUp playanimation BS_ATTACKER, B_ANIM_GULP_MISSILE waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE effectivenesssound hitanimation BS_ATTACKER waitstate jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_GulpMissileNoDmgGorging - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER jumpiffainted BS_ATTACKER, TRUE, BattleScript_GulpMissileNoSecondEffectGorging BattleScript_GulpMissileNoDmgGorging: @@ -5972,13 +5260,12 @@ BattleScript_GulpMissileGulping:: call BattleScript_AbilityPopUp playanimation BS_ATTACKER, B_ANIM_GULP_MISSILE waitanimation - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE effectivenesssound hitanimation BS_ATTACKER waitstate jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_GulpMissileNoDmgGulping - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER jumpiffainted BS_ATTACKER, TRUE, BattleScript_GulpMissileNoSecondEffectGulping BattleScript_GulpMissileNoDmgGulping: @@ -6008,32 +5295,39 @@ BattleScript_SeedSowerActivates:: call BattleScript_ActivateTerrainEffects return -BattleScript_AngerShellActivates:: +BattleScript_BerserkActivates:: saveattacker - copybyte gBattlerAttacker, gBattlerTarget + copybyte gBattlerAttacker, gEffectBattler call BattleScript_AbilityPopUp - jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef - jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef - jumpifstat BS_TARGET, CMP_LESS_THAN, STAT_SPEED, MAX_STAT_STAGE, BattleScript_AngerShellTryDef - jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_AngerShellTryDef - jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPDEF, MIN_STAT_STAGE, BattleScript_RestoreAttackerButItFailed -BattleScript_AngerShellTryDef:: - modifybattlerstatstage BS_ATTACKER, STAT_DEF, DECREASE, 1, BattleScript_AngerShellTrySpDef, ANIM_ON -BattleScript_AngerShellTrySpDef: - modifybattlerstatstage BS_ATTACKER, STAT_SPDEF, DECREASE, 1, BattleScript_AngerShellTryAttack, ANIM_ON -BattleScript_AngerShellTryAttack: - modifybattlerstatstage BS_ATTACKER, STAT_ATK, INCREASE, 1, BattleScript_AngerShellTrySpAtk, ANIM_ON -BattleScript_AngerShellTrySpAtk: - modifybattlerstatstage BS_ATTACKER, STAT_SPATK, INCREASE, 1, BattleScript_AngerShellTrySpeed, ANIM_ON -BattleScript_AngerShellTrySpeed: - modifybattlerstatstage BS_ATTACKER, STAT_SPEED, INCREASE, 1, BattleScript_AngerShellRet, ANIM_ON -BattleScript_AngerShellRet: + statbuffchange BS_EFFECT_BATTLER, STAT_CHANGE_CERTAIN, BattleScript_BerserkActivatesTryBerry + call BattleScript_StatUp +BattleScript_BerserkActivatesTryBerry: restoreattacker return +BattleScript_AngerShellActivates:: + call BattleScript_AbilityPopUp + jumpifstat BS_EFFECT_BATTLER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef + jumpifstat BS_EFFECT_BATTLER, CMP_LESS_THAN, STAT_SPATK, MAX_STAT_STAGE, BattleScript_AngerShellTryDef + jumpifstat BS_EFFECT_BATTLER, CMP_LESS_THAN, STAT_SPEED, MAX_STAT_STAGE, BattleScript_AngerShellTryDef + jumpifstat BS_EFFECT_BATTLER, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_AngerShellTryDef + jumpifstat BS_EFFECT_BATTLER, CMP_EQUAL, STAT_SPDEF, MIN_STAT_STAGE, BattleScript_RestoreAttackerButItFailed +BattleScript_AngerShellTryDef:: + modifybattlerstatstage BS_EFFECT_BATTLER, STAT_DEF, DECREASE, 1, BattleScript_AngerShellTrySpDef, ANIM_ON +BattleScript_AngerShellTrySpDef: + modifybattlerstatstage BS_EFFECT_BATTLER, STAT_SPDEF, DECREASE, 1, BattleScript_AngerShellTryAttack, ANIM_ON +BattleScript_AngerShellTryAttack: + modifybattlerstatstage BS_EFFECT_BATTLER, STAT_ATK, INCREASE, 1, BattleScript_AngerShellTrySpAtk, ANIM_ON +BattleScript_AngerShellTrySpAtk: + modifybattlerstatstage BS_EFFECT_BATTLER, STAT_SPATK, INCREASE, 1, BattleScript_AngerShellTrySpeed, ANIM_ON +BattleScript_AngerShellTrySpeed: + modifybattlerstatstage BS_EFFECT_BATTLER, STAT_SPEED, INCREASE, 1, BattleScript_AngerShellRet, ANIM_ON +BattleScript_AngerShellRet: + return + BattleScript_WindPowerActivates:: call BattleScript_AbilityPopUp - setcharge BS_TARGET + setvolatile BS_TARGET, VOLATILE_CHARGE_TIMER, 1 printstring STRINGID_BEINGHITCHARGEDPKMNWITHPOWER waitmessage B_WAIT_TIME_LONG return @@ -6053,9 +5347,8 @@ BattleScript_EarthEaterActivates:: call BattleScript_AbilityPopUp pause B_WAIT_TIME_LONG tryhealquarterhealth BS_TARGET, BattleScript_EarthEaterRet - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_EarthEaterRet: @@ -6150,8 +5443,8 @@ BattleScript_DoFutureAttackHit:: effectivenesssound hitanimation BS_TARGET waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE + datahpupdate BS_TARGET, MOVE_DAMAGE_HP_UPDATE critmessage waitmessage B_WAIT_TIME_LONG BattleScript_DoFutureAttackResult: @@ -6160,17 +5453,21 @@ BattleScript_DoFutureAttackResult: tryfaintmon BS_TARGET checkteamslost BattleScript_FutureAttackEnd BattleScript_FutureAttackEnd:: + moveendcase MOVEEND_SET_VALUES moveendcase MOVEEND_RAGE moveendcase MOVEEND_ABILITIES - moveendfromto MOVEEND_ITEM_EFFECTS_ALL, MOVEEND_UPDATE_LAST_MOVES - setmoveresultflags 0 - end2 + moveendcase MOVEEND_COLOR_CHANGE + moveendcase MOVEEND_ITEM_EFFECTS_TARGET + moveendfromto MOVEEND_SYMBIOSIS, MOVEEND_UPDATE_LAST_MOVES + goto BattleScript_FutureAttackClearResults BattleScript_FutureAttackMiss:: pause B_WAIT_TIME_SHORT setmoveresultflags MOVE_RESULT_FAILED resultmessage waitmessage B_WAIT_TIME_LONG +BattleScript_FutureAttackClearResults: setmoveresultflags 0 + clearspecialstatuses end2 BattleScript_NoMovesLeft:: @@ -6182,7 +5479,7 @@ BattleScript_SelectingMoveWithNoPP:: endselectionscript BattleScript_NoPPForMove:: - attackstring + printattackstring pause B_WAIT_TIME_SHORT printstring STRINGID_BUTNOPPLEFT waitmessage B_WAIT_TIME_LONG @@ -6294,9 +5591,8 @@ BattleScript_WishComesTrue:: playanimation BS_TARGET, B_ANIM_WISH_HEAL printstring STRINGID_PKMNWISHCAMETRUE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG end2 @@ -6322,9 +5618,8 @@ BattleScript_IngrainTurnHeal:: printstring STRINGID_PKMNABSORBEDNUTRIENTS BattleScript_TurnHeal: waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE end2 BattleScript_AquaRingHeal:: @@ -6347,7 +5642,7 @@ BattleScript_PrintMonIsRootedRet:: BattleScript_AtkDefDown:: setstatchanger STAT_ATK, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_CERTAIN | STAT_CHANGE_ALLOW_PTR, BattleScript_AtkDefDownTryDef, BIT_DEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_AtkDefDownTryDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_AtkDefDownTryDef printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_AtkDefDownTryDef: @@ -6361,13 +5656,13 @@ BattleScript_AtkDefDownRet: BattleScript_DefSpDefDown:: setstatchanger STAT_DEF, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_CERTAIN | STAT_CHANGE_ALLOW_PTR, BattleScript_DefSpDefDownTrySpDef, BIT_SPDEF - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_DefSpDefDownTrySpDef + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_DefSpDefDownTrySpDef printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_DefSpDefDownTrySpDef:: setstatchanger STAT_SPDEF, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_CERTAIN | STAT_CHANGE_ALLOW_PTR, BattleScript_DefSpDefDownRet - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_DefSpDefDownRet + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_DefSpDefDownRet printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_DefSpDefDownRet:: @@ -6379,13 +5674,13 @@ BattleScript_DefDownSpeedUp:: BattleScript_DefDownSpeedUpTryDef:: setstatchanger STAT_DEF, 1, TRUE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_CERTAIN, BattleScript_DefDownSpeedUpTrySpeed - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DefDownSpeedUpTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_DefDownSpeedUpTrySpeed printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_DefDownSpeedUpTrySpeed: setstatchanger STAT_SPEED, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_CERTAIN, BattleScript_DefDownSpeedUpRet - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DefDownSpeedUpRet + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_DefDownSpeedUpRet printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_DefDownSpeedUpRet:: @@ -6416,31 +5711,21 @@ BattleScript_GrudgeTakesPp:: return BattleScript_MagicBounce:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printstring STRINGID_PKMNMOVEBOUNCEDABILITY waitmessage B_WAIT_TIME_LONG setmagiccoattarget - orword gHitMarker, HITMARKER_ATTACKSTRING_PRINTED | HITMARKER_NO_PPDEDUCT | HITMARKER_ALLOW_NO_PP - bicword gHitMarker, HITMARKER_NO_ATTACKSTRING return BattleScript_MagicCoat:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT setmagiccoattarget printstring STRINGID_PKMNMOVEBOUNCED waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_ATTACKSTRING_PRINTED | HITMARKER_NO_PPDEDUCT | HITMARKER_ALLOW_NO_PP - bicword gHitMarker, HITMARKER_NO_ATTACKSTRING return BattleScript_MagicCoatPrankster:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT printstring STRINGID_PKMNMOVEBOUNCED waitmessage B_WAIT_TIME_LONG @@ -6450,13 +5735,10 @@ BattleScript_MagicCoatPrankster:: goto BattleScript_MoveEnd BattleScript_SnatchedMove:: - attackstring - ppreduce snatchsetbattlers playanimation BS_TARGET, B_ANIM_SNATCH_MOVE printstring STRINGID_PKMNSNATCHEDMOVE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_ATTACKSTRING_PRINTED | HITMARKER_NO_PPDEDUCT | HITMARKER_ALLOW_NO_PP swapattackerwithtarget return @@ -6534,7 +5816,7 @@ BattleScript_PowerConstruct:: handleformchange BS_SCRIPTING, 2 printstring STRINGID_POWERCONSTRUCTTRANSFORM waitmessage B_WAIT_TIME_SHORT - end3 + end2 BattleScript_UltraBurst:: flushtextbox @@ -6572,7 +5854,11 @@ BattleScript_BattlerFormChangeEnd3:: BattleScript_BattlerFormChangeEnd3NoPopup:: call BattleScript_BattlerFormChangeNoPopup - end3 + end2 + +BattleScript_BattlerFormChangeEnd2:: + call BattleScript_BattlerFormChange + end2 BattleScript_BattlerFormChangeWithStringEnd3:: pause 5 @@ -6603,7 +5889,7 @@ BattleScript_BallFetch:: call BattleScript_AbilityPopUp printstring STRINGID_FETCHEDPOKEBALL waitmessage B_WAIT_TIME_LONG - end3 + end2 BattleScript_CudChewActivates:: pause B_WAIT_TIME_SHORTEST @@ -6611,13 +5897,12 @@ BattleScript_CudChewActivates:: setbyte sBERRY_OVERRIDE, 1 @ override the requirements for eating berries consumeberry BS_ATTACKER, FALSE setbyte sBERRY_OVERRIDE, 0 - end3 + end2 BattleScript_ApplyDisguiseFormChangeHPLoss:: jumpifgenconfiglowerthan GEN_CONFIG_DISGUISE_HP_LOSS, GEN_8, BattleScript_ApplyDisguiseFormChangeHPLossReturn - orword gHitMarker, HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE BattleScript_ApplyDisguiseFormChangeHPLossReturn: return @@ -6681,7 +5966,7 @@ BattleScript_CottonDownLoop: setstatchanger STAT_SPEED, 1, TRUE jumpifbyteequal gBattlerTarget, gEffectBattler, BattleScript_CottonDownLoopIncrement statbuffchange BS_TARGET, STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_CottonDownLoopIncrement - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_CottonDownTargetSpeedCantGoLower + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CottonDownTargetSpeedCantGoLower printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG goto BattleScript_CottonDownLoopIncrement @@ -6706,9 +5991,8 @@ BattleScript_AftermathDmg:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUpScripting jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_AftermathDmgRet - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_AFTERMATHDMG waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -6749,12 +6033,11 @@ BattleScript_PoisonTurnDmg:: BattleScript_DoStatusTurnDmg:: statusanimation BS_ATTACKER BattleScript_DoTurnDmg: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE tryfaintmon BS_ATTACKER checkteamslost BattleScript_DoTurnDmgEnd - tryrestorehpberry + tryactivateitem BS_ATTACKER, ACTIVATION_ON_HP_THRESHOLD BattleScript_DoTurnDmgEnd: end2 @@ -6764,9 +6047,8 @@ BattleScript_PoisonHealActivates:: printstring STRINGID_POISONHEALHPUP waitmessage B_WAIT_TIME_LONG statusanimation BS_ATTACKER - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE end2 BattleScript_BurnTurnDmg:: @@ -6817,8 +6099,6 @@ BattleScript_MoveUsedIsParalyzed:: goto BattleScript_MoveEnd BattleScript_PowderMoveNoEffect:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT jumpiftype BS_TARGET, TYPE_GRASS, BattleScript_PowderMoveNoEffectPrint jumpifability BS_TARGET, ABILITY_OVERCOAT, BattleScript_PowderMoveNoEffectOvercoat @@ -6844,7 +6124,7 @@ BattleScript_MoveUsedFlinchedEnd: BattleScript_TryActivateSteadFast: setstatchanger STAT_SPEED, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_MoveUsedFlinchedEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_MoveUsedFlinchedEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_MoveUsedFlinchedEnd copybyte gBattlerAbility, gBattlerAttacker call BattleScript_AbilityPopUp statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_MoveUsedFlinchedEnd @@ -6878,9 +6158,9 @@ BattleScript_DoSelfConfusionDmg:: effectivenesssound hitanimation BS_ATTACKER waitstate - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + isdmgblockedbydisguise + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE resultmessage waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -6889,9 +6169,6 @@ BattleScript_MoveUsedIsConfusedRet:: return BattleScript_MoveUsedPowder:: - bicword gHitMarker, HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED - attackstring - ppreduce pause B_WAIT_TIME_SHORT cancelmultiturnmoves volatileanimation BS_ATTACKER, VOLATILE_POWDER @@ -6899,9 +6176,8 @@ BattleScript_MoveUsedPowder:: effectivenesssound hitanimation BS_ATTACKER waitstate - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_POWDEREXPLODES waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -7002,7 +6278,7 @@ BattleScript_YawnEnd: BattleScript_EmbargoEndTurn:: printstring STRINGID_EMBARGOENDS waitmessage B_WAIT_TIME_LONG - tryrestorehpberry + tryactivateitem BS_ATTACKER, ACTIVATION_ON_USABLE_AGAIN end2 BattleScript_TelekinesisEndTurn:: @@ -7085,18 +6361,11 @@ BattleScript_MoveEffectConfusion:: return BattleScript_MoveEffectRecoil:: - jumpifmove MOVE_STRUGGLE, BattleScript_DoRecoil - jumpifability BS_ATTACKER, ABILITY_ROCK_HEAD, BattleScript_RecoilEnd - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_RecoilEnd -BattleScript_DoRecoil:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNHITWITHRECOIL waitmessage B_WAIT_TIME_LONG - tryupdaterecoiltracker tryfaintmon BS_ATTACKER -BattleScript_RecoilEnd:: return BattleScript_ItemSteal:: @@ -7145,10 +6414,8 @@ BattleScript_AbilityPopUpTarget:: copybyte gBattlerAbility, gBattlerTarget BattleScript_AbilityPopUp:: tryactivateabilityshield BS_ABILITY_BATTLER - .if B_ABILITY_POP_UP == TRUE showabilitypopup pause B_WAIT_TIME_SHORT - .endif recordability BS_ABILITY_BATTLER sethword sABILITY_OVERWRITE, 0 return @@ -7169,14 +6436,6 @@ BattleScript_AbilityPopUpOverwriteThenNormal: setbyte sFIXED_ABILITY_POPUP, FALSE return -BattleScript_SpeedBoostActivates:: - call BattleScript_AbilityPopUp - statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_SpeedBoostActivatesEnd - printstring STRINGID_PKMNRAISEDSPEED - waitmessage B_WAIT_TIME_LONG -BattleScript_SpeedBoostActivatesEnd: - end3 - @ Can't compare directly to a value, have to compare to value at pointer sZero: .byte 0 @@ -7185,25 +6444,23 @@ BattleScript_MoodyActivates:: call BattleScript_AbilityPopUp jumpifbyteequal sSTATCHANGER, sZero, BattleScript_MoodyLower statbuffchange BS_ATTACKER, STAT_CHANGE_CERTAIN | STAT_CHANGE_NOT_PROTECT_AFFECTED, BattleScript_MoodyLower - jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_ROSE, BattleScript_MoodyLower + jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_CHANGED, BattleScript_MoodyLower printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_MoodyLower: jumpifbyteequal sSAVED_STAT_CHANGER, sZero, BattleScript_MoodyEnd copybyte sSTATCHANGER, sSAVED_STAT_CHANGER statbuffchange BS_ATTACKER, STAT_CHANGE_CERTAIN | STAT_CHANGE_NOT_PROTECT_AFFECTED, BattleScript_MoodyEnd - jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_FELL, BattleScript_MoodyEnd + jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_CHANGED, BattleScript_MoodyEnd printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_MoodyEnd: - end3 + end2 BattleScript_EmergencyExit:: - .if B_ABILITY_POP_UP == TRUE pause 5 call BattleScript_AbilityPopUpScripting pause B_WAIT_TIME_LONG - .endif playanimation BS_SCRIPTING, B_ANIM_SLIDE_OFFSCREEN waitanimation openpartyscreen BS_SCRIPTING, BattleScript_EmergencyExitRet @@ -7222,11 +6479,9 @@ BattleScript_EmergencyExitRet: return BattleScript_EmergencyExitWild:: - .if B_ABILITY_POP_UP == TRUE pause 5 call BattleScript_AbilityPopUpScripting pause B_WAIT_TIME_LONG - .endif playanimation BS_SCRIPTING, B_ANIM_SLIDE_OFFSCREEN waitanimation setteleportoutcome BS_SCRIPTING @@ -7285,14 +6540,13 @@ BattleScript_AbilityHpHeal: call BattleScript_AbilityPopUp printstring STRINGID_PKMNSXRESTOREDHPALITTLE2 waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE return BattleScript_RainDishActivates:: call BattleScript_AbilityHpHeal - end3 + end2 BattleScript_CheekPouchActivates:: copybyte sSAVED_BATTLER, gBattlerAttacker @@ -7307,9 +6561,9 @@ BattleScript_PickupActivates:: call BattleScript_AbilityPopUp printstring STRINGID_XFOUNDONEY waitmessage B_WAIT_TIME_LONG - tryrestorehpberry + tryactivateitem BS_ATTACKER, ACTIVATION_ON_PICK_UP BattleScript_PickupActivatesEnd: - end3 + end2 BattleScript_HarvestActivates:: pause 5 @@ -7317,19 +6571,18 @@ BattleScript_HarvestActivates:: call BattleScript_AbilityPopUp printstring STRINGID_HARVESTBERRY waitmessage B_WAIT_TIME_LONG - tryrestorehpberry + tryactivateitem BS_ATTACKER, ACTIVATION_ON_HARVEST BattleScript_HarvestActivatesEnd: - end3 + end2 BattleScript_SolarPowerActivates:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE call BattleScript_AbilityPopUp - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_SOLARPOWERHPDROP waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER - end3 + end2 BattleScript_HealerActivates:: call BattleScript_AbilityPopUp @@ -7337,7 +6590,7 @@ BattleScript_HealerActivates:: updatestatusicon BS_SCRIPTING printstring STRINGID_HEALERCURE waitmessage B_WAIT_TIME_LONG - end3 + end2 BattleScript_SandstreamActivates:: pause B_WAIT_TIME_SHORT @@ -7362,7 +6615,7 @@ BattleScript_ShedSkinActivates:: printstring STRINGID_PKMNSXCUREDYPROBLEM waitmessage B_WAIT_TIME_LONG updatestatusicon BS_ATTACKER - end3 + end2 BattleScript_ActivateWeatherAbilities: saveattacker @@ -7379,7 +6632,6 @@ BattleScript_ActivateWeatherAbilities_Loop: return BattleScript_TryIntimidateHoldEffects: - itemstatchangeeffects BS_TARGET jumpifnoholdeffect BS_TARGET, HOLD_EFFECT_ADRENALINE_ORB, BattleScript_TryIntimidateHoldEffectsRet jumpifstat BS_TARGET, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_TryIntimidateHoldEffectsRet setstatchanger STAT_SPEED, 1, FALSE @@ -7406,8 +6658,7 @@ BattleScript_IntimidateEffect: copybyte sBATTLER, gBattlerAttacker setstatchanger STAT_ATK, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_IntimidateLoopIncrement - jumpifability BS_TARGET, ABILITY_CONTRARY, BattleScript_IntimidateContrary - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_IntimidateWontDecrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_IntimidateWontDecrease printstring STRINGID_PKMNCUTSATTACKWITH BattleScript_IntimidateEffect_WaitString: waitmessage B_WAIT_TIME_LONG @@ -7437,10 +6688,6 @@ BattleScript_IntimidateWontDecrease: printstring STRINGID_STATSWONTDECREASE goto BattleScript_IntimidateEffect_WaitString -BattleScript_IntimidateContrary: - printfromtable gStatUpStringIds - goto BattleScript_IntimidateEffect_WaitString - BattleScript_IntimidateInReverse:: copybyte sBATTLER, gBattlerTarget call BattleScript_AbilityPopUpTarget @@ -7463,8 +6710,7 @@ BattleScript_SupersweetSyrupEffect: copybyte sBATTLER, gBattlerAttacker setstatchanger STAT_EVASION, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_SupersweetSyrupLoopIncrement - jumpifability BS_TARGET, ABILITY_CONTRARY, BattleScript_SupersweetSyrupContrary - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_SupersweetSyrupWontDecrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_SupersweetSyrupWontDecrease printfromtable gStatDownStringIds BattleScript_SupersweetSyrupEffect_WaitString: waitmessage B_WAIT_TIME_LONG @@ -7488,10 +6734,6 @@ BattleScript_SupersweetSyrupWontDecrease: printstring STRINGID_STATSWONTDECREASE goto BattleScript_SupersweetSyrupEffect_WaitString -BattleScript_SupersweetSyrupContrary: - printfromtable gStatUpStringIds - goto BattleScript_SupersweetSyrupEffect_WaitString - BattleScript_DroughtActivates:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp @@ -7511,11 +6753,7 @@ BattleScript_DesolateLandActivates:: end3 BattleScript_PrimalWeatherBlocksMove:: - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_ATTACKSTRING_PRINTED, BattleScript_MoveEnd @in case of multi-target moves, if move fails once, no point in printing the message twice - accuracycheck BattleScript_PrintMoveMissed, NO_ACC_CALC_CHECK_LOCK_ON - attackstring pause B_WAIT_TIME_SHORT - ppreduce printfromtable gPrimalWeatherBlocksStringIds waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -7588,31 +6826,31 @@ BattleScript_CommanderActivates:: BattleScript_CommanderAtkIncrease: setstatchanger STAT_ATK, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderDefIncrease, BIT_DEF | BIT_SPATK | BIT_SPDEF | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderDefIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CommanderDefIncrease printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CommanderDefIncrease: setstatchanger STAT_DEF, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpAtkIncrease, BIT_SPATK | BIT_SPDEF | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpAtkIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CommanderSpAtkIncrease printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CommanderSpAtkIncrease: setstatchanger STAT_SPATK, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpDefIncrease, BIT_SPDEF | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpDefIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CommanderSpDefIncrease printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CommanderSpDefIncrease: setstatchanger STAT_SPDEF, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpeedIncrease, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpeedIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CommanderSpeedIncrease printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CommanderSpeedIncrease: setstatchanger STAT_SPEED, 2, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_CommanderEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_CommanderEnd: @@ -7624,10 +6862,9 @@ BattleScript_HospitalityActivates:: call BattleScript_AbilityPopUp printstring STRINGID_HOSPITALITYRESTORATION waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE playanimation BS_EFFECT_BATTLER, B_ANIM_SIMPLE_HEAL - healthbarupdate BS_EFFECT_BATTLER - datahpupdate BS_EFFECT_BATTLER + healthbarupdate BS_EFFECT_BATTLER, PASSIVE_HP_UPDATE + datahpupdate BS_EFFECT_BATTLER, PASSIVE_HP_UPDATE end3 BattleScript_AttackWeakenedByStrongWinds:: @@ -7729,9 +6966,8 @@ BattleScript_BadDreams_DmgAfterPopUp: printstring STRINGID_BADDREAMSDMG waitmessage B_WAIT_TIME_LONG dmg_1_8_targethp - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE jumpifhasnohp BS_TARGET, BattleScript_BadDreams_HidePopUp BattleScript_BadDreamsIncrement: addbyte gBattlerTarget, 1 @@ -7740,7 +6976,7 @@ BattleScript_BadDreamsIncrement: destroyabilitypopup pause 15 BattleScript_BadDreamsEnd: - end3 + end2 BattleScript_BadDreams_ShowPopUp: copybyte gBattlerAbility, gBattlerAttacker call BattleScript_AbilityPopUp @@ -7752,11 +6988,9 @@ BattleScript_BadDreams_HidePopUp: goto BattleScript_BadDreamsIncrement BattleScript_TookAttack:: - attackstring pause B_WAIT_TIME_SHORT printstring STRINGID_PKMNSXTOOKATTACK waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_ATTACKSTRING_PRINTED return BattleScript_SturdyPreventsOHKO:: @@ -7775,24 +7009,17 @@ BattleScript_DampStopsExplosion:: moveendcase MOVEEND_CLEAR_BITS end -BattleScript_MoveHPDrain_PPLoss:: - ppreduce BattleScript_MoveHPDrain:: - attackstring pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNRESTOREDHPUSING waitmessage B_WAIT_TIME_LONG setmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE goto BattleScript_MoveEnd -BattleScript_MoveStatDrain_PPLoss:: - ppreduce BattleScript_MoveStatDrain:: - attackstring pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_MoveStatDrain_Cont @@ -7807,10 +7034,7 @@ BattleScript_MoveStatDrain_Cont: clearsemiinvulnerablebit goto BattleScript_MoveEnd -BattleScript_MonMadeMoveUseless_PPLoss:: - ppreduce BattleScript_MonMadeMoveUseless:: - attackstring pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printstring STRINGID_PKMNSXMADEYUSELESS @@ -7818,10 +7042,7 @@ BattleScript_MonMadeMoveUseless:: setmoveresultflags MOVE_RESULT_DOESNT_AFFECT_FOE goto BattleScript_MoveEnd -BattleScript_FlashFireBoost_PPLoss:: - ppreduce BattleScript_FlashFireBoost:: - attackstring pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printfromtable gFlashFireStringIds @@ -7869,13 +7090,12 @@ BattleScript_FlinchPrevention:: BattleScript_OwnTempoPrevents:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp + copybyte sBATTLER, gBattlerTarget printstring STRINGID_PKMNPREVENTSCONFUSIONWITH waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd BattleScript_SoundproofProtected:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printstring STRINGID_PKMNSXBLOCKSY @@ -7888,8 +7108,6 @@ BattleScript_IceFaceNullsDamage:: return BattleScript_DazzlingProtected:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUpScripting printstring STRINGID_POKEMONCANNOTUSEMOVE @@ -7897,17 +7115,17 @@ BattleScript_DazzlingProtected:: goto BattleScript_MoveEnd BattleScript_MoveUsedPsychicTerrainPrevents:: - printstring STRINGID_POKEMONCANNOTUSEMOVE + pause B_WAIT_TIME_SHORT + printstring STRINGID_PSYCHICTERRAINPREVENTS waitmessage B_WAIT_TIME_LONG + setmoveresultflags MOVE_RESULT_NO_EFFECT goto BattleScript_MoveEnd BattleScript_GrassyTerrainHeals:: printstring STRINGID_GRASSYTERRAINHEALS waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - bicword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE end2 BattleScript_AbilityNoSpecificStatLoss:: @@ -7915,16 +7133,20 @@ BattleScript_AbilityNoSpecificStatLoss:: call BattleScript_AbilityPopUp printstring STRINGID_PKMNSXPREVENTSYLOSS waitmessage B_WAIT_TIME_LONG - setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY + setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY setmoveresultflags MOVE_RESULT_NO_EFFECT return BattleScript_StickyHoldActivates:: + call BattleScript_StickyHoldActivatesRet + goto BattleScript_MoveEnd + +BattleScript_StickyHoldActivatesRet:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp printstring STRINGID_PKMNSXMADEYINEFFECTIVE waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_ColorChangeActivates:: call BattleScript_AbilityPopUp @@ -7958,13 +7180,11 @@ BattleScript_CursedBodyActivates:: return BattleScript_MummyActivates:: -.if B_ABILITY_POP_UP == TRUE setbyte sFIXED_ABILITY_POPUP, TRUE call BattleScript_AbilityPopUpTarget copybyte gBattlerAbility, gBattlerAttacker copyhword sABILITY_OVERWRITE, gLastUsedAbility call BattleScript_AbilityPopUpOverwriteThenNormal -.endif recordability BS_TARGET recordability BS_ATTACKER printstring STRINGID_ATTACKERACQUIREDABILITY @@ -7978,14 +7198,12 @@ BattleScript_MummyActivates:: BattleScript_WanderingSpiritActivates:: saveattacker savetarget -.if B_ABILITY_POP_UP == TRUE copybyte gBattlerAbility, gBattlerTarget sethword sABILITY_OVERWRITE, ABILITY_WANDERING_SPIRIT call BattleScript_AbilityPopUpOverwriteThenNormal copybyte gBattlerAbility, gBattlerAttacker copyhword sABILITY_OVERWRITE, gLastUsedAbility call BattleScript_AbilityPopUpOverwriteThenNormal -.endif recordability BS_TARGET recordability BS_ATTACKER printstring STRINGID_SWAPPEDABILITIES @@ -8010,7 +7228,7 @@ BattleScript_BattlerAbilityStatRaiseOnSwitchIn:: call BattleScript_AbilityPopUpScripting statbuffchange BS_SCRIPTING, STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_CERTAIN, BattleScript_BattlerAbilityStatRaiseOnSwitchInRet waitanimation - printstring STRINGID_BATTLERABILITYRAISEDSTAT + printstring STRINGID_SCRIPTINGABILITYSTATRAISE waitmessage B_WAIT_TIME_LONG BattleScript_BattlerAbilityStatRaiseOnSwitchInRet: end3 @@ -8031,8 +7249,8 @@ BattleScript_WeakArmorActivates:: call BattleScript_AbilityPopUp setstatchanger STAT_DEF, 1, TRUE statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_WeakArmorActivatesSpeed - jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_WeakArmorDefPrintString - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_WeakArmorActivatesSpeed + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_WeakArmorDefPrintString + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_WeakArmorActivatesSpeed pause B_WAIT_TIME_SHORTEST printfromtable gStatDownStringIds clearmoveresultflags MOVE_RESULT_MISSED @ Set by statbuffchange when stat can't be decreased @@ -8049,8 +7267,8 @@ BattleScript_WeakArmorSetSpeedGen6: setstatchanger STAT_SPEED, 1, FALSE BattleScript_WeakArmorDoSpeed: statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_WeakArmorActivatesEnd - jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_WeakArmorSpeedPrintString - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_EMPTY, BattleScript_WeakArmorActivatesEnd + jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_WeakArmorSpeedPrintString + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGE_EMPTY, BattleScript_WeakArmorActivatesEnd pause B_WAIT_TIME_SHORTEST printstring STRINGID_TARGETSTATWONTGOHIGHER clearmoveresultflags MOVE_RESULT_MISSED @@ -8083,7 +7301,7 @@ BattleScript_AttackerAbilityStatRaise_End: BattleScript_FellStingerRaisesStat:: statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_FellStingerRaisesAtkEnd - jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_ROSE, BattleScript_FellStingerRaisesAtkEnd + jumpifbyte CMP_GREATER_THAN, cMULTISTRING_CHOOSER, B_MSG_DEFENDER_STAT_CHANGED, BattleScript_FellStingerRaisesAtkEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_FellStingerRaisesAtkEnd: @@ -8094,12 +7312,23 @@ BattleScript_AttackerAbilityStatRaiseEnd3:: restoreattacker end3 +BattleScript_AttackerAbilityStatRaiseEnd2:: + call BattleScript_AttackerAbilityStatRaise + restoreattacker + end2 + BattleScript_SwitchInAbilityMsg:: call BattleScript_AbilityPopUp printfromtable gSwitchInAbilityStringIds waitmessage B_WAIT_TIME_LONG end3 +BattleScript_SwitchInAbilityMsgRet:: + call BattleScript_AbilityPopUp + printfromtable gSwitchInAbilityStringIds + waitmessage B_WAIT_TIME_LONG + return + BattleScript_ActivateAsOne:: call BattleScript_AbilityPopUp printfromtable gSwitchInAbilityStringIds @@ -8141,9 +7370,8 @@ BattleScript_ImposterActivates:: end3 BattleScript_HurtAttacker: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNHURTSWITH waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -8165,10 +7393,9 @@ BattleScript_RockyHelmetActivatesDmg: BattleScript_SpikyShieldEffect:: jumpifabsent BS_ATTACKER, BattleScript_SpikyShieldRet - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE clearmoveresultflags MOVE_RESULT_NO_EFFECT - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_PKMNHURTSWITH waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -8177,7 +7404,6 @@ BattleScript_SpikyShieldRet:: return BattleScript_KingsShieldEffect:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE clearmoveresultflags MOVE_RESULT_NO_EFFECT seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_NONE copybyte sBATTLER, gBattlerTarget @@ -8187,7 +7413,6 @@ BattleScript_KingsShieldEffect:: return BattleScript_BanefulBunkerEffect:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE clearmoveresultflags MOVE_RESULT_NO_EFFECT setnonvolatilestatus TRIGGER_ON_PROTECT setmoveresultflags MOVE_RESULT_MISSED @@ -8234,19 +7459,19 @@ BattleScript_EffectBattleBondStatIncrease:: call BattleScript_AbilityPopUp setstatchanger STAT_ATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectBattleBondStatIncreaseTrySpAtk, BIT_SPATK | BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectBattleBondStatIncreaseTrySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectBattleBondStatIncreaseTrySpAtk printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectBattleBondStatIncreaseTrySpAtk: setstatchanger STAT_SPATK, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectBattleBondStatIncreaseTrySpeed, BIT_SPEED - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectBattleBondStatIncreaseTrySpeed + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectBattleBondStatIncreaseTrySpeed printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectBattleBondStatIncreaseTrySpeed: setstatchanger STAT_SPEED, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_EffectBattleBondStatIncreaseRet - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectBattleBondStatIncreaseRet + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_EffectBattleBondStatIncreaseRet printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_EffectBattleBondStatIncreaseRet: @@ -8255,7 +7480,6 @@ BattleScript_EffectBattleBondStatIncreaseRet: BattleScript_DancerActivates:: call BattleScript_AbilityPopUp waitmessage B_WAIT_TIME_SHORT - orword gHitMarker, HITMARKER_ALLOW_NO_PP jumptocalledmove TRUE BattleScript_SynchronizeActivates:: @@ -8305,8 +7529,7 @@ BattleScript_IgnoresWhileAsleep:: BattleScript_IgnoresAndUsesRandomMove:: printstring STRINGID_PKMNIGNOREDORDERS waitmessage B_WAIT_TIME_LONG - setbyte sMOVE_EFFECT, 0 - jumptocalledmove FALSE + return BattleScript_MoveUsedLoafingAround:: jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_LOAFING, BattleScript_MoveUsedLoafingAroundMsg @@ -8342,73 +7565,13 @@ BattleScript_SubstituteFade:: printstring STRINGID_PKMNSUBSTITUTEFADED return -BattleScript_BerryCurePrlzEnd2:: - call BattleScript_BerryCureParRet +BattleScript_BerryCureStatusEnd2:: + call BattleScript_BerryCureStatusRet end2 -BattleScript_BerryCureParRet:: +BattleScript_BerryCureStatusRet:: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMCUREDPARALYSIS - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCurePsnEnd2:: - call BattleScript_BerryCurePsnRet - end2 - -BattleScript_BerryCurePsnRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMCUREDPOISON - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureBrnEnd2:: - call BattleScript_BerryCureBrnRet - end2 - -BattleScript_BerryCureBrnRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMHEALEDBURN - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureFrzEnd2:: - call BattleScript_BerryCureFrzRet - end2 - -BattleScript_BerryCureFrzRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMDEFROSTEDIT - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureFrbEnd2:: - call BattleScript_BerryCureFrzRet - end2 - -BattleScript_BerryCureFrbRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMHEALEDFROSTBITE - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - -BattleScript_BerryCureSlpEnd2:: - call BattleScript_BerryCureSlpRet - end2 - -BattleScript_BerryCureSlpRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printstring STRINGID_PKMNSITEMWOKEIT + printfromtable CureStatusBerryEffectStringID waitmessage B_WAIT_TIME_LONG updatestatusicon BS_SCRIPTING removeitem BS_SCRIPTING @@ -8443,25 +7606,12 @@ BattleScript_BerryCureConfusionRet:: removeitem BS_SCRIPTING return -BattleScript_BerryCureChosenStatusEnd2:: - call BattleScript_BerryCureChosenStatusRet - end2 - -BattleScript_BerryCureChosenStatusRet:: - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT - printfromtable gBerryEffectStringIds - waitmessage B_WAIT_TIME_LONG - updatestatusicon BS_SCRIPTING - removeitem BS_SCRIPTING - return - BattleScript_MentalHerbCureRet:: - playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT + playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printfromtable gMentalHerbCureStringIds waitmessage B_WAIT_TIME_LONG updatestatusicon BS_SCRIPTING removeitem BS_SCRIPTING - copybyte gBattlerAttacker, sSAVED_BATTLER @ restore the original attacker just to be safe return BattleScript_MentalHerbCureEnd2:: @@ -8483,14 +7633,13 @@ BattleScript_ItemHealHP_RemoveItemRet:: jumpifability BS_SCRIPTING, ABILITY_RIPEN, BattleScript_ItemHealHP_RemoveItemRet_AbilityPopUp goto BattleScript_ItemHealHP_RemoveItemRet_Anim BattleScript_ItemHealHP_RemoveItemRet_AbilityPopUp: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting BattleScript_ItemHealHP_RemoveItemRet_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE removeitem BS_SCRIPTING return @@ -8498,14 +7647,13 @@ BattleScript_ItemHealHP_RemoveItemEnd2:: jumpifability BS_ATTACKER, ABILITY_RIPEN, BattleScript_ItemHealHP_RemoveItemEnd2_AbilityPopUp goto BattleScript_ItemHealHP_RemoveItemEnd2_Anim BattleScript_ItemHealHP_RemoveItemEnd2_AbilityPopUp: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting BattleScript_ItemHealHP_RemoveItemEnd2_Anim: playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE removeitem BS_ATTACKER end2 @@ -8529,21 +7677,25 @@ BattleScript_ItemHealHP_End2:: call BattleScript_ItemHealHP_Ret end2 -BattleScript_AirBaloonMsgIn:: +BattleScript_AirBalloonMsgIn:: printstring STRINGID_AIRBALLOONFLOAT waitmessage B_WAIT_TIME_LONG end3 -BattleScript_AirBaloonMsgPop:: +BattleScript_AirBalloonMsgInRet:: + printstring STRINGID_AIRBALLOONFLOAT + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_AirBalloonMsgPop:: printstring STRINGID_AIRBALLOONPOP waitmessage B_WAIT_TIME_LONG removeitem BS_TARGET return BattleScript_ItemHurtRet:: - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_IGNORE_DISGUISE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE printstring STRINGID_HURTBYITEM waitmessage B_WAIT_TIME_LONG tryfaintmon BS_ATTACKER @@ -8559,9 +7711,8 @@ BattleScript_ItemHealHP_Ret:: playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHPALITTLE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER + healthbarupdate BS_ATTACKER, PASSIVE_HP_UPDATE + datahpupdate BS_ATTACKER, PASSIVE_HP_UPDATE return BattleScript_SelectingNotAllowedMoveChoiceItem:: @@ -8614,9 +7765,8 @@ BattleScript_BerryConfuseHealEnd2_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE seteffectprimary BS_SCRIPTING, BS_SCRIPTING, MOVE_EFFECT_CONFUSION removeitem BS_SCRIPTING end2 @@ -8630,9 +7780,8 @@ BattleScript_BerryConfuseHealRet_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDHEALTH waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE seteffectprimary BS_SCRIPTING, BS_SCRIPTING, MOVE_EFFECT_CONFUSION removeitem BS_SCRIPTING return @@ -8642,24 +7791,22 @@ BattleScript_ConsumableStatRaiseEnd2:: end2 BattleScript_ConsumableStatRaiseRet:: - @ to ensure `statbuffchange` has correct battler id, backup and use target - savetarget - copybyte gBattlerTarget, sBATTLER jumpifnotberry BS_SCRIPTING, BattleScript_ConsumableStatRaiseRet_Anim - @ check ripen popup if consuming berry jumpifability BS_SCRIPTING, ABILITY_RIPEN, BattleScript_ConsumableStatRaiseRet_AbilityPopup goto BattleScript_ConsumableStatRaiseRet_Anim BattleScript_ConsumableStatRaiseRet_AbilityPopup: call BattleScript_AbilityPopUp BattleScript_ConsumableStatRaiseRet_Anim: - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_ConsumableStatRaiseRet_End + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_ConsumableStatRaiseRet_End playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_ConsumableStatRaiseRet_End - setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_ConsumableStatRaiseRet_End + setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGED_ITEM + savetarget + copybyte gBattlerTarget, sBATTLER @ BattleScript_StatUp uses target as a message arg call BattleScript_StatUp + restoretarget removeitem BS_SCRIPTING BattleScript_ConsumableStatRaiseRet_End: - restoretarget return BattleScript_BerryFocusEnergyRet:: @@ -8823,7 +7970,7 @@ BattleScript_MirrorHerbCopyStatChange:: removeitem BS_SCRIPTING BattleScript_MirrorHerbStartCopyStats: copyfoesstatincrease BS_SCRIPTING, BattleScript_MirrorHerbStartReturn - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_MirrorHerbStartReturn + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_MirrorHerbStartReturn setbyte sSTAT_ANIM_PLAYED, TRUE @ play stat change animation only once goto BattleScript_MirrorHerbStartCopyStats BattleScript_MirrorHerbStartReturn: @@ -8834,13 +7981,17 @@ BattleScript_OpportunistCopyStatChange:: call BattleScript_AbilityPopUpScripting BattleScript_OpportunistStartCopyStats: copyfoesstatincrease BS_SCRIPTING, BattleScript_OpportunistCopyStatChangeEnd - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_OpportunistCopyStatChangeEnd + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_OpportunistCopyStatChangeEnd printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG setbyte sSTAT_ANIM_PLAYED, TRUE @ play stat change animation only once goto BattleScript_OpportunistStartCopyStats BattleScript_OpportunistCopyStatChangeEnd: setbyte sSTAT_ANIM_PLAYED, FALSE + return + +BattleScript_OpportunistCopyStatChangeEnd3:: + call BattleScript_OpportunistCopyStatChange end3 BattleScript_TotemVar:: @@ -8939,7 +8090,7 @@ BattleScript_MicleBerryActivateRet:: jumpifability BS_SCRIPTING, ABILITY_RIPEN, BattleScript_MicleBerryActivateRet_Ripen goto BattleScript_MicleBerryActivateRet_Anim BattleScript_MicleBerryActivateRet_Ripen: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting BattleScript_MicleBerryActivateRet_Anim: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_MICLEBERRYACTIVATES @@ -8982,31 +8133,21 @@ BattleScript_ZMoveActivateStatus:: copybyte sSTATCHANGER, sSAVED_STAT_CHANGER return -BattleScript_ZMoveActivatePowder:: - flushtextbox - trytrainerslidezmovemsg - savetarget - printstring STRINGID_ZPOWERSURROUNDS - playanimation BS_ATTACKER, B_ANIM_ZMOVE_ACTIVATE, NULL - setzeffect - restoretarget - goto BattleScript_MoveUsedPowder - BattleScript_ZEffectPrintString:: printfromtable gZEffectStringIds waitmessage B_WAIT_TIME_LONG return BattleScript_RecoverHPZMove:: - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE printfromtable gZEffectStringIds waitmessage B_WAIT_TIME_LONG return BattleScript_StatUpZMove:: statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR, BattleScript_StatUpZMoveEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_StatUpZMoveEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_StatUpZMoveEnd printstring STRINGID_ZMOVESTATUP waitmessage B_WAIT_TIME_LONG printfromtable gStatUpStringIds @@ -9018,14 +8159,12 @@ BattleScript_HealReplacementZMove:: playanimation BS_SCRIPTING, B_ANIM_WISH_HEAL, 0x0 printfromtable gZEffectStringIds waitmessage B_WAIT_TIME_LONG - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE return BattleScript_EffectExtremeEvoboost:: attackcanceler - attackstring - ppreduce jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_ExtremeEvoboostAnim jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_DEF, MAX_STAT_STAGE, BattleScript_ExtremeEvoboostAnim jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_SPEED, MAX_STAT_STAGE, BattleScript_ExtremeEvoboostAnim @@ -9062,38 +8201,6 @@ BattleScript_ExtremeEvoboostSpDef:: BattleScript_ExtremeEvoboostEnd:: goto BattleScript_MoveEnd -BattleScript_EffectHitSetTerrain:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG - setterrain BattleScript_TryFaint - playanimation BS_ATTACKER, B_ANIM_RESTORE_BG - printfromtable gTerrainStringIds - waitmessage B_WAIT_TIME_LONG -BattleScript_TryFaint: - tryfaintmon BS_TARGET - goto BattleScript_MoveEnd - -BattleScript_EffectSteelRoller:: - attackcanceler - jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_FailedFromAtkString - goto BattleScript_HitFromAccCheck - BattleScript_RemoveTerrain:: removeterrain playanimation BS_ATTACKER, B_ANIM_RESTORE_BG @@ -9207,8 +8314,6 @@ BattleScript_EjectPackActivates:: goto BattleScript_EjectPackActivate_Ret BattleScript_DoesntAffectTargetAtkString:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT printstring STRINGID_ITDOESNTAFFECT waitmessage B_WAIT_TIME_LONG @@ -9216,8 +8321,6 @@ BattleScript_DoesntAffectTargetAtkString:: goto BattleScript_MoveEnd BattleScript_WellBakedBodyActivates:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUpTarget setmoveresultflags MOVE_RESULT_NO_EFFECT @@ -9226,8 +8329,6 @@ BattleScript_WellBakedBodyEnd: goto BattleScript_MoveEnd BattleScript_WindRiderActivatesMoveEnd:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUpTarget setmoveresultflags MOVE_RESULT_NO_EFFECT @@ -9236,8 +8337,6 @@ BattleScript_WindRiderActivatesMoveEnd_End: goto BattleScript_MoveEnd BattleScript_GoodAsGoldActivates:: - attackstring - ppreduce call BattleScript_AbilityPopUpTarget pause B_WAIT_TIME_SHORT printstring STRINGID_ITDOESNTAFFECT @@ -9301,21 +8400,18 @@ BattleScript_SymbiosisActivates:: return BattleScript_TargetAbilityStatRaiseRet:: - copybyte sSAVED_BATTLER, gBattlerAttacker - copybyte gBattlerAbility, gEffectBattler - copybyte gBattlerAttacker, gBattlerTarget + saveattacker + copybyte gBattlerAttacker, gEffectBattler call BattleScript_AbilityPopUp statbuffchange BS_ATTACKER, STAT_CHANGE_CERTAIN, BattleScript_TargetAbilityStatRaiseRet_End call BattleScript_StatUp BattleScript_TargetAbilityStatRaiseRet_End: - copybyte gBattlerAttacker, sSAVED_BATTLER + restoreattacker return @@@ MAX MOVES @@@ BattleScript_EffectMaxMove:: attackcanceler - attackstring - ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON goto BattleScript_HitFromCritCalc @@ -9327,7 +8423,7 @@ BattleScript_RaiseSideStatsLoop: jumpifabsent BS_TARGET, BattleScript_RaiseSideStatsIncrement copybyte sSTATCHANGER, sSAVED_STAT_CHANGER statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_RaiseSideStatsIncrement - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_RaiseSideStatsIncrement + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_RaiseSideStatsIncrement printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG BattleScript_RaiseSideStatsIncrement: @@ -9345,7 +8441,7 @@ BattleScript_LowerSideStatsLoop: jumpifabsent BS_TARGET, BattleScript_LowerSideStatsIncrement copybyte sSTATCHANGER, sSAVED_STAT_CHANGER statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_LowerSideStatsIncrement - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_LowerSideStatsIncrement + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_CHANGE, BattleScript_LowerSideStatsIncrement printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG BattleScript_LowerSideStatsIncrement: @@ -9538,9 +8634,8 @@ BattleScript_EffectHealOneSixthAllies:: BattleScript_HealOneSixthAlliesLoop: jumpifabsent BS_TARGET, BattleScript_HealOneSixthAlliesIncrement tryhealsixthhealth BattleScript_HealOneSixthAlliesIncrement - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_TARGET - datahpupdate BS_TARGET + healthbarupdate BS_TARGET, PASSIVE_HP_UPDATE + datahpupdate BS_TARGET, PASSIVE_HP_UPDATE printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_HealOneSixthAlliesIncrement: @@ -9622,19 +8717,13 @@ BattleScript_DynamaxEnds_Ret:: return BattleScript_MoveBlockedByDynamax:: - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring + accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE pause B_WAIT_TIME_SHORT - ppreduce - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_STRING_PRINTED, BattleScript_MoveEnd printstring STRINGID_MOVEBLOCKEDBYDYNAMAX waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_STRING_PRINTED goto BattleScript_MoveEnd BattleScript_PokemonCantUseTheMove:: - attackstring - ppreduce pause B_WAIT_TIME_SHORT printstring STRINGID_BUTPOKEMONCANTUSETHEMOVE waitmessage B_WAIT_TIME_LONG @@ -9646,18 +8735,15 @@ BattleScript_CouldntFullyProtect:: return BattleScript_BerserkGeneRet:: - saveattacker - savetarget - copybyte gBattlerTarget, sBATTLER - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_BerserkGeneRet_TryConfuse - playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 - statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_BerserkGeneRet_TryConfuse - setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_BerserkGeneRet_TryConfuse + playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 + statbuffchange BS_SCRIPTING, STAT_CHANGE_ALLOW_PTR, BattleScript_BerserkGeneRet_TryConfuse + setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_CHANGED_ITEM call BattleScript_StatUp BattleScript_BerserkGeneRet_TryConfuse: - jumpifability BS_ATTACKER, ABILITY_OWN_TEMPO, BattleScript_BerserkGeneRet_OwnTempoPrevents + jumpifability BS_SCRIPTING, ABILITY_OWN_TEMPO, BattleScript_BerserkGeneRet_OwnTempoPrevents jumpifsafeguard BattleScript_BerserkGeneRet_SafeguardProtected - seteffectprimary BS_ATTACKER, BS_ATTACKER, MOVE_EFFECT_CONFUSION + seteffectprimary BS_SCRIPTING, BS_SCRIPTING, MOVE_EFFECT_CONFUSION goto BattleScript_BerserkGeneRet_End BattleScript_BerserkGeneRet_SafeguardProtected:: pause B_WAIT_TIME_SHORT @@ -9666,13 +8752,11 @@ BattleScript_BerserkGeneRet_SafeguardProtected:: goto BattleScript_BerserkGeneRet_End BattleScript_BerserkGeneRet_OwnTempoPrevents: pause B_WAIT_TIME_SHORT - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting printstring STRINGID_PKMNPREVENTSCONFUSIONWITH waitmessage B_WAIT_TIME_LONG BattleScript_BerserkGeneRet_End: - restoreattacker - restoretarget - removeitem BS_ATTACKER + removeitem BS_SCRIPTING return BattleScript_BerserkGeneRetEnd2:: @@ -9695,8 +8779,6 @@ BattleScript_BoosterEnergyRet:: BattleScript_EffectSnow:: attackcanceler - attackstring - ppreduce call BattleScript_CheckPrimalWeather setfieldweather BATTLE_WEATHER_SNOW goto BattleScript_MoveWeatherChange @@ -9728,3 +8810,44 @@ BattleScript_ForfeitBattleGaveMoney:: .endif waitmessage B_WAIT_TIME_LONG end2 + +BattleScript_Attackstring:: + printattackstring + return + +BattleScript_SubmoveAttackstring:: + printattackstring + pause B_WAIT_TIME_LONG + attackanimation + waitanimation + setcalledmove + return + +BattleScript_SleepTalkAttackstring:: + printattackstring + pause B_WAIT_TIME_LONG + printstring STRINGID_PKMNFASTASLEEP + waitmessage B_WAIT_TIME_LONG + statusanimation BS_ATTACKER + attackanimation + waitanimation + setcalledmove + return + +BattleScript_MetronomeAttackstring:: + printattackstring + pause B_WAIT_TIME_LONG + attackanimation + waitanimation + setcalledmove + printstring STRINGID_WAGGLINGAFINGER + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_NaturePowerAttackstring:: + printattackstring + pause B_WAIT_TIME_SHORT + setcalledmove + printstring STRINGID_NATUREPOWERTURNEDINTO + waitmessage B_WAIT_TIME_LONG + return diff --git a/data/battle_scripts_2.s b/data/battle_scripts_2.s index 2c7a56078f..5f7cc23a8c 100755 --- a/data/battle_scripts_2.s +++ b/data/battle_scripts_2.s @@ -49,9 +49,8 @@ BattleScript_UseItemMessage: BattleScript_ItemRestoreHPRet: clearmoveresultflags MOVE_RESULT_NO_EFFECT - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE - healthbarupdate BS_SCRIPTING - datahpupdate BS_SCRIPTING + healthbarupdate BS_SCRIPTING, PASSIVE_HP_UPDATE + datahpupdate BS_SCRIPTING, PASSIVE_HP_UPDATE printstring STRINGID_ITEMRESTOREDSPECIESHEALTH waitmessage B_WAIT_TIME_LONG return diff --git a/data/event_scripts.s b/data/event_scripts.s index 23ce59545b..bc9388be64 100644 --- a/data/event_scripts.s +++ b/data/event_scripts.s @@ -3,6 +3,7 @@ #include "config/item.h" #include "constants/global.h" #include "constants/apprentice.h" +#include "constants/apricorn_tree.h" #include "constants/battle.h" #include "constants/battle_arena.h" #include "constants/battle_dome.h" @@ -43,6 +44,7 @@ #include "constants/maps.h" #include "constants/mauville_old_man.h" #include "constants/metatile_labels.h" +#include "constants/move_relearner.h" #include "constants/moves.h" #include "constants/party_menu.h" #include "constants/pokedex.h" @@ -62,6 +64,7 @@ #include "constants/union_room.h" #include "constants/vars.h" #include "constants/weather.h" +#include "constants/speaker_names.h" .include "asm/macros.inc" .include "asm/macros/event.inc" .include "constants/constants.inc" @@ -695,6 +698,7 @@ EventScript_SetBrineyLocation_Route109:: .include "data/scripts/obtain_item.inc" .include "data/scripts/record_mix.inc" .include "data/scripts/pc.inc" + .include "data/scripts/move_relearner.inc" @ scripts/notices.inc? signs.inc? See comment about text/notices.inc Common_EventScript_ShowPokemartSign:: @@ -880,6 +884,7 @@ Common_EventScript_PlayerHandedOverTheItem:: .include "data/text/pkmn_center_nurse.inc" .include "data/text/mart_clerk.inc" .include "data/text/obtain_item.inc" + .include "data/text/move_relearner.inc" @ The below and surf.inc could be split into some text/notices.inc gText_PokemartSign:: @@ -1112,9 +1117,6 @@ EventScript_VsSeekerChargingDone:: .include "data/scripts/cable_club.inc" .include "data/text/cable_club.inc" .include "data/scripts/contest_hall.inc" - .include "data/text/contest_strings.inc" - .include "data/text/contest_link.inc" - .include "data/text/contest_painting.inc" .include "data/scripts/tv.inc" .include "data/text/tv.inc" .include "data/scripts/interview.inc" @@ -1158,3 +1160,5 @@ EventScript_VsSeekerChargingDone:: .include "data/text/save.inc" .include "data/text/birch_speech.inc" .include "data/scripts/dexnav.inc" + .include "data/scripts/battle_frontier.inc" + .include "data/scripts/apricorn_tree.inc" diff --git a/data/field_effect_scripts.s b/data/field_effect_scripts.s index 34678bb293..ce71a102fd 100644 --- a/data/field_effect_scripts.s +++ b/data/field_effect_scripts.s @@ -83,6 +83,7 @@ gFieldEffectScriptPointers:: .4byte gFieldEffectScript_Defog @ FLDEFF_DEFOG .4byte gFieldEffectScript_UseRockClimb @ FLDEFF_USE_ROCK_CLIMB .4byte gFieldEffectScript_RockClimbDust @ FLDEFF_ROCK_CLIMB_DUST + .4byte gFieldEffectScript_ORASDowse @ FLDEFF_ORAS_DOWSE gFieldEffectScript_ExclamationMarkIcon1:: field_eff_callnative FldEff_ExclamationMarkIcon @@ -386,6 +387,7 @@ gFieldEffectScript_CaveDust:: gFieldEffectScript_Defog:: field_eff_callnative FldEff_Defog field_eff_end + gFieldEffectScript_UseRockClimb:: @ 82DBC3F field_eff_callnative FldEff_UseRockClimb field_eff_end @@ -394,3 +396,7 @@ gFieldEffectScript_RockClimbDust:: @ 82DBB28 field_eff_loadfadedpal_callnative gSpritePalette_BigDust, FldEff_RockClimbDust field_eff_end +gFieldEffectScript_ORASDowse:: + field_eff_callnative FldEff_ORASDowsing + field_eff_end + diff --git a/data/map_events.s b/data/map_events.s index 729f9725df..13064da025 100644 --- a/data/map_events.s +++ b/data/map_events.s @@ -13,6 +13,7 @@ #include "constants/trainer_types.h" #include "constants/berry.h" #include "constants/species.h" +#include "constants/apricorn_tree.h" .include "asm/macros.inc" .include "constants/constants.inc" diff --git a/data/maps/BattleFrontier_BattleArenaLobby/scripts.inc b/data/maps/BattleFrontier_BattleArenaLobby/scripts.inc index 7969ca9eb7..fdcd609bc8 100644 --- a/data/maps/BattleFrontier_BattleArenaLobby/scripts.inc +++ b/data/maps/BattleFrontier_BattleArenaLobby/scripts.inc @@ -182,10 +182,14 @@ BattleFrontier_BattleArenaLobby_EventScript_NotEnoughValidMons:: BattleFrontier_BattleArenaLobby_EventScript_NotEnoughValidMonsLv50:: msgbox BattleFrontier_BattleArenaLobby_Text_NotEnoughValidMonsLv50, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleArenaLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleArenaLobby_EventScript_EndCancelChallenge BattleFrontier_BattleArenaLobby_EventScript_NotEnoughValidMonsLvOpen:: msgbox BattleFrontier_BattleArenaLobby_Text_NotEnoughValidMonsLvOpen, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleArenaLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleArenaLobby_EventScript_EndCancelChallenge BattleFrontier_BattleArenaLobby_EventScript_CancelChallengeSaveFailed:: @@ -409,7 +413,9 @@ BattleFrontier_BattleArenaLobby_Text_NotEnoughValidMonsLvOpen: .string "different kinds of POKéMON.\p" .string "They also must not hold the same\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" + .string "EGGS{STR_VAR_1}.$" + +BattleFrontier_BattleArenaLobby_Text_NotEnoughValidMonsEnd: .string "When you have made your preparations,\n" .string "please do return.$" @@ -423,9 +429,7 @@ BattleFrontier_BattleArenaLobby_Text_NotEnoughValidMonsLv50: .string "must all be Level 50 or lower.\p" .string "They also must not hold the same\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "When you have made your preparations,\n" - .string "please do return.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleArenaLobby_Text_GuideYouToArena: .string "I shall now guide you to\n" diff --git a/data/maps/BattleFrontier_BattleDomeLobby/scripts.inc b/data/maps/BattleFrontier_BattleDomeLobby/scripts.inc index cf6510189c..f3522ccfb6 100644 --- a/data/maps/BattleFrontier_BattleDomeLobby/scripts.inc +++ b/data/maps/BattleFrontier_BattleDomeLobby/scripts.inc @@ -210,10 +210,14 @@ BattleFrontier_BattleDomeLobby_EventScript_NotEnoughValidMons:: BattleFrontier_BattleDomeLobby_EventScript_NotEnoughValidMonsLv50:: msgbox BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsLv50, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleDomeLobby_EventScript_EndCancelChallenge BattleFrontier_BattleDomeLobby_EventScript_NotEnoughValidMonsLvOpen:: msgbox BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsLvOpen, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleDomeLobby_EventScript_EndCancelChallenge BattleFrontier_BattleDomeLobby_EventScript_CancelChallengeSaveFailed:: @@ -486,7 +490,9 @@ BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsLvOpen: .string "You don't have three eligible POKéMON.\p" .string "Also, the POKéMON must be holding\n" .string "different kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" + .string "EGGS{STR_VAR_1}.$" + +BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsEnd: .string "Please come see me when you are ready.$" BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsLv50: @@ -496,8 +502,7 @@ BattleFrontier_BattleDomeLobby_Text_NotEnoughValidMonsLv50: .string "of Level 50 or less to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleDomeLobby_Text_ShowYouToBattleDome: .string "I will now show you to\n" diff --git a/data/maps/BattleFrontier_BattlePalaceLobby/scripts.inc b/data/maps/BattleFrontier_BattlePalaceLobby/scripts.inc index d80eaa49c2..9ef4479f2e 100644 --- a/data/maps/BattleFrontier_BattlePalaceLobby/scripts.inc +++ b/data/maps/BattleFrontier_BattlePalaceLobby/scripts.inc @@ -202,10 +202,14 @@ BattleFrontier_BattlePalaceLobby_EventScript_NotEnoughValidMons:: BattleFrontier_BattlePalaceLobby_EventScript_NotEnoughValidMonsLv50:: msgbox BattleFrontier_BattlePalaceLobby_Text_NotEnoughValidMonsLv50, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattlePalaceLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattlePalaceLobby_EventScript_EndCancelChallenge BattleFrontier_BattlePalaceLobby_EventScript_NotEnoughValidMonsLvOpen:: msgbox BattleFrontier_BattlePalaceLobby_Text_NotEnoughValidMonsLvOpen, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattlePalaceLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattlePalaceLobby_EventScript_EndCancelChallenge BattleFrontier_BattlePalaceLobby_EventScript_CancelChallengeSaveFailed:: @@ -427,7 +431,9 @@ BattleFrontier_BattlePalaceLobby_Text_NotEnoughValidMonsLv50: .string "Level 50 or lower.\p" .string "They also must not be holding\n" .string "the same kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" + .string "EGGS{STR_VAR_1}.$" + +BattleFrontier_BattlePalaceLobby_Text_NotEnoughValidMonsEnd: .string "Come back when you have made\n" .string "your preparations.$" @@ -439,9 +445,7 @@ BattleFrontier_BattlePalaceLobby_Text_NotEnoughValidMonsLvOpen: .string "different kinds of POKéMON.\p" .string "They also must not be holding\n" .string "the same kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Come back when you have made\n" - .string "your preparations.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattlePalaceLobby_Text_NowSelectThreeMons: .string "Good. Now, you must select your\n" diff --git a/data/maps/BattleFrontier_BattlePikeLobby/scripts.inc b/data/maps/BattleFrontier_BattlePikeLobby/scripts.inc index 6e72a30ec0..db00673550 100644 --- a/data/maps/BattleFrontier_BattlePikeLobby/scripts.inc +++ b/data/maps/BattleFrontier_BattlePikeLobby/scripts.inc @@ -172,10 +172,14 @@ BattleFrontier_BattlePikeLobby_EventScript_NotEnoughValidMons:: BattleFrontier_BattlePikeLobby_EventScript_NotEnoughValidMonsLv50:: msgbox BattleFrontier_BattlePikeLobby_Text_NotEnoughValidMonsLv50, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattlePikeLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattlePikeLobby_EventScript_EndCancelChallenge BattleFrontier_BattlePikeLobby_EventScript_NotEnoughValidMonsLvOpen:: msgbox BattleFrontier_BattlePikeLobby_Text_NotEnoughValidMonsLvOpen, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattlePikeLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattlePikeLobby_EventScript_EndCancelChallenge BattleFrontier_BattlePikeLobby_EventScript_CancelChallengeSaveFailed:: @@ -315,7 +319,9 @@ BattleFrontier_BattlePikeLobby_Text_NotEnoughValidMonsLv50: .string "of Level 50 or less to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" + .string "EGGS{STR_VAR_1}.$" + +BattleFrontier_BattlePikeLobby_Text_NotEnoughValidMonsEnd: .string "Please come see me when\n" .string "you are ready…$" @@ -327,9 +333,7 @@ BattleFrontier_BattlePikeLobby_Text_NotEnoughValidMonsLvOpen: .string "POKéMON to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when\n" - .string "you are ready…$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattlePikeLobby_Text_PleaseChooseThreeMons: .string "Please choose the three POKéMON\n" diff --git a/data/maps/BattleFrontier_BattlePyramidLobby/scripts.inc b/data/maps/BattleFrontier_BattlePyramidLobby/scripts.inc index a8f949ca58..75f3c37cd8 100644 --- a/data/maps/BattleFrontier_BattlePyramidLobby/scripts.inc +++ b/data/maps/BattleFrontier_BattlePyramidLobby/scripts.inc @@ -184,10 +184,14 @@ BattleFrontier_BattlePyramidLobby_EventScript_NotEnoughValidMons:: BattleFrontier_BattlePyramidLobby_EventScript_NotEnoughValidMonsLv50:: msgbox BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsLv50, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattlePyramidLobby_EventScript_EndCancelChallenge BattleFrontier_BattlePyramidLobby_EventScript_NotEnoughValidMonsLvOpen:: msgbox BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsLvOpen, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattlePyramidLobby_EventScript_EndCancelChallenge BattleFrontier_BattlePyramidLobby_EventScript_CancelChallengeSaveFailed:: @@ -573,9 +577,7 @@ BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsLvOpen: .string "POKéMON qualified for the challenge.\p" .string "Please also remember to take all\n" .string "items from your POKéMON.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "When you are ready, please have\n" - .string "a word with me.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsLv50: .string "A slight problem, adventurer!\p" @@ -585,7 +587,9 @@ BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsLv50: .string "and each no higher than Level 50.\p" .string "Please also remember to take all\n" .string "items from your POKéMON.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" + .string "EGGS{STR_VAR_1}.$" + +BattleFrontier_BattlePyramidLobby_Text_NotEnoughValidMonsEnd: .string "When you are ready, please have\n" .string "a word with me.$" diff --git a/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc b/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc index 945335f7b7..3240683f95 100644 --- a/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc +++ b/data/maps/BattleFrontier_BattleTowerLobby/scripts.inc @@ -543,16 +543,22 @@ BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLv50:: case FRONTIER_MODE_SINGLES, BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLv50Singles case FRONTIER_MODE_DOUBLES, BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLv50Doubles msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Multis, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleTowerLobby_EventScript_EndCancelChallenge end BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLv50Singles:: msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Singles, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleTowerLobby_EventScript_EndCancelChallenge end BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLv50Doubles:: msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Doubles, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleTowerLobby_EventScript_EndCancelChallenge end @@ -561,16 +567,22 @@ BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLvOpen:: case FRONTIER_MODE_SINGLES, BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLvOpenSingles case FRONTIER_MODE_DOUBLES, BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLvOpenDoubles msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenMultis, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleTowerLobby_EventScript_EndCancelChallenge end BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLvOpenSingles:: msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenSingles, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleTowerLobby_EventScript_EndCancelChallenge end BattleFrontier_BattleTowerLobby_EventScript_NotEnoughValidMonsLvOpenDoubles:: msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenDoubles, MSGBOX_DEFAULT + call BattleFrontier_ShowCaughtBannedSpecies + msgbox BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsEnd, MSGBOX_DEFAULT goto BattleFrontier_BattleTowerLobby_EventScript_EndCancelChallenge end @@ -1083,7 +1095,9 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50: .string "of Level 50 or less to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" + .string "EGGS{STR_VAR_1}.$" + +BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsEnd: .string "Please come see me when you are ready.$" @ Unused @@ -1094,8 +1108,7 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpen: .string "to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Singles: .string "Excuse me!\p" @@ -1104,8 +1117,7 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Singles: .string "of Level 50 or less to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenSingles: .string "Excuse me!\p" @@ -1114,8 +1126,7 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenSingles: .string "to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Doubles: .string "Excuse me!\p" @@ -1124,8 +1135,7 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Doubles: .string "of Level 50 or less to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenDoubles: .string "Excuse me!\p" @@ -1134,8 +1144,7 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenDoubles: .string "to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Multis: .string "Excuse me!\p" @@ -1144,8 +1153,7 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLv50Multis: .string "of Level 50 or less to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenMultis: .string "Excuse me!\p" @@ -1154,8 +1162,7 @@ BattleFrontier_BattleTowerLobby_Text_NotEnoughValidMonsLvOpenMultis: .string "to enter.\p" .string "They also must be holding different\n" .string "kinds of items.\p" - .string "EGGS{STR_VAR_1} ineligible.\p" - .string "Please come see me when you are ready.$" + .string "EGGS{STR_VAR_1}.$" BattleFrontier_BattleTowerLobby_Text_WelcomSingleBattle: .string "Where the talents of TRAINERS\n" diff --git a/data/maps/FallarborTown_MoveRelearnersHouse/scripts.inc b/data/maps/FallarborTown_MoveRelearnersHouse/scripts.inc index 8dd70b9b04..ea58d275df 100644 --- a/data/maps/FallarborTown_MoveRelearnersHouse/scripts.inc +++ b/data/maps/FallarborTown_MoveRelearnersHouse/scripts.inc @@ -22,6 +22,7 @@ FallarborTown_MoveRelearnersHouse_EventScript_AskTeachMove:: FallarborTown_MoveRelearnersHouse_EventScript_ChooseMon:: msgbox FallarborTown_MoveRelearnersHouse_Text_TutorWhichMon, MSGBOX_DEFAULT + setmoverelearnerstate MOVE_RELEARNER_LEVEL_UP_MOVES @ Specifically supposed to teach level up moves special ChooseMonForMoveRelearner waitstate goto_if_eq VAR_0x8004, PARTY_NOTHING_CHOSEN, FallarborTown_MoveRelearnersHouse_EventScript_ComeBackWithHeartScale diff --git a/data/maps/map_groups.json b/data/maps/map_groups.json index 8a90679c8d..78e82055f6 100644 --- a/data/maps/map_groups.json +++ b/data/maps/map_groups.json @@ -620,72 +620,5 @@ ], "gMapGroup_IndoorRoute124": [ "Route124_DivingTreasureHuntersHouse" - ], - "connections_include_order": [ - "LittlerootTown", - "OldaleTown", - "DewfordTown", - "LavaridgeTown", - "FallarborTown", - "VerdanturfTown", - "PacifidlogTown", - "PetalburgCity", - "SlateportCity", - "MauvilleCity", - "RustboroCity", - "FortreeCity", - "LilycoveCity", - "MossdeepCity", - "SootopolisCity", - "EverGrandeCity", - "Route101", - "Route102", - "Route103", - "Route104", - "Route105", - "Route106", - "Route107", - "Route108", - "Route109", - "Route110", - "Route111", - "Route112", - "Route113", - "Route114", - "Route115", - "Route116", - "Route117", - "Route118", - "Route119", - "Route120", - "Route121", - "Route122", - "Route123", - "Route124", - "Route125", - "Route126", - "Route127", - "Route128", - "Route129", - "Route130", - "Route131", - "Route132", - "Route133", - "Route134", - "Underwater_Route105", - "Underwater_Route124", - "Underwater_Route125", - "Underwater_Route126", - "Underwater_Route127", - "Underwater_Route128", - "Underwater_Route129", - "SafariZone_Northwest", - "SafariZone_North", - "SafariZone_Southwest", - "SafariZone_South", - "SafariZone_Northeast", - "SafariZone_Southeast", - "BattleFrontier_OutsideWest", - "BattleFrontier_OutsideEast" ] } diff --git a/data/scripts/apricorn_tree.inc b/data/scripts/apricorn_tree.inc new file mode 100644 index 0000000000..019b2b76b0 --- /dev/null +++ b/data/scripts/apricorn_tree.inc @@ -0,0 +1,89 @@ +ApricornTreeScript:: + lock + faceplayer + message ApricornTree_Text_Intro + waitmessage + special ObjectEventInteractionGetApricornTreeData + goto_if_gt VAR_0x8005, 0, ApricornTree_EventScript_WantToPick + message ApricornTree_Text_Empty + waitmessage + waitbuttonpress + release + end + +ApricornTree_EventScript_WantToPick:: + buffernumberstring STR_VAR_2, VAR_0x8005 + msgbox ApricornTree_Text_WantToPick, MSGBOX_YESNO + goto_if_eq VAR_RESULT, YES, ApricornTree_EventScript_PickApricorn + goto_if_eq VAR_RESULT, NO, ApricornTree_EventScript_CancelPickingApricorn + +.set APRICORN_NORMAL_BAG_FULL, 0 +.set APRICORN_NORMAL_SPACE_IN_BAG, 1 + +ApricornTree_EventScript_PickApricorn:: + special ObjectEventInteractionPickApricornTree + call EventScript_BufferPocketNameAndTryFanfare + goto_if_eq VAR_0x8006, APRICORN_NORMAL_BAG_FULL, ApricornTree_EventScript_PocketFull + message ApricornTree_Text_PickedTheApricorn +.if OW_SHOW_ITEM_DESCRIPTIONS != OW_ITEM_DESCRIPTIONS_OFF + copyvar VAR_0x8006 VAR_0x8004 +.endif + delay 10 +.if OW_SHOW_ITEM_DESCRIPTIONS != OW_ITEM_DESCRIPTIONS_OFF + showberrydescription +.endif + playfanfare MUS_OBTAIN_BERRY + waitmessage + waitfanfare + waitbuttonpress + message ApricornTree_Text_PutAwayApricorn + waitmessage + waitbuttonpress +.if OW_SHOW_ITEM_DESCRIPTIONS != OW_ITEM_DESCRIPTIONS_OFF + hideitemdescription +.endif + release + end + +ApricornTree_EventScript_PocketFull:: + message ApricornTree_Text_PocketFull + waitmessage + waitbuttonpress + release + end + +ApricornTree_EventScript_CancelPickingApricorn:: + message ApricornTree_Text_ApricornLeftUnpicked + waitmessage + waitbuttonpress + release + end + +ApricornTree_Text_Intro: + .string "It's an Apricorn Tree!$" + +ApricornTree_Text_Empty: + .string "There are no Apricorns…$" + +ApricornTree_Text_WantToPick: + .string "…It's {STR_VAR_2} {STR_VAR_1}!\p" + .string "Do you want to pick the\n" + .string "{STR_VAR_1}?$" + +ApricornTree_Text_PickedTheApricorn: + .string "{PLAYER} obtained\n" + .string "{STR_VAR_2} {STR_VAR_1}.$" + +ApricornTree_Text_PutAwayApricorn: + .string "{PLAYER} put away the\n" + .string "{STR_VAR_1} in\l" + .string "the BAG's {STR_VAR_3} POCKET.$" + +ApricornTree_Text_PocketFull: + .string "The BAG's {STR_VAR_3} POCKET is full.\p" + .string "{PLAYER} gave up on the\p" + .string "{STR_VAR_1}…$" + +ApricornTree_Text_ApricornLeftUnpicked: + .string "{PLAYER} gave up on the\p" + .string "{STR_VAR_1}…$" diff --git a/data/scripts/battle_frontier.inc b/data/scripts/battle_frontier.inc new file mode 100644 index 0000000000..cbfd1ac5ee --- /dev/null +++ b/data/scripts/battle_frontier.inc @@ -0,0 +1,13 @@ +BattleFrontier_ShowCaughtBannedSpecies:: + goto_if_eq VAR_0x8005, 0, BattleFrontier_ShowCaughtBannedSpeciesEnd + msgbox BattleFrontier_DoYouWantToSeeTheListOfCaughtBannedSpecies, MSGBOX_YESNO + goto_if_eq VAR_RESULT, NO, BattleFrontier_ShowCaughtBannedSpeciesEnd + callnative ShowBattleFrontierCaughtBannedSpecies + waitstate +BattleFrontier_ShowCaughtBannedSpeciesEnd: + return + + +BattleFrontier_DoYouWantToSeeTheListOfCaughtBannedSpecies: + .string "Do you want to see the list of\n" + .string "POKéMON species you can't bring?$" diff --git a/data/scripts/debug.inc b/data/scripts/debug.inc index e43df32813..921a3247e4 100644 --- a/data/scripts/debug.inc +++ b/data/scripts/debug.inc @@ -87,6 +87,15 @@ Debug_FlagsNotSetBattleConfigMessage_Text: .string "Please define a usable flag in:\l" .string "'include/config/battle.h'!$" +Debug_VarsNotSetBattleConfigMessage:: + message Debug_VarsNotSetBattleConfigMessage_Text + goto Debug_MessageEnd + +Debug_VarsNotSetBattleConfigMessage_Text: + .string "Feature unavailable!\n" + .string "Please define a usable var in:\l" + .string "'include/config/battle.h'!$" + Debug_BoxFilledMessage:: message Debug_BoxFilledMessage_Text goto Debug_MessageEnd @@ -387,7 +396,29 @@ Debug_EventScript_SetHiddenNature:: dynmultistack 0, 0, TRUE, 7, FALSE, 0, NULL switch VAR_RESULT case MULTI_B_PRESSED, Debug_EventScript_InflictStatus1_Close - special SetHiddenNature + special SetHiddenNature + releaseall + end + +Debug_EventScript_SetAbility:: + special ChoosePartyMon + waitstate + callnative DebugNative_GetAbilityNames + dynmultipush gStringVar1, 0 + dynmultipush gStringVar2, 1 + dynmultipush gStringVar3, 2 + dynmultistack 0, 0, FALSE, 3 FALSE, 0, NULL + switch VAR_RESULT + case MULTI_B_PRESSED, Debug_EventScript_SetAbilityClose + special SetAbility +Debug_EventScript_SetAbilityClose: + releaseall + end + +Debug_EventScript_SetFriendship:: + special ChoosePartyMon + waitstate + callnative DebugNative_Party_SetFriendship releaseall end diff --git a/data/scripts/move_relearner.inc b/data/scripts/move_relearner.inc new file mode 100644 index 0000000000..15c80733df --- /dev/null +++ b/data/scripts/move_relearner.inc @@ -0,0 +1,105 @@ +Common_EventScript_MoveRelearner:: + lockall + faceplayer + message MoveRelearner_Text_WouldLearnNewMoves + waitmessage + goto Common_EventScript_MoveRelearnerDynMultiChoice + end + +Common_EventScript_MoveRelearnerDynMultiChoice:: + dynmultipush MoveRelearner_Text_LevelUpMoves, 0 +.if P_ENABLE_MOVE_RELEARNERS == TRUE + dynmultipush MoveRelearner_Text_EggMoves, 1 + dynmultipush MoveRelearner_Text_TMMoves, 2 + dynmultipush MoveRelearner_Text_TutormoveMoves, 3 +.else + call_if_set P_FLAG_EGG_MOVES, MoveRelearner_EventScript_PushEggMoves + istmrelearneractive MoveRelearner_EventScript_PushTMMoves + call_if_set P_FLAG_TUTOR_MOVES, MoveRelearner_EventScript_PushTutorMoves +.endif @ P_ENABLE_MOVE_RELEARNERS + dynmultipush MoveRelearner_Text_SeeYa, 4 + dynmultistack 0, 0, FALSE, 5, 0, 0, DYN_MULTICHOICE_CB_NONE + closemessage + switch VAR_RESULT + case 0, MoveRelearner_EventScript_TeachLevelUpMoves + case 1, MoveRelearner_EventScript_TeachEggMoves + case 2, MoveRelearner_EventScript_TeachTMMoves + case 3, MoveRelearner_EventScript_TeachTutorMoves + case 4, MoveRelearner_EventScript_PleaseComeAgain +MoveRelearner_EventScript_PleaseComeAgain: + msgbox MoveRelearner_Text_ThankYouComeAgain, MSGBOX_DEFAULT + releaseall + end + +MoveRelearner_EventScript_PushEggMoves: + dynmultipush MoveRelearner_Text_EggMoves, 1 + return + +MoveRelearner_EventScript_PushTMMoves: + dynmultipush MoveRelearner_Text_TMMoves, 2 + return + +MoveRelearner_EventScript_PushTutorMoves: + dynmultipush MoveRelearner_Text_TutormoveMoves, 3 + return + +MoveRelearner_EventScript_TeachLevelUpMoves: + setmoverelearnerstate MOVE_RELEARNER_LEVEL_UP_MOVES + bufferstring STR_VAR_3, MoveRelearner_Text_LevelUpMoveLWR + goto MoveRelearner_EventScript_TeachMove + end + +MoveRelearner_EventScript_TeachEggMoves: + setmoverelearnerstate MOVE_RELEARNER_EGG_MOVES + bufferstring STR_VAR_3, MoveRelearner_Text_EggMoveLWR + goto MoveRelearner_EventScript_TeachMove + end + +MoveRelearner_EventScript_TeachTMMoves: + setmoverelearnerstate MOVE_RELEARNER_TM_MOVES + bufferstring STR_VAR_3, MoveRelearner_Text_TMMoveLWR + goto MoveRelearner_EventScript_TeachMove + end + +MoveRelearner_EventScript_TeachTutorMoves: + setmoverelearnerstate MOVE_RELEARNER_TUTOR_MOVES + bufferstring STR_VAR_3, MoveRelearner_Text_TutorMoveLWR + goto MoveRelearner_EventScript_TeachMove + end + +MoveRelearner_EventScript_TeachMove:: + getpartysize + goto_if_eq VAR_RESULT, 0, MoveRelearner_EventScript_NoPkmn + msgbox MoveRelearner_Text_ChoosePkmn, MSGBOX_DEFAULT + special ChooseMonForMoveRelearner + waitstate + call_if_eq VAR_0x8004, PARTY_NOTHING_CHOSEN, MoveRelearner_EventScript_AnythingElse + special IsSelectedMonEgg + call_if_eq VAR_RESULT, YES, MoveRelearner_EventScript_CantTeachMoveToEgg + call_if_eq VAR_0x8005, NO, MoveRelearner_EventScript_CantTeachMoveToPkmn + msgbox MoveRelearner_Text_WhichXmoveShouldTeach, MSGBOX_DEFAULT + special TeachMoveRelearnerMove + waitstate + goto MoveRelearner_EventScript_AnythingElse + end + +MoveRelearner_EventScript_NoPkmn: + msgbox MoveRelearner_Text_HaveNoPkmn, MSGBOX_AUTOCLOSE + releaseall + end + +MoveRelearner_EventScript_CantTeachMoveToEgg: + msgbox MoveRelearner_Text_CantTeachMoveToEgg, MSGBOX_AUTOCLOSE + goto MoveRelearner_EventScript_AnythingElse + end + +MoveRelearner_EventScript_CantTeachMoveToPkmn: + msgbox MoveRelearner_Text_CantTeachMoveToPkmn, MSGBOX_AUTOCLOSE + goto MoveRelearner_EventScript_AnythingElse + end + +MoveRelearner_EventScript_AnythingElse:: + message MoveRelearner_Text_AnythingElse + waitmessage + goto Common_EventScript_MoveRelearnerDynMultiChoice + end diff --git a/data/scripts/obtain_item.inc b/data/scripts/obtain_item.inc index 599961c821..3eb7f4f0d4 100644 --- a/data/scripts/obtain_item.inc +++ b/data/scripts/obtain_item.inc @@ -205,6 +205,7 @@ EventScript_FoundHiddenItem:: end EventScript_PutHiddenItemInPocket:: + callnative Script_ClearDowsingColor delay 10 showitemdescription waitmessage @@ -215,6 +216,7 @@ EventScript_PutHiddenItemInPocket:: hideitemdescription special TryPutTreasureInvestigatorsOnAir special SetHiddenItemFlag + callnative Script_UpdateDowseState releaseall end diff --git a/data/specials.inc b/data/specials.inc index 0a2ae2da50..f80933c011 100644 --- a/data/specials.inc +++ b/data/specials.inc @@ -564,3 +564,6 @@ gSpecials:: def_special EnterCode def_special GetCodeFeedback def_special SetHiddenNature + def_special SetAbility + def_special ObjectEventInteractionGetApricornTreeData + def_special ObjectEventInteractionPickApricornTree diff --git a/data/text/contest_link.inc b/data/text/contest_link.inc deleted file mode 100644 index f2f1469e0f..0000000000 --- a/data/text/contest_link.inc +++ /dev/null @@ -1,38 +0,0 @@ -@ With the exception of Link standby, none of the below texts are used - -gTest_MissedTurn:: - .string "Missed turn$" - -gText_LinkStandby4:: - .string "Link standby!$" - -gText_WinnerIsPlayersMonCongrats:: - .string "The winner is {STR_VAR_1}'s {STR_VAR_2}!\n" - .string "Congratulations!$" - -gText_WinnerIsPlayersMon:: - .string "The winner is {STR_VAR_1}'s {STR_VAR_2}!{PAUSE_UNTIL_PRESS}$" - -gText_PrimaryJudgingNumX:: - .string "Primary judging: No. {STR_VAR_1}{PAUSE_UNTIL_PRESS}$" - -gText_SecondaryJudgingNumX:: - .string "Secondary judging: No. {STR_VAR_1}{PAUSE_UNTIL_PRESS}$" - -gText_SetEventNumX:: - .string "Set event: No. {STR_VAR_1}{PAUSE_UNTIL_PRESS}$" - -gText_MoveUsedMostOften:: - .string "The move used most often:\n" - .string "{STR_VAR_1}{PAUSE_UNTIL_PRESS}$" - -gText_MostImpressiveMon:: - .string "The most impressive POKéMON:\n" - .string "{STR_VAR_1}'s {STR_VAR_2}{PAUSE_UNTIL_PRESS}$" - -gText_SetEventNumX2:: - .string "Set event: No. {STR_VAR_1}{PAUSE_UNTIL_PRESS}$" - -gText_LinkTVProgramWillNotBeMadeTrainerLost:: - .string "A link TV program will not be made\n" - .string "because the TRAINER lost.{PAUSE_UNTIL_PRESS}$" diff --git a/data/text/contest_painting.inc b/data/text/contest_painting.inc deleted file mode 100644 index 5152cb3bb8..0000000000 --- a/data/text/contest_painting.inc +++ /dev/null @@ -1,96 +0,0 @@ -gContestHallPaintingCaption:: - .string "{STR_VAR_1}\n" - .string "{STR_VAR_2}'s {STR_VAR_3}$" - -@ Unused -gContestPaintingContest:: - .string "CONTEST$" - -gContestRankNormal:: - .string "NORMAL RANK$" - -gContestRankSuper:: - .string "SUPER RANK$" - -gContestRankHyper:: - .string "HYPER RANK$" - -gContestRankMaster:: - .string "MASTER RANK$" - -gContestLink:: - .string "LINK$" - -gContestCoolness:: - .string "COOLNESS$" - -gContestBeauty:: - .string "BEAUTY$" - -gContestCuteness:: - .string "CUTENESS$" - -gContestSmartness:: - .string "SMARTNESS$" - -gContestToughness:: - .string "TOUGHNESS$" - -gContestPaintingCool1:: - .string "Nonstop supercool--\n" - .string "the inestimable {STR_VAR_1}$" - -gContestPaintingCool2:: - .string "Hey, there!\n" - .string "The good-looking POKéMON {STR_VAR_1}$" - -gContestPaintingCool3:: - .string "The marvelous, wonderful, and\n" - .string "very great {STR_VAR_1}$" - -gContestPaintingBeauty1:: - .string "This century's last Venus--\n" - .string "the beautiful {STR_VAR_1}$" - -gContestPaintingBeauty2:: - .string "{STR_VAR_1}'s dazzling,\n" - .string "glittering smile$" - -gContestPaintingBeauty3:: - .string "POKéMON CENTER's super idol--\n" - .string "the incomparable {STR_VAR_1}$" - -gContestPaintingCute1:: - .string "The lovely and sweet {STR_VAR_1}$" - -gContestPaintingCute2:: - .string "The pretty {STR_VAR_1}'s\n" - .string "winning portrait$" - -gContestPaintingCute3:: - .string "Give us a wink!\n" - .string "The cutie POKéMON {STR_VAR_1}$" - -gContestPaintingSmart1:: - .string "The smartness maestro--\n" - .string "the wise POKéMON {STR_VAR_1}$" - -gContestPaintingSmart2:: - .string "{STR_VAR_1}--the one chosen\n" - .string "above all POKéMON$" - -gContestPaintingSmart3:: - .string "The excellent {STR_VAR_1}'s\n" - .string "moment of elegance$" - -gContestPaintingTough1:: - .string "The powerfully muscular\n" - .string "speedster {STR_VAR_1}$" - -gContestPaintingTough2:: - .string "The strong, stronger, and\n" - .string "strongest {STR_VAR_1}$" - -gContestPaintingTough3:: - .string "The mighty tough\n" - .string "hyper POKéMON {STR_VAR_1}$" diff --git a/data/text/contest_strings.inc b/data/text/contest_strings.inc deleted file mode 100644 index 4b144a21bc..0000000000 --- a/data/text/contest_strings.inc +++ /dev/null @@ -1,314 +0,0 @@ -gText_AppealNumWhichMoveWillBePlayed:: - .string "Appeal no. {STR_VAR_1}!\n" - .string "Which move will be played?$" - -gText_AppealNumButItCantParticipate:: - .string "Appeal no. {STR_VAR_1}!\n" - .string "But it can't participate!$" - -gText_MonAppealedWithMove:: - .string "{STR_VAR_1} appealed with\n" - .string "{STR_VAR_2}!$" - -gText_MonWasWatchingOthers:: - .string "{STR_VAR_1} was watching\n" - .string "the others.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_AllOutOfAppealTime:: - .string "We're all out of\n" - .string "Appeal Time!{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -@ Appeal result texts - -gText_BecameMoreConsciousOfOtherMons:: - .string "It became more conscious\n" - .string "of the other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonCantMakeAnAppealAfterThis:: - .string "{STR_VAR_1} can't make an\n" - .string "appeal after this.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_SettledDownJustLittleBit:: - .string "It settled down just a\n" - .string "little bit.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_BecameObliviousToOtherMons:: - .string "It became oblivious to\n" - .string "the other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_BecameLessAwareOfOtherMons:: - .string "It became less aware of\n" - .string "the other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_StoppedCaringAboutOtherMons:: - .string "It stopped caring about\n" - .string "other POKéMON much.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_TriedToStartleOtherMons:: - .string "It tried to startle the\n" - .string "other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_TriedToDazzleOthers:: - .string "It tried to dazzle the\n" - .string "others.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_JudgeLookedAwayFromMon:: - .string "The JUDGE looked away\n" - .string "from {STR_VAR_1}.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_TriedToUnnerveNextMon:: - .string "It tried to unnerve the\n" - .string "next POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonBecameNervous:: - .string "{STR_VAR_1} became\n" - .string "nervous.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_AppealTriedToUnnerveWaitingMons:: - .string "The appeal tried to\n" - .string "unnerve waiting POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_TauntedMonsDoingWell:: - .string "It taunted POKéMON\n" - .string "doing well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonRegainedItsForm:: - .string "{STR_VAR_1} regained its\n" - .string "form.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_TriedToJamMonDoingWell:: - .string "It tried to jam POKéMON\n" - .string "doing well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_StandoutMonHustledEvenMore:: - .string "The standout {STR_VAR_1}\n" - .string "hustled even more.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_LargelyUnnoticedMonWorkedHard:: - .string "The largely unnoticed\n" - .string "{STR_VAR_1} worked hard.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_WorkedAsMuchAsMonBefore:: - .string "It worked as much as\n" - .string "POKéMON before it.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealDidNotGoWell:: - .string "{STR_VAR_1}'s appeal did\n" - .string "not go well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_WorkedAsMuchAsPrecedingMon:: - .string "It worked as much as the\n" - .string "preceding POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealDidNotGoWell2:: - .string "{STR_VAR_1}'s appeal did\n" - .string "not go well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealDidNotGoWell3:: - .string "{STR_VAR_1}'s appeal did\n" - .string "not go well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWentSlightlyWell:: - .string "{STR_VAR_1}'s appeal\n" - .string "went slightly well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWentPrettyWell:: - .string "{STR_VAR_1}'s appeal\n" - .string "went pretty well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWentExcellently:: - .string "{STR_VAR_1}'s appeal\n" - .string "went excellently.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWasDud:: - .string "{STR_VAR_1}'s appeal was\n" - .string "a dud.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealDidNotWorkVeryWell:: - .string "{STR_VAR_1}'s appeal did\n" - .string "not work very well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWentSlightlyWell2:: - .string "{STR_VAR_1}'s appeal\n" - .string "went slightly well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWentPrettyWell2:: - .string "{STR_VAR_1}'s appeal\n" - .string "went pretty well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWentVeryWell:: - .string "{STR_VAR_1}'s appeal\n" - .string "went very well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsAppealWentExcellently2:: - .string "{STR_VAR_1}'s appeal\n" - .string "went excellently.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_SameTypeAsOneBeforeGood:: - .string "It's the same type as the\n" - .string "POKéMON before--good!{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_NotSameTypeAsOneBeforeGood:: - .string "It's not the same type as\n" - .string "the one before--good!{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_StoodOutMuchMoreThanMonBefore:: - .string "It stood out much more\n" - .string "than the POKéMON before.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_DidntDoAsWellAsMonBefore:: - .string "It didn't do as well as the\n" - .string "POKéMON before.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsConditionRoseAboveUsual:: - .string "{STR_VAR_1}'s condition\n" - .string "rose above usual.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MonsHotStatusMadeGreatAppeal:: - .string "{STR_VAR_1}'s hot status\n" - .string "made it a great appeal!{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MovedUpInLineForNextAppeal:: - .string "It moved up in line for\n" - .string "the next appeal.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_MovedBackInLineForNextAppeal:: - .string "It moved back in line once\n" - .string "for the next appeal.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_ScrambledUpOrderForNextTurn:: - .string "It scrambled up the\n" - .string "order for the next turn.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" - -gText_JudgeLookedAtMonExpectantly:: - .string "The JUDGE looked at\n" - .string "{STR_VAR_1} expectantly.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_AppealComboWentOverWell:: - .string "The appeal combo went\n" - .string "over well.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_AppealComboWentOverVeryWell:: - .string "The appeal combo went\n" - .string "over very well.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_AppealComboWentOverExcellently:: - .string "The appeal combo went\n" - .string "over excellently.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonManagedToAvertGaze:: - .string "{STR_VAR_1} managed to\n" - .string "avert its gaze.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonManagedToAvoidSeeingIt:: - .string "{STR_VAR_1} managed to\n" - .string "avoid seeing it.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonIsntFazedByThatSortOfThing:: - .string "{STR_VAR_1} isn't fazed\n" - .string "by that sort of thing.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonBecameALittleDistracted:: - .string "{STR_VAR_1} became a\n" - .string "little distracted.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_TriedToStartleOtherPokemon:: - .string "It tried to startle the\n" - .string "other POKéMON.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonLookedDownOutOfDistraction:: - .string "{STR_VAR_1} looked down\n" - .string "out of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonTurnedBackOutOfDistraction:: - .string "{STR_VAR_1} turned back\n" - .string "out of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonCouldntHelpUtteringCry:: - .string "{STR_VAR_1} couldn't help\n" - .string "uttering a cry.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonCouldntHelpLeapingUp:: - .string "{STR_VAR_1} couldn't help\n" - .string "leaping up.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonTrippedOutOfDistraction:: - .string "{STR_VAR_1} tripped over\n" - .string "out of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonWasTooNervousToMove:: - .string "{STR_VAR_1} was too\n" - .string "nervous to move.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_ButItMessedUp2:: - .string "But it messed up.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_ButItFailedToMakeTargetNervous:: - .string "But it failed to make\n" - .string "the target nervous.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_ButItFailedToMakeAnyoneNervous:: - .string "But it failed to make\n" - .string "anyone nervous.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_ButItWasIgnored:: - .string "But it was ignored…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_CouldntImproveItsCondition:: - .string "But it couldn't improve\n" - .string "its condition…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_BadConditionResultedInWeakAppeal:: - .string "Its bad condition\n" - .string "resulted in a weak appeal.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonWasUnaffected:: - .string "{STR_VAR_1} was\n" - .string "unaffected.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_RepeatedAppeal:: - .string "{STR_VAR_1} disappointed\n" - .string "by repeating an appeal.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonsXWentOverGreat:: - .string "{STR_VAR_1}'s {STR_VAR_3}\n" - .string "went over great.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonsXDidntGoOverWell:: - .string "{STR_VAR_1}'s {STR_VAR_3}\n" - .string "didn't go over well here…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonsXGotTheCrowdGoing:: - .string "{STR_VAR_1}'s {STR_VAR_3}\n" - .string "got the crowd going.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonCantAppealNextTurn:: - .string "{STR_VAR_1} can't appeal\n" - .string "next turn…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_AttractedCrowdsAttention:: - .string "It attracted the crowd's\n" - .string "attention.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_CrowdContinuesToWatchMon:: - .string "The crowd continues to\n" - .string "watch {STR_VAR_3}.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_MonsMoveIsIgnored:: - .string "{STR_VAR_1}'s\n" - .string "{STR_VAR_2} is ignored.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" - -gText_Contest_Shyness:: - .string "shyness$" - -gText_Contest_Anxiety:: - .string "anxiety$" - -gText_Contest_Laziness:: - .string "laziness$" - -gText_Contest_Hesitancy:: - .string "hesitancy$" - -gText_Contest_Fear:: - .string "fear$" diff --git a/data/text/move_relearner.inc b/data/text/move_relearner.inc new file mode 100644 index 0000000000..b9400fd62b --- /dev/null +++ b/data/text/move_relearner.inc @@ -0,0 +1,55 @@ +MoveRelearner_Text_WouldLearnNewMoves: + .string "Hi, I'm the Move Relearner.\n" + .string "Would you like to learn new moves?$" + +MoveRelearner_Text_LevelUpMoves: + .string "Level Up Moves$" + +MoveRelearner_Text_EggMoves: + .string "Egg Moves$" + +MoveRelearner_Text_TMMoves: + .string "TM Moves$" + +MoveRelearner_Text_TutormoveMoves: + .string "Tutor Moves$" + +MoveRelearner_Text_SeeYa: + .string "See ya!$" + +MoveRelearner_Text_AnythingElse: + .string "Is there anything else I may do for you?$" + +MoveRelearner_Text_ChoosePkmn: + .string "Please choose your Pokémon.$" + +MoveRelearner_Text_HaveNoPkmn: + .string "You have no Pokémon.$" + +MoveRelearner_Text_CantTeachMoveToEgg: + .string "Sorry…\n" + .string "But an Egg can't learn moves.$" + +MoveRelearner_Text_CantTeachMoveToPkmn: + .string "Sorry…\p" + .string "It doesn't appear as if I have any move\n" + .string "I can teach that Pokémon.$" + +MoveRelearner_Text_LevelUpMoveLWR:: + .string "level up move$" + +MoveRelearner_Text_EggMoveLWR:: + .string "egg move$" + +MoveRelearner_Text_TMMoveLWR:: + .string "TM move$" + +MoveRelearner_Text_TutorMoveLWR:: + .string "tutor move$" + +MoveRelearner_Text_WhichXmoveShouldTeach: + .string "Which {STR_VAR_3} should I teach?$" + +MoveRelearner_Text_ThankYouComeAgain: + .string "Thank you for using our services.\n" + .string "Please come again!$" diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index a38a539bef..08e6cd4fd0 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -39,7 +39,10 @@ - [How to use Trainer Party Pools](tutorials/how_to_trainer_party_pool.md) - [Vs. Seeker](tutorials/vs_seeker.md) - [Changelog](./CHANGELOG.md) + - [1.14.x]() + - [Version 1.14.0](changelogs/1.14.x/1.14.0.md) - [1.13.x]() + - [Version 1.13.4](changelogs/1.13.x/1.13.4.md) - [Version 1.13.3](changelogs/1.13.x/1.13.3.md) - [Version 1.13.2](changelogs/1.13.x/1.13.2.md) - [Version 1.13.1](changelogs/1.13.x/1.13.1.md) diff --git a/docs/changelogs/1.13.x/1.13.4.md b/docs/changelogs/1.13.x/1.13.4.md new file mode 100644 index 0000000000..6884bbd95c --- /dev/null +++ b/docs/changelogs/1.13.x/1.13.4.md @@ -0,0 +1,213 @@ +```md +## How to update +- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`. +- Once you have your remote set up, run the command `git pull RHH expansion/1.13.4 +`. +``` + + +## 🧬 General 🧬 +### Changed +* 1.13.3 release by @hedara90 in [#8109](https://github.com/rh-hideout/pokeemerald-expansion/pull/8109) +* Adds an auto-generated include file of script commands by @FosterProgramming in [#8156](https://github.com/rh-hideout/pokeemerald-expansion/pull/8156) +* Adjust label workflow to only run if PR is approved by @hedara90 in [#8183](https://github.com/rh-hideout/pokeemerald-expansion/pull/8183) +* Add include/constants/script_commands.h to gitignore by @AlexOn1ine in [#8169](https://github.com/rh-hideout/pokeemerald-expansion/pull/8169) +* add fdeblasio as a contributor for code by @allcontributors[bot] in [#8200](https://github.com/rh-hideout/pokeemerald-expansion/pull/8200) +* Adjust Canceler naming to contain only one l by @AlexOn1ine in [#8258](https://github.com/rh-hideout/pokeemerald-expansion/pull/8258) +* Pret merge (16th of November, 2025) by @AlexOn1ine in [#8262](https://github.com/rh-hideout/pokeemerald-expansion/pull/8262) +* *.party: text with lfs by @mrgriffin in [#8320](https://github.com/rh-hideout/pokeemerald-expansion/pull/8320) +* Fedora install instructions by @estellarc in [#8355](https://github.com/rh-hideout/pokeemerald-expansion/pull/8355) +* Indent unintented if statement by @hedara90 in [#8367](https://github.com/rh-hideout/pokeemerald-expansion/pull/8367) + +### Fixed +* Update mdbook to v0.5.0-beta.1 by @rayrobdod in [#8133](https://github.com/rh-hideout/pokeemerald-expansion/pull/8133) +* Fix wild_encounters script not closing arrays properly by @FosterProgramming in [#8123](https://github.com/rh-hideout/pokeemerald-expansion/pull/8123) +* Fix missing FREE_MATCH_CALL by @FosterProgramming in [#8171](https://github.com/rh-hideout/pokeemerald-expansion/pull/8171) +* Fix scroll prompt sometimes being off-screen with automatic line breaks by @hedara90 in [#8182](https://github.com/rh-hideout/pokeemerald-expansion/pull/8182) +* Fix gcc11 again by @AsparagusEduardo in [#8188](https://github.com/rh-hideout/pokeemerald-expansion/pull/8188) +* Fixed decompression error reporter OOB window creation by @hedara90 in [#8199](https://github.com/rh-hideout/pokeemerald-expansion/pull/8199) +* Fix error when compiling with P_FUSION_FORMS disabled by @cawtds in [#8298](https://github.com/rh-hideout/pokeemerald-expansion/pull/8298) +* Fix compile on gcc11 by @AlexOn1ine in [#8300](https://github.com/rh-hideout/pokeemerald-expansion/pull/8300) +* Fix debug battle flag never being cleared by @FosterProgramming in [#8357](https://github.com/rh-hideout/pokeemerald-expansion/pull/8357) + +## 🗺️ Overworld 🗺️ +### Changed +* Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in [#8117](https://github.com/rh-hideout/pokeemerald-expansion/pull/8117) + +### Fixed +* Fix berry blender not computing flavor correctly by @FosterProgramming in [#8113](https://github.com/rh-hideout/pokeemerald-expansion/pull/8113) +* Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in [#8062](https://github.com/rh-hideout/pokeemerald-expansion/pull/8062) + - VS seeker now work with trainers who don't start with trainer_battle. You can use `vsseeker_rematchid TRAINER_ID` to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. ` vsseeker_rematchid` work like a `cant_see_if_trainerflag_set` with additional functionality to handle vs seeker. + All NPCs who don't start with either `vsseeker_rematchid` or `trainerbattle` will show as "X"/unmatchable by the vs seeker, so non-rematchable trainer who do not start with `trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a `vsseeker_rematchid` for them too. +* Fix grade in summary screen not accounting for 26 IV by @FosterProgramming in [#8157](https://github.com/rh-hideout/pokeemerald-expansion/pull/8157) +* Fix match call regression by @FosterProgramming in [#8227](https://github.com/rh-hideout/pokeemerald-expansion/pull/8227) +* Fix mew sprite not appearing correctly by @FosterProgramming in [#8235](https://github.com/rh-hideout/pokeemerald-expansion/pull/8235) +* Fix wrong palette for types sprites in hgss dex after catching mon by @FosterProgramming in [#8153](https://github.com/rh-hideout/pokeemerald-expansion/pull/8153) +* Fix mirage tower ceiling crumble color by @FosterProgramming in [#8081](https://github.com/rh-hideout/pokeemerald-expansion/pull/8081) +* Fix light flickering when different types of light sprite are present by @FosterProgramming in [#8043](https://github.com/rh-hideout/pokeemerald-expansion/pull/8043) + - Light intensity of neon signs was reduced to avoid conflicts with other light sources + - Fix flickering when both neon signs and light ball are present on screen +* Bug Fix: NPC Followers not working on slow sideways stairs by @Bivurnum in [#8257](https://github.com/rh-hideout/pokeemerald-expansion/pull/8257) +* Fix not enough memory being allocated when moves load background in contests by @FosterProgramming in [#8284](https://github.com/rh-hideout/pokeemerald-expansion/pull/8284) +* Make MON_DATA_NICKNAME10 return a 10 character string by @FosterProgramming in [#8291](https://github.com/rh-hideout/pokeemerald-expansion/pull/8291) + - Fix bug where interviews would print bad data in their string +* Fix game freeze when trainers try to walk on sideway stairs by @FosterProgramming in [#8316](https://github.com/rh-hideout/pokeemerald-expansion/pull/8316) +* Fix tossing items applying to the wrong stack by @FosterProgramming in [#8282](https://github.com/rh-hideout/pokeemerald-expansion/pull/8282) +* Prevent moves to be changed when choosing half party by @FosterProgramming in [#8336](https://github.com/rh-hideout/pokeemerald-expansion/pull/8336) + +## 🐉 Pokémon 🐉 +### Changed +* Fix Kyurem typo in swap move tables by @Bassoonian in [#8139](https://github.com/rh-hideout/pokeemerald-expansion/pull/8139) +* Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in [#8143](https://github.com/rh-hideout/pokeemerald-expansion/pull/8143) +* Fix some followers sprites by @estellarc in [#8208](https://github.com/rh-hideout/pokeemerald-expansion/pull/8208) + +## ⚔️ Battle General ⚔️ +### Changed +* Clean up redundant todo by @AlexOn1ine in [#8094](https://github.com/rh-hideout/pokeemerald-expansion/pull/8094) +* Powder Move blocking cleanup by @PhallenTree in [#8194](https://github.com/rh-hideout/pokeemerald-expansion/pull/8194) +* Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in [#8387](https://github.com/rh-hideout/pokeemerald-expansion/pull/8387) + +### Fixed +* Allow to send active mon to PC when capturing a Pokemon by @FosterProgramming in [#8111](https://github.com/rh-hideout/pokeemerald-expansion/pull/8111) +* Fix transform not loading the correct sprites when facing shiny or unown by @FosterProgramming in [#8146](https://github.com/rh-hideout/pokeemerald-expansion/pull/8146) +* Fixes Receiver not immediately activating copied abilities by @PhallenTree in [#8162](https://github.com/rh-hideout/pokeemerald-expansion/pull/8162) +* Fix destiny knot behavior and add tests by @FosterProgramming in [#8174](https://github.com/rh-hideout/pokeemerald-expansion/pull/8174) +* Fix recharge moves + add recharge move tests by @FosterProgramming in [#8181](https://github.com/rh-hideout/pokeemerald-expansion/pull/8181) +* Fixes Magician for spread moves by @AlexOn1ine in [#8170](https://github.com/rh-hideout/pokeemerald-expansion/pull/8170) +* Fix tera tint not applying on activation by @FosterProgramming in [#8135](https://github.com/rh-hideout/pokeemerald-expansion/pull/8135) +* Fixes wrongly assigned count for Semi Invulnerable state by @AlexOn1ine in [#8175](https://github.com/rh-hideout/pokeemerald-expansion/pull/8175) +* Fixes Drain Punch / Parental Bond / Scale Shot interaction by @AlexOn1ine in [#8198](https://github.com/rh-hideout/pokeemerald-expansion/pull/8198) +* Fix wrong ditto sprite on capture by @FosterProgramming in [#8226](https://github.com/rh-hideout/pokeemerald-expansion/pull/8226) +* Fixed an issue related to same turn Encore targeting by @LinathanZel in [#8230](https://github.com/rh-hideout/pokeemerald-expansion/pull/8230) +* Fixes Shell Trap not activating on contact but no damage by @AlexOn1ine in [#8243](https://github.com/rh-hideout/pokeemerald-expansion/pull/8243) +* Fix Magic Coat reflecting hazard moves incorrectly when used by a partner by @moostoet in [#8272](https://github.com/rh-hideout/pokeemerald-expansion/pull/8272) + - Magic Coat now properly reflects hazard moves from either slot in double battles. +* Shell Trap tests and Fix for Encore interaction by @AlexOn1ine in [#8268](https://github.com/rh-hideout/pokeemerald-expansion/pull/8268) +* Fix max mushroom unable to be selected when one stat is maxed by @FosterProgramming in [#8287](https://github.com/rh-hideout/pokeemerald-expansion/pull/8287) +* Block selecting x items when contrary pokemon are at minimum stages by @FosterProgramming in [#8288](https://github.com/rh-hideout/pokeemerald-expansion/pull/8288) +* Fix Fur Coat affecting confusion self-damage by @moostoet in [#8267](https://github.com/rh-hideout/pokeemerald-expansion/pull/8267) + - Fix confusion self-damage ignoring defense/attack abilities such as Fur Coat. +* Fixes End Turn Speed Order by @AlexOn1ine in [#8289](https://github.com/rh-hideout/pokeemerald-expansion/pull/8289) +* Make switchout abilities trigger after a pokemon has returned to its ball by @FosterProgramming in [#8304](https://github.com/rh-hideout/pokeemerald-expansion/pull/8304) +* Fix Shed Shell allowing fleeing/teleporting and Smoke Ball failing to guarantee escape by @moostoet in [#8286](https://github.com/rh-hideout/pokeemerald-expansion/pull/8286) +* Fix bug where defiant/competitive would pass their stat change to the next target by @FosterProgramming in [#8312](https://github.com/rh-hideout/pokeemerald-expansion/pull/8312) +* Fix max move message against semi invulnerable target by @FosterProgramming in [#8313](https://github.com/rh-hideout/pokeemerald-expansion/pull/8313) +* Fixes Neutralizing Gas displaying message when exiting with multiple users by @PhallenTree in [#8318](https://github.com/rh-hideout/pokeemerald-expansion/pull/8318) +* Fix Kings Rock not being ignored by flinch moves by @AlexOn1ine in [#8327](https://github.com/rh-hideout/pokeemerald-expansion/pull/8327) +* Fix Protosynthesis stat boosts ignoring speed drops by @moostoet in [#8277](https://github.com/rh-hideout/pokeemerald-expansion/pull/8277) + - Protosynthesis and Quark Drive now recalculate their boosted stat when Speed is lowered or Neutralizing Gas temporarily disables the ability. +* Fix switch-in abilities not triggering on revive by @FosterProgramming in [#8293](https://github.com/rh-hideout/pokeemerald-expansion/pull/8293) +* More Neutralizing Gas cleanup by @PhallenTree in [#8335](https://github.com/rh-hideout/pokeemerald-expansion/pull/8335) +* Fix cure status item effect not working properly in doubles by @FosterProgramming in [#8339](https://github.com/rh-hideout/pokeemerald-expansion/pull/8339) +* Fix infinite confusion (berserk gene) not being cured by cure_status bag items by @FosterProgramming in [#8343](https://github.com/rh-hideout/pokeemerald-expansion/pull/8343) +* Fix `B_PHYSICAL_SPECIAL_SPLIT` when set to Gen 4 by @AsparagusEduardo in [#8348](https://github.com/rh-hideout/pokeemerald-expansion/pull/8348) +* Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in [#8307](https://github.com/rh-hideout/pokeemerald-expansion/pull/8307) + - BUGFIX: Beat Up (`GEN =< 5`) now no longer doubles its damage on every non-critical hit + - Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules +* Fix substitute graphic not disappearing after using a pivor move by @FosterProgramming in [#8340](https://github.com/rh-hideout/pokeemerald-expansion/pull/8340) +* Fixes Beak Blast burning after Beak Blast was already used by @PhallenTree in [#8361](https://github.com/rh-hideout/pokeemerald-expansion/pull/8361) +* Fix Roar not being recorded for LastUsedMove by @AlexOn1ine in [#8362](https://github.com/rh-hideout/pokeemerald-expansion/pull/8362) +* Fixes Neutralizing Gas / Mold Breaker / Dragon Darts interaction by @AlexOn1ine in [#8389](https://github.com/rh-hideout/pokeemerald-expansion/pull/8389) +* Fixes battle tv overwriting damage values by @AlexOn1ine in [#8378](https://github.com/rh-hideout/pokeemerald-expansion/pull/8378) +* Fix ball cycling not working properly when the same ball take multiple bag slots by @FosterProgramming in [#8163](https://github.com/rh-hideout/pokeemerald-expansion/pull/8163) + - Two new defines added to items.h `FIRST_BALL_INDEX` and `LAST_BALL_INDEX` + - We now assume the indexes of all regular ball usable in wild battle have consecutive indexes and some features (throw ball shortcut in battle) might break if not true + +## 🤹 Moves 🤹 +### Changed +* Fixed Uproar's description and spacing by @fdeblasio in [#8187](https://github.com/rh-hideout/pokeemerald-expansion/pull/8187) +* Clean usage of gMovesInfo by @AsparagusEduardo in [#8234](https://github.com/rh-hideout/pokeemerald-expansion/pull/8234) + - Also, fixed an OOB in `HasMoveThatChangesKOThreshold` +* Make tailwind anim mirror based on side by @FosterProgramming in [#8249](https://github.com/rh-hideout/pokeemerald-expansion/pull/8249) +* Make rainbow effect anim change based on side by @FosterProgramming in [#8269](https://github.com/rh-hideout/pokeemerald-expansion/pull/8269) + - Art assets by [SonikkuA-DatH](https://github.com/SonikkuA-DatH) +* Update Lash Out description to clarify its effect by @PhallenTree in [#8372](https://github.com/rh-hideout/pokeemerald-expansion/pull/8372) + +### Fixed +* Fix some move animations leaking VRAM and freeing already freed tags by @hedara90 in [#7977](https://github.com/rh-hideout/pokeemerald-expansion/pull/7977) + +## 🧶 Items 🧶 +### Fixed +* Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in [#8062](https://github.com/rh-hideout/pokeemerald-expansion/pull/8062) + - VS seeker now work with trainers who don't start with trainer_battle. You can use `vsseeker_rematchid TRAINER_ID` to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. ` vsseeker_rematchid` work like a `cant_see_if_trainerflag_set` with additional functionality to handle vs seeker. + All NPCs who don't start with either `vsseeker_rematchid` or `trainerbattle` will show as "X"/unmatchable by the vs seeker, so non-rematchable trainer who do not start with `trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a `vsseeker_rematchid` for them too. + +## 🤖 Battle AI 🤖 +### Fixed +* fix (AI scoring): shield dust considerations, IsMoveEffectInMinus self effect edge case, hitsToKO zero-case consideration by @ghostyboyy97 in [#8126](https://github.com/rh-hideout/pokeemerald-expansion/pull/8126) + - The AI now sees Shield Dust on the player's Pokemon correctly + - The AI now sees self-targeted positive effect boosts correctly +* fix (contrary): Contrary stat down handling in MoveEffectInPlus by @ghostyboyy97 in [#8165](https://github.com/rh-hideout/pokeemerald-expansion/pull/8165) + - When comparing positive move effects in damaging move comparison, the AI will correctly see moves like Leaf Storm as beneficial if their Pokemon has Contrary. +* Added check for parental bond killing through sturdy by @MaximeGr00 in [#8206](https://github.com/rh-hideout/pokeemerald-expansion/pull/8206) + AI now accounts for Parental Bond when checking if a move can ko the player through sturdy/focus sash. +* Fix AI_FLAG_DOUBLE_ACE_POKEMON sending duplicate Pokémon in doubles by @moostoet in [#8279](https://github.com/rh-hideout/pokeemerald-expansion/pull/8279) + - Fixed AI_FLAG_DOUBLE_ACE_POKEMON trainers resending the same Pokémon after a KO instead of their two Ace Pokémon in double battles. +* Fix switchin KO threshold logic by @Pawkkie in [#8370](https://github.com/rh-hideout/pokeemerald-expansion/pull/8370) + +## 🧹 Other Cleanup 🧹 +* Clean up redundant todo by @AlexOn1ine in [#8094](https://github.com/rh-hideout/pokeemerald-expansion/pull/8094) +* Fix Kyurem typo in swap move tables by @Bassoonian in [#8139](https://github.com/rh-hideout/pokeemerald-expansion/pull/8139) +* Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in [#8143](https://github.com/rh-hideout/pokeemerald-expansion/pull/8143) +* Fixed Uproar's description and spacing by @fdeblasio in [#8187](https://github.com/rh-hideout/pokeemerald-expansion/pull/8187) +* Add include/constants/script_commands.h to gitignore by @AlexOn1ine in [#8169](https://github.com/rh-hideout/pokeemerald-expansion/pull/8169) +* Powder Move blocking cleanup by @PhallenTree in [#8194](https://github.com/rh-hideout/pokeemerald-expansion/pull/8194) +* Clean usage of gMovesInfo by @AsparagusEduardo in [#8234](https://github.com/rh-hideout/pokeemerald-expansion/pull/8234) + - Also, fixed an OOB in `HasMoveThatChangesKOThreshold` +* Adjust Canceler naming to contain only one l by @AlexOn1ine in [#8258](https://github.com/rh-hideout/pokeemerald-expansion/pull/8258) +* Fix wrongly renamed logs by @AlexOn1ine in [#8264](https://github.com/rh-hideout/pokeemerald-expansion/pull/8264) +* Tests for Max Moves already exist by @AlexOn1ine in [#8314](https://github.com/rh-hideout/pokeemerald-expansion/pull/8314) +* Use MAP_OFFSET by @estellarc in [#8328](https://github.com/rh-hideout/pokeemerald-expansion/pull/8328) +* Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in [#7872](https://github.com/rh-hideout/pokeemerald-expansion/pull/7872) +* Indent unintented if statement by @hedara90 in [#8367](https://github.com/rh-hideout/pokeemerald-expansion/pull/8367) +* Update Lash Out description to clarify its effect by @PhallenTree in [#8372](https://github.com/rh-hideout/pokeemerald-expansion/pull/8372) +* Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in [#8387](https://github.com/rh-hideout/pokeemerald-expansion/pull/8387) + +## 🧪 Test Runner 🧪 +### Added +* Prevent EXPECT functions from casting negative numbers into unsigned by @FosterProgramming in [#7866](https://github.com/rh-hideout/pokeemerald-expansion/pull/7866) + +### Changed +* Added Soundproof and Bulletproof tests by @AsparagusEduardo in [#8189](https://github.com/rh-hideout/pokeemerald-expansion/pull/8189) +* Wrote some missing tests by @AsparagusEduardo in [#8203](https://github.com/rh-hideout/pokeemerald-expansion/pull/8203) +* A couple more tests by @AsparagusEduardo in [#8209](https://github.com/rh-hideout/pokeemerald-expansion/pull/8209) +* Fixed some failing tests with GEN_LATEST = GEN_5 by @AsparagusEduardo in [#8241](https://github.com/rh-hideout/pokeemerald-expansion/pull/8241) +* Add test for mold breaker/ice scales interaction by @FosterProgramming in [#8240](https://github.com/rh-hideout/pokeemerald-expansion/pull/8240) +* Yet more tests by @AsparagusEduardo in [#8228](https://github.com/rh-hideout/pokeemerald-expansion/pull/8228) + - Added tests for: + - Dark Aura + - Fairy Aura + - Flare Boost + - Toxic Boost + - Added test names for Flying Press. +* Slightly increase headless test speed by modifying animations by @AsparagusEduardo in [#8299](https://github.com/rh-hideout/pokeemerald-expansion/pull/8299) +* Make `gTestRunnerHeadless` into a constant outside of tests by @hedara90 in [#8306](https://github.com/rh-hideout/pokeemerald-expansion/pull/8306) +* Tests for Max Moves already exist by @AlexOn1ine in [#8314](https://github.com/rh-hideout/pokeemerald-expansion/pull/8314) +* Finished fixing tests when setting `GEN_LATEST` to `GEN_5` by @AsparagusEduardo in [#8263](https://github.com/rh-hideout/pokeemerald-expansion/pull/8263) +* Wrote missing Fling tests by @AsparagusEduardo in [#8383](https://github.com/rh-hideout/pokeemerald-expansion/pull/8383) + +### Fixed +* Fixes difficulty not being restored after tests by @grintoul1 in [#8129](https://github.com/rh-hideout/pokeemerald-expansion/pull/8129) +* Reset saveblock data between test runs by @hedara90 in [#8145](https://github.com/rh-hideout/pokeemerald-expansion/pull/8145) +* Fix ohko moves ai tests by @FosterProgramming in [#8309](https://github.com/rh-hideout/pokeemerald-expansion/pull/8309) +* Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in [#7872](https://github.com/rh-hideout/pokeemerald-expansion/pull/7872) +* Add tests to verify aromatherapy is not affected by heal bell config by @FosterProgramming in [#8344](https://github.com/rh-hideout/pokeemerald-expansion/pull/8344) +* Pre gen 5 encored move now signals the test engine a move is happening by @FosterProgramming in [#8338](https://github.com/rh-hideout/pokeemerald-expansion/pull/8338) +* Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in [#8307](https://github.com/rh-hideout/pokeemerald-expansion/pull/8307) + - BUGFIX: Beat Up (`GEN =< 5`) now no longer doubles its damage on every non-critical hit + - Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules +* Fix known failing AI trace test by @FosterProgramming in [#8337](https://github.com/rh-hideout/pokeemerald-expansion/pull/8337) + +## 📚 Documentation 📚 +* Lock mdbook to v0.4.35 to fix docs not building by @grintoul1 in [#8130](https://github.com/rh-hideout/pokeemerald-expansion/pull/8130) +* Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in [#8117](https://github.com/rh-hideout/pokeemerald-expansion/pull/8117) +* Fix wrongly renamed logs by @AlexOn1ine in [#8264](https://github.com/rh-hideout/pokeemerald-expansion/pull/8264) +* Use MAP_OFFSET by @estellarc in [#8328](https://github.com/rh-hideout/pokeemerald-expansion/pull/8328) +* Fedora install instructions by @estellarc in [#8355](https://github.com/rh-hideout/pokeemerald-expansion/pull/8355) + + +**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.3...expansion/1.13.4 + + + + diff --git a/docs/changelogs/1.14.x/1.14.0.md b/docs/changelogs/1.14.x/1.14.0.md new file mode 100644 index 0000000000..3a75d35e6e --- /dev/null +++ b/docs/changelogs/1.14.x/1.14.0.md @@ -0,0 +1,534 @@ +```md +## How to update +- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`. +- Once you have your remote set up, run the command `git pull RHH expansion/1.14.0 +`. +``` + +## 🌋 *REFACTORS* 🌋 +📜 = Uses a migration script. +* Refactors Attackstring and PP deduction by @AlexOn1ine in [#7402](https://github.com/rh-hideout/pokeemerald-expansion/pull/7402) +* Attackcanceller fixes and improvements by @AlexOn1ine in [#7698](https://github.com/rh-hideout/pokeemerald-expansion/pull/7698) +* Fixes activation order for a couple abilities by @AlexOn1ine in [#7732](https://github.com/rh-hideout/pokeemerald-expansion/pull/7732) +* feat: change defines in `constants/abilities.h` to an enum by @khbsd in [#7006](https://github.com/rh-hideout/pokeemerald-expansion/pull/7006) +* Item battle effect refactor by @AlexOn1ine in [#7857](https://github.com/rh-hideout/pokeemerald-expansion/pull/7857) +* Optimize GetWhichBattlerFasterOrTies by @AlexOn1ine in [#7953](https://github.com/rh-hideout/pokeemerald-expansion/pull/7953) +* Decouple passive hp updates from move damage updates by @AlexOn1ine in [#7942](https://github.com/rh-hideout/pokeemerald-expansion/pull/7942) +* Make movelist calculations happen during compilation instead of runtime by @FosterProgramming in [#7967](https://github.com/rh-hideout/pokeemerald-expansion/pull/7967) + - tmIlliterate flag in speciesInfo changed to teachingType. The options are `DEFAULT_LEARNING`, `TM_ILLITERATE` and `ALL_TEACHABLES`. The first two options match the tmIlliterate = false and tmIlliterate = true while the third one allow a pokemon to learn all teachables similarly to Mew + - Reduce EWRAM usage of HGSS dex + - Fix pokemon.c needing to be recompiled everytime a .inc file was changed + - P_TUTOR_MOVES_ARRAY has been removed (now always true when HGSS dex is enabled) + - Mew move teaching exception and univeral moves are now coded in the JSON file `src/data/pokemon/special_movesets.json` under the name signatureTeachables and universalMoves +* Grudge, Destiny Bond and FaintBattler refactor by @AlexOn1ine in [#8072](https://github.com/rh-hideout/pokeemerald-expansion/pull/8072) +* Increase number of additional move effects by @AlexOn1ine in [#8149](https://github.com/rh-hideout/pokeemerald-expansion/pull/8149) +* 📜 update: time-based encounters system tuneup and @cawtds' header script by @khbsd in [#8158](https://github.com/rh-hideout/pokeemerald-expansion/pull/8158) +* Refactor random functions to be runner specific by @FosterProgramming in [#7816](https://github.com/rh-hideout/pokeemerald-expansion/pull/7816) + +## 🧬 General 🧬 +### Added +* Battle debug menu: highlight chosen action and change separator by @grintoul1 in [#7709](https://github.com/rh-hideout/pokeemerald-expansion/pull/7709) +* Implement `field_name_box` by @mudskipper13 in [#7697](https://github.com/rh-hideout/pokeemerald-expansion/pull/7697) +* Add new actions to Debug Menu by @FosterProgramming in [#7837](https://github.com/rh-hideout/pokeemerald-expansion/pull/7837) + - Adds an action to change a Pokemon ability in the party side of the Debug Menu + - Adds an action to set the friendship of a Pokemon in the party side of the Debug Menu + +* Display TM/HM's move name in the debug menu by @estellarc in [#7994](https://github.com/rh-hideout/pokeemerald-expansion/pull/7994) + +### Changed +* Text rendering optimizations by @mrgriffin in [#7497](https://github.com/rh-hideout/pokeemerald-expansion/pull/7497) +* Battle debug menu now checks correct parties depending on battler party by @grintoul1 in [#7652](https://github.com/rh-hideout/pokeemerald-expansion/pull/7652) +* Add make release target by @jschoeny in [#7296](https://github.com/rh-hideout/pokeemerald-expansion/pull/7296) + - Most of what's above. But most importantly, that normal `make` will have all the debug stuff enabled and so releases should be done with `make release`. +* Add pool rules for Mega Stones and Z-Crystals by @hedara90 in [#7720](https://github.com/rh-hideout/pokeemerald-expansion/pull/7720) +* `field_name_box` smol followup by @mudskipper13 in [#7762](https://github.com/rh-hideout/pokeemerald-expansion/pull/7762) +* Added COMPOUND_STRINGs to region_map_entries.h by @fdeblasio in [#7669](https://github.com/rh-hideout/pokeemerald-expansion/pull/7669) +* Improve ability/heldEffect access for IsBattlerGrounded func by @AlexOn1ine in [#7753](https://github.com/rh-hideout/pokeemerald-expansion/pull/7753) +* Removed `SAVE_TYPE_ERROR_SCREEN` config by @AsparagusEduardo in [#7836](https://github.com/rh-hideout/pokeemerald-expansion/pull/7836) +* Give the Coin Case when coins are maxed by @estellarc in [#7973](https://github.com/rh-hideout/pokeemerald-expansion/pull/7973) +* Revert HGSS dex and movelist changes by @FosterProgramming in [#8016](https://github.com/rh-hideout/pokeemerald-expansion/pull/8016) +* Converts some defines to enums and name unnamed enums by @Bassoonian in [#8019](https://github.com/rh-hideout/pokeemerald-expansion/pull/8019) +* Some more documentation and cleanup by @Bassoonian in [#8020](https://github.com/rh-hideout/pokeemerald-expansion/pull/8020) +* Even more enums and documentation by @Bassoonian in [#8029](https://github.com/rh-hideout/pokeemerald-expansion/pull/8029) +* Add type enum by @Bassoonian in [#8054](https://github.com/rh-hideout/pokeemerald-expansion/pull/8054) +* Minor clean up in menu.c by @estellarc in [#8060](https://github.com/rh-hideout/pokeemerald-expansion/pull/8060) +* Adds an auto-generated include file of script commands by @FosterProgramming in [#8156](https://github.com/rh-hideout/pokeemerald-expansion/pull/8156) +* Master to upcoming merge 20251107 by @grintoul1 in [#8167](https://github.com/rh-hideout/pokeemerald-expansion/pull/8167) +* porymap default settings by @FosterProgramming in [#8038](https://github.com/rh-hideout/pokeemerald-expansion/pull/8038) + - WARNING: A change was made for new projects map files to match poymap output. This change might break people's projects with existing versions of those files. The files affected are ` data/maps/map_groups.json`, `src/data/heal_locations.json`, `src/data/region_map/region_map_sections.json` and `src/data/wild_encounters.json` + If you have an issue with one of those files during the merging process, you should run this command + `git checkout HEAD -- ` + which will reset the file to the version before you initiated the merge +* Adjust label workflow to only run if PR is approved by @hedara90 in [#8183](https://github.com/rh-hideout/pokeemerald-expansion/pull/8183) +* Add include/constants/script_commands.h to gitignore by @AlexOn1ine in [#8169](https://github.com/rh-hideout/pokeemerald-expansion/pull/8169) +* Converted landmarks to COMPOUND_STRINGs by @fdeblasio in [#8205](https://github.com/rh-hideout/pokeemerald-expansion/pull/8205) +* Added contest config and cleaned up contest category variables by @fdeblasio in [#8178](https://github.com/rh-hideout/pokeemerald-expansion/pull/8178) +* Moves name box configs into a new file by @AlexOn1ine in [#8250](https://github.com/rh-hideout/pokeemerald-expansion/pull/8250) +* Converted options text into COMPOUND_STRINGs by @fdeblasio in [#8248](https://github.com/rh-hideout/pokeemerald-expansion/pull/8248) +* Adjust Canceler naming to contain only one l by @AlexOn1ine in [#8258](https://github.com/rh-hideout/pokeemerald-expansion/pull/8258) +* Pret merge (16th of November, 2025) by @AlexOn1ine in [#8262](https://github.com/rh-hideout/pokeemerald-expansion/pull/8262) +* Fixed bKGD for last_used_ball_r_cycle.png by @montmoguri in [#8261](https://github.com/rh-hideout/pokeemerald-expansion/pull/8261) +* Small bg drawing optimization by @estellarc in [#8259](https://github.com/rh-hideout/pokeemerald-expansion/pull/8259) +* Added missing 'coolness' string by @fdeblasio in [#8274](https://github.com/rh-hideout/pokeemerald-expansion/pull/8274) +* *.party: text with lfs by @mrgriffin in [#8320](https://github.com/rh-hideout/pokeemerald-expansion/pull/8320) +* Fedora install instructions by @estellarc in [#8355](https://github.com/rh-hideout/pokeemerald-expansion/pull/8355) +* Indent unintented if statement by @hedara90 in [#8367](https://github.com/rh-hideout/pokeemerald-expansion/pull/8367) + +### Fixed +* Added brackets where needed by @hedara90 in [#7781](https://github.com/rh-hideout/pokeemerald-expansion/pull/7781) +* Fix shiny stars being freed before shiny animation was played by @FosterProgramming in [#7917](https://github.com/rh-hideout/pokeemerald-expansion/pull/7917) + - Fixes shiny sparks in battle not appearing properly in rare circumstances (more common with various speedup options) +* Make movelist calculations happen during compilation instead of runtime by @FosterProgramming in [#7967](https://github.com/rh-hideout/pokeemerald-expansion/pull/7967) + - tmIlliterate flag in speciesInfo changed to teachingType. The options are `DEFAULT_LEARNING`, `TM_ILLITERATE` and `ALL_TEACHABLES`. The first two options match the tmIlliterate = false and tmIlliterate = true while the third one allow a pokemon to learn all teachables similarly to Mew + - Reduce EWRAM usage of HGSS dex + - Fix pokemon.c needing to be recompiled everytime a .inc file was changed + - P_TUTOR_MOVES_ARRAY has been removed (now always true when HGSS dex is enabled) + - Mew move teaching exception and univeral moves are now coded in the JSON file `src/data/pokemon/special_movesets.json` under the name signatureTeachables and universalMoves +* Fix unhandled config in hgss dex by @FosterProgramming in [#7999](https://github.com/rh-hideout/pokeemerald-expansion/pull/7999) +* Fixes compilation error due to #8002 by @AlexOn1ine in [#8050](https://github.com/rh-hideout/pokeemerald-expansion/pull/8050) +* Fix compile issue in gcc 11 by @AsparagusEduardo in [#8095](https://github.com/rh-hideout/pokeemerald-expansion/pull/8095) +* Update mdbook to v0.5.0-beta.1 by @rayrobdod in [#8133](https://github.com/rh-hideout/pokeemerald-expansion/pull/8133) +* Fix build failing with NOOPT=1 due to discarding static data. by @Ultimate-Bob in [#8053](https://github.com/rh-hideout/pokeemerald-expansion/pull/8053) +* Fix wild_encounters script not closing arrays properly by @FosterProgramming in [#8123](https://github.com/rh-hideout/pokeemerald-expansion/pull/8123) +* Fix missing FREE_MATCH_CALL by @FosterProgramming in [#8171](https://github.com/rh-hideout/pokeemerald-expansion/pull/8171) +* Again fixed compiling in GCC11 by @AsparagusEduardo in [#8184](https://github.com/rh-hideout/pokeemerald-expansion/pull/8184) +* Fix scroll prompt sometimes being off-screen with automatic line breaks by @hedara90 in [#8182](https://github.com/rh-hideout/pokeemerald-expansion/pull/8182) +* Fix gcc11 again by @AsparagusEduardo in [#8188](https://github.com/rh-hideout/pokeemerald-expansion/pull/8188) +* Fixed decompression error reporter OOB window creation by @hedara90 in [#8199](https://github.com/rh-hideout/pokeemerald-expansion/pull/8199) +* Fix error when compiling with P_FUSION_FORMS disabled by @cawtds in [#8298](https://github.com/rh-hideout/pokeemerald-expansion/pull/8298) +* Fix compile on gcc11 by @AlexOn1ine in [#8300](https://github.com/rh-hideout/pokeemerald-expansion/pull/8300) +* Fix debug battle flag never being cleared by @FosterProgramming in [#8357](https://github.com/rh-hideout/pokeemerald-expansion/pull/8357) + +## 🗺️ Overworld 🗺️ +### Added +* New Feature: ORAS Dowsing by @Bivurnum in [#7211](https://github.com/rh-hideout/pokeemerald-expansion/pull/7211) + - Added ORAS Dowsing Machine mechanics. +* feat: adds stevebeller's instant text and MandL27's faster text printing by @khbsd in [#8063](https://github.com/rh-hideout/pokeemerald-expansion/pull/8063) +* Implement GSC berry/apricorn tree functionality. by @GraionDilach in [#7777](https://github.com/rh-hideout/pokeemerald-expansion/pull/7777) + - Implement GSC berry/apricorn tree functionality. + +### Changed +* Trainers trigger in local id order by @grintoul1 in [#7424](https://github.com/rh-hideout/pokeemerald-expansion/pull/7424) +* Added regional form evolution condition by @AsparagusEduardo in [#6990](https://github.com/rh-hideout/pokeemerald-expansion/pull/6990) +* Update fishing odds to match official games by @FosterProgramming in [#7574](https://github.com/rh-hideout/pokeemerald-expansion/pull/7574) + - (BREAKING!) Fishing config has been moved to a new file. If you did not use default config fishing, make sure to reapply your config settings in the new file. + - (WARNING!) If you wrote custom code that calls one the following function, you may need to include `fishing.h` to get access to them(their functionaly was not affected): + - `StartFishing`previously defined in `field_player_avatar.h` + - `CalculateChainFishingShinyRolls` previously_defined in `wild_encounter.h` + - Adds a new config option to increase fish bite chance in morning and evening to match XY + - Modifies the way fishing "proximity boost" is calculated to match XY + - Fix Sticky Hold / Suction Cups bug which were increasing odds the wrong way +* Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in [#8117](https://github.com/rh-hideout/pokeemerald-expansion/pull/8117) +* update: time-based encounters system tuneup and @cawtds' header script by @khbsd in [#8158](https://github.com/rh-hideout/pokeemerald-expansion/pull/8158) +* Sets instant text speed flag to false by default by @khbsd in [#8179](https://github.com/rh-hideout/pokeemerald-expansion/pull/8179) +* Follower NPCs no longer move if the player would be forced back onto the same tile. by @Bivurnum in [#8260](https://github.com/rh-hideout/pokeemerald-expansion/pull/8260) + - Follower NPCs no longer move if the player would be forced back onto the same tile + +### Fixed +* CheckForTrainersWantingBattle trainerObjects array now initialized to zero and loop now starts at zero by @grintoul1 in [#7765](https://github.com/rh-hideout/pokeemerald-expansion/pull/7765) +* Bugfix `setspeaker` Namebox not beign drawn correctly by @estellarc in [#7771](https://github.com/rh-hideout/pokeemerald-expansion/pull/7771) +* Banned species list by @FosterProgramming in [#8003](https://github.com/rh-hideout/pokeemerald-expansion/pull/8003) + - Add a window displaying caught banned species list in the Battle Frontier instead of the string detailing all the is +* Fix namebox bug when reloading the map mid-script by @FosterProgramming in [#8073](https://github.com/rh-hideout/pokeemerald-expansion/pull/8073) +* Fix copyvar instead of setvar causing issue with LTO by @FosterProgramming in [#8097](https://github.com/rh-hideout/pokeemerald-expansion/pull/8097) +* Fix berry blender not computing flavor correctly by @FosterProgramming in [#8113](https://github.com/rh-hideout/pokeemerald-expansion/pull/8113) +* Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in [#8062](https://github.com/rh-hideout/pokeemerald-expansion/pull/8062) + - VS seeker now work with trainers who don't start with trainer_battle. You can use `vsseeker_rematchid TRAINER_ID` to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. ` vsseeker_rematchid` work like a `cant_see_if_trainerflag_set` with additional functionality to handle vs seeker. + - All NPCs who don't start with either `vsseeker_rematchid` or `trainerbattle` will show as "X"/unmatchable by the vs seeker, so non-rematchable trainer who do not start with `trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a `vsseeker_rematchid` for them too. +* Fix grade in summary screen not accounting for 26 IV by @FosterProgramming in [#8157](https://github.com/rh-hideout/pokeemerald-expansion/pull/8157) +* Fix match call regression by @FosterProgramming in [#8227](https://github.com/rh-hideout/pokeemerald-expansion/pull/8227) +* Fix mew sprite not appearing correctly by @FosterProgramming in [#8235](https://github.com/rh-hideout/pokeemerald-expansion/pull/8235) +* Fix wrong palette for types sprites in hgss dex after catching mon by @FosterProgramming in [#8153](https://github.com/rh-hideout/pokeemerald-expansion/pull/8153) +* Fix Apricorns with OW_SHOW_ITEM_DESCRIPTIONS not off by @hedara90 in [#8253](https://github.com/rh-hideout/pokeemerald-expansion/pull/8253) +* Fix mirage tower ceiling crumble color by @FosterProgramming in [#8081](https://github.com/rh-hideout/pokeemerald-expansion/pull/8081) +* Fix light flickering when different types of light sprite are present by @FosterProgramming in [#8043](https://github.com/rh-hideout/pokeemerald-expansion/pull/8043) + - Light intensity of neon signs was reduced to avoid conflicts with other light sources + - Fix flickering when both neon signs and light ball are present on screen +* Bug Fix: NPC Followers not working on slow sideways stairs by @Bivurnum in [#8257](https://github.com/rh-hideout/pokeemerald-expansion/pull/8257) + - Fixed NPC followers on slow sideways stairs +* Fix not enough memory being allocated when moves load background in contests by @FosterProgramming in [#8284](https://github.com/rh-hideout/pokeemerald-expansion/pull/8284) +* Make MON_DATA_NICKNAME10 return a 10 character string by @FosterProgramming in [#8291](https://github.com/rh-hideout/pokeemerald-expansion/pull/8291) + - Fix bug where interviews would print bad data in their string +* Fix game freeze when trainers try to walk on sideway stairs by @FosterProgramming in [#8316](https://github.com/rh-hideout/pokeemerald-expansion/pull/8316) +* Fix tossing items applying to the wrong stack by @FosterProgramming in [#8282](https://github.com/rh-hideout/pokeemerald-expansion/pull/8282) +* Prevent moves to be changed when choosing half party by @FosterProgramming in [#8336](https://github.com/rh-hideout/pokeemerald-expansion/pull/8336) + +## 🐉 Pokémon 🐉 +### Added +* Add Legends Z-A content by @Bassoonian in [#7935](https://github.com/rh-hideout/pokeemerald-expansion/pull/7935) + * To retain compatibility with your new items and species, make sure to move the new additions behind your own additions. + * The save block will shift if you have enabled `USE_DEXNAV_SEARCH_LEVELS` (due to the new species) or if `OW_SHOW_ITEM_DESCRIPTIONS` is set to `OW_ITEM_DESCRIPTIONS_FIRST_TIME` (due to the new items). +* Move Relearners for TMs, Tutors and Egg moves by @PCG06 in [#8040](https://github.com/rh-hideout/pokeemerald-expansion/pull/8040) + - Increased the size of `MAX_RELEARNER_MOVES` to 60 to prevent crashes when viewing Mew. + +### Changed +* Nickit & Thievul visual revamp by @purrfectdoodle in [#7689](https://github.com/rh-hideout/pokeemerald-expansion/pull/7689) +* Fix Kyurem typo in swap move tables by @Bassoonian in [#8139](https://github.com/rh-hideout/pokeemerald-expansion/pull/8139) +* Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in [#8143](https://github.com/rh-hideout/pokeemerald-expansion/pull/8143) +* Fix some followers sprites by @estellarc in [#8208](https://github.com/rh-hideout/pokeemerald-expansion/pull/8208) + +### Fixed +* Fix gba sprites trying load non existent female versions by @FosterProgramming in [#7996](https://github.com/rh-hideout/pokeemerald-expansion/pull/7996) + - Fixes issues with pokemon getting gender differences in later gens when using gen3 sprite config +* GetEggSpecies: Only enabled species by @mrgriffin in [#8221](https://github.com/rh-hideout/pokeemerald-expansion/pull/8221) +* Fix compiling using `make debug` by @PCG06 in [#8380](https://github.com/rh-hideout/pokeemerald-expansion/pull/8380) + +## ⚔️ Battle General ⚔️ +### Added +* Config for capture to appear critical if the pokemon is already caught by @FosterProgramming in [#7730](https://github.com/rh-hideout/pokeemerald-expansion/pull/7730) + +### Changed +* Separates FRB and FRZ animations by @grintoul1 in [#7611](https://github.com/rh-hideout/pokeemerald-expansion/pull/7611) +* Update multiple battle messages by @AsparagusEduardo in [#7529](https://github.com/rh-hideout/pokeemerald-expansion/pull/7529) + - Removed unused messages + - Changed ability "X prevents Y" to "It doesn't affect X..." + - Eg. `"The opposing Snorlax's Immunity prevents poisoning!"` + - Removed `B_ABILITY_POP_UP`. Revert commit `b501fe7354bcd957396465c621ae7af5959ac5b0` to undo this. +* Refactors Attackstring and PP deduction by @AlexOn1ine in [#7402](https://github.com/rh-hideout/pokeemerald-expansion/pull/7402) +* Remove Uproar attack battle script by @AlexOn1ine in [#7715](https://github.com/rh-hideout/pokeemerald-expansion/pull/7715) +* Fix up end turn scripts plus small documentation by @AlexOn1ine in [#7758](https://github.com/rh-hideout/pokeemerald-expansion/pull/7758) +* Remove redundant function call by @AlexOn1ine in [#7752](https://github.com/rh-hideout/pokeemerald-expansion/pull/7752) +* Minor White Herb and Neutralizing Gas clean up by @AlexOn1ine in [#7754](https://github.com/rh-hideout/pokeemerald-expansion/pull/7754) +* Minor clean up for Lightning Rod / Storm Drain by @AlexOn1ine in [#7778](https://github.com/rh-hideout/pokeemerald-expansion/pull/7778) +* Improve ability/heldEffect access for IsBattlerGrounded func by @AlexOn1ine in [#7753](https://github.com/rh-hideout/pokeemerald-expansion/pull/7753) +* Add func GetChosenMoveFromPosition by @AlexOn1ine in [#7810](https://github.com/rh-hideout/pokeemerald-expansion/pull/7810) +* GetBattlerHoldEffect clean up by @AlexOn1ine in [#7819](https://github.com/rh-hideout/pokeemerald-expansion/pull/7819) +* Remove unused gBattleStruct fields by @Bassoonian in [#7822](https://github.com/rh-hideout/pokeemerald-expansion/pull/7822) +* feat: change defines in `constants/abilities.h` to an enum by @khbsd in [#7006](https://github.com/rh-hideout/pokeemerald-expansion/pull/7006) +* Streamline tryheal macros by @Bassoonian in [#7830](https://github.com/rh-hideout/pokeemerald-expansion/pull/7830) +* No bag use flag changed to a varable by @FosterProgramming in [#7780](https://github.com/rh-hideout/pokeemerald-expansion/pull/7780) + - IMPORTANT: The config flag B_FLAG_NO_BAG_USE has been removed + - A config var B_VAR_NO_BAG_USE has been added to replace it. It allows you to choose between: + bag available in battle, bag available in wild battle only, and unavailable bag +* Remove two unused bits from battle structs by @Bassoonian in [#7835](https://github.com/rh-hideout/pokeemerald-expansion/pull/7835) +* Removes a few redundant hitmarkers by @AlexOn1ine in [#7915](https://github.com/rh-hideout/pokeemerald-expansion/pull/7915) +* Remove EffectHitSetTerrain script to use moveeffect by @AlexOn1ine in [#7938](https://github.com/rh-hideout/pokeemerald-expansion/pull/7938) +* Clean up follow up for AtkCanceller refactor by @AlexOn1ine in [#7951](https://github.com/rh-hideout/pokeemerald-expansion/pull/7951) +* Optimize GetWhichBattlerFasterOrTies by @AlexOn1ine in [#7953](https://github.com/rh-hideout/pokeemerald-expansion/pull/7953) +* Decouple passive hp updates from move damage updates by @AlexOn1ine in [#7942](https://github.com/rh-hideout/pokeemerald-expansion/pull/7942) +* Remove appearedInBattle bitfield & redundant use of sentOut partyState by @Nopinou in [#8011](https://github.com/rh-hideout/pokeemerald-expansion/pull/8011) +* Volatile cleared in a redundant spot by @AlexOn1ine in [#8015](https://github.com/rh-hideout/pokeemerald-expansion/pull/8015) +* Moved usedHeldItem to Party State struct by @AlexOn1ine in [#8006](https://github.com/rh-hideout/pokeemerald-expansion/pull/8006) +* Remove usage of gBattlerTarget for MirrorHerb/Opportunist by @AlexOn1ine in [#8033](https://github.com/rh-hideout/pokeemerald-expansion/pull/8033) +* Fixed test "Revival Blessing cannot revive a partner's party member" by @grintoul1 in [#8031](https://github.com/rh-hideout/pokeemerald-expansion/pull/8031) +* Decouple (Overworld) Statuses from ability function by @AlexOn1ine in [#8002](https://github.com/rh-hideout/pokeemerald-expansion/pull/8002) +* Combine Simple Beam and Worry Seed into one effect by @AlexOn1ine in [#8039](https://github.com/rh-hideout/pokeemerald-expansion/pull/8039) +* Clean up for item hold effect refactor by @AlexOn1ine in [#8014](https://github.com/rh-hideout/pokeemerald-expansion/pull/8014) +* Grudge, Destiny Bond and FaintBattler refactor by @AlexOn1ine in [#8072](https://github.com/rh-hideout/pokeemerald-expansion/pull/8072) +* Parametrized Ice Face's weather form change by @AsparagusEduardo in [#8115](https://github.com/rh-hideout/pokeemerald-expansion/pull/8115) +* Clean up redundant todo by @AlexOn1ine in [#8094](https://github.com/rh-hideout/pokeemerald-expansion/pull/8094) +* Deprecate various macro by @AlexOn1ine in [#8092](https://github.com/rh-hideout/pokeemerald-expansion/pull/8092) +* Fixes hacky SetMoveEffect script calls by @AlexOn1ine in [#7987](https://github.com/rh-hideout/pokeemerald-expansion/pull/7987) +* Create BattleStruct sub struct for event states by @AlexOn1ine in [#8131](https://github.com/rh-hideout/pokeemerald-expansion/pull/8131) +* Attackstring hitmarker clean up by @AlexOn1ine in [#8136](https://github.com/rh-hideout/pokeemerald-expansion/pull/8136) +* Clean up ability effect hitmarker by @AlexOn1ine in [#8138](https://github.com/rh-hideout/pokeemerald-expansion/pull/8138) +* Increase number of additional move effects by @AlexOn1ine in [#8149](https://github.com/rh-hideout/pokeemerald-expansion/pull/8149) +* Remove redundant Future Sight flag by @AlexOn1ine in [#8185](https://github.com/rh-hideout/pokeemerald-expansion/pull/8185) +* Powder Move blocking cleanup by @PhallenTree in [#8194](https://github.com/rh-hideout/pokeemerald-expansion/pull/8194) +* Micro clean up in BattleStruct by @AlexOn1ine in [#8177](https://github.com/rh-hideout/pokeemerald-expansion/pull/8177) +* HandleAction_UseMove minor cleanup by @mrgriffin in [#8214](https://github.com/rh-hideout/pokeemerald-expansion/pull/8214) +* Revert gBattleTurnCounter change by @AlexOn1ine in [#8197](https://github.com/rh-hideout/pokeemerald-expansion/pull/8197) +* Canceller -> Canceler rename by @AlexOn1ine in [#8294](https://github.com/rh-hideout/pokeemerald-expansion/pull/8294) +* Remove leftover scrtipt redirection by @AlexOn1ine in [#8317](https://github.com/rh-hideout/pokeemerald-expansion/pull/8317) +* Expand usage of FaintedActions enum in HandleFaintedMonActions by @PhallenTree in [#8346](https://github.com/rh-hideout/pokeemerald-expansion/pull/8346) +* Move end clear bits clean up by @AlexOn1ine in [#8354](https://github.com/rh-hideout/pokeemerald-expansion/pull/8354) +* Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in [#8387](https://github.com/rh-hideout/pokeemerald-expansion/pull/8387) + +### Fixed +* Fixes Weak Armor and items not displaying stat change attributes by @PhallenTree in [#7701](https://github.com/rh-hideout/pokeemerald-expansion/pull/7701) +* Refactors ruin ability checks into a field effect by @AlexOn1ine in [#7711](https://github.com/rh-hideout/pokeemerald-expansion/pull/7711) +* Attackcanceller fixes and improvements by @AlexOn1ine in [#7698](https://github.com/rh-hideout/pokeemerald-expansion/pull/7698) +* Fix Critical Capture RNG and Catching Charm boost by @kittenchilly in [#7534](https://github.com/rh-hideout/pokeemerald-expansion/pull/7534) +* Fixes activation order for a couple abilities by @AlexOn1ine in [#7732](https://github.com/rh-hideout/pokeemerald-expansion/pull/7732) +* More White Herb fixes/clean up by @AlexOn1ine in [#7826](https://github.com/rh-hideout/pokeemerald-expansion/pull/7826) +* Missing IsBattlerAlive checks in Opportunist/Mirror Herb by @AlexOn1ine in [#7829](https://github.com/rh-hideout/pokeemerald-expansion/pull/7829) +* Item battle effect refactor by @AlexOn1ine in [#7857](https://github.com/rh-hideout/pokeemerald-expansion/pull/7857) +* Fix Fling Mental Herb message by @AlexOn1ine in [#7984](https://github.com/rh-hideout/pokeemerald-expansion/pull/7984) +* Fixes Ruin field statuses negation conditions + upcoming cleanup by @PhallenTree in [#8042](https://github.com/rh-hideout/pokeemerald-expansion/pull/8042) +* Fix nature power string and add support for evnvironment in tests by @FosterProgramming in [#8068](https://github.com/rh-hideout/pokeemerald-expansion/pull/8068) + - Add option to choose an environment when setting up a battle test +* Corrects battler position checks in battle_message.c by @grintoul1 in [#8070](https://github.com/rh-hideout/pokeemerald-expansion/pull/8070) +* Emergency Exit on hazards activation + fix end of turn activation by @PhallenTree in [#8075](https://github.com/rh-hideout/pokeemerald-expansion/pull/8075) +* Improve sBattleIntroSlideFuncs bounds check by @hedara90 in [#8084](https://github.com/rh-hideout/pokeemerald-expansion/pull/8084) +* Fixes Sticky Barb never getting transferred to attacker + tests by @PhallenTree in [#8108](https://github.com/rh-hideout/pokeemerald-expansion/pull/8108) +* Fixes flung items sometimes being blocked by Unnerve by @PhallenTree in [#8114](https://github.com/rh-hideout/pokeemerald-expansion/pull/8114) +* Adjust faint battler script by @AlexOn1ine in [#8137](https://github.com/rh-hideout/pokeemerald-expansion/pull/8137) +* Allow to send active mon to PC when capturing a Pokemon by @FosterProgramming in [#8111](https://github.com/rh-hideout/pokeemerald-expansion/pull/8111) +* Fix transform not loading the correct sprites when facing shiny or unown by @FosterProgramming in [#8146](https://github.com/rh-hideout/pokeemerald-expansion/pull/8146) +* Fixes Receiver not immediately activating copied abilities by @PhallenTree in [#8162](https://github.com/rh-hideout/pokeemerald-expansion/pull/8162) +* Fix destiny knot behavior and add tests by @FosterProgramming in [#8174](https://github.com/rh-hideout/pokeemerald-expansion/pull/8174) +* Fix recharge moves + add recharge move tests by @FosterProgramming in [#8181](https://github.com/rh-hideout/pokeemerald-expansion/pull/8181) +* Fixes Magician for spread moves by @AlexOn1ine in [#8170](https://github.com/rh-hideout/pokeemerald-expansion/pull/8170) +* Fix tera tint not applying on activation by @FosterProgramming in [#8135](https://github.com/rh-hideout/pokeemerald-expansion/pull/8135) +* Fixes wrongly assigned count for Semi Invulnerable state by @AlexOn1ine in [#8175](https://github.com/rh-hideout/pokeemerald-expansion/pull/8175) +* Fixes Drain Punch / Parental Bond / Scale Shot interaction by @AlexOn1ine in [#8198](https://github.com/rh-hideout/pokeemerald-expansion/pull/8198) +* Avoid illegal GetBattlerAtPosition by @mrgriffin in [#8225](https://github.com/rh-hideout/pokeemerald-expansion/pull/8225) +* DamageContext: chosenMove by @mrgriffin in [#8224](https://github.com/rh-hideout/pokeemerald-expansion/pull/8224) +* AccuracyCheck: Avoid calling GetMoveEffect with NO_ACC_CALC_CHECK_LOC… by @mrgriffin in [#8222](https://github.com/rh-hideout/pokeemerald-expansion/pull/8222) +* moveend: Handle MOVE_UNAVAILABLE in MOVEEND_THIRD_MOVE_BLOCK by @mrgriffin in [#8215](https://github.com/rh-hideout/pokeemerald-expansion/pull/8215) +* Fix wrong ditto sprite on capture by @FosterProgramming in [#8226](https://github.com/rh-hideout/pokeemerald-expansion/pull/8226) +* SpriteCB_EnemyShadow: Avoid use-after-free by @mrgriffin in [#8220](https://github.com/rh-hideout/pokeemerald-expansion/pull/8220) +* trysethelpinghand avoid illegal target by @mrgriffin in [#8218](https://github.com/rh-hideout/pokeemerald-expansion/pull/8218) +* Fixed an issue related to same turn Encore targeting by @LinathanZel in [#8230](https://github.com/rh-hideout/pokeemerald-expansion/pull/8230) +* Avoid illegal move retargeting in singles by @mrgriffin in [#8217](https://github.com/rh-hideout/pokeemerald-expansion/pull/8217) +* Fixes Shell Trap not activating on contact but no damage by @AlexOn1ine in [#8243](https://github.com/rh-hideout/pokeemerald-expansion/pull/8243) +* Fix Magic Coat reflecting hazard moves incorrectly when used by a partner by @moostoet in [#8272](https://github.com/rh-hideout/pokeemerald-expansion/pull/8272) + - Magic Coat now properly reflects hazard moves from either slot in double battles. +* Shell Trap tests and Fix for Encore interaction by @AlexOn1ine in [#8268](https://github.com/rh-hideout/pokeemerald-expansion/pull/8268) +* Fix max mushroom unable to be selected when one stat is maxed by @FosterProgramming in [#8287](https://github.com/rh-hideout/pokeemerald-expansion/pull/8287) +* Block selecting x items when contrary pokemon are at minimum stages by @FosterProgramming in [#8288](https://github.com/rh-hideout/pokeemerald-expansion/pull/8288) +* Fix Fur Coat affecting confusion self-damage by @moostoet in [#8267](https://github.com/rh-hideout/pokeemerald-expansion/pull/8267) + - Fix confusion self-damage ignoring defense/attack abilities such as Fur Coat. +* Fixes End Turn Speed Order by @AlexOn1ine in [#8289](https://github.com/rh-hideout/pokeemerald-expansion/pull/8289) +* Make switchout abilities trigger after a pokemon has returned to its ball by @FosterProgramming in [#8304](https://github.com/rh-hideout/pokeemerald-expansion/pull/8304) +* Fix Shed Shell allowing fleeing/teleporting and Smoke Ball failing to guarantee escape by @moostoet in [#8286](https://github.com/rh-hideout/pokeemerald-expansion/pull/8286) +* Fix bug where defiant/competitive would pass their stat change to the next target by @FosterProgramming in [#8312](https://github.com/rh-hideout/pokeemerald-expansion/pull/8312) +* Fix max move message against semi invulnerable target by @FosterProgramming in [#8313](https://github.com/rh-hideout/pokeemerald-expansion/pull/8313) +* Fixes Neutralizing Gas displaying message when exiting with multiple users by @PhallenTree in [#8318](https://github.com/rh-hideout/pokeemerald-expansion/pull/8318) +* Fix Kings Rock not being ignored by flinch moves by @AlexOn1ine in [#8327](https://github.com/rh-hideout/pokeemerald-expansion/pull/8327) +* Fix Upper Hand failure still activating Protean by @AlexOn1ine in [#8329](https://github.com/rh-hideout/pokeemerald-expansion/pull/8329) +* Fix Protosynthesis stat boosts ignoring speed drops by @moostoet in [#8277](https://github.com/rh-hideout/pokeemerald-expansion/pull/8277) + - Protosynthesis and Quark Drive now recalculate their boosted stat when Speed is lowered or Neutralizing Gas temporarily disables the ability. +* Fix switch-in abilities not triggering on revive by @FosterProgramming in [#8293](https://github.com/rh-hideout/pokeemerald-expansion/pull/8293) +* More Neutralizing Gas cleanup by @PhallenTree in [#8335](https://github.com/rh-hideout/pokeemerald-expansion/pull/8335) +* Clear Destiny Bond/Grudge bits when not activated by @PhallenTree in [#8334](https://github.com/rh-hideout/pokeemerald-expansion/pull/8334) +* Fix cure status item effect not working properly in doubles by @FosterProgramming in [#8339](https://github.com/rh-hideout/pokeemerald-expansion/pull/8339) +* Fix infinite confusion (berserk gene) not being cured by cure_status bag items by @FosterProgramming in [#8343](https://github.com/rh-hideout/pokeemerald-expansion/pull/8343) +* Fix `B_PHYSICAL_SPECIAL_SPLIT` when set to Gen 4 by @AsparagusEduardo in [#8348](https://github.com/rh-hideout/pokeemerald-expansion/pull/8348) +* Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in [#8307](https://github.com/rh-hideout/pokeemerald-expansion/pull/8307) + - BUGFIX: Beat Up (`GEN =< 5`) now no longer doubles its damage on every non-critical hit + - Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules +* Fix substitute graphic not disappearing after using a pivor move by @FosterProgramming in [#8340](https://github.com/rh-hideout/pokeemerald-expansion/pull/8340) +* Fixes Beak Blast burning after Beak Blast was already used by @PhallenTree in [#8361](https://github.com/rh-hideout/pokeemerald-expansion/pull/8361) +* Fix Roar not being recorded for LastUsedMove by @AlexOn1ine in [#8362](https://github.com/rh-hideout/pokeemerald-expansion/pull/8362) +* Fixes Neutralizing Gas / Mold Breaker / Dragon Darts interaction by @AlexOn1ine in [#8389](https://github.com/rh-hideout/pokeemerald-expansion/pull/8389) +* Fixes battle tv overwriting damage values by @AlexOn1ine in [#8378](https://github.com/rh-hideout/pokeemerald-expansion/pull/8378) +* Fix ball cycling not working properly when the same ball take multiple bag slots by @FosterProgramming in [#8163](https://github.com/rh-hideout/pokeemerald-expansion/pull/8163) + - Two new defines added to items.h `FIRST_BALL_INDEX` and `LAST_BALL_INDEX` + - We now assume the indexes of all regular ball usable in wild battle have consecutive indexes and some features (throw ball shortcut in battle) might break if not true +* Prevent double Dynamax for single-trainer 2v1 multi battles by @moostoet in [#8323](https://github.com/rh-hideout/pokeemerald-expansion/pull/8323) + - Fixed AI 2v1 multibattles incorrectly allowing both opponent leads to Dynamax in the same turn. + +## 🤹 Moves 🤹 +### Changed +* Separates FRB and FRZ animations by @grintoul1 in [#7611](https://github.com/rh-hideout/pokeemerald-expansion/pull/7611) +* Fixed test "Revival Blessing cannot revive a partner's party member" by @grintoul1 in [#8031](https://github.com/rh-hideout/pokeemerald-expansion/pull/8031) +* Fixed Uproar's description and spacing by @fdeblasio in [#8187](https://github.com/rh-hideout/pokeemerald-expansion/pull/8187) +* Clean usage of gMovesInfo by @AsparagusEduardo in [#8234](https://github.com/rh-hideout/pokeemerald-expansion/pull/8234) + - Also, fixed an OOB in `HasMoveThatChangesKOThreshold` +* Added Gen 6 contest combos by @fdeblasio in [#8251](https://github.com/rh-hideout/pokeemerald-expansion/pull/8251) +* Make tailwind anim mirror based on side by @FosterProgramming in [#8249](https://github.com/rh-hideout/pokeemerald-expansion/pull/8249) +* Make rainbow effect anim change based on side by @FosterProgramming in [#8269](https://github.com/rh-hideout/pokeemerald-expansion/pull/8269) + - Art assets by [SonikkuA-DatH](https://github.com/SonikkuA-DatH) +* Update Lash Out description to clarify its effect by @PhallenTree in [#8372](https://github.com/rh-hideout/pokeemerald-expansion/pull/8372) + +### Fixed +* Fix some move animations leaking VRAM and freeing already freed tags by @hedara90 in [#7977](https://github.com/rh-hideout/pokeemerald-expansion/pull/7977) + +## 🎭 Abilities 🎭 +### Changed +* followup: AbilityBattleEffects return type is incorrect by @khbsd in [#7827](https://github.com/rh-hideout/pokeemerald-expansion/pull/7827) + +## 🧶 Items 🧶 +### Fixed +* Allow vs seekers to work with script not starting with trainerbattle by @FosterProgramming in [#8062](https://github.com/rh-hideout/pokeemerald-expansion/pull/8062) + - VS seeker now work with trainers who don't start with trainer_battle. You can use `vsseeker_rematchid TRAINER_ID` to indicate that this NPC is a battling trainer and the game will fetch the appropriate rematch if necessary. ` vsseeker_rematchid` work like a `cant_see_if_trainerflag_set` with additional functionality to handle vs seeker. + - All NPCs who don't start with either `vsseeker_rematchid` or `trainerbattle` will show as "X"/unmatchable by the vs seeker, so non-rematchable trainer who do not start with `trainerbattle may "lie" and not show an excalmation mark showing they haven't been fought yet. This can be fixed by including a `vsseeker_rematchid` for them too. +* Removed extra period in Pokéshi Doll description by @montmoguri in [#8252](https://github.com/rh-hideout/pokeemerald-expansion/pull/8252) + +## 🤖 Battle AI 🤖 +### Added +* Improved move additional effect handling; now accounts for Shield Dust. by @surskitty in [#7650](https://github.com/rh-hideout/pokeemerald-expansion/pull/7650) +* Adjusted AI handling for Gravity; AI for weather/field status additional effects. by @surskitty in [#7651](https://github.com/rh-hideout/pokeemerald-expansion/pull/7651) +* Improved AI for status curing; trainer items, Purify, Smelling Salts, Sparkling Aria by @surskitty in [#7853](https://github.com/rh-hideout/pokeemerald-expansion/pull/7853) + +### Changed +* AI uses Magnetic Flux. by @surskitty in [#7642](https://github.com/rh-hideout/pokeemerald-expansion/pull/7642) +* AI uses Flower Shield. by @surskitty in [#7640](https://github.com/rh-hideout/pokeemerald-expansion/pull/7640) +* AI uses Life Dew. by @surskitty in [#7643](https://github.com/rh-hideout/pokeemerald-expansion/pull/7643) +* AI uses Gear Up. by @surskitty in [#7641](https://github.com/rh-hideout/pokeemerald-expansion/pull/7641) +* Correcting test AI won't use status moves if partner chose Helping Hand by @surskitty in [#7649](https://github.com/rh-hideout/pokeemerald-expansion/pull/7649) +* IncreaseStatUpScore adjustments for Simple, +3 moves, Acupressure, max move effects by @surskitty in [#7662](https://github.com/rh-hideout/pokeemerald-expansion/pull/7662) +* AI handling for Coaching. by @surskitty in [#7661](https://github.com/rh-hideout/pokeemerald-expansion/pull/7661) +* Simplifying calls to IsBattlerTrapped; treats being unable to switch as trappedness by @surskitty in [#7671](https://github.com/rh-hideout/pokeemerald-expansion/pull/7671) +* AI Tests: Gimmick Support by @mrgriffin in [#7694](https://github.com/rh-hideout/pokeemerald-expansion/pull/7694) +* AI can use Z-status moves by @surskitty in [#7666](https://github.com/rh-hideout/pokeemerald-expansion/pull/7666) +* Move some checks out of IncreaseStatUpScore to ShouldRaiseAnyStat by @surskitty in [#7722](https://github.com/rh-hideout/pokeemerald-expansion/pull/7722) +* Moving additional effects out of AI_CalcMoveEffectScore and into AI_CalcMoveAdditionalEffectScore by @surskitty in [#7727](https://github.com/rh-hideout/pokeemerald-expansion/pull/7727) +* AI sees dynamic moves and Nature Power as correct types for weather, terrain by @surskitty in [#7759](https://github.com/rh-hideout/pokeemerald-expansion/pull/7759) +* Fix abusable two-turn-move switch behaviour by @Pawkkie in [#7770](https://github.com/rh-hideout/pokeemerald-expansion/pull/7770) +* Z Status move handling: Conversion, Detect, Nature Power, Transform by @surskitty in [#7721](https://github.com/rh-hideout/pokeemerald-expansion/pull/7721) +* Use stored values for ai switch-in effectiveness checks by @AlexOn1ine in [#7794](https://github.com/rh-hideout/pokeemerald-expansion/pull/7794) +* Changing all HasBattlerSideAbility to AI_IsAbilityOnSide. by @surskitty in [#7927](https://github.com/rh-hideout/pokeemerald-expansion/pull/7927) +* Weather/Terrain AI touch-ups. by @surskitty in [#7933](https://github.com/rh-hideout/pokeemerald-expansion/pull/7933) +* Improving the checks for the AI to avoid Encore; adding RISK_ENCORE_CHANCE config. by @surskitty in [#7929](https://github.com/rh-hideout/pokeemerald-expansion/pull/7929) +* Fixes CanUseLastResort and resolves 3 KNOWN_FAILING Last Resort tests by @grintoul1 in [#8032](https://github.com/rh-hideout/pokeemerald-expansion/pull/8032) +* Add AI flag AI_FLAG_KNOW_OPPONENT_PARTY to know all species in party by @moostoet in [#8290](https://github.com/rh-hideout/pokeemerald-expansion/pull/8290) + +### Fixed +* Score adjustments towards guaranteed stat drops. by @surskitty in [#7670](https://github.com/rh-hideout/pokeemerald-expansion/pull/7670) +* AI uses Extreme Evoboost. by @surskitty in [#7706](https://github.com/rh-hideout/pokeemerald-expansion/pull/7706) +* Fixes AI scoring when Priority moves are blocked by @PhallenTree in [#7745](https://github.com/rh-hideout/pokeemerald-expansion/pull/7745) +* fix (AI scoring): shield dust considerations, IsMoveEffectInMinus self effect edge case, hitsToKO zero-case consideration by @ghostyboyy97 in [#8126](https://github.com/rh-hideout/pokeemerald-expansion/pull/8126) + - The AI now sees Shield Dust on the player's Pokemon correctly + - The AI now sees self-targeted positive effect boosts correctly +* fix (contrary): Contrary stat down handling in MoveEffectInPlus by @ghostyboyy97 in [#8165](https://github.com/rh-hideout/pokeemerald-expansion/pull/8165) + - When comparing positive move effects in damaging move comparison, the AI will correctly see moves like Leaf Storm as beneficial if their Pokemon has Contrary. +* Added check for parental bond killing through sturdy by @MaximeGr00 in [#8206](https://github.com/rh-hideout/pokeemerald-expansion/pull/8206) + - AI now accounts for Parental Bond when checking if a move can ko the player through sturdy/focus sash. +* AI: Handle MOVE_UNAVAILABLE in last used moves by @mrgriffin in [#8219](https://github.com/rh-hideout/pokeemerald-expansion/pull/8219) +* Fix AI_FLAG_DOUBLE_ACE_POKEMON sending duplicate Pokémon in doubles by @moostoet in [#8279](https://github.com/rh-hideout/pokeemerald-expansion/pull/8279) + - Fixed AI_FLAG_DOUBLE_ACE_POKEMON trainers resending the same Pokémon after a KO instead of their two Ace Pokémon in double battles. +* Rework switch AI and add more tests for ace pokemon flags by @FosterProgramming in [#8321](https://github.com/rh-hideout/pokeemerald-expansion/pull/8321) + - All remaining issues with the AI flags Ace Pokemon and Double Ace pokemon should be fixed + - The smart switching AI should be less likely to switch a pokemon about to die if it doesn't have a pokemon with a good matchup to replace it +* Fix switchin KO threshold logic by @Pawkkie in [#8370](https://github.com/rh-hideout/pokeemerald-expansion/pull/8370) + +## 🧹 Other Cleanup 🧹 +* Update multiple battle messages by @AsparagusEduardo in [#7529](https://github.com/rh-hideout/pokeemerald-expansion/pull/7529) + - Removed unused messages + - Changed ability "X prevents Y" to "It doesn't affect X..." + - Eg. `"The opposing Snorlax's Immunity prevents poisoning!"` + - Removed `B_ABILITY_POP_UP`. Revert commit `b501fe7354bcd957396465c621ae7af5959ac5b0` to undo this. +* Battle debug menu now checks correct parties depending on battler party by @grintoul1 in [#7652](https://github.com/rh-hideout/pokeemerald-expansion/pull/7652) +* Correcting test AI won't use status moves if partner chose Helping Hand by @surskitty in [#7649](https://github.com/rh-hideout/pokeemerald-expansion/pull/7649) +* Remove Uproar attack battle script by @AlexOn1ine in [#7715](https://github.com/rh-hideout/pokeemerald-expansion/pull/7715) +* Fix up end turn scripts plus small documentation by @AlexOn1ine in [#7758](https://github.com/rh-hideout/pokeemerald-expansion/pull/7758) +* `field_name_box` smol followup by @mudskipper13 in [#7762](https://github.com/rh-hideout/pokeemerald-expansion/pull/7762) +* Remove redundant function call by @AlexOn1ine in [#7752](https://github.com/rh-hideout/pokeemerald-expansion/pull/7752) +* Minor White Herb and Neutralizing Gas clean up by @AlexOn1ine in [#7754](https://github.com/rh-hideout/pokeemerald-expansion/pull/7754) +* Minor clean up for Lightning Rod / Storm Drain by @AlexOn1ine in [#7778](https://github.com/rh-hideout/pokeemerald-expansion/pull/7778) +* Add func GetChosenMoveFromPosition by @AlexOn1ine in [#7810](https://github.com/rh-hideout/pokeemerald-expansion/pull/7810) +* GetBattlerHoldEffect clean up by @AlexOn1ine in [#7819](https://github.com/rh-hideout/pokeemerald-expansion/pull/7819) +* Remove unused gBattleStruct fields by @Bassoonian in [#7822](https://github.com/rh-hideout/pokeemerald-expansion/pull/7822) +* followup: AbilityBattleEffects return type is incorrect by @khbsd in [#7827](https://github.com/rh-hideout/pokeemerald-expansion/pull/7827) +* Streamline tryheal macros by @Bassoonian in [#7830](https://github.com/rh-hideout/pokeemerald-expansion/pull/7830) +* Remove two unused bits from battle structs by @Bassoonian in [#7835](https://github.com/rh-hideout/pokeemerald-expansion/pull/7835) +* Removes a few redundant hitmarkers by @AlexOn1ine in [#7915](https://github.com/rh-hideout/pokeemerald-expansion/pull/7915) +* Remove EffectHitSetTerrain script to use moveeffect by @AlexOn1ine in [#7938](https://github.com/rh-hideout/pokeemerald-expansion/pull/7938) +* Clean up follow up for AtkCanceller refactor by @AlexOn1ine in [#7951](https://github.com/rh-hideout/pokeemerald-expansion/pull/7951) +* Remove appearedInBattle bitfield & redundant use of sentOut partyState by @Nopinou in [#8011](https://github.com/rh-hideout/pokeemerald-expansion/pull/8011) +* Some more documentation and cleanup by @Bassoonian in [#8020](https://github.com/rh-hideout/pokeemerald-expansion/pull/8020) +* Volatile cleared in a redundant spot by @AlexOn1ine in [#8015](https://github.com/rh-hideout/pokeemerald-expansion/pull/8015) +* Moved usedHeldItem to Party State struct by @AlexOn1ine in [#8006](https://github.com/rh-hideout/pokeemerald-expansion/pull/8006) +* Remove usage of gBattlerTarget for MirrorHerb/Opportunist by @AlexOn1ine in [#8033](https://github.com/rh-hideout/pokeemerald-expansion/pull/8033) +* Even more enums and documentation by @Bassoonian in [#8029](https://github.com/rh-hideout/pokeemerald-expansion/pull/8029) +* Decouple (Overworld) Statuses from ability function by @AlexOn1ine in [#8002](https://github.com/rh-hideout/pokeemerald-expansion/pull/8002) +* Fixes Ruin field statuses negation conditions + upcoming cleanup by @PhallenTree in [#8042](https://github.com/rh-hideout/pokeemerald-expansion/pull/8042) +* Minor clean up in menu.c by @estellarc in [#8060](https://github.com/rh-hideout/pokeemerald-expansion/pull/8060) +* Clean up for item hold effect refactor by @AlexOn1ine in [#8014](https://github.com/rh-hideout/pokeemerald-expansion/pull/8014) +* Parametrized Ice Face's weather form change by @AsparagusEduardo in [#8115](https://github.com/rh-hideout/pokeemerald-expansion/pull/8115) +* Clean up redundant todo by @AlexOn1ine in [#8094](https://github.com/rh-hideout/pokeemerald-expansion/pull/8094) +* Deprecate various macro by @AlexOn1ine in [#8092](https://github.com/rh-hideout/pokeemerald-expansion/pull/8092) +* Fixes hacky SetMoveEffect script calls by @AlexOn1ine in [#7987](https://github.com/rh-hideout/pokeemerald-expansion/pull/7987) +* Create BattleStruct sub struct for event states by @AlexOn1ine in [#8131](https://github.com/rh-hideout/pokeemerald-expansion/pull/8131) +* Attackstring hitmarker clean up by @AlexOn1ine in [#8136](https://github.com/rh-hideout/pokeemerald-expansion/pull/8136) +* Clean up ability effect hitmarker by @AlexOn1ine in [#8138](https://github.com/rh-hideout/pokeemerald-expansion/pull/8138) +* Fix Kyurem typo in swap move tables by @Bassoonian in [#8139](https://github.com/rh-hideout/pokeemerald-expansion/pull/8139) +* Fix typo in Voltorb-Hisui pokedex entry by @PhallenTree in [#8143](https://github.com/rh-hideout/pokeemerald-expansion/pull/8143) +* porymap default settings by @FosterProgramming in [#8038](https://github.com/rh-hideout/pokeemerald-expansion/pull/8038) + - WARNING: A change was made for new projects map files to match poymap output. This change might break people's projects with existing versions of those files. The files affected are ` data/maps/map_groups.json`, `src/data/heal_locations.json`, `src/data/region_map/region_map_sections.json` and `src/data/wild_encounters.json` + If you have an issue with one of those files during the merging process, you should run this command + `git checkout HEAD -- ` + which will reset the file to the version before you initiated the merge +* Sets instant text speed flag to false by default by @khbsd in [#8179](https://github.com/rh-hideout/pokeemerald-expansion/pull/8179) +* Remove redundant Future Sight flag by @AlexOn1ine in [#8185](https://github.com/rh-hideout/pokeemerald-expansion/pull/8185) +* Fix incorrect comments by @AlexOn1ine in [#8193](https://github.com/rh-hideout/pokeemerald-expansion/pull/8193) +* Fixed Uproar's description and spacing by @fdeblasio in [#8187](https://github.com/rh-hideout/pokeemerald-expansion/pull/8187) +* Add include/constants/script_commands.h to gitignore by @AlexOn1ine in [#8169](https://github.com/rh-hideout/pokeemerald-expansion/pull/8169) +* Powder Move blocking cleanup by @PhallenTree in [#8194](https://github.com/rh-hideout/pokeemerald-expansion/pull/8194) +* Converted landmarks to COMPOUND_STRINGs by @fdeblasio in [#8205](https://github.com/rh-hideout/pokeemerald-expansion/pull/8205) +* Micro clean up in BattleStruct by @AlexOn1ine in [#8177](https://github.com/rh-hideout/pokeemerald-expansion/pull/8177) +* Clean usage of gMovesInfo by @AsparagusEduardo in [#8234](https://github.com/rh-hideout/pokeemerald-expansion/pull/8234) + - Also, fixed an OOB in `HasMoveThatChangesKOThreshold` +* HandleAction_UseMove minor cleanup by @mrgriffin in [#8214](https://github.com/rh-hideout/pokeemerald-expansion/pull/8214) +* Revert gBattleTurnCounter change by @AlexOn1ine in [#8197](https://github.com/rh-hideout/pokeemerald-expansion/pull/8197) +* Added contest config and cleaned up contest category variables by @fdeblasio in [#8178](https://github.com/rh-hideout/pokeemerald-expansion/pull/8178) +* Adjust Canceler naming to contain only one l by @AlexOn1ine in [#8258](https://github.com/rh-hideout/pokeemerald-expansion/pull/8258) +* Fix wrongly renamed logs by @AlexOn1ine in [#8264](https://github.com/rh-hideout/pokeemerald-expansion/pull/8264) +* Test type enum indentation by @AsparagusEduardo in [#8273](https://github.com/rh-hideout/pokeemerald-expansion/pull/8273) +* Added missing 'coolness' string by @fdeblasio in [#8274](https://github.com/rh-hideout/pokeemerald-expansion/pull/8274) +* Canceller -> Canceler rename by @AlexOn1ine in [#8294](https://github.com/rh-hideout/pokeemerald-expansion/pull/8294) +* Tests for Max Moves already exist by @AlexOn1ine in [#8314](https://github.com/rh-hideout/pokeemerald-expansion/pull/8314) +* Documentation clean up for MoveCanceler by @AlexOn1ine in [#8297](https://github.com/rh-hideout/pokeemerald-expansion/pull/8297) +* Use MAP_OFFSET by @estellarc in [#8328](https://github.com/rh-hideout/pokeemerald-expansion/pull/8328) +* Remove leftover scrtipt redirection by @AlexOn1ine in [#8317](https://github.com/rh-hideout/pokeemerald-expansion/pull/8317) +* Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in [#7872](https://github.com/rh-hideout/pokeemerald-expansion/pull/7872) +* Expand usage of FaintedActions enum in HandleFaintedMonActions by @PhallenTree in [#8346](https://github.com/rh-hideout/pokeemerald-expansion/pull/8346) +* Move end clear bits clean up by @AlexOn1ine in [#8354](https://github.com/rh-hideout/pokeemerald-expansion/pull/8354) +* Indent unintented if statement by @hedara90 in [#8367](https://github.com/rh-hideout/pokeemerald-expansion/pull/8367) +* Update Lash Out description to clarify its effect by @PhallenTree in [#8372](https://github.com/rh-hideout/pokeemerald-expansion/pull/8372) +* Slight Protect moveend cleanup by @AsparagusEduardo in [#8385](https://github.com/rh-hideout/pokeemerald-expansion/pull/8385) +* Restored encourageEncore flag to non-volatile status effects by @AsparagusEduardo in [#8387](https://github.com/rh-hideout/pokeemerald-expansion/pull/8387) + +## 🧪 Test Runner 🧪 +### Added +* Multibattle testing system by @grintoul1 in [#7257](https://github.com/rh-hideout/pokeemerald-expansion/pull/7257) +* Prevent EXPECT functions from casting negative numbers into unsigned by @FosterProgramming in [#7866](https://github.com/rh-hideout/pokeemerald-expansion/pull/7866) + +### Changed +* AI Tests: Gimmick Support by @mrgriffin in [#7694](https://github.com/rh-hideout/pokeemerald-expansion/pull/7694) +* Some tests for future Dynamax AI behavior. by @surskitty in [#7707](https://github.com/rh-hideout/pokeemerald-expansion/pull/7707) +* Add some missing move animations to the move animation tests by @FosterProgramming in [#7507](https://github.com/rh-hideout/pokeemerald-expansion/pull/7507) +* Fixes CanUseLastResort and resolves 3 KNOWN_FAILING Last Resort tests by @grintoul1 in [#8032](https://github.com/rh-hideout/pokeemerald-expansion/pull/8032) +* Fixed test "Revival Blessing cannot revive a partner's party member" by @grintoul1 in [#8031](https://github.com/rh-hideout/pokeemerald-expansion/pull/8031) +* Added Soundproof and Bulletproof tests by @AsparagusEduardo in [#8189](https://github.com/rh-hideout/pokeemerald-expansion/pull/8189) +* Wrote some missing tests by @AsparagusEduardo in [#8203](https://github.com/rh-hideout/pokeemerald-expansion/pull/8203) +* Refactor random functions to be runner specific by @FosterProgramming in [#7816](https://github.com/rh-hideout/pokeemerald-expansion/pull/7816) +* A couple more tests by @AsparagusEduardo in [#8209](https://github.com/rh-hideout/pokeemerald-expansion/pull/8209) +* Fixed some failing tests with GEN_LATEST = GEN_5 by @AsparagusEduardo in [#8241](https://github.com/rh-hideout/pokeemerald-expansion/pull/8241) +* Add test for mold breaker/ice scales interaction by @FosterProgramming in [#8240](https://github.com/rh-hideout/pokeemerald-expansion/pull/8240) +* Yet more tests by @AsparagusEduardo in [#8228](https://github.com/rh-hideout/pokeemerald-expansion/pull/8228) + - Added tests for: + - Dark Aura + - Fairy Aura + - Flare Boost + - Toxic Boost + - Added test names for Flying Press. +* Test type enum indentation by @AsparagusEduardo in [#8273](https://github.com/rh-hideout/pokeemerald-expansion/pull/8273) +* Slightly increase headless test speed by modifying animations by @AsparagusEduardo in [#8299](https://github.com/rh-hideout/pokeemerald-expansion/pull/8299) +* Make `gTestRunnerHeadless` into a constant outside of tests by @hedara90 in [#8306](https://github.com/rh-hideout/pokeemerald-expansion/pull/8306) +* Tests for Max Moves already exist by @AlexOn1ine in [#8314](https://github.com/rh-hideout/pokeemerald-expansion/pull/8314) +* Finished fixing tests when setting `GEN_LATEST` to `GEN_5` by @AsparagusEduardo in [#8263](https://github.com/rh-hideout/pokeemerald-expansion/pull/8263) +* Wrote missing Fling tests by @AsparagusEduardo in [#8383](https://github.com/rh-hideout/pokeemerald-expansion/pull/8383) + +### Fixed +* Corrects ONE_VS_TWO_BATTLE_TEST to use BATTLE_TEST_ARGS_ONE_VS_TWO by @grintoul1 in [#8061](https://github.com/rh-hideout/pokeemerald-expansion/pull/8061) +* Fixes difficulty not being restored after tests by @grintoul1 in [#8129](https://github.com/rh-hideout/pokeemerald-expansion/pull/8129) +* Reset saveblock data between test runs by @hedara90 in [#8145](https://github.com/rh-hideout/pokeemerald-expansion/pull/8145) +* Sheer force test fix by @grintoul1 in [#8142](https://github.com/rh-hideout/pokeemerald-expansion/pull/8142) +* Test only enabled species by @mrgriffin in [#8216](https://github.com/rh-hideout/pokeemerald-expansion/pull/8216) +* Fix ohko moves ai tests by @FosterProgramming in [#8309](https://github.com/rh-hideout/pokeemerald-expansion/pull/8309) +* Fixed broken friendship from items in battle test and added new test for opposite case by @pkmnsnfrn in [#7872](https://github.com/rh-hideout/pokeemerald-expansion/pull/7872) +* Add tests to verify aromatherapy is not affected by heal bell config by @FosterProgramming in [#8344](https://github.com/rh-hideout/pokeemerald-expansion/pull/8344) +* Pre gen 5 encored move now signals the test engine a move is happening by @FosterProgramming in [#8338](https://github.com/rh-hideout/pokeemerald-expansion/pull/8338) +* Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage by @moostoet in [#8307](https://github.com/rh-hideout/pokeemerald-expansion/pull/8307) + - BUGFIX: Beat Up (`GEN =< 5`) now no longer doubles its damage on every non-critical hit + - Beat Up now precomputes eligible party members/strikers for consistent multi-hit resolution and expanded tests covering both pre-Gen5 and Gen5+ rules +* Fix player and partner trainer sprite palettes to 8 and 9, preventing unwanted palette changes by @grintoul1 in [#8127](https://github.com/rh-hideout/pokeemerald-expansion/pull/8127) +* Fix known failing AI trace test by @FosterProgramming in [#8337](https://github.com/rh-hideout/pokeemerald-expansion/pull/8337) + +## 📚 Documentation 📚 +* Converts some defines to enums and name unnamed enums by @Bassoonian in [#8019](https://github.com/rh-hideout/pokeemerald-expansion/pull/8019) +* Some more documentation and cleanup by @Bassoonian in [#8020](https://github.com/rh-hideout/pokeemerald-expansion/pull/8020) +* Even more enums and documentation by @Bassoonian in [#8029](https://github.com/rh-hideout/pokeemerald-expansion/pull/8029) +* Add type enum by @Bassoonian in [#8054](https://github.com/rh-hideout/pokeemerald-expansion/pull/8054) +* Revert reversion by @AlexOn1ine in [#8112](https://github.com/rh-hideout/pokeemerald-expansion/pull/8112) +* Lock mdbook to v0.4.35 to fix docs not building by @grintoul1 in [#8130](https://github.com/rh-hideout/pokeemerald-expansion/pull/8130) +* Add additional comment explaing map name popup transparency side-effects by @FosterProgramming in [#8117](https://github.com/rh-hideout/pokeemerald-expansion/pull/8117) +* Fix incorrect comments by @AlexOn1ine in [#8193](https://github.com/rh-hideout/pokeemerald-expansion/pull/8193) +* Moves name box configs into a new file by @AlexOn1ine in [#8250](https://github.com/rh-hideout/pokeemerald-expansion/pull/8250) +* Fix wrongly renamed logs by @AlexOn1ine in [#8264](https://github.com/rh-hideout/pokeemerald-expansion/pull/8264) +* Documentation clean up for MoveCanceler by @AlexOn1ine in [#8297](https://github.com/rh-hideout/pokeemerald-expansion/pull/8297) +* Use MAP_OFFSET by @estellarc in [#8328](https://github.com/rh-hideout/pokeemerald-expansion/pull/8328) +* Fedora install instructions by @estellarc in [#8355](https://github.com/rh-hideout/pokeemerald-expansion/pull/8355) + +## New Contributors +* @purrfectdoodle made their first contribution in [#7689](https://github.com/rh-hideout/pokeemerald-expansion/pull/7689) +* @montmoguri made their first contribution in [#8252](https://github.com/rh-hideout/pokeemerald-expansion/pull/8252) + +**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.3...expansion/1.14.0 + + + + diff --git a/docs/tutorials/how_to_apricorn_tree.md b/docs/tutorials/how_to_apricorn_tree.md new file mode 100644 index 0000000000..1efd5f62fe --- /dev/null +++ b/docs/tutorials/how_to_apricorn_tree.md @@ -0,0 +1,58 @@ +# How to interact with Apricorn Trees + +![apricorn-tree](/docs/tutorials/img/apricorn_tree/apricorn-tree.gif) + +### Adding a new apricorn tree + +To add a new tree, first increase the tree count and expand the tree list in `include/constants/apricorn_tree.h`. + +Note that each tree will take a bit in the savegame's `SaveBlock3` struct so increasing `APRICORN_TREE_COUNT` **breaks the savegame**. +Due to this, pokeemerald-expansion doesn't have any trees set up by default to prevent breaking downstream savegames. +The trees support random yields and properly use plural case on plural yields. + +```diff +#define APRICORN_TREE_NONE 0 + +-#define APRICORN_TREE_COUNT 0 ++#define APRICORN_TREE_ROUTE101_RED_TREE 1 ++ ++#define APRICORN_TREE_COUNT 32 +``` + +Then list its data in `src/data/apricorns.h`. + +```diff +const struct ApricornTree gApricornTrees[APRICORN_TREE_COUNT] = +{ + [APRICORN_TREE_NONE] = + { + .minimum = 1, + .maximum = 1, + .apricornType = APRICORN_RED, + }, + ++ [APRICORN_TREE_ROUTE101_RED_TREE] = ++ { ++ .minimum = 1, ++ .maximum = 1, ++ .apricornType = APRICORN_RED, ++ }, +}; +``` +Finally, just place your new tree using Porymap. +Similarly to berries, the Sight Radius / Berry Tree ID field is used for the tree's ID. + +![apricorn-tree-porymap](/docs/tutorials/img/apricorn_tree/apricorn-tree-porymap.png) + +### Add a new apricorn type + +After you created your new item, simply expand the `ApricornType` enum in `include/constants/apricorn_tree.h`. + +```diff +enum ApricornType +{ + [...] + APRICORN_BERRY_MARANGA = ITEM_MARANGA_BERRY, ++ APRICORN_BROWN = ITEM_BROWN_APRICORN, +}; +``` diff --git a/docs/tutorials/how_to_namebox.md b/docs/tutorials/how_to_namebox.md new file mode 100644 index 0000000000..db059af61d --- /dev/null +++ b/docs/tutorials/how_to_namebox.md @@ -0,0 +1,100 @@ +# How to Use Namebox + +_New implementation made by mudskipper13, originally made by Tustin2121._ + +## Overview + +![Npc Trainers](/docs/tutorials/img/namebox/npc_trainers.gif) +![Pokenav](/docs/tutorials/img/namebox/pokenav.gif) +![Messagebox](/docs/tutorials/img/namebox/msgbox.gif) + +This is a broad and self-contained implementation of Tustin2121's namebox feature branch [here](https://github.com/tustin2121/pokeemerald/tree/feature/namebox), which includes the following: +- Cleaner implementation of namebox onto both the field message box _and_ the field PokéNav textbox. +- New configs: + - `OW_NAME_BOX_USE_DYNAMIC_WIDTH` lets the namebox use dynamic window width depending on the speaker's string length. + - When disabled and/or the speaker name is too long, `OW_NAME_BOX_DEFAULT_WIDTH` will be used as the maximum width. + - `OW_NAME_BOX_NPC_TRAINER` lets any approaching NPC trainers shows a namebox in their dialogue automagically. + - `OW_NAME_BOX_DEFAULT_WIDTH` and `OW_NAME_BOX_DEFAULT_HEIGHT` sets the default width and height. + - `OW_NAME_BOX_FOREGROUND_COLOR` and `OW_NAME_BOX_SHADOW_COLOR` sets the default text colors, the background color is handled by the engine. + - `OW_FLAG_SUPPRESS_NAME_BOX` lets you enable/disable the namebox globally, assign a flag from [`include/constants/flags.h`](/include/constants/flags.h) onto this config to be able to use it. +- Added a Speaker Name table, frequently-used names can be stored into `gSpeakerNamesTable` in [`src/data/speaker_names.h`](/src/data/speaker_names.h) and they can accessed by using a `SP_NAME_*` constant defined in [`include/constants/speaker_names.h`](/include/constants/speaker_names.h). +- Added a new scripting macro `setspeaker ([textPointer]/[SP_NAME_*])`. + - Besides a text pointer, it is possible to use the Speaker Name table to set the textPointer with the `gSpeakerNamesTable` array instead. + - Feed it either `NULL` or `SP_NAME_NONE` will remove the namebox instead. + - `release`, `releaseall`, and `closemessage` will automatically remove the namebox, together with the messagebox. +- Added a new text control code/inline text `{SPEAKER NAME_*}`. + - Unlike the `setspeaker` macro, you can only use the `SP_NAME_*` constants for this. It is partly due to the text engine's limitation itself. + - You'll need to add the constants into `charmap.txt` to be able to use them for the same reason as above. + - Feed it `SP_NAME_NONE` to remove the namebox manually. + - Similarly, `release`, `releaseall`, and `closemessage` will automatically remove the namebox, together with the message box. + +## Usage + +### `setspeaker` +#### Using a text pointer +First, define your speaker's string. +``` +Speaker_Jeremy: + .string "Jeremy$" +``` + +And then in your script, add the `setspeaker` with the speaker's name earlier. +``` +... + setspeaker Speaker_Jeremy +... +``` + +If you are using poryscript, you can also include the string right there with the `setspeaker` aka inline. +``` +... + setspeaker("Jeremy") +... +``` +#### Using a `SP_NAME_*` constant +Add the `setspeaker` with your constant. +``` + setspeaker SP_NAME_JEREMY +``` +For instruction on how to add a new Speaker Name, continue [here](#adding-a-new-speaker-name). + +### `SPEAKER` inline +The usage is identical to using `setspeaker` with `SP_NAME_*` constant, but instead it's within your _text_ script and uses the constant you added to `charmap.txt`. +``` + "{SPEAKER NAME_JEREMY}Yo wassup!" +``` +For instruction on how to add a new Speaker Name, continue [here](#adding-a-new-speaker-name). + +### Adding a new Speaker Name +1. Add a new constant to [`include/constants/speaker_names.h`](/include/constants/speaker_names.h) just after `SP_NAME_NONE` _and_ before `SP_NAME_COUNT`. +```diff + enum SpeakerNames { + SP_NAME_NONE = 0, + SP_NAME_MOM, + SP_NAME_PLAYER, ++ SP_NAME_JEREMY, + SP_NAME_COUNT + }; + +``` + +2. Add an entry to `gSpeakerNamesTable` in [`src/data/speaker_names.h`](/src/data/speaker_names.h) with your newly added constant as the array index. +```diff + const u8 *const gSpeakerNamesTable[SP_NAME_COUNT] = + { + [SP_NAME_MOM] = COMPOUND_STRING("MOM"), + [SP_NAME_PLAYER] = COMPOUND_STRING("{PLAYER}"), ++ [SP_NAME_JEREMY] = COMPOUND_STRING("JEREMY"), + }; +``` + +3. In order for this constant to be usable for `{SPEAKER}` inline, you'll need to add your constant onto [`charmap.txt`](/charmap.txt). **Do note that the order here MUST match with the one in [`include/constants/speaker_names.h`](/include/constants/speaker_names.h)!** +```diff + @ Speaker names, the order must be matching with include/constants/speaker_names.h + NAME_NONE = 00 + NAME_MOM = 01 + NAME_PLAYER = 02 +-NAME_COUNT = 03 ++NAME_JEREMY = 03 ++NAME_COUNT = 04 +``` diff --git a/docs/tutorials/how_to_new_move.md b/docs/tutorials/how_to_new_move.md index 442e2b28c9..0f7ca1d15c 100644 --- a/docs/tutorials/how_to_new_move.md +++ b/docs/tutorials/how_to_new_move.md @@ -93,14 +93,21 @@ Contains more fundamental functions that control the flow of the battle. Functio ### data/battle_scripts_1.s Each move's effect is governed by a script defined here. For a simple example, let's look at the script for Fake Out/First Impression: +TODO: New Script ``` -BattleScript_EffectFirstTurnOnly:: +BattleScript_EffectTaunt:: attackcanceler - jumpifnotfirstturn BattleScript_FailedFromAtkString - goto BattleScript_EffectHit + jumpifability BS_TARGET_SIDE, ABILITY_AROMA_VEIL, BattleScript_AromaVeilProtects + accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE + settaunt BattleScript_ButItFailed + attackanimation + waitanimation + printstring STRINGID_PKMNFELLFORTAUNT + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd ``` -`attackcanceler` is a command that covers all the cases that could cause a move to fail before it's even attempted (e.g. paralysis). And as we can tell from the commands, if it's not the first turn, we go to `BattleScript_FailedFromAtkString` which evidently causes us to print the `attackstring` ("POKEMON used MOVE") then fail ("But it failed!"). Otherwise, we go to the generic "hit" effect which is the same script for moves that just deal damage and nothing else. +`attackcanceler` is a command that covers all cases that could cause a move to fail before it's even attempted (e.g. paralysis). The next command is a jump command. A jump command can check anything and usually comes with a jump instruction. Usually it jumps to a place from where the move should pick up because of certain conditions. The next one is an accuracy check. Accuracy checks happen after all prior move failure checks happened. The next set of commands are unique to a certain move, they are mostly the same for damaging moves but can widely differ for status moves. Lastly there is `BattleScript_MoveEnd` which the move after a succesful hit. An ability activation or specific move effect like Burn, Freeze, Absorb etc. This is the most advanced part of the ROM. There are dozens upon dozens of commands and hundreds of scripts so this guide would go on forever if I were to go into more detail. To learn how these scripts work, it's best to look at a few examples of moves you know. diff --git a/docs/tutorials/how_to_testing_system.md b/docs/tutorials/how_to_testing_system.md index b663ad54b4..53b56bd26b 100644 --- a/docs/tutorials/how_to_testing_system.md +++ b/docs/tutorials/how_to_testing_system.md @@ -164,17 +164,17 @@ ASSUMPTIONS ``` ### `SINGLE_BATTLE_TEST` -`SINGLE_BATTLE_TEST(name, results...)` and `DOUBLE_BATTLE_TEST(name, results...)` -Define single- and double- battles. The names should start with the name of the mechanic being tested so that it is easier to run all the related tests. `results` contains variable declarations to be placed into the `results` array which is available in tests using `PARAMETRIZE` commands. -The main differences for doubles are: +`SINGLE_BATTLE_TEST(name, results...)`, `DOUBLE_BATTLE_TEST(name, results...)`, `MULTI_BATTLE_TEST(name, results...)`, `TWO_VS_ONE_BATTLE_TEST(name, results...)`, and `ONE_VS_TWO_BATTLE_TEST(name, results...)` +Define single-, double-, 2v2-multi-, 2v1-multi-, and 1v2- battles. The names should start with the name of the mechanic being tested so that it is easier to run all the related tests. `results` contains variable declarations to be placed into the `results` array which is available in tests using `PARAMETRIZE` commands. +The main differences for doubles, 2v2, 2v1, and 1v2 are: - Move targets sometimes need to be explicit. - Instead of `player` and `opponent` there is `playerLeft`, `playerRight`, `opponentLeft`, and `opponentRight`. ### `AI_SINGLE_BATTLE_TEST` -`AI_SINGLE_BATTLE_TEST(name, results...)` and `AI_DOUBLE_BATTLE_TEST(name, results...)` +`AI_SINGLE_BATTLE_TEST(name, results...)`, `AI_DOUBLE_BATTLE_TEST(name, results...)`, `AI_MULTI_BATTLE_TEST(name, results...)`, `AI_TWO_VS_ONE_BATTLE_TEST(name, results...)`, and `AI_ONE_VS_TWO_BATTLE_TEST(name, results...)` Define battles where opponent mons are controlled by AI, the same that runs when battling regular Trainers. The flags for AI should be specified by the `AI_FLAGS` command. -The rules remain the same as with the `SINGLE` and `DOUBLE` battle tests with some differences: +The rules remain the same as with the `SINGLE`, `DOUBLE`, `MULTI`, `TWO_VS_ONE`, and `ONE_VS_TWO` battle tests with some differences: - opponent's action is specified by the `EXPECT_MOVE` / `EXPECT_SEND_OUT` / `EXPECT_SWITCH` commands - we don't control what opponent actually does, instead we make sure the opponent does what we expect it to do - we still control the player's action the same way @@ -268,7 +268,7 @@ GIVEN { ``` ### `PLAYER` and `OPPONENT` -`PLAYER(species)` and `OPPONENT(species` +`PLAYER(species)` and `OPPONENT(species)` Adds the species to the player's or opponent's party respectively. The Pokémon can be further customized with the following functions: - `Gender(MON_MALE | MON_FEMALE)` @@ -285,11 +285,29 @@ For example to create a level 42 Wobbuffet that is poisoned: **Note if Speed is specified for any Pokémon then it must be specified for all Pokémon.** **Note if Moves is specified then MOVE will not automatically add moves to the moveset.** +### `MULTI_PLAYER`, `MULTI_PARTNER`, `MULTI_OPPONENT_A`, and `MULTI_OPPONENT_B` +For tests using `MULTI_BATTLE_TEST`, `AI_MULTI_BATTLE_TEST`, `TWO_VS_ONE_BATTLE_TEST`, `AI_TWO_VS_ONE_BATTLE_TEST`, `ONE_VS_TWO_BATTLE_TEST`, and `AI_ONE_VS_TWO_BATTLE_TEST`, the below must be used instead of `PLAYER(species)` and `OPPONENT(species)`. +`MULTI_PLAYER(species)`, `MULTI_PARTNER(species)`, `MULTI_OPPONENT_A(species)`, and `MULTI_OPPONENT_B(species)` +Adds the species to the player's, player partner's, opponent A's, or opponent B's party, respectively. +Pokemon can be customised as per the guidance for `PLAYER(species)` and `OPPONENT(species)`. +The functions assign the Pokémon to the party of the trainer at `B_POSITION_PLAYER_LEFT`, `B_POSITION_PLAYER_RIGHT`, `B_POSITION_OPPONENT_LEFT`, and `B_POSITION_OPPONENT_RIGHT`, respectively. +`MULTI_PLAYER(species)` and `MULTI_OPPONENT_A(species)` set Pokémon starting at party index 0, while `MULTI_PARTNER(species)` and `MULTI_OPPONENT_B(species)` set Pokémon starting at party index 3. +For `ONE_VS_TWO` tests, `MULTI_PLAYER(species)` must be used for all player-side Pokémon, and for `TWO_VS_ONE` tests, `MULTI_OPPONENT_A(species)` must be used for all opponent-side Pokémon. +All `MULTI_PLAYER(species)` Pokémon must be set before any `MULTI_PARTNER(species)` Pokémon, and all `MULTI_OPPONENT_A(species)` must be set before any `MULTI_OPPONENT_B(species)` Pokémon, else Pokémon will be set in the incorrect parties in the test. +**Note where a side in a test has two trainers, the test setup manages the assigning of correct multi-party orders, therefore when using functions such as SEND_OUT, Player and Opponent A Pokémon may be referenced using indexes 0, 1, and 2, and Player's Partner and Opponent B Pokémon may be referenced using indexes 3, 4, and 5.** + ### `AI_FLAGS` `AI_FLAGS(flags)` -Specifies which AI flags are run during the test. Has use only for AI tests. +Specifies which AI flags are run for all battlers during the test. Has use only for AI tests. The most common combination is `AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT)` which is the general 'smart' AI. +### `BATTLER_AI_FLAGS` +`BATTLER_AI_FLAGS(battler, flags)` +Specifies additional AI flags to be applied to specific battlers (battler 0/1/2/3). Has use only for AI tests. +Must be used strictly after `AI_FLAGS(flags)`, which overwrites all existing flags. +Example: `BATTLER_AI_FLAGS(3, AI_FLAG_RISKY)` used after `AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT)` +will set `AI_FLAG_RISKY` to only `battler3` (Opponent B), in addition to the flags set by `AI_FLAGS`. + ### `WHEN` ``` ... diff --git a/docs/tutorials/img/apricorn_tree/apricorn-tree-porymap.png b/docs/tutorials/img/apricorn_tree/apricorn-tree-porymap.png new file mode 100644 index 0000000000..1b75f885da Binary files /dev/null and b/docs/tutorials/img/apricorn_tree/apricorn-tree-porymap.png differ diff --git a/docs/tutorials/img/apricorn_tree/apricorn-tree.gif b/docs/tutorials/img/apricorn_tree/apricorn-tree.gif new file mode 100644 index 0000000000..e7769d87c8 Binary files /dev/null and b/docs/tutorials/img/apricorn_tree/apricorn-tree.gif differ diff --git a/docs/tutorials/img/namebox/msgbox.gif b/docs/tutorials/img/namebox/msgbox.gif new file mode 100644 index 0000000000..a5d9455725 Binary files /dev/null and b/docs/tutorials/img/namebox/msgbox.gif differ diff --git a/docs/tutorials/img/namebox/npc_trainers.gif b/docs/tutorials/img/namebox/npc_trainers.gif new file mode 100644 index 0000000000..6e9e1b13fb Binary files /dev/null and b/docs/tutorials/img/namebox/npc_trainers.gif differ diff --git a/docs/tutorials/img/namebox/pokenav.gif b/docs/tutorials/img/namebox/pokenav.gif new file mode 100644 index 0000000000..6de3f1370d Binary files /dev/null and b/docs/tutorials/img/namebox/pokenav.gif differ diff --git a/graphics/battle_interface/last_used_ball_r_cycle.png b/graphics/battle_interface/last_used_ball_r_cycle.png index 0a73148e15..55b7bc7c0c 100644 Binary files a/graphics/battle_interface/last_used_ball_r_cycle.png and b/graphics/battle_interface/last_used_ball_r_cycle.png differ diff --git a/graphics/field_effects/palettes/oras_dowsing.pal b/graphics/field_effects/palettes/oras_dowsing.pal new file mode 100644 index 0000000000..d3446e3971 --- /dev/null +++ b/graphics/field_effects/palettes/oras_dowsing.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +115 197 164 +0 0 0 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 0 255 diff --git a/graphics/field_effects/pics/oras_dowsing_brendan.png b/graphics/field_effects/pics/oras_dowsing_brendan.png new file mode 100644 index 0000000000..fd83519819 Binary files /dev/null and b/graphics/field_effects/pics/oras_dowsing_brendan.png differ diff --git a/graphics/field_effects/pics/oras_dowsing_may.png b/graphics/field_effects/pics/oras_dowsing_may.png new file mode 100644 index 0000000000..6a4eb08f02 Binary files /dev/null and b/graphics/field_effects/pics/oras_dowsing_may.png differ diff --git a/graphics/object_events/pics/misc/apricorn_tree.png b/graphics/object_events/pics/misc/apricorn_tree.png new file mode 100644 index 0000000000..6267970061 Binary files /dev/null and b/graphics/object_events/pics/misc/apricorn_tree.png differ diff --git a/graphics/pokemon/nickit/front.png b/graphics/pokemon/nickit/front.png index 9aba8f113c..6bcf9854fc 100644 Binary files a/graphics/pokemon/nickit/front.png and b/graphics/pokemon/nickit/front.png differ diff --git a/graphics/pokemon/nickit/normal.pal b/graphics/pokemon/nickit/normal.pal index 487647accd..74565685e7 100644 --- a/graphics/pokemon/nickit/normal.pal +++ b/graphics/pokemon/nickit/normal.pal @@ -5,12 +5,12 @@ JASC-PAL 40 40 32 64 64 48 16 16 16 -136 64 48 +136 64 62 64 24 16 -192 80 24 +193 108 65 216 216 224 -136 120 136 -200 184 0 +159 147 159 +197 148 0 0 0 0 0 0 0 0 0 0 diff --git a/graphics/pokemon/nickit/overworld.png b/graphics/pokemon/nickit/overworld.png index 2b868637e5..206e266190 100644 Binary files a/graphics/pokemon/nickit/overworld.png and b/graphics/pokemon/nickit/overworld.png differ diff --git a/graphics/pokemon/nickit/overworld_normal.pal b/graphics/pokemon/nickit/overworld_normal.pal index faa146c087..ff8c34acea 100644 --- a/graphics/pokemon/nickit/overworld_normal.pal +++ b/graphics/pokemon/nickit/overworld_normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -255 0 25 +128 196 156 8 8 7 -0 0 0 52 51 48 -21 20 18 -121 53 31 -185 90 59 -36 14 7 -255 255 255 -210 184 61 +91 41 25 92 92 92 -0 0 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 +136 59 35 +185 90 59 +210 184 61 +159 147 159 +223 218 223 +255 255 255 +255 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 diff --git a/graphics/pokemon/nickit/overworld_shiny.pal b/graphics/pokemon/nickit/overworld_shiny.pal index 50a8845599..7327a9c8b6 100644 --- a/graphics/pokemon/nickit/overworld_shiny.pal +++ b/graphics/pokemon/nickit/overworld_shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -152 208 160 -0 0 24 -0 0 0 -8 41 115 -0 16 74 -115 106 98 -164 148 139 -24 24 24 +128 196 156 +8 8 7 +51 76 95 +82 75 73 +92 92 92 +122 112 109 +167 154 149 +210 184 61 +159 147 159 +223 218 223 255 255 255 -213 189 57 -90 90 90 -0 0 0 -0 0 0 -0 0 0 -0 0 0 -0 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 diff --git a/graphics/pokemon/thievul/back.png b/graphics/pokemon/thievul/back.png index 7658e0ec22..10b145f4ea 100644 Binary files a/graphics/pokemon/thievul/back.png and b/graphics/pokemon/thievul/back.png differ diff --git a/graphics/pokemon/thievul/front.png b/graphics/pokemon/thievul/front.png index 447aeaf02b..941b0b9a2a 100644 Binary files a/graphics/pokemon/thievul/front.png and b/graphics/pokemon/thievul/front.png differ diff --git a/graphics/pokemon/thievul/normal.pal b/graphics/pokemon/thievul/normal.pal index 3f3b4bf6d1..74565685e7 100644 --- a/graphics/pokemon/thievul/normal.pal +++ b/graphics/pokemon/thievul/normal.pal @@ -2,18 +2,18 @@ JASC-PAL 0100 16 152 208 160 -24 24 16 40 40 32 +64 64 48 16 16 16 -104 56 48 +136 64 62 64 24 16 -192 80 24 -136 120 136 -136 64 48 +193 108 65 216 216 224 -216 136 0 -176 160 184 -80 72 80 +159 147 159 +197 148 0 +0 0 0 +0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/graphics/pokemon/thievul/overworld.png b/graphics/pokemon/thievul/overworld.png index c835302471..53cf0b5b0e 100644 Binary files a/graphics/pokemon/thievul/overworld.png and b/graphics/pokemon/thievul/overworld.png differ diff --git a/graphics/pokemon/thievul/overworld_normal.pal b/graphics/pokemon/thievul/overworld_normal.pal index 764d23bb60..ff8c34acea 100644 --- a/graphics/pokemon/thievul/overworld_normal.pal +++ b/graphics/pokemon/thievul/overworld_normal.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 255 0 +128 196 156 8 8 7 52 51 48 -0 0 0 -121 53 31 -21 20 18 -185 90 59 -36 14 7 -255 255 255 -210 184 61 +91 41 25 92 92 92 -176 176 176 -0 0 0 -0 0 0 -0 0 0 -0 0 0 +136 59 35 +185 90 59 +210 184 61 +159 147 159 +223 218 223 +255 255 255 +255 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 diff --git a/graphics/pokemon/thievul/overworld_shiny.pal b/graphics/pokemon/thievul/overworld_shiny.pal index 6584b3d19e..f2d8cccbaf 100644 --- a/graphics/pokemon/thievul/overworld_shiny.pal +++ b/graphics/pokemon/thievul/overworld_shiny.pal @@ -1,19 +1,19 @@ JASC-PAL 0100 16 -238 255 0 -8 8 0 -8 41 115 -0 0 0 -115 106 98 -0 16 74 -164 148 139 -24 24 24 +128 196 156 +8 8 7 +56 76 139 +78 73 71 +92 92 92 +117 108 106 +159 148 145 +210 184 61 +159 147 159 +223 218 223 255 255 255 -213 189 57 -90 90 90 -180 180 180 -0 0 0 -0 0 0 -0 0 0 -0 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 +255 0 0 diff --git a/graphics/pokemon/thievul/shiny.pal b/graphics/pokemon/thievul/shiny.pal index a6c7735277..dce4bdc484 100644 --- a/graphics/pokemon/thievul/shiny.pal +++ b/graphics/pokemon/thievul/shiny.pal @@ -2,14 +2,14 @@ JASC-PAL 0100 16 152 208 160 -8 24 40 -16 40 64 +37 73 109 +14 62 109 16 16 16 88 80 80 40 40 32 168 160 152 -144 144 120 -128 120 112 +228 228 228 +175 180 191 216 216 200 216 136 0 184 184 168 diff --git a/graphics/pokenav/name_box.png b/graphics/pokenav/name_box.png new file mode 100644 index 0000000000..7c2ed7036b Binary files /dev/null and b/graphics/pokenav/name_box.png differ diff --git a/graphics/text_window/name_box.png b/graphics/text_window/name_box.png new file mode 100644 index 0000000000..735f39247e Binary files /dev/null and b/graphics/text_window/name_box.png differ diff --git a/include/apricorn_tree.h b/include/apricorn_tree.h new file mode 100644 index 0000000000..fc9e95b438 --- /dev/null +++ b/include/apricorn_tree.h @@ -0,0 +1,15 @@ +#ifndef GUARD_APRICORN_TREE_H +#define GUARD_APRICORN_TREE_H + +#include "constants/apricorn_tree.h" + +bool8 IsApricornTreePicked(u32 id); +void SetApricornTreePicked(u32 id); + +void DailyResetApricornTrees(void); +void ObjectEventInteractionGetApricornTreeData(void); +void ObjectEventInteractionPickApricornTree(void); +enum ApricornType GetApricornTypeByApricornTreeId(u32 id); +u8 GetApricornCountByApricornTreeId(u32 id); + +#endif //GUARD_APRICORN_TREE_H diff --git a/include/battle.h b/include/battle.h index 57e92bccef..3cd40cb16b 100755 --- a/include/battle.h +++ b/include/battle.h @@ -2,8 +2,12 @@ #define GUARD_BATTLE_H // should they be included here or included individually by every file? +#include "constants/battle_end_turn.h" +#include "constants/abilities.h" #include "constants/battle.h" #include "constants/form_change_types.h" +#include "constants/hold_effects.h" +#include "constants/moves.h" #include "battle_main.h" #include "battle_message.h" #include "battle_util.h" @@ -98,8 +102,7 @@ struct DisableStruct u8 battlerWithSureHit; u8 isFirstTurn; u8 mimickedMoves:4; - u8 chargeTimer:4; - u8 rechargeTimer; + u8 rechargeTimer:4; u8 autotomizeCount; u16 slowStartTimer; u16 embargoTimer; @@ -114,7 +117,6 @@ struct DisableStruct u8 usedMoves:4; u8 truantCounter:1; u8 truantSwitchInHack:1; - u8 noRetreat:1; u8 tarShot:1; u8 octolock:1; u8 cudChew:1; @@ -124,6 +126,7 @@ struct DisableStruct u8 usedProteanLibero:1; u8 flashFireBoosted:1; u8 boosterEnergyActivated:1; + u8 padding1:1; u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching) u8 roostActive:1; u8 unburdenActive:1; @@ -132,9 +135,10 @@ struct DisableStruct u8 unnerveActivated:1; // Unnerve and As One (Unnerve part) activate only once per switch in u8 hazardsDone:1; u8 endured:1; - u8 octolockedBy:3; u8 tryEjectPack:1; + u8 octolockedBy:3; u8 paradoxBoostedStat:4; + u8 padding2:1; }; // Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects @@ -149,9 +153,8 @@ struct ProtectStruct u32 chargingTurn:1; u32 fleeType:2; // 0: Normal, 1: FLEE_ITEM, 2: FLEE_ABILITY u32 unableToUseMove:1; // Not to be confused with HITMARKER_UNABLE_TO_USE_MOVE (It is questionable though if there is a difference. Needs further research) - u32 notFirstStrike:1; + u32 laggingTail:1; u32 palaceUnableToUseMove:1; - u32 powderSelfDmg:1; u32 statRaised:1; u32 usedCustapBerry:1; // also quick claw u32 touchedProtectLike:1; @@ -165,11 +168,10 @@ struct ProtectStruct u16 usedAllySwitch:1; u16 lashOutAffected:1; // End of 32-bit bitfield - u32 helpingHand:3; + u16 helpingHand:3; u16 assuranceDoubled:1; u16 myceliumMight:1; - u16 laggingTail:1; - u16 padding:10; + u16 padding:11; // End of 16-bit bitfield u16 physicalDmg; u16 specialDmg; @@ -184,20 +186,20 @@ struct SpecialStatus s32 specialDmg; u8 changedStatsBattlerId; // Battler that was responsible for the latest stat change. Can be self. u8 statLowered:1; - u8 lightningRodRedirected:1; + u8 abilityRedirected:1; u8 restoredBattlerSprite: 1; u8 faintedHasReplacement:1; - u8 preventLifeOrbDamage:1; // So that Life Orb doesn't activate various effects. u8 afterYou:1; u8 enduredDamage:1; - u8 stormDrainRedirected:1; + u8 dancerUsedMove:1; + u8 padding1:1; // End of byte u8 switchInAbilityDone:1; u8 switchInItemDone:1; u8 instructedChosenTarget:3; u8 berryReduced:1; u8 neutralizingGasRemoved:1; // See VARIOUS_TRY_END_NEUTRALIZING_GAS - u8 padding:1; + u8 padding2:1; // End of byte u8 gemParam; // End of byte @@ -209,9 +211,8 @@ struct SpecialStatus u8 teraShellAbilityDone:1; u8 criticalHit:1; // End of byte - u8 dancerUsedMove:1; u8 dancerOriginalTarget:3; - u8 unused:4; + u8 padding3:5; // End of byte }; @@ -234,7 +235,7 @@ struct SideTimer u8 followmePowder:1; // Rage powder, does not affect grass type pokemon. u8 retaliateTimer; u16 damageNonTypesTimer; - u8 damageNonTypesType; + enum Type damageNonTypesType; u16 rainbowTimer; u16 seaOfFireTimer; u16 swampTimer; @@ -266,12 +267,12 @@ struct WishFutureKnock struct AI_SavedBattleMon { - u16 ability; + enum Ability ability; u16 moves[MAX_MON_MOVES]; u16 heldItem; u16 species:15; u16 saved:1; - u8 types[3]; + enum Type types[3]; }; struct AiPartyMon @@ -279,7 +280,7 @@ struct AiPartyMon u16 species; u16 item; u16 heldEffect; - u16 ability; + enum Ability ability; u16 level; u16 moves[MAX_MON_MOVES]; u32 status; @@ -312,7 +313,7 @@ struct SimulatedDamage // Ai Data used when deciding which move to use, computed only once before each turn's start. struct AiLogicData { - u16 abilities[MAX_BATTLERS_COUNT]; + enum Ability abilities[MAX_BATTLERS_COUNT]; u16 items[MAX_BATTLERS_COUNT]; u16 holdEffects[MAX_BATTLERS_COUNT]; u8 holdEffectParams[MAX_BATTLERS_COUNT]; @@ -356,7 +357,7 @@ struct AiThinkingStruct struct BattleHistory { - u16 abilities[MAX_BATTLERS_COUNT]; + enum Ability abilities[MAX_BATTLERS_COUNT]; u8 itemEffects[MAX_BATTLERS_COUNT]; u16 usedMoves[MAX_BATTLERS_COUNT][MAX_MON_MOVES]; u16 moveHistory[MAX_BATTLERS_COUNT][AI_MOVE_HISTORY_COUNT]; // 3 last used moves for each battler @@ -583,10 +584,11 @@ struct BattlerState u32 pursuitTarget:1; u32 stompingTantrumTimer:2; u32 canPickupItem:1; - u32 itemCanBeKnockedOff:1; u32 ateBoost:1; + u32 wasAboveHalfHp:1; // For Berserk, Emergency Exit, Wimp Out and Anger Shell. u32 commanderSpecies:11; - u32 padding:4; + u32 selectionScriptFinished:1; + u32 padding:3; // End of Word }; @@ -602,6 +604,23 @@ struct PartyState u32 changedSpecies:11; // For forms when multiple mons can change into the same pokemon. u32 sentOut:1; u32 padding:9; + u16 usedHeldItem; +}; + +struct EventStates +{ + enum EndTurnResolutionOrder endTurn:8; + u32 endTurnBlock:8; // FirstEventBlock, SecondEventBlock, ThirdEventBlock + enum BattlerId endTurnBattler:4; + u32 arenaTurn:8; + enum BattleSide battlerSide:4; + enum BattlerId moveEndBattler:4; + enum FirstTurnEventsStates beforeFristTurn:8; + enum FaintedActions faintedAction:8; + enum BattlerId faintedActionBattler:4; + enum MoveSuccessOrder atkCanceler:8; + enum BattleIntroStates battleIntro:8; + u32 padding:24; }; // Cleared at the beginning of the battle. Fields need to be cleared when needed manually otherwise. @@ -609,10 +628,7 @@ struct BattleStruct { struct BattlerState battlerState[MAX_BATTLERS_COUNT]; struct PartyState partyState[NUM_BATTLE_SIDES][PARTY_SIZE]; - u8 eventBlockCounter; - u8 turnEffectsBattlerId; - u8 endTurnEventsCounter; - u16 wrappedMove[MAX_BATTLERS_COUNT]; + struct EventStates eventState; u16 moveTarget[MAX_BATTLERS_COUNT]; u32 expShareExpValue; u32 expValue; @@ -624,18 +640,13 @@ struct BattleStruct u8 givenExpMons; // Bits for enemy party's pokemon that gave exp to player's party. u8 expSentInMons; // As bits for player party mons - not including exp share mons. u8 wildVictorySong; - u8 dynamicMoveType; - u8 wrappedBy[MAX_BATTLERS_COUNT]; + enum Type dynamicMoveType; u8 battlerPreventingSwitchout; u8 moneyMultiplier:6; u8 moneyMultiplierItem:1; u8 moneyMultiplierMove:1; u8 savedTurnActionNumber; - u8 eventsBeforeFirstTurnState; - u8 faintedActionsState; - u8 faintedActionsBattlerId; u8 scriptPartyIdx; // for printing the nickname - bool8 selectionScriptFinished[MAX_BATTLERS_COUNT]; u8 battlerPartyIndexes[MAX_BATTLERS_COUNT]; u8 monToSwitchIntoId[MAX_BATTLERS_COUNT]; u8 battlerPartyOrders[MAX_BATTLERS_COUNT][PARTY_SIZE / 2]; @@ -667,32 +678,26 @@ struct BattleStruct u8 multipleSwitchInState:2; u8 multipleSwitchInCursor:3; u8 sleepClauseNotBlocked:1; - u8 moldBreakerActive:1; + u8 isSkyBattle:1; u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT]; void (*savedCallback)(void); - u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle u16 chosenItem[MAX_BATTLERS_COUNT]; u16 choicedMove[MAX_BATTLERS_COUNT]; u16 changedItems[MAX_BATTLERS_COUNT]; u8 switchInBattlerCounter; - u8 arenaTurnCounter; - u8 turnSideTracker; u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker] union { struct LinkBattlerHeader linkBattlerHeader; struct BattleVideo battleVideo; } multiBuffer; - u8 startingStatus:6; // status to apply at battle start. defined in constants/battle.h - u8 startingStatusDone:1; - u8 terrainDone:1; - u8 overworldWeatherDone:1; + u8 startingStatus; // status to apply at battle start. defined in constants/battle.h u8 battlerKOAnimsRunning:3; - u8 isAtkCancelerForCalledMove:1; // Certain cases in atk canceler should only be checked once, when the original move is called, however others need to be checked the twice. u8 friskedAbility:1; // If identifies two mons, show the ability pop-up only once. u8 fickleBeamBoosted:1; u8 poisonPuppeteerConfusion:1; + u8 toxicChainPriority:1; // If Toxic Chain will trigger on target, all other non volatiles will be blocked + u8 moldBreakerActive:1; u16 startingStatusTimer; - u8 atkCancelerTracker; struct BattleTvMovePoints tvMovePoints; struct BattleTv tv; u8 AI_monToSwitchIntoId[MAX_BATTLERS_COUNT]; @@ -704,7 +709,6 @@ struct BattleStruct u8 debugBattler; u8 magnitudeBasePower; u8 presentBasePower; - u8 roostTypes[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES]; u8 savedBattlerTarget[5]; u8 savedBattlerAttacker[5]; u8 savedTargetCount:4; @@ -714,11 +718,9 @@ struct BattleStruct struct DynamaxData dynamax; struct BattleGimmickData gimmick; const u8 *trainerSlideMsg; - enum BattleIntroStates introState:8; u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct - u16 tracedAbility[MAX_BATTLERS_COUNT]; - u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell. + enum Ability tracedAbility[MAX_BATTLERS_COUNT]; struct Illusion illusion[MAX_BATTLERS_COUNT]; u8 soulheartBattlerId; u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles. @@ -735,7 +737,6 @@ struct BattleStruct u8 throwingPokeBall:1; u8 ballSpriteIds[2]; // item gfx, window gfx u8 moveInfoSpriteId; // move info, window gfx - u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. // When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without. u16 beatUpSpecies[PARTY_SIZE]; // Species for Gen5+ Beat Up, otherwise party indexes @@ -747,11 +748,9 @@ struct BattleStruct u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies. u8 itemPartyIndex[MAX_BATTLERS_COUNT]; u8 itemMoveIndex[MAX_BATTLERS_COUNT]; - u8 isSkyBattle:1; s32 aiDelayTimer; // Counts number of frames AI takes to choose an action. s32 aiDelayFrames; // Number of frames it took to choose an action. s32 aiDelayCycles; // Number of cycles it took to choose an action. - u8 stickySyrupdBy[MAX_BATTLERS_COUNT]; u8 supremeOverlordCounter[MAX_BATTLERS_COUNT]; u8 shellSideArmCategory[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; u8 speedTieBreaks; // MAX_BATTLERS_COUNT! values. @@ -764,6 +763,7 @@ struct BattleStruct u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch s32 battlerExpReward; u16 prevTurnSpecies[MAX_BATTLERS_COUNT]; // Stores species the AI has in play at start of turn + s16 passiveHpUpdate[MAX_BATTLERS_COUNT]; // non-move damage and healing s16 moveDamage[MAX_BATTLERS_COUNT]; s16 critChance[MAX_BATTLERS_COUNT]; u16 moveResultFlags[MAX_BATTLERS_COUNT]; @@ -775,15 +775,19 @@ struct BattleStruct u8 printedStrongWindsWeakenedAttack:1; u8 numSpreadTargets:2; u8 noTargetPresent:1; - u8 cheekPouchActivated:1; - s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg + u8 padding2:1; struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; u8 hazardsQueue[NUM_BATTLE_SIDES][HAZARDS_MAX_COUNT]; u8 numHazards[NUM_BATTLE_SIDES]; u8 hazardsCounter:4; // Counter for applying hazard on switch in + enum SubmoveState submoveAnnouncement:2; + u8 tryDestinyBond:1; + u8 tryGrudge:1; + u16 flingItem; u8 incrementEchoedVoice:1; u8 echoedVoiceCounter:3; + u8 padding3:4; }; struct AiBattleData @@ -827,7 +831,7 @@ static inline bool32 IsBattleMoveStatus(u32 move) * times with one type because it shares the 'GetBattlerTypes' result. */ #define _IS_BATTLER_ANY_TYPE(battler, ignoreTera, ...) \ ({ \ - u32 types[3]; \ + enum Type types[3]; \ GetBattlerTypes(battler, ignoreTera, types); \ RECURSIVELY(R_FOR_EACH(_IS_BATTLER_ANY_TYPE_HELPER, __VA_ARGS__)) FALSE; \ }) @@ -841,7 +845,7 @@ static inline bool32 IsBattleMoveStatus(u32 move) #define IS_BATTLER_TYPELESS(battlerId) \ ({ \ - u32 types[3]; \ + enum Type types[3]; \ GetBattlerTypes(battlerId, FALSE, types); \ types[0] == TYPE_MYSTERY && types[1] == TYPE_MYSTERY && types[2] == TYPE_MYSTERY; \ }) @@ -905,7 +909,7 @@ struct BattleScripting s32 savedDmg; u16 unused_0x2c; u16 moveEffect; - u16 multihitMoveEffect; + u16 unused_0x30; u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN. bool8 fixedPopup; // Force ability popup to stick until manually called back u16 abilityPopupOverwrite; @@ -1052,7 +1056,7 @@ extern u16 gChosenMove; extern u16 gCalledMove; extern s32 gBideDmg[MAX_BATTLERS_COUNT]; extern u16 gLastUsedItem; -extern u16 gLastUsedAbility; +extern enum Ability gLastUsedAbility; extern u8 gBattlerAttacker; extern u8 gBattlerTarget; extern u8 gBattlerFainted; @@ -1188,7 +1192,7 @@ static inline u32 GetBattlerSide(u32 battler) return GetBattlerPosition(battler) & BIT_SIDE; } -static inline u32 IsOnPlayerSide(u32 battler) +static inline bool32 IsOnPlayerSide(u32 battler) { return GetBattlerSide(battler) == B_SIDE_PLAYER; } @@ -1209,7 +1213,7 @@ static inline struct Pokemon* GetBattlerMon(u32 battler) return !IsOnPlayerSide(battler) ? &gEnemyParty[index] : &gPlayerParty[index]; } -static inline struct Pokemon *GetSideParty(u32 side) +static inline struct Pokemon *GetSideParty(enum BattleSide side) { return side == B_SIDE_PLAYER ? gPlayerParty : gEnemyParty; } @@ -1226,7 +1230,7 @@ static inline struct PartyState *GetBattlerPartyState(u32 battler) static inline bool32 IsDoubleBattle(void) { - return gBattleTypeFlags & BATTLE_TYPE_DOUBLE; + return (gBattleTypeFlags & BATTLE_TYPE_MORE_THAN_TWO_BATTLERS); } static inline bool32 IsSpreadMove(u32 moveTarget) @@ -1237,7 +1241,7 @@ static inline bool32 IsSpreadMove(u32 moveTarget) static inline bool32 IsDoubleSpreadMove(void) { return gBattleStruct->numSpreadTargets > 1 - && !(gHitMarker & (HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE | HITMARKER_UNABLE_TO_USE_MOVE)) + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && IsSpreadMove(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove)); } @@ -1253,4 +1257,18 @@ static inline u32 GetChosenMoveFromPosition(u32 battler) return gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; } +static inline void SetPassiveDamageAmount(u32 battler, s32 value) +{ + if (value == 0) + value = 1; + gBattleStruct->passiveHpUpdate[battler] = value; +} + +static inline void SetHealAmount(u32 battler, s32 value) +{ + if (value == 0) + value = 1; + gBattleStruct->passiveHpUpdate[battler] = -1 * value; +} + #endif // GUARD_BATTLE_H diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index b3bc57c4e9..4330f9d2bc 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -23,6 +23,11 @@ enum StatChange STAT_CHANGE_SPEED_2, STAT_CHANGE_SPATK_2, STAT_CHANGE_SPDEF_2, + STAT_CHANGE_ATK_3, + STAT_CHANGE_DEF_3, + STAT_CHANGE_SPEED_3, + STAT_CHANGE_SPATK_3, + STAT_CHANGE_SPDEF_3, STAT_CHANGE_ACC, STAT_CHANGE_EVASION }; diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_script_commands.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/include/battle_ai_switch_items.h b/include/battle_ai_switch_items.h index b91d452097..7612d2084a 100644 --- a/include/battle_ai_switch_items.h +++ b/include/battle_ai_switch_items.h @@ -38,14 +38,15 @@ enum ShouldSwitchScenario enum SwitchType { SWITCH_AFTER_KO, - SWITCH_MID_BATTLE, + SWITCH_MID_BATTLE_FORCED, + SWITCH_MID_BATTLE_OPTIONAL, }; void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId); void AI_TrySwitchOrUseItem(u32 battler); u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType); bool32 ShouldSwitch(u32 battler); -bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2); +bool32 IsMonGrounded(enum HoldEffect heldItemEffect, enum Ability ability, enum Type type1, enum Type type2); void ModifySwitchAfterMoveScoring(u32 battler); #endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 46e1e2d7b7..2c87608935 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -4,8 +4,6 @@ #include "battle_ai_main.h" #include "battle_ai_field_statuses.h" -#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE) - // Roll boundaries used by AI when scoring. Doesn't affect actual damage dealt. #define MAX_ROLL_PERCENTAGE DMG_ROLL_PERCENT_HI #define MIN_ROLL_PERCENTAGE DMG_ROLL_PERCENT_LO @@ -76,6 +74,7 @@ bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 aiMove, u32 playerMove, en bool32 AI_IsPartyMonFaster(u32 battlerAi, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 aiMove, u32 playerMove, enum ConsiderPriority considerPriority); bool32 AI_IsPartyMonSlower(u32 battlerAi, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 aiMove, u32 playerMove, enum ConsiderPriority considerPriority); bool32 AI_RandLessThan(u32 val); +bool32 AI_IsBattlerGrounded(u32 battler); u32 AI_GetDamage(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcContext calcContext, struct AiLogicData *aiData); bool32 IsAiVsAiBattle(void); bool32 BattlerHasAi(u32 battlerId); @@ -88,9 +87,9 @@ void ClearBattlerMoveHistory(u32 battlerId); void RecordLastUsedMoveBy(u32 battlerId, u32 move); void RecordAllMoves(u32 battler); void RecordKnownMove(u32 battlerId, u32 move); -void RecordAbilityBattle(u32 battlerId, u32 abilityId); +void RecordAbilityBattle(u32 battlerId, enum Ability abilityId); void ClearBattlerAbilityHistory(u32 battlerId); -void RecordItemEffectBattle(u32 battlerId, u32 itemEffect); +void RecordItemEffectBattle(u32 battlerId, enum HoldEffect itemEffect); void ClearBattlerItemEffectHistory(u32 battlerId); void SaveBattlerData(u32 battlerId); void SetBattlerData(u32 battlerId); @@ -110,32 +109,35 @@ u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef, enum DamageCalcCon u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget, enum DamageCalcContext calcContext); bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits); bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod); -s32 AI_DecideKnownAbilityForTurn(u32 battlerId); -enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId); -bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move); +enum Ability AI_DecideKnownAbilityForTurn(u32 battlerId); +enum HoldEffect AI_DecideHoldEffectForTurn(u32 battlerId); +bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, enum Ability atkAbility, u32 move); u32 AI_GetWeather(void); u32 AI_GetSwitchinWeather(struct BattlePokemon battleMon); enum WeatherState IsWeatherActive(u32 flags); bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits); bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, enum DamageCalcContext calcContext); -bool32 HasDamagingMove(u32 battlerId); -bool32 HasDamagingMoveOfType(u32 battlerId, u32 type); +bool32 HasDamagingMove(u32 battler); +bool32 HasDamagingMoveOfType(u32 battler, enum Type type); u32 GetBattlerSecondaryDamage(u32 battlerId); -bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability); -bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability); -bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move); +bool32 BattlerWillFaintFromWeather(u32 battler, enum Ability ability); +bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, enum Ability ability); +bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, enum Ability defAbility, u32 move); bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 moveIndex); bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage); bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent); bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects moveEffect); -enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex); +bool32 ShouldCureStatus(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); +bool32 ShouldCureStatusWithItem(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); +enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 moveIndex); bool32 IsRecycleEncouragedItem(u32 item); bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item); bool32 IsStatBoostingBerry(u32 item); bool32 CanKnockOffItem(u32 battler, u32 item); -bool32 IsAbilityOfRating(u32 ability, s8 rating); -bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); -bool32 AI_MoveMakesContact(u32 ability, enum ItemHoldEffect holdEffect, u32 move); +bool32 IsAbilityOfRating(enum Ability ability, s8 rating); +bool32 AI_IsAbilityOnSide(u32 battlerId, enum Ability ability); +bool32 AI_MoveMakesContact(enum Ability ability, enum HoldEffect holdEffect, u32 move); +bool32 IsConsideringZMove(u32 battlerAtk, u32 battlerDef, u32 move); bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove); void SetAIUsingGimmick(u32 battler, enum AIConsiderGimmick use); bool32 IsAIUsingGimmick(u32 battler); @@ -144,13 +146,14 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move); // stat stage checks bool32 AnyStatIsRaised(u32 battlerId); -bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, u32 stat); -bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat); +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, enum Stat stat); +bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, enum Stat stat); bool32 AreBattlersStatsMaxed(u32 battler); u32 CountPositiveStatStages(u32 battlerId); u32 CountNegativeStatStages(u32 battlerId); // move checks +bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData); bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category); enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo); struct SimulatedDamage AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef); @@ -166,9 +169,10 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef); u16 *GetMovesArray(u32 battler); bool32 IsConfusionMoveEffect(enum BattleMoveEffects moveEffect); bool32 HasMove(u32 battlerId, u32 move); +u32 GetIndexInMoveArray(u32 battler, u32 move); bool32 HasOnlyMovesWithCategory(u32 battlerId, enum DamageCategory category, bool32 onlyOffensive); bool32 HasMoveWithCategory(u32 battler, enum DamageCategory category); -bool32 HasMoveWithType(u32 battler, u32 type); +bool32 HasMoveWithType(u32 battler, enum Type type); bool32 HasMoveWithEffect(u32 battler, enum BattleMoveEffects moveEffect); bool32 HasMoveWithAIEffect(u32 battler, u32 aiEffect); bool32 HasBattlerSideMoveWithEffect(u32 battler, u32 effect); @@ -181,15 +185,16 @@ bool32 HasBattlerSideMoveWithAdditionalEffect(u32 battler, u32 moveEffect); bool32 HasMoveWithCriticalHitChance(u32 battlerId); bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, enum BattleMoveEffects exception); bool32 HasMoveThatLowersOwnStats(u32 battlerId); -bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); +bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus); bool32 HasAnyKnownMove(u32 battlerId); bool32 IsAromaVeilProtectedEffect(enum BattleMoveEffects moveEffect); bool32 IsNonVolatileStatusMove(u32 moveEffect); -bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility); +bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, enum Ability atkAbility); bool32 IsHazardMove(u32 move); bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move); bool32 IsBattlerDamagedByStatus(u32 battler); s32 ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove); +bool32 ShouldRaiseAnyStat(u32 battlerAtk, u32 battlerDef); bool32 ShouldSetWeather(u32 battler, u32 weather); bool32 ShouldClearWeather(u32 battler, u32 weather); bool32 ShouldSetFieldStatus(u32 battler, u32 fieldStatus); @@ -215,38 +220,38 @@ bool32 IsHazardClearingMove(u32 move); bool32 IsSubstituteEffect(enum BattleMoveEffects effect); // status checks -bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability); -bool32 IsBattlerIncapacitated(u32 battler, u32 ability); -bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove); +bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability ability); +bool32 IsBattlerIncapacitated(u32 battler, enum Ability ability); +bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove); bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef); -bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove); -bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove); -bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); -bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef, u32 abilityDef); -bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef); -bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, u32 abilityDef); -bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); -bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); -bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility); +bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove); +bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove); +bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); +bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); +bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); +bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove); +bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, enum Ability defAbility); bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof); -u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move); +u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, enum Ability defAbility, u32 move); bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move); bool32 IsWakeupTurn(u32 battler); bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId); // ability logic -bool32 IsMoxieTypeAbility(u32 ability); -bool32 DoesAbilityRaiseStatsWhenLowered(u32 ability); -bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, u32 ability); -bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct AiLogicData *aiData); -void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, struct AiLogicData *aiData); -s32 BattlerBenefitsFromAbilityScore(u32 battler, u32 ability, struct AiLogicData *aiData); +bool32 IsMoxieTypeAbility(enum Ability ability); +bool32 DoesAbilityRaiseStatsWhenLowered(enum Ability ability); +bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability); +bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData); +void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score, struct AiLogicData *aiData); +s32 BattlerBenefitsFromAbilityScore(u32 battler, enum Ability ability, struct AiLogicData *aiData); // partner logic bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef); // IsTargetingPartner includes a check to make sure the adjacent pokemon is truly a partner. u32 GetAllyChosenMove(u32 battlerId); -bool32 IsBattle1v1(); +bool32 IsBattle1v1(void); // IsBattle1v1 is distinct from !IsDoubleBattle. If the player is fighting Maxie and Tabitha, with Steven as their partner, and both Tabitha and Steven have run out of Pokemon, the battle is 1v1, even though mechanically it is a Double Battle for how battlers and flags are set. // Most AI checks should be using IsBattle1v1; most engine checks should be using !IsDoubleBattle bool32 HasTwoOpponents(u32 battler); @@ -277,7 +282,7 @@ bool32 SideHasMoveCategory(u32 battlerId, enum DamageCategory category); // score increases u32 IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, enum StatChange statId); u32 IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, enum StatChange statId); -u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat); +u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, enum Stat stat); void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); @@ -285,7 +290,7 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); -s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, enum DamageCalcContext calcContext); +s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, uq4_12_t *effectiveness, enum DamageCalcContext calcContext); u32 AI_WhoStrikesFirstPartyMon(u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, u32 aiMoveConsidered, u32 playerMoveConsidered, enum ConsiderPriority ConsiderPriority); s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle); bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef); @@ -297,8 +302,6 @@ bool32 IsBattlerItemEnabled(u32 battler); bool32 IsBattlerPredictedToSwitch(u32 battler); u32 GetIncomingMove(u32 battler, u32 opposingBattler, struct AiLogicData *aiData); u32 GetIncomingMoveSpeedCheck(u32 battler, u32 opposingBattler, struct AiLogicData *aiData); -bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef); -bool32 HasBattlerSideAbility(u32 battlerDef, u32 ability, struct AiLogicData *aiData); bool32 IsNaturalEnemy(u32 speciesAttacker, u32 speciesTarget); // These are for the purpose of not doubling up on moves during double battles. @@ -308,7 +311,7 @@ bool32 IsNaturalEnemy(u32 speciesAttacker, u32 speciesTarget); #define AI_EFFECT_TERRAIN (1 << 1) #define AI_EFFECT_CLEAR_HAZARDS (1 << 2) #define AI_EFFECT_BREAK_SCREENS (1 << 3) -#define AI_EFFECT_RESET_STATS (1 << 4) +#define AI_EFFECT_RESET_STATS (1 << 4) #define AI_EFFECT_FORCE_SWITCH (1 << 5) #define AI_EFFECT_TORMENT (1 << 6) #define AI_EFFECT_LIGHT_SCREEN (1 << 7) diff --git a/include/battle_anim.h b/include/battle_anim.h index 7cef5445da..2c8631e899 100644 --- a/include/battle_anim.h +++ b/include/battle_anim.h @@ -211,7 +211,8 @@ u8 GetSubstituteSpriteDefault_Y(u8 battler); #define STAT_ANIM_MULTIPLE_MINUS1 57 #define STAT_ANIM_MULTIPLE_MINUS2 58 -enum { +enum StatAnimPal +{ STAT_ANIM_PAL_ATK, STAT_ANIM_PAL_DEF, STAT_ANIM_PAL_ACC, diff --git a/include/battle_anim_scripts.h b/include/battle_anim_scripts.h index 0bffbda8ea..193696375d 100644 --- a/include/battle_anim_scripts.h +++ b/include/battle_anim_scripts.h @@ -948,6 +948,7 @@ extern const u8 gBattleAnimStatus_Paralysis[]; extern const u8 gBattleAnimStatus_Freeze[]; extern const u8 gBattleAnimStatus_Curse[]; extern const u8 gBattleAnimStatus_Nightmare[]; +extern const u8 gBattleAnimStatus_Frostbite[]; // general animations extern const u8 gBattleAnimGeneral_StatsChange[]; diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 4728c17a84..c3b5fff97f 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -203,7 +203,7 @@ struct ChooseMoveStruct u8 currentPp[MAX_MON_MOVES]; u8 maxPp[MAX_MON_MOVES]; u16 species; - u8 monTypes[3]; + enum Type monTypes[3]; struct ZMoveData zmove; }; @@ -364,7 +364,7 @@ void BtlController_HandleSpriteInvisibility(u32 battler); bool32 TwoPlayerIntroMons(u32 battlerId); // Double battle with both player pokemon active. bool32 TwoOpponentIntroMons(u32 battlerId); // Double battle with both opponent pokemon active. void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, const u16 *trainerPal, s16 framesToWait, void (*controllerCallback)(u32 battler)); -void BtlController_HandleDrawPartyStatusSummary(u32 battler, u32 side, bool32 considerDelay); +void BtlController_HandleDrawPartyStatusSummary(u32 battler, enum BattleSide side, bool32 considerDelay); void BtlController_HandleHidePartyStatusSummary(u32 battler); void BtlController_HandleBattleAnimation(u32 battler); @@ -395,6 +395,10 @@ void HandleChooseMoveAfterDma3(u32 battler); void SetControllerToRecordedPlayer(u32 battler); void RecordedPlayerBufferExecCompleted(u32 battler); +// recorded partner controller +void SetControllerToRecordedPartner(u32 battler); +void RecordedPartnerBufferExecCompleted(u32 battler); + // opponent controller void SetControllerToOpponent(u32 battler); void OpponentBufferExecCompleted(u32 battler); @@ -437,4 +441,7 @@ void BtlController_HandleSwitchInTryShinyAnim(u32 battler); void BtlController_HandleSwitchInSoundAndEnd(u32 battler); void BtlController_HandleSwitchInShowSubstitute(u32 battler); +bool32 ShouldBattleRestrictionsApply(u32 battler); +void FreeShinyStars(void); + #endif // GUARD_BATTLE_CONTROLLERS_H diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index ed295bb1e6..d9fa48706d 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -5,18 +5,17 @@ bool32 CanDynamax(u32 battler); bool32 IsGigantamaxed(u32 battler); -void ApplyDynamaxHPMultiplier(struct Pokemon* mon); +void ApplyDynamaxHPMultiplier(struct Pokemon *mon); void ActivateDynamax(u32 battler); u16 GetNonDynamaxHP(u32 battler); u16 GetNonDynamaxMaxHP(u32 battler); void UndoDynamax(u32 battler); bool32 IsMoveBlockedByMaxGuard(u32 move); -bool32 IsMoveBlockedByDynamax(u32 move); u16 GetMaxMove(u32 battler, u32 baseMove); u32 GetMaxMovePower(u32 move); bool32 IsMaxMove(u32 move); -void ChooseDamageNonTypesString(u8 type); +void ChooseDamageNonTypesString(enum Type type); void BS_UpdateDynamax(void); void BS_SetSteelsurge(void); diff --git a/include/battle_environment.h b/include/battle_environment.h index e9435aa454..f4870f795c 100644 --- a/include/battle_environment.h +++ b/include/battle_environment.h @@ -4,11 +4,11 @@ #include "constants/battle.h" #include "battle_bg.h" -struct BattleEnvironment { - u8 name[26]; +struct BattleEnvironment +{ u16 naturePower; u16 secretPowerEffect; - u8 camouflageType; + enum Type camouflageType; struct BattleBackground background; }; diff --git a/include/battle_hold_effects.h b/include/battle_hold_effects.h new file mode 100644 index 0000000000..51e63ea20a --- /dev/null +++ b/include/battle_hold_effects.h @@ -0,0 +1,52 @@ +#ifndef GUARD_BATTLE_HOLD_EFFECTS +#define GUARD_BATTLE_HOLD_EFFECTS + +struct HoldEffectInfo +{ + u32 onSwitchIn:1; + u32 onSwitchInFirstTurn:1; + u32 mirrorHerb:1; + u32 mirrorHerbFirstTurn:1; + u32 whiteHerb:1; + u32 whiteHerbFirstTurn:1; + u32 whiteHerbEndTurn:1; + u32 onStatusChange:1; + u32 onHpThreshold:1; + u32 keeMarangaBerry:1; + u32 MentalHerb:1; + u32 onTargetAfterHit:1; + u32 onAttackerAfterHit:1; + u32 lifeOrbShellBell:1; + u32 leftovers:1; + u32 orbs:1; + u32 onEffect:1; + u32 onFling:1; + u32 padding:14; +}; + +extern const struct HoldEffectInfo gHoldEffectsInfo[]; + +typedef bool32 (*ActivationTiming)(enum HoldEffect holdEffect); +enum ItemEffect ItemBattleEffects(u32 primaryBattler, u32 secondaryBattler, enum HoldEffect holdEffect, ActivationTiming timing); + +bool32 IsOnSwitchInActivation(enum HoldEffect holdEffect); +bool32 IsOnSwitchInFirstTurnActivation(enum HoldEffect holdEffect); +bool32 IsMirrorHerbActivation(enum HoldEffect holdEffect); +bool32 IsMirrorHerbFirstTurnActivation(enum HoldEffect holdEffect); +bool32 IsWhiteHerbActivation(enum HoldEffect holdEffect); +bool32 IsWhiteHerbFirstTurnActivation(enum HoldEffect holdEffect); +bool32 IsWhiteHerbEndTurnActivation(enum HoldEffect holdEffect); +bool32 IsOnStatusChangeActivation(enum HoldEffect holdEffect); +bool32 IsOnHpThresholdActivation(enum HoldEffect holdEffect); +bool32 IsKeeMarangaBerryActivation(enum HoldEffect holdEffect); +bool32 IsOnTargetHitActivation(enum HoldEffect holdEffect); +bool32 IsOnAttackerAfterHitActivation(enum HoldEffect holdEffect); +bool32 IsLifeOrbShellBellActivation(enum HoldEffect holdEffect); +bool32 IsLeftoversActivation(enum HoldEffect holdEffect); +bool32 IsOrbsActivation(enum HoldEffect holdEffect); +bool32 IsOnEffectActivation(enum HoldEffect holdEffect); +bool32 IsForceTriggerItemActivation(enum HoldEffect holdEffect); +bool32 IsOnBerryActivation(enum HoldEffect holdEffect); +bool32 IsOnFlingActivation(enum HoldEffect holdEffect); + +#endif // GUARD_BATTLE_HOLD_EFFECTS diff --git a/include/battle_interface.h b/include/battle_interface.h index 5bc1e10aa7..ea5559d165 100644 --- a/include/battle_interface.h +++ b/include/battle_interface.h @@ -126,7 +126,7 @@ void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elem s32 MoveBattleBar(u8 battler, u8 healthboxSpriteId, u8 whichBar, u8 unused); u8 GetScaledHPFraction(s16 hp, s16 maxhp, u8 scale); u8 GetHPBarLevel(s16 hp, s16 maxhp); -void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle); +void CreateAbilityPopUp(u8 battlerId, enum Ability ability, bool32 isDoubleBattle); void DestroyAbilityPopUp(u8 battlerId); bool32 CanThrowLastUsedBall(void); void TryHideLastUsedBall(void); diff --git a/include/battle_main.h b/include/battle_main.h index bf8e88fc5d..c08da1d9ca 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -1,6 +1,7 @@ #ifndef GUARD_BATTLE_MAIN_H #define GUARD_BATTLE_MAIN_H +#include "battle_util.h" #include "pokemon.h" #include "data.h" #include "constants/hold_effects.h" @@ -57,9 +58,10 @@ enum FirstTurnEventsStates FIRST_TURN_EVENTS_TOTEM_BOOST, FIRST_TURN_EVENTS_NEUTRALIZING_GAS, FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES, - FIRST_TURN_EVENTS_OPPORTUNIST_1, FIRST_TURN_EVENTS_ITEM_EFFECTS, - FIRST_TURN_EVENTS_OPPORTUNIST_2, + FIRST_TURN_EVENTS_WHITE_HERB, + FIRST_TURN_EVENTS_OPPORTUNIST, + FIRST_TURN_EVENTS_MIRROR_HERB, FIRST_TURN_EVENTS_EJECT_PACK, FIRST_TURN_EVENTS_END, }; @@ -96,18 +98,15 @@ u8 IsRunningFromBattleImpossible(u32 battler); void SwitchTwoBattlersInParty(u32 battler, u32 battler2); void SwitchPartyOrder(u32 battler); void SwapTurnOrder(u8 id1, u8 id2); -u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect holdEffect); -u32 GetBattlerTotalSpeedStat(u32 battler); -s32 GetChosenMovePriority(u32 battler, u32 ability); -s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move); -s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2, - enum ItemHoldEffect holdEffectBattler1, enum ItemHoldEffect holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2); -s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves); -s32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves); +u32 GetBattlerTotalSpeedStat(u32 battler, enum Ability ability, enum HoldEffect holdEffect); +s32 GetChosenMovePriority(u32 battler, enum Ability ability); +s32 GetBattleMovePriority(u32 battler, enum Ability ability, u32 move); +s32 GetWhichBattlerFasterArgs(struct BattleContext *ctx, bool32 ignoreChosenMoves, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2); +s32 GetWhichBattlerFasterOrTies(struct BattleContext *ctx, bool32 ignoreChosenMoves); +s32 GetWhichBattlerFaster(struct BattleContext *ctx, bool32 ignoreChosenMoves); void RunBattleScriptCommands_PopCallbacksStack(void); void RunBattleScriptCommands(void); -void SpecialStatusesClear(void); -u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState monInBattle); +enum Type GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState monInBattle); void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk); bool32 IsWildMonSmart(void); u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags); diff --git a/include/battle_message.h b/include/battle_message.h index 28be583551..9809589243 100644 --- a/include/battle_message.h +++ b/include/battle_message.h @@ -1,6 +1,7 @@ #ifndef GUARD_BATTLE_MESSAGE_H #define GUARD_BATTLE_MESSAGE_H +#include "constants/abilities.h" #include "constants/battle.h" #include "constants/battle_string_ids.h" @@ -238,13 +239,13 @@ struct BattleMsgData u16 currentMove; u16 originallyUsedMove; u16 lastItem; - u16 lastAbility; + enum Ability lastAbility; u8 scrActive; u8 bakScriptPartyIdx; u8 hpScale; u8 itemEffectBattler; - u8 moveType; - u16 abilities[MAX_BATTLERS_COUNT]; + enum Type moveType; + enum Ability abilities[MAX_BATTLERS_COUNT]; u8 textBuffs[3][TEXT_BUFF_ARRAY_COUNT]; }; @@ -334,5 +335,6 @@ extern const u8 gText_BattleTourney[]; extern const u16 gMissStringIds[]; extern const u16 gStatUpStringIds[]; +extern const u16 gStatDownStringIds[]; #endif // GUARD_BATTLE_MESSAGE_H diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 7bce90abde..d011b50947 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -40,16 +40,15 @@ union TRANSPARENT StatChangeFlags }; }; -s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk); -s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk); +s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk); +s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk); s32 GetCritHitOdds(s32 critChanceIndex); -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); bool32 HasBattlerActedThisTurn(u32 battler); u32 GetBattlerTurnOrderNum(u32 battler); bool32 NoAliveMonsForBattlerSide(u32 battler); bool32 NoAliveMonsForPlayer(void); bool32 NoAliveMonsForEitherParty(void); -void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certain); +void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags); bool32 CanBattlerSwitch(u32 battlerId); void BattleDestroyYesNoCursorAt(u8 cursorPosition); void BattleCreateYesNoCursorAt(u8 cursorPosition); @@ -60,18 +59,14 @@ bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move); bool32 DoesDisguiseBlockMove(u32 battler, u32 move); bool32 CanUseLastResort(u8 battlerId); u32 IsFlowerVeilProtected(u32 battler); -u32 IsLeafGuardProtected(u32 battler, u32 ability); -bool32 IsShieldsDownProtected(u32 battler, u32 ability); -u32 IsAbilityStatusProtected(u32 battler, u32 ability); +u32 IsLeafGuardProtected(u32 battler, enum Ability ability); +bool32 IsShieldsDownProtected(u32 battler, enum Ability ability); +u32 IsAbilityStatusProtected(u32 battler, enum Ability ability); bool32 TryResetBattlerStatChanges(u8 battler); bool32 CanCamouflage(u8 battlerId); -u32 GetNaturePowerMove(u32 battler); void StealTargetItem(u8 battlerStealer, u8 battlerItem); u8 GetCatchingBattler(void); -u32 GetHighestStatId(u32 battlerId); -u32 GetParadoxHighestStatId(u32 battlerId); -u32 GetParadoxBoostedStatId(u32 battlerId); -bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType); +bool32 ProteanTryChangeType(u32 battler, enum Ability ability, u32 move, enum Type moveType); bool32 IsMoveNotAllowedInSkyBattles(u32 move); bool32 DoSwitchInAbilities(u32 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId); @@ -79,6 +74,7 @@ bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler); void SaveBattlerTarget(u32 battler); void SaveBattlerAttacker(u32 battler); bool32 CanBurnHitThaw(u16 move); +bool32 EmergencyExitCanBeTriggered(u32 battler); extern void (*const gBattleScriptingCommandsTable[])(void); extern const struct StatFractions gAccuracyStageRatios[]; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index b5d9d25109..e2f9f1636c 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -3,17 +3,18 @@ extern const u8 BattleScript_SupersweetSyrupActivates[]; extern const u8 BattleScript_OpportunistCopyStatChange[]; +extern const u8 BattleScript_OpportunistCopyStatChangeEnd3[]; extern const u8 BattleScript_MirrorHerbCopyStatChange[]; extern const u8 BattleScript_MirrorHerbCopyStatChangeEnd2[]; extern const u8 BattleScript_NotAffected[]; extern const u8 BattleScript_HitFromCritCalc[]; extern const u8 BattleScript_MoveEnd[]; extern const u8 BattleScript_MakeMoveMissed[]; -extern const u8 BattleScript_PrintMoveMissed[]; +extern const u8 BattleScript_MoveMissedPause[]; extern const u8 BattleScript_MoveMissedPause[]; extern const u8 BattleScript_MoveMissed[]; extern const u8 BattleScript_FlingFailConsumeItem[]; -extern const u8 BattleScript_FailedFromAtkString[]; +extern const u8 BattleScript_FlingBlockedByShieldDust[]; extern const u8 BattleScript_FailedFromAtkCanceler[]; extern const u8 BattleScript_ButItFailed[]; extern const u8 BattleScript_StatUp[]; @@ -21,8 +22,7 @@ extern const u8 BattleScript_StatDown[]; extern const u8 BattleScript_AlreadyAtFullHp[]; extern const u8 BattleScript_PresentHealTarget[]; extern const u8 BattleScript_MoveUsedMustRecharge[]; -extern const u8 BattleScript_FaintAttacker[]; -extern const u8 BattleScript_FaintTarget[]; +extern const u8 BattleScript_FaintBattler[]; extern const u8 BattleScript_GiveExp[]; extern const u8 BattleScript_HandleFaintedMon[]; extern const u8 BattleScript_LocalTrainerBattleWon[]; @@ -168,7 +168,6 @@ extern const u8 BattleScript_DoRecoil33[]; extern const u8 BattleScript_Recoil33End[]; extern const u8 BattleScript_ItemSteal[]; extern const u8 BattleScript_DrizzleActivates[]; -extern const u8 BattleScript_SpeedBoostActivates[]; extern const u8 BattleScript_TraceActivates[]; extern const u8 BattleScript_RainDishActivates[]; extern const u8 BattleScript_SandstreamActivates[]; @@ -180,11 +179,8 @@ extern const u8 BattleScript_DroughtActivates[]; extern const u8 BattleScript_TookAttack[]; extern const u8 BattleScript_SturdyPreventsOHKO[]; extern const u8 BattleScript_DampStopsExplosion[]; -extern const u8 BattleScript_MoveHPDrain_PPLoss[]; extern const u8 BattleScript_MoveHPDrain[]; -extern const u8 BattleScript_MonMadeMoveUseless_PPLoss[]; extern const u8 BattleScript_MonMadeMoveUseless[]; -extern const u8 BattleScript_FlashFireBoost_PPLoss[]; extern const u8 BattleScript_FlashFireBoost[]; extern const u8 BattleScript_AbilityNoStatLoss[]; extern const u8 BattleScript_ItemNoStatLoss[]; @@ -195,6 +191,7 @@ extern const u8 BattleScript_OwnTempoPrevents[]; extern const u8 BattleScript_SoundproofProtected[]; extern const u8 BattleScript_AbilityNoSpecificStatLoss[]; extern const u8 BattleScript_StickyHoldActivates[]; +extern const u8 BattleScript_StickyHoldActivatesRet[]; extern const u8 BattleScript_ColorChangeActivates[]; extern const u8 BattleScript_RoughSkinActivates[]; extern const u8 BattleScript_CuteCharmActivates[]; @@ -210,22 +207,10 @@ extern const u8 BattleScript_TruantLoafingAround[]; extern const u8 BattleScript_IgnoresAndFallsAsleep[]; extern const u8 BattleScript_IgnoresAndHitsItself[]; extern const u8 BattleScript_SubstituteFade[]; -extern const u8 BattleScript_BerryCurePrlzEnd2[]; -extern const u8 BattleScript_BerryCureParRet[]; -extern const u8 BattleScript_BerryCurePsnEnd2[]; -extern const u8 BattleScript_BerryCurePsnRet[]; -extern const u8 BattleScript_BerryCureBrnEnd2[]; -extern const u8 BattleScript_BerryCureBrnRet[]; -extern const u8 BattleScript_BerryCureFrzEnd2[]; -extern const u8 BattleScript_BerryCureFrzRet[]; -extern const u8 BattleScript_BerryCureFrbEnd2[]; -extern const u8 BattleScript_BerryCureFrbRet[]; -extern const u8 BattleScript_BerryCureSlpEnd2[]; -extern const u8 BattleScript_BerryCureSlpRet[]; +extern const u8 BattleScript_BerryCureStatusEnd2[]; +extern const u8 BattleScript_BerryCureStatusRet[]; extern const u8 BattleScript_BerryCureConfusionEnd2[]; extern const u8 BattleScript_BerryCureConfusionRet[]; -extern const u8 BattleScript_BerryCureChosenStatusEnd2[]; -extern const u8 BattleScript_BerryCureChosenStatusRet[]; extern const u8 BattleScript_WhiteHerbEnd2[]; extern const u8 BattleScript_WhiteHerbRet[]; extern const u8 BattleScript_ItemHealHP_RemoveItemRet[]; @@ -280,13 +265,14 @@ extern const u8 BattleScript_WaterSportEnds[]; extern const u8 BattleScript_SturdiedMsg[]; extern const u8 BattleScript_GravityEnds[]; extern const u8 BattleScript_MoveStatDrain[]; -extern const u8 BattleScript_MoveStatDrain_PPLoss[]; extern const u8 BattleScript_TargetsStatWasMaxedOut[]; extern const u8 BattleScript_AttackerAbilityStatRaise[]; extern const u8 BattleScript_AttackerAbilityStatRaiseEnd3[]; +extern const u8 BattleScript_AttackerAbilityStatRaiseEnd2[]; extern const u8 BattleScript_PoisonHealActivates[]; extern const u8 BattleScript_BadDreamsActivates[]; extern const u8 BattleScript_SwitchInAbilityMsg[]; +extern const u8 BattleScript_SwitchInAbilityMsgRet[]; extern const u8 BattleScript_ToxicSpikesPoisoned[]; extern const u8 BattleScript_ToxicSpikesBadlyPoisoned[]; extern const u8 BattleScript_ToxicSpikesAbsorbed[]; @@ -328,7 +314,6 @@ extern const u8 BattleScript_ProteanActivates[]; extern const u8 BattleScript_DazzlingProtected[]; extern const u8 BattleScript_MoveUsedPsychicTerrainPrevents[]; extern const u8 BattleScript_MoveUsedPowder[]; -extern const u8 BattleScript_ZMoveActivatePowder[]; extern const u8 BattleScript_SelectingNotAllowedStuffCheeks[]; extern const u8 BattleScript_SelectingNotAllowedStuffCheeksInPalace[]; extern const u8 BattleScript_SelectingNotAllowedBelch[]; @@ -339,7 +324,6 @@ extern const u8 BattleScript_MistySurgeActivates[]; extern const u8 BattleScript_ElectricSurgeActivates[]; extern const u8 BattleScript_EffectSpectralThief[]; extern const u8 BattleScript_EffectLifeDew[]; -extern const u8 BattleScript_EffectSteelRoller[]; extern const u8 BattleScript_AbilityRaisesDefenderStat[]; extern const u8 BattleScript_PowderMoveNoEffect[]; extern const u8 BattleScript_GrassyTerrainHeals[]; @@ -360,8 +344,9 @@ extern const u8 BattleScript_WeaknessPolicy[]; extern const u8 BattleScript_TargetItemStatRaise[]; extern const u8 BattleScript_RockyHelmetActivates[]; extern const u8 BattleScript_ItemHurtEnd2[]; -extern const u8 BattleScript_AirBaloonMsgIn[]; -extern const u8 BattleScript_AirBaloonMsgPop[]; +extern const u8 BattleScript_AirBalloonMsgIn[]; +extern const u8 BattleScript_AirBalloonMsgInRet[]; +extern const u8 BattleScript_AirBalloonMsgPop[]; extern const u8 BattleScript_ItemHurtRet[]; extern const u8 BattleScript_ToxicOrb[]; extern const u8 BattleScript_FlameOrb[]; @@ -373,6 +358,7 @@ extern const u8 BattleScript_IllusionOffAndTerastallization[]; extern const u8 BattleScript_DancerActivates[]; extern const u8 BattleScript_AftermathDmg[]; extern const u8 BattleScript_BattlerFormChange[]; +extern const u8 BattleScript_BattlerFormChangeEnd2[]; extern const u8 BattleScript_BattlerFormChangeEnd3[]; extern const u8 BattleScript_AttackerFormChangeWithString[]; extern const u8 BattleScript_BattlerFormChangeWithStringEnd3[]; @@ -467,6 +453,7 @@ extern const u8 BattleScript_RemoveFireType[]; extern const u8 BattleScript_TargetAbilityStatRaiseRet[]; extern const u8 BattleScript_RemoveElectricType[]; extern const u8 BattleScript_SeedSowerActivates[]; +extern const u8 BattleScript_BerserkActivates[]; extern const u8 BattleScript_AngerShellActivates[]; extern const u8 BattleScript_WellBakedBodyActivates[]; extern const u8 BattleScript_WindRiderActivatesMoveEnd[]; @@ -582,7 +569,6 @@ extern const u8 BattleScript_EffectAbsorb[]; extern const u8 BattleScript_EffectAbsorbLiquidOoze[]; extern const u8 BattleScript_EffectExplosion[]; extern const u8 BattleScript_EffectDreamEater[]; -extern const u8 BattleScript_EffectMirrorMove[]; extern const u8 BattleScript_EffectAttackUp[]; extern const u8 BattleScript_EffectDefenseUp[]; extern const u8 BattleScript_EffectSpeedUp[]; @@ -606,6 +592,8 @@ extern const u8 BattleScript_EffectConversion[]; extern const u8 BattleScript_EffectRestoreHp[]; extern const u8 BattleScript_EffectLightScreen[]; extern const u8 BattleScript_EffectRest[]; +extern const u8 BattleScript_RestIsAlreadyAsleep[]; +extern const u8 BattleScript_InsomniaProtects[]; extern const u8 BattleScript_EffectOHKO[]; extern const u8 BattleScript_EffectHealBlock[]; extern const u8 BattleScript_RecoilIfMiss[]; @@ -632,7 +620,6 @@ extern const u8 BattleScript_EffectTwoTurnsAttack[]; extern const u8 BattleScript_EffectSubstitute[]; extern const u8 BattleScript_EffectRage[]; extern const u8 BattleScript_EffectMimic[]; -extern const u8 BattleScript_EffectMetronome[]; extern const u8 BattleScript_EffectLeechSeed[]; extern const u8 BattleScript_EffectDoNothing[]; extern const u8 BattleScript_EffectHoldHands[]; @@ -646,7 +633,6 @@ extern const u8 BattleScript_EffectSnore[]; extern const u8 BattleScript_EffectConversion2[]; extern const u8 BattleScript_EffectLockOn[]; extern const u8 BattleScript_EffectSketch[]; -extern const u8 BattleScript_EffectSleepTalk[]; extern const u8 BattleScript_EffectDestinyBond[]; extern const u8 BattleScript_EffectSpite[]; extern const u8 BattleScript_EffectHealBell[]; @@ -688,12 +674,10 @@ extern const u8 BattleScript_EffectBeatUp[]; extern const u8 BattleScript_EffectSemiInvulnerable[]; extern const u8 BattleScript_EffectDefenseCurl[]; extern const u8 BattleScript_EffectSoftboiled[]; -extern const u8 BattleScript_EffectFirstTurnOnly[]; -extern const u8 BattleScript_EffectUproar[]; extern const u8 BattleScript_EffectStockpile[]; extern const u8 BattleScript_EffectSpitUp[]; extern const u8 BattleScript_EffectSwallow[]; -extern const u8 BattleScript_EffectWorrySeed[]; +extern const u8 BattleScript_EffectOverwriteAbility[]; extern const u8 BattleScript_EffectHail[]; extern const u8 BattleScript_EffectTorment[]; extern const u8 BattleScript_EffectFlatter[]; @@ -701,14 +685,12 @@ extern const u8 BattleScript_EffectNonVolatileStatus[]; extern const u8 BattleScript_EffectMemento[]; extern const u8 BattleScript_EffectFocusPunch[]; extern const u8 BattleScript_EffectFollowMe[]; -extern const u8 BattleScript_EffectNaturePower[]; extern const u8 BattleScript_EffectCharge[]; extern const u8 BattleScript_EffectTaunt[]; extern const u8 BattleScript_EffectHelpingHand[]; extern const u8 BattleScript_EffectTrick[]; extern const u8 BattleScript_EffectRolePlay[]; extern const u8 BattleScript_EffectWish[]; -extern const u8 BattleScript_EffectAssist[]; extern const u8 BattleScript_EffectIngrain[]; extern const u8 BattleScript_EffectMagicCoat[]; extern const u8 BattleScript_EffectRecycle[]; @@ -756,8 +738,6 @@ extern const u8 BattleScript_EffectGuardSplit[]; extern const u8 BattleScript_EffectStickyWeb[]; extern const u8 BattleScript_EffectMetalBurst[]; extern const u8 BattleScript_EffectLuckyChant[]; -extern const u8 BattleScript_EffectSuckerPunch[]; -extern const u8 BattleScript_EffectSimpleBeam[]; extern const u8 BattleScript_EffectEntrainment[]; extern const u8 BattleScript_EffectHealPulse[]; extern const u8 BattleScript_EffectQuash[]; @@ -769,14 +749,12 @@ extern const u8 BattleScript_EffectElectricTerrain[]; extern const u8 BattleScript_EffectPsychicTerrain[]; extern const u8 BattleScript_EffectAttackAccUp[]; extern const u8 BattleScript_EffectAttackSpAttackUp[]; -extern const u8 BattleScript_EffectMeFirst[]; extern const u8 BattleScript_EffectQuiverDance[]; extern const u8 BattleScript_EffectCoil[]; extern const u8 BattleScript_EffectElectrify[]; extern const u8 BattleScript_EffectReflectType[]; extern const u8 BattleScript_EffectSoak[]; extern const u8 BattleScript_EffectGrowth[]; -extern const u8 BattleScript_EffectLastResort[]; extern const u8 BattleScript_EffectShellSmash[]; extern const u8 BattleScript_EffectShiftGear[]; extern const u8 BattleScript_EffectDefenseUp3[]; @@ -789,7 +767,6 @@ extern const u8 BattleScript_AbilityPreventsPhasingOutRet[]; extern const u8 BattleScript_PrintMonIsRootedRet[]; extern const u8 BattleScript_FinalGambit[]; extern const u8 BattleScript_EffectAutotomize[]; -extern const u8 BattleScript_EffectCopycat[]; extern const u8 BattleScript_EffectDefog[]; extern const u8 BattleScript_EffectHitEnemyHealAlly[]; extern const u8 BattleScript_EffectSynchronoise[]; @@ -806,14 +783,12 @@ extern const u8 BattleScript_EffectAcupressure[]; extern const u8 BattleScript_EffectAromaticMist[]; extern const u8 BattleScript_EffectPowder[]; extern const u8 BattleScript_EffectPartingShot[]; -extern const u8 BattleScript_EffectMatBlock[]; extern const u8 BattleScript_EffectInstruct[]; extern const u8 BattleScript_EffectLaserFocus[]; extern const u8 BattleScript_EffectMagneticFlux[]; extern const u8 BattleScript_EffectGearUp[]; extern const u8 BattleScript_EffectStrengthSap[]; extern const u8 BattleScript_EffectPurify[]; -extern const u8 BattleScript_FailIfNotArgType[]; extern const u8 BattleScript_EffectShoreUp[]; extern const u8 BattleScript_EffectGeomancy[]; extern const u8 BattleScript_EffectFairyLock[]; @@ -830,7 +805,6 @@ extern const u8 BattleScript_MoveEffectLeechSeed[]; extern const u8 BattleScript_MoveEffectHaze[]; extern const u8 BattleScript_MoveEffectIonDeluge[]; extern const u8 BattleScript_EffectHyperspaceFury[]; -extern const u8 BattleScript_EffectAuraWheel[]; extern const u8 BattleScript_EffectNoRetreat[]; extern const u8 BattleScript_EffectTarShot[]; extern const u8 BattleScript_EffectPoltergeist[]; @@ -840,7 +814,6 @@ extern const u8 BattleScript_EffectSkyDrop[]; extern const u8 BattleScript_EffectMeteorBeam[]; extern const u8 BattleScript_EffectCourtChange[]; extern const u8 BattleScript_EffectExtremeEvoboost[]; -extern const u8 BattleScript_EffectHitSetTerrain[]; extern const u8 BattleScript_EffectDarkVoid[]; extern const u8 BattleScript_EffectVictoryDance[]; extern const u8 BattleScript_EffectTeatime[]; @@ -858,7 +831,6 @@ extern const u8 BattleScript_EffectBrickBreak[]; extern const u8 BattleScript_EffectDoodle[]; extern const u8 BattleScript_EffectFilletAway[]; extern const u8 BattleScript_EffectShedTail[]; -extern const u8 BattleScript_EffectUpperHand[]; extern const u8 BattleScript_EffectTidyUp[]; extern const u8 BattleScript_EffectSpicyExtract[]; extern const u8 BattleScript_EffectFickleBeam[]; @@ -866,5 +838,11 @@ extern const u8 BattleScript_FickleBeamDoubled[]; extern const u8 BattleScript_QuestionForfeitBattle[]; extern const u8 BattleScript_ForfeitBattleGaveMoney[]; extern const u8 BattleScript_AbilityPopUp[]; +extern const u8 BattleScript_Attackstring[]; +extern const u8 BattleScript_SubmoveAttackstring[]; +extern const u8 BattleScript_MetronomeAttackstring[]; +extern const u8 BattleScript_SleepTalkAttackstring[]; +extern const u8 BattleScript_NaturePowerAttackstring[]; +extern const u8 BattleScript_PokemonCantUseTheMove[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_setup.h b/include/battle_setup.h index 1323971f67..689d163696 100644 --- a/include/battle_setup.h +++ b/include/battle_setup.h @@ -1,6 +1,7 @@ #ifndef GUARD_BATTLE_SETUP_H #define GUARD_BATTLE_SETUP_H +#include "battle_transition.h" #include "gym_leader_rematch.h" #define REMATCHES_COUNT 5 @@ -61,9 +62,9 @@ void BattleSetup_StartLegendaryBattle(void); void StartGroudonKyogreBattle(void); void StartRegiBattle(void); enum BattleEnvironments BattleSetup_GetEnvironmentId(void); -u8 GetWildBattleTransition(void); -u8 GetTrainerBattleTransition(void); -u8 GetSpecialBattleTransition(s32 id); +enum BattleTransition GetWildBattleTransition(void); +enum BattleTransition GetTrainerBattleTransition(void); +enum BattleTransition GetSpecialBattleTransition(enum BattleTransitionGroup id); void ChooseStarter(void); void ResetTrainerOpponentIds(void); void SetMapVarsToTrainerA(void); diff --git a/include/battle_terastal.h b/include/battle_terastal.h index 6b5c385463..6bfb74986a 100644 --- a/include/battle_terastal.h +++ b/include/battle_terastal.h @@ -4,11 +4,11 @@ void ActivateTera(u32 battler); void ApplyBattlerVisualsForTeraAnim(u32 battler); bool32 CanTerastallize(u32 battler); -u32 GetBattlerTeraType(u32 battler); -void ExpendTypeStellarBoost(u32 battler, u32 type); -bool32 IsTypeStellarBoosted(u32 battler, u32 type); -uq4_12_t GetTeraMultiplier(u32 battler, u32 type); +enum Type GetBattlerTeraType(u32 battler); +void ExpendTypeStellarBoost(u32 battler, enum Type type); +bool32 IsTypeStellarBoosted(u32 battler, enum Type type); +uq4_12_t GetTeraMultiplier(struct DamageContext *ctx); -u16 GetTeraTypeRGB(u32 type); +u16 GetTeraTypeRGB(enum Type type); #endif diff --git a/include/battle_transition.h b/include/battle_transition.h index 8bc80dc642..fcfe42fde8 100644 --- a/include/battle_transition.h +++ b/include/battle_transition.h @@ -10,7 +10,8 @@ void GetBg0TilesDst(u16 **tilemap, u16 **tileset); extern const struct SpritePalette gSpritePalette_Pokeball; -enum { +enum MugshotColor +{ MUGSHOT_COLOR_NONE, MUGSHOT_COLOR_PURPLE, MUGSHOT_COLOR_GREEN, @@ -20,7 +21,8 @@ enum { MUGSHOT_COLOR_COUNT }; -enum { +enum BattleTransition +{ B_TRANSITION_BLUR, B_TRANSITION_SWIRL, B_TRANSITION_SHUFFLE, @@ -63,7 +65,8 @@ enum { }; // IDs for GetSpecialBattleTransition -enum { +enum BattleTransitionGroup +{ B_TRANSITION_GROUP_B_TOWER, B_TRANSITION_GROUP_B_DOME = 3, B_TRANSITION_GROUP_B_PALACE, diff --git a/include/battle_util.h b/include/battle_util.h index e63b3a5395..36ca129206 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -3,6 +3,7 @@ #include "move.h" #include "constants/battle_string_ids.h" +#include "constants/hold_effects.h" #define MOVE_LIMITATION_ZEROMOVE (1 << 0) #define MOVE_LIMITATION_PP (1 << 1) @@ -39,42 +40,33 @@ enum MoveAbsorbed MOVE_ABSORBED_BY_BOOST_FLASH_FIRE, }; -enum { +enum FieldEffectCases +{ + FIELD_EFFECT_TRAINER_STATUSES, + FIELD_EFFECT_OVERWORLD_TERRAIN, + FIELD_EFFECT_OVERWORLD_WEATHER, +}; + +enum AbilityEffect +{ ABILITYEFFECT_ON_SWITCHIN, ABILITYEFFECT_ENDTURN, ABILITYEFFECT_MOVE_END_ATTACKER, + ABILITYEFFECT_COLOR_CHANGE, // Color Change, Berserk, Anger Shell ABILITYEFFECT_MOVE_END, ABILITYEFFECT_IMMUNITY, ABILITYEFFECT_SYNCHRONIZE, ABILITYEFFECT_ATK_SYNCHRONIZE, ABILITYEFFECT_MOVE_END_OTHER, ABILITYEFFECT_NEUTRALIZINGGAS, + ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN, ABILITYEFFECT_ON_WEATHER, ABILITYEFFECT_ON_TERRAIN, - ABILITYEFFECT_SWITCH_IN_TERRAIN, - ABILITYEFFECT_SWITCH_IN_WEATHER, ABILITYEFFECT_OPPORTUNIST, - ABILITYEFFECT_SWITCH_IN_STATUSES, + ABILITYEFFECT_OPPORTUNIST_FIRST_TURN, ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES, }; -// For the first argument of ItemBattleEffects, to deteremine which block of item effects to try -enum ItemCaseId -{ - ITEMEFFECT_NONE, - ITEMEFFECT_ON_SWITCH_IN, - ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN, - ITEMEFFECT_NORMAL, - ITEMEFFECT_TRY_HEALING, - ITEMEFFECT_MOVE_END, - ITEMEFFECT_KINGSROCK, - ITEMEFFECT_TARGET, - ITEMEFFECT_ORBS, - ITEMEFFECT_LIFEORB_SHELLBELL, - ITEMEFFECT_USE_LAST_ITEM, // move end effects for just the battler, not whole field - ITEMEFFECT_STATS_CHANGED, // For White Herb and Eject Pack -}; - enum ItemEffect { ITEM_NO_EFFECT, @@ -99,40 +91,44 @@ enum ItemEffect // for Natural Gift and Fling struct TypePower { - u8 type; + enum Type type; u8 power; u16 effect; }; enum MoveSuccessOrder { - CANCELER_FLAGS, CANCELER_STANCE_CHANGE_1, + CANCELER_CLEAR_FLAGS, CANCELER_SKY_DROP, CANCELER_RECHARGE, CANCELER_ASLEEP_OR_FROZEN, + CANCELER_POWER_POINTS, CANCELER_OBEDIENCE, CANCELER_TRUANT, CANCELER_FLINCH, CANCELER_DISABLED, - CANCELER_VOLATILE_BLOCKED, + CANCELER_VOLATILE_BLOCKED, // Gravity / Heal Block / Throat Chop CANCELER_TAUNTED, CANCELER_IMPRISONED, CANCELER_CONFUSED, CANCELER_PARALYZED, CANCELER_INFATUATION, CANCELER_BIDE, + CANCELER_Z_MOVES, + CANCELER_CHOICE_LOCK, + CANCELER_CALLSUBMOVE, CANCELER_THAW, CANCELER_STANCE_CHANGE_2, - CANCELER_CHOICE_LOCK, + CANCELER_ATTACKSTRING, + CANCELER_PPDEDUCTION, CANCELER_WEATHER_PRIMAL, - CANCELER_DYNAMAX_BLOCKED, + CANCELER_MOVE_FAILURE, CANCELER_POWDER_STATUS, + CANCELER_PRIORITY_BLOCK, CANCELER_PROTEAN, - CANCELER_PSYCHIC_TERRAIN, CANCELER_EXPLODING_DAMP, CANCELER_MULTIHIT_MOVES, - CANCELER_Z_MOVES, CANCELER_MULTI_TARGET_MOVES, CANCELER_END, }; @@ -150,7 +146,8 @@ enum Obedience enum MoveCanceler { MOVE_STEP_SUCCESS, - MOVE_STEP_BREAK, + MOVE_STEP_BREAK, // Breaks out of the function to run a script + MOVE_STEP_FAILURE, // Same as break but breaks out of it due to move failure and jumps to script that handles the failure MOVE_STEP_REMOVES_STATUS, }; @@ -161,7 +158,7 @@ struct DamageContext u32 battlerAtk:3; u32 battlerDef:3; u32 move:16; - u32 moveType:5; + enum Type moveType:5; u32 isCrit:1; u32 randomFactor:1; u32 updateFlags:1; @@ -170,11 +167,23 @@ struct DamageContext u32 weather:16; u32 fixedBasePower:8; u32 padding2:8; + u32 chosenMove:16; // May be different to 'move', e.g. for Z moves. + u32 padding3:16; uq4_12_t typeEffectivenessModifier; - u32 abilityAtk:16; - u32 abilityDef:16; - enum ItemHoldEffect holdEffectAtk:16; - enum ItemHoldEffect holdEffectDef:16; + enum Ability abilityAtk; + enum Ability abilityDef; + enum HoldEffect holdEffectAtk; + enum HoldEffect holdEffectDef; +}; + +struct BattleContext +{ + u32 battlerAtk:3; + u32 battlerDef:3; + u32 currentMove:16; + u32 padding:10; + enum Ability abilities[MAX_BATTLERS_COUNT]; + enum HoldEffect holdEffects[MAX_BATTLERS_COUNT]; }; enum SleepClauseBlock @@ -196,9 +205,17 @@ enum SkyDropState #define SKY_DROP_NO_TARGET 0xFF #define SKY_DROP_RELEASED_TARGET 0xFE +enum EjectPackTiming +{ + FIRST_TURN, + END_TURN, + OTHER, +}; + void HandleAction_ThrowBall(void); u32 GetCurrentBattleWeather(void); bool32 EndOrContinueWeather(void); +bool32 IsUnnerveBlocked(u32 battler, u32 itemId); bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move); bool32 HandleMoveTargetRedirection(void); void HandleAction_UseMove(void); @@ -221,7 +238,7 @@ void MarkBattlerForControllerExec(u32 battler); void MarkBattlerReceivedLinkData(u32 battler); const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState); bool32 WasUnableToUseMove(u32 battler); -bool32 ShouldDefiantCompetitiveActivate(u32 battler, u32 ability); +bool32 ShouldDefiantCompetitiveActivate(u32 battler, enum Ability ability); void PrepareStringBattle(enum StringID stringId, u32 battler); void ResetSentPokesToOpponentValue(void); void OpponentSwitchInResetSentPokesToOpponentValue(u32 battler); @@ -235,48 +252,48 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check); bool32 AreAllMovesUnusable(u32 battler); u8 GetImprisonedMovesCount(u32 battler, u16 move); s32 GetDrainedBigRootHp(u32 battler, s32 hp); -bool32 IsAbilityAndRecord(u32 battler, u32 battlerAbility, u32 abilityToCheck); +bool32 IsAbilityAndRecord(u32 battler, enum Ability battlerAbility, enum Ability abilityToCheck); u32 DoEndTurnEffects(void); bool32 HandleFaintedMonActions(void); void TryClearRageAndFuryCutter(void); -enum MoveCanceler AtkCanceler_MoveSuccessOrder(void); -void SetAtkCancelerForCalledMove(void); +enum MoveCanceler AtkCanceler_MoveSuccessOrder(struct BattleContext *ctx); bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2); bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability); bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag); -bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option); -bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType, enum FunctionCallOption option); -u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg); +bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option); +bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, u32 move, enum Type moveType, enum FunctionCallOption option); +bool32 TryFieldEffects(enum FieldEffectCases caseId); +u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ability, u32 special, u32 moveArg); bool32 TryPrimalReversion(u32 battler); bool32 IsNeutralizingGasOnField(void); -bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability); +bool32 IsMoldBreakerTypeAbility(u32 battler, enum Ability ability); u32 GetBattlerAbilityIgnoreMoldBreaker(u32 battler); u32 GetBattlerAbilityNoAbilityShield(u32 battler); u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityShield); -u32 GetBattlerAbility(u32 battler); -u32 IsAbilityOnSide(u32 battler, u32 ability); -u32 IsAbilityOnOpposingSide(u32 battler, u32 ability); -u32 IsAbilityOnField(u32 ability); -u32 IsAbilityOnFieldExcept(u32 battler, u32 ability); +enum Ability GetBattlerAbility(u32 battler); +u32 IsAbilityOnSide(u32 battler, enum Ability ability); +u32 IsAbilityOnOpposingSide(u32 battler, enum Ability ability); +u32 IsAbilityOnField(enum Ability ability); +u32 IsAbilityOnFieldExcept(u32 battler, enum Ability ability); u32 IsAbilityPreventingEscape(u32 battler); bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move); u32 GetProtectType(enum ProtectMethod method); bool32 CanBattlerEscape(u32 battler); // no ability check void BattleScriptExecute(const u8 *BS_ptr); void BattleScriptPushCursorAndCallback(const u8 *BS_ptr); -u32 ItemBattleEffects(enum ItemCaseId, u32 battler); void ClearVariousBattlerFlags(u32 battler); void HandleAction_RunBattleScript(void); u32 SetRandomTarget(u32 battler); u32 GetBattleMoveTarget(u16 move, u8 setTarget); u8 GetAttackerObedienceForAction(); -enum ItemHoldEffect GetBattlerHoldEffect(u32 battler, bool32 checkNegating); -enum ItemHoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating); -enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegating, bool32 checkAbility); +enum HoldEffect GetBattlerHoldEffect(u32 battler); +enum HoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler); +enum HoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler); +enum HoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability); u32 GetBattlerHoldEffectParam(u32 battler); -bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move); -bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move); -bool32 IsBattlerGrounded(u32 battler); +bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move); +bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move); +bool32 IsBattlerGrounded(u32 battler, enum Ability ability, enum HoldEffect holdEffect); u32 GetMoveSlot(u16 *moves, u32 move); u32 GetBattlerWeight(u32 battler); u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer); @@ -286,12 +303,12 @@ s32 CalculateMoveDamageVars(struct DamageContext *ctx); s32 DoFixedDamageMoveCalc(struct DamageContext *ctx); s32 ApplyModifiersAfterDmgRoll(struct DamageContext *ctx, s32 dmg); uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx); -uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef); -uq4_12_t GetTypeModifier(u32 atkType, u32 defType); -uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType); +uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, enum Ability abilityDef); +uq4_12_t GetTypeModifier(enum Type atkType, enum Type defType); +uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, enum Type moveType); void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags); s32 GetStealthHazardDamage(enum TypeSideHazard hazardType, u32 battler); -s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, u8 type2, u32 maxHp); +s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, enum Type type1, enum Type type2, u32 maxHp); bool32 CanMegaEvolve(u32 battler); bool32 CanUltraBurst(u32 battler); void ActivateMegaEvolution(u32 battler); @@ -305,13 +322,13 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method); bool32 DoBattlersShareType(u32 battler1, u32 battler2); bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId); u32 GetBattlerVisualSpecies(u32 battler); -bool32 TryClearIllusion(u32 battler, u32 caseID); +bool32 TryClearIllusion(u32 battler, enum AbilityEffect caseID); u32 GetIllusionMonSpecies(u32 battler); struct Pokemon *GetIllusionMonPtr(u32 battler); void ClearIllusionMon(u32 battler); u32 GetIllusionMonPartyId(struct Pokemon *party, struct Pokemon *mon, struct Pokemon *partnerMon, u32 battler); bool32 SetIllusionMon(struct Pokemon *mon, u32 battler); -u32 TryImmunityAbilityHealStatus(u32 battler, u32 caseID); +u32 TryImmunityAbilityHealStatus(u32 battler, enum AbilityEffect caseID); bool32 ShouldGetStatBadgeBoost(u16 flagId, u32 battler); uq4_12_t GetBadgeBoostModifier(void); enum DamageCategory GetBattleMoveCategory(u32 move); @@ -320,7 +337,7 @@ bool32 CanFling(u32 battler); bool32 IsTelekinesisBannedSpecies(u16 species); bool32 IsHealBlockPreventingMove(u32 battler, u32 move); bool32 IsBelchPreventingMove(u32 battler, u32 move); -bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId); +bool32 HasEnoughHpToEatBerry(u32 battler, enum Ability ability, u32 hpFraction, u32 itemId); bool32 IsPartnerMonFromSameTrainer(u32 battler); enum DamageCategory GetCategoryBasedOnStats(u32 battler); void SetShellSideArmCategory(void); @@ -330,14 +347,10 @@ void TryRestoreHeldItems(void); bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item); void TrySaveExchangedItem(u32 battler, u16 stolenItem); bool32 IsPartnerMonFromSameTrainer(u32 battler); -enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, u32 statId, u32 itemId, enum ItemCaseId caseID); bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes); void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast); -bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind, u32 ability); -bool32 TryRoomService(u32 battler); -void BufferStatChange(u32 battler, u8 statId, enum StringID stringId); +bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind, enum Ability ability); bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget); -u16 GetUsedHeldItem(u32 battler); bool32 PickupHasValidTarget(u32 battler); bool32 CantPickupItem(u32 battler); bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags); @@ -356,16 +369,19 @@ bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef); bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef); bool32 MoodyCantRaiseStat(u32 stat); bool32 MoodyCantLowerStat(u32 stat); +bool32 IsBattlerTerrainAffected(u32 battler, enum Ability ability, enum HoldEffect holdEffect, u32 terrainFlag); +u32 GetHighestStatId(u32 battler); +u32 GetParadoxHighestStatId(u32 battler); +u32 GetParadoxBoostedStatId(u32 battler); -bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, u32 abilityDef, enum SleepClauseBlock isBlockedBySleepClause); -bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef); -bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, u32 ability); -bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, u32 abilityDef); -bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef); -bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef); -bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffect secondaryMoveEffect, enum FunctionCallOption option); +bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, enum SleepClauseBlock isBlockedBySleepClause); +bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef); +bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, enum Ability ability); +bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); +bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); +bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef); +bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum MoveEffect secondaryMoveEffect, enum FunctionCallOption option); bool32 CanBeConfused(u32 battler); -bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag); u32 GetBattlerAffectionHearts(u32 battler); void TryToRevertMimicryAndFlags(void); bool32 BattleArenaTurnEnd(void); @@ -375,35 +391,32 @@ void RemoveConfusionStatus(u32 battler); u8 GetBattlerGender(u32 battler); bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2); bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2); -u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect); -bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect); -void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]); -u32 GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera); +u32 CalcSecondaryEffectChance(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect); +bool32 MoveEffectIsGuaranteed(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect); +void GetBattlerTypes(u32 battler, bool32 ignoreTera, enum Type types[static 3]); +enum Type GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera); bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon); bool8 IsMonBannedFromSkyBattles(u16 species); -void RemoveBattlerType(u32 battler, u8 type); -u32 GetBattleMoveType(u32 move); +void RemoveBattlerType(u32 battler, enum Type type); +enum Type GetBattleMoveType(u32 move); void TryActivateSleepClause(u32 battler, u32 indexInParty); void TryDeactivateSleepClause(u32 battlerSide, u32 indexInParty); bool32 IsSleepClauseActiveForSide(u32 battlerSide); bool32 IsSleepClauseEnabled(); void ClearDamageCalcResults(void); u32 DoesDestinyBondFail(u32 battler); -bool32 IsMoveEffectBlockedByTarget(u32 ability); +bool32 IsMoveEffectBlockedByTarget(enum Ability ability); bool32 IsPursuitTargetSet(void); void ClearPursuitValuesIfSet(u32 battler); void ClearPursuitValues(void); bool32 HasWeatherEffect(void); -bool32 IsAnyTargetAffected(u32 battlerAtk); -u32 RestoreWhiteHerbStats(u32 battler); bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move); bool32 HadMoreThanHalfHpNowDoesnt(u32 battler); +void ChooseStatBoostAnimation(u32 battler); void UpdateStallMons(void); -bool32 TryRestoreHPBerries(u32 battler, enum ItemCaseId caseId); -bool32 TrySwitchInEjectPack(enum ItemCaseId caseID); +bool32 TrySwitchInEjectPack(enum EjectPackTiming timing); u32 GetBattlerVolatile(u32 battler, enum Volatile _volatile); void SetMonVolatile(u32 battler, enum Volatile _volatile, u32 newValue); -u32 TryBoosterEnergy(u32 battler, u32 ability, enum ItemCaseId caseID); bool32 ItemHealMonVolatile(u32 battler, u16 itemId); void PushHazardTypeToQueue(u32 side, enum Hazards hazardType); bool32 IsHazardOnSide(u32 side, enum Hazards hazardType); @@ -411,11 +424,18 @@ bool32 AreAnyHazardsOnSide(u32 side); void RemoveAllHazardsFromField(u32 side); bool32 IsHazardOnSideAndClear(u32 side, enum Hazards hazardType); void RemoveHazardFromField(u32 side, enum Hazards hazardType); -bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option); -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); +bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option); +u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, enum HoldEffect atkHoldEffect, enum HoldEffect defHoldEffect); bool32 IsSemiInvulnerable(u32 battler, enum SemiInvulnerableExclusion excludeCommander); bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move); bool32 HasPartnerTrainer(u32 battler); -bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum ItemHoldEffect holdEffect); +bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum HoldEffect holdEffect); +u32 GetNaturePowerMove(u32 battler); +u32 GetNaturePowerMove(u32 battler); +void RemoveAbilityFlags(u32 battler); +bool32 IsDazzlingAbility(enum Ability ability); +bool32 IsAllowedToUseBag(void); +bool32 IsAnyTargetTurnDamaged(u32 battlerAtk); +bool32 IsMimikyuDisguised(u32 battler); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/config/ai.h b/include/config/ai.h index b6eb7bfe21..5a7ce40783 100644 --- a/include/config/ai.h +++ b/include/config/ai.h @@ -15,7 +15,7 @@ #define SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE 100 #define SHOULD_SWITCH_ABSORBS_HIDDEN_POWER_PERCENTAGE 50 #define SHOULD_SWITCH_TRAPPER_PERCENTAGE 100 -#define SHOULD_SWITCH_FREE_TURN_PERCENTAGE 100 +#define SHOULD_SWITCH_FREE_TURN_PERCENTAGE 50 #define STAY_IN_ABSORBING_PERCENTAGE 66 // Chance to stay in if outgoing mon has super effective move against player, will prevent switching out for an absorber with this likelihood #define SHOULD_SWITCH_HASBADODDS_PERCENTAGE 50 #define SHOULD_SWITCH_ENCORE_STATUS_PERCENTAGE 100 @@ -110,4 +110,9 @@ #define POWER_SPLIT_ALLY_PERCENTAGE 150 #define POWER_SPLIT_ENEMY_PERCENTAGE 50 +// HP thresholds to use a status z-move. +#define Z_EFFECT_FOLLOW_ME_THRESHOLD 30 +#define Z_EFFECT_RESTORE_HP_LOWER_THRESHOLD ENABLE_RECOVERY_THRESHOLD // threshold used for moves you could conceivably use more than once +#define Z_EFFECT_RESTORE_HP_HIGHER_THRESHOLD 90 // these moves are one-time use or drop your HP + #endif // GUARD_CONFIG_AI_H diff --git a/include/config/battle.h b/include/config/battle.h index 67008ba027..3a702ef225 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -169,8 +169,6 @@ #define B_POWDER_OVERCOAT GEN_LATEST // In Gen6+, Overcoat blocks powder and spore moves from affecting the user. // Item settings -#define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore HP activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. -#define B_BERRIES_INSTANT GEN_LATEST // In Gen4+, most berries activate on battle start/switch-in if applicable. In Gen3, they only activate either at the move end or turn end. #define B_CONFUSE_BERRIES_HEAL GEN_LATEST // Before Gen7, Figy and similar berries restore 1/8th of HP and trigger at half HP. In Gen7 they restore half HP, triggering at 25% HP. In Gen8 they heal 1/3rd of HP. #define B_X_ITEMS_BUFF GEN_LATEST // In Gen7+, the X Items raise a stat by 2 stages instead of 1. #define B_MENTAL_HERB GEN_LATEST // In Gen5+, the Mental Herb cures Taunt, Encore, Torment, Heal Block, and Disable in addition to Infatuation from before. @@ -209,7 +207,6 @@ #define B_FLAG_INVERSE_BATTLE 0 // If this flag is set, the battle's type effectiveness are inversed. For example, fire is super effective against water. #define B_FLAG_FORCE_DOUBLE_WILD 0 // If this flag is set, all land and surfing wild battles will be double battles. #define B_SMART_WILD_AI_FLAG 0 // If this flag is set, wild Pokémon will become smart, with all AI flags enabled. -#define B_FLAG_NO_BAG_USE 0 // If this flag is set, the ability to use the bag in battle is disabled. #define B_FLAG_NO_CATCHING 0 // If this flag is set, the ability to catch wild Pokémon is disabled. #define B_FLAG_NO_RUNNING 0 // If this flag is set, the ability to escape from wild battles is disabled. Also makes Roar/Whirlwind and Teleport (under Gen8) fail. #define B_FLAG_AI_VS_AI_BATTLE 0 // If this flag is set, the player's mons will be controlled by the ai next battles. @@ -231,6 +228,13 @@ #define B_VAR_DIFFICULTY 0 // If not 0, you can use this var to control which difficulty version of a Trainer is loaded. This should be manually set by the developer using Script_SetDifficulty AFTER NewGameInitData has run. +// No bag settings +#define NO_BAG_RESTRICTION 0 +#define NO_BAG_AGAINST_TRAINER 1 +#define NO_BAG_IN_BATTLE 2 + +#define B_VAR_NO_BAG_USE 0 // If 1, the ability to use the bag in battle is disabled in trainer battles. If 2, it is also disabled in wild battles. + // Sky Battles #define B_FLAG_SKY_BATTLE 0 // If this flag has a value, the player will be able to engage in scripted Sky Battles. #define B_VAR_SKY_BATTLE 0 // If this var has a value, the game will remember the positions of Pokémon used in Sky Battles. @@ -269,7 +273,6 @@ #define B_NEW_TERRAIN_BACKGROUNDS FALSE // If set to TRUE, uses new terrain backgrounds for Electric, Misty, Grassy and Psychic Terrain. // Interface settings -#define B_ABILITY_POP_UP TRUE // In Gen5+, the Pokémon abilities are displayed in a pop-up, when they activate in battle. #define B_FAST_INTRO_PKMN_TEXT TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end. #define B_FAST_INTRO_NO_SLIDE FALSE // If set to TRUE, the slide animation that happens at the beginning of the battle is skipped. #define B_FAST_HP_DRAIN TRUE // If set to TRUE, HP bars will move faster. @@ -288,9 +291,10 @@ // Catching settings #define B_SEMI_INVULNERABLE_CATCH GEN_LATEST // In Gen4+, you cannot throw a ball against a Pokemon that is in a semi-invulnerable state (dig/fly/etc) -#define B_CATCHING_CHARM_BOOST 20 // % boost in Critical Capture odds if player has the Catching Charm. +#define B_CATCHING_CHARM_BOOST 100 // % boost in Critical Capture odds if player has the Catching Charm. #define B_CRITICAL_CAPTURE TRUE // If set to TRUE, Critical Capture will be enabled. #define B_CRITICAL_CAPTURE_LOCAL_DEX TRUE // If set to FALSE, Critical Capture % is based off of the National Pokedex estimated by enabled generations. +#define B_CRITICAL_CAPTURE_IF_OWNED GEN_LATEST // In Gen9, a capture appear critical if the pokemon you are trying to catch already has a dex entry (has already been caught) #define B_LAST_USED_BALL TRUE // If TRUE, the "last used ball" feature from Gen 7 will be implemented #define B_LAST_USED_BALL_BUTTON R_BUTTON // If last used ball is implemented, this button (or button combo) will trigger throwing the last used ball. @@ -367,5 +371,7 @@ #define B_POOL_RULE_EXCLUDE_FORMS FALSE // Exclude different forms from the Species Clause #define B_POOL_RULE_ITEM_CLAUSE FALSE // Only allow each item to be picked once #define B_POOL_RULES_USE_ITEM_EXCLUSIONS FALSE // Exclude items listed in poolItemClauseExclusions +#define B_POOL_RULE_MEGA_STONE_CLAUSE FALSE // Pick only 1 mon with mega stone +#define B_POOL_RULE_Z_CRYSTAL_CLAUSE FALSE // Pick only 1 mon with Z-crystal #endif // GUARD_CONFIG_BATTLE_H diff --git a/include/config/contest.h b/include/config/contest.h new file mode 100644 index 0000000000..1307acc06f --- /dev/null +++ b/include/config/contest.h @@ -0,0 +1,8 @@ +#ifndef GUARD_CONFIG_CONTEST_H +#define GUARD_CONFIG_CONTEST_H + +// Move data settings +#define C_UPDATED_MOVE_CATEGORIES GEN_LATEST // Updates contest category. +#define C_UPDATED_MOVE_EFFECTS GEN_LATEST // Updates contest effects. + +#endif // GUARD_CONFIG_CONTEST_H diff --git a/include/config/debug.h b/include/config/debug.h index 2446b9360c..7e28d33504 100644 --- a/include/config/debug.h +++ b/include/config/debug.h @@ -2,16 +2,16 @@ #define GUARD_CONFIG_DEBUG_H // Overworld Debug -#define DEBUG_OVERWORLD_MENU TRUE // Enables an overworld debug menu to change flags, variables, giving pokemon and more, accessed by holding R and pressing START while in the overworld by default. +#define DEBUG_OVERWORLD_MENU DISABLED_ON_RELEASE // Enables an overworld debug menu to change flags, variables, giving pokemon and more, accessed by holding R and pressing START while in the overworld by default. #define DEBUG_OVERWORLD_HELD_KEYS (R_BUTTON) // The keys required to be held to open the debug menu. #define DEBUG_OVERWORLD_TRIGGER_EVENT pressedStartButton // The event that opens the menu when holding the key(s) defined in DEBUG_OVERWORLD_HELD_KEYS. #define DEBUG_OVERWORLD_IN_MENU FALSE // Replaces the overworld debug menu button combination with a start menu entry (above Pokédex). // Battle Debug Menu -#define DEBUG_BATTLE_MENU TRUE // If set to TRUE, enables a debug menu to use in battles by pressing the Select button. +#define DEBUG_BATTLE_MENU DISABLED_ON_RELEASE // If set to TRUE, enables a debug menu to use in battles by pressing the Select button. #define DEBUG_AI_DELAY_TIMER FALSE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. // Pokémon Debug -#define DEBUG_POKEMON_SPRITE_VISUALIZER TRUE // Enables a debug menu for Pokémon sprites and icons, accessed by pressing Select in the summary screen. +#define DEBUG_POKEMON_SPRITE_VISUALIZER DISABLED_ON_RELEASE // Enables a debug menu for Pokémon sprites and icons, accessed by pressing Select in the summary screen. #endif // GUARD_CONFIG_DEBUG_H diff --git a/include/config/fishing.h b/include/config/fishing.h new file mode 100644 index 0000000000..0cbf666a54 --- /dev/null +++ b/include/config/fishing.h @@ -0,0 +1,13 @@ +#ifndef GUARD_CONFIG_FISHING_H +#define GUARD_CONFIG_FISHING_H + +#define I_FISHING_BITE_ODDS GEN_LATEST // In Gen 1 and Gen 2, the Old Rod has a 100% chance for a bite, Good Rod has a 66% chance for a bite, and Super Rod has a 50% chance for a bite. In Gen 3, all rods have a base 50% chance for a bite. In Gen 4 onwards, the Old Rod has a base 25% chance for a bite, Good Rod has a 50% chance for a bite, and Super Rod has a 75% chance for a bite. +#define I_FISHING_MINIGAME GEN_3 // Each generation uses a variation of reeling in Pokémon once they have been hooked. NOTE: Only the Gen 1/2 and Gen 3 minigames are implemented right now! +#define I_FISHING_ENVIRONMENT GEN_LATEST // In Gen 3, the battle environment when fighting a hooked Pokémon is based on the tile the player is standing on. In Gen 4 onwards, the environment is based on tile that is being fished in, resulting in it usually being a water environment. +#define I_FISHING_STICKY_BOOST GEN_LATEST // In Gen 3, a Pokemon with Suction Cups or Sticky Hold in the first slot of the party causes the chance for a bite to increase by about 35%. In Gen 4 onwards, it doubles the base bite chance. +#define I_FISHING_FOLLOWER_BOOST FALSE // In HGSS, fishing bite odds are increased depending on the friendship of the current following Pokémon. +#define I_FISHING_CHAIN FALSE // Introduced in XY, hooking the same Pokémon repeatedly will increase the odds of that mon being shiny. NOTE: This implementation is an approximation of the actual feature, as XY have not been throughoutly documented or datamined. +#define I_FISHING_PROXIMITY FALSE // In XY, bite chance is boosted by the number of adjacent non-surfable tiles next to your fishing line +#define I_FISHING_TIME_OF_DAY_BOOST FALSE // In XY, bite chance is boosted during morning and evening + +#endif // GUARD_CONFIG_FISHING_H diff --git a/include/config/general.h b/include/config/general.h index d363c345ff..68ac0ec462 100644 --- a/include/config/general.h +++ b/include/config/general.h @@ -6,11 +6,16 @@ // still has them in the ROM. This is because the developers forgot // to define NDEBUG before release, however this has been changed as // Ruby's actual debug build does not use the AGBPrint features. +// +// Use `make release` to automatically enable NDEBUG. +#ifdef RELEASE #define NDEBUG +#endif -// To enable printf debugging, comment out "#define NDEBUG". This allows +// printf debugging is now enabled by default. This allows // the various AGBPrint functions to be used. (See include/gba/isagbprint.h). // See below for enabling different pretty printing versions. +// To disable printf debugging, build a release build using `make release`. #ifndef NDEBUG @@ -69,8 +74,6 @@ // General settings #define EXPANSION_INTRO TRUE // If TRUE, a custom RHH intro will play after the vanilla copyright screen. #define HQ_RANDOM TRUE // If TRUE, replaces the default RNG with an implementation of SFC32 RNG. May break code that relies on RNG. -#define AUTO_SCROLL_TEXT FALSE // If TRUE, text will automatically scroll to the next line after NUM_FRAMES_AUTO_SCROLL_DELAY. Players can still press A_BUTTON or B_BUTTON to scroll on their own. -#define NUM_FRAMES_AUTO_SCROLL_DELAY 49 #define PHONEMES_SHARED FALSE // If TRUE, bard phonemes all reference the same sound (sound/direct_sound_samples/phonemes/shared.bin) to save ROM space. // Measurement system constants to be used for UNITS @@ -83,5 +86,4 @@ // Naming Screen #define AUTO_LOWERCASE_KEYBOARD GEN_LATEST // Starting in GEN_6, after entering the first uppercase character, the keyboard switches to lowercase letters. -#define SAVE_TYPE_ERROR_SCREEN FALSE // When enabled, this shows an error message when the game is loaded on a cart without a flash chip or on an emulator with the wrong save type setting instead of crashing. #endif // GUARD_CONFIG_GENERAL_H diff --git a/include/config/item.h b/include/config/item.h index 4222754ead..8a5a0009dd 100644 --- a/include/config/item.h +++ b/include/config/item.h @@ -38,13 +38,15 @@ // Vs. Seeker #define I_VS_SEEKER_CHARGING 0 // If this flag is assigned, the Vs Seeker functionality will be enabled. When the player has the Vs. Seeker, Match Call rematch functions will stop working. Documentation for the Vs. Seeker can be found in docs/tutorials/vs_seeker.md. -// Fishing -#define I_FISHING_BITE_ODDS GEN_LATEST // In Gen 1 and Gen 2, the Old Rod has a 100% chance for a bite, Good Rod has a 66% chance for a bite, and Super Rod has a 50% chance for a bite. In Gen 3, all rods have a base 50% chance for a bite. In Gen 4 onwards, the Old Rod has a base 25% chance for a bite, Good Rod has a 50% chance for a bite, and Super Rod has a 75% chance for a bite. -#define I_FISHING_MINIGAME GEN_3 // Each generation uses a variation of reeling in Pokémon once they have been hooked. NOTE: Only the Gen 1/2 and Gen 3 minigames are implemented right now! -#define I_FISHING_ENVIRONMENT GEN_LATEST // In Gen 3, the battle environment when fighting a hooked Pokémon is based on the tile the player is standing on. In Gen 4 onwards, the environment is based on tile that is being fished in, resulting in it usually being a water environment. -#define I_FISHING_STICKY_BOOST GEN_LATEST // In Gen 3, a Pokemon with Suction Cups or Sticky Hold in the first slot of the party causes the chance for a bite to increase by about 35%. In Gen 4 onwards, it doubles the base bite chance. -#define I_FISHING_FOLLOWER_BOOST FALSE // In HGSS, fishing bite odds are increased depending on the friendship of the current following Pokémon. -#define I_FISHING_CHAIN FALSE // Introduced in XY, hooking the same Pokémon repeatedly will increase the odds of that mon being shiny. NOTE: This implementation is an approximation of the actual feature, as XY have not been throughoutly documented or datamined. -#define I_FISHING_PROXIMITY FALSE // Introduced in XY, fishing away from other people in enclosed areas will increase the chances of a Pokémon being hooked. NOTE: This implementation is an approximation of the actual feature, as XY have not been throughoutly documented or datamined. +// ORAS Dowsing Machine +#define I_ORAS_DOWSING_FLAG 0 // Replace 0 with an unused flag to enable the Dowsing Machine mechanic from ORAS. +#define I_ORAS_DOWSING_SOUNDS TRUE // If TRUE, the Dowsing Machine will make sounds based on how far away the hidden item is. +#define I_ORAS_DOWSING_COLOR_PAL 15 // The color within the palette that will change based on proximity to the item. +// Color values for the ORAS dowsing distances/anims +#define I_ORAS_DOWSING_COLOR_NONE RGB_GRAY +#define I_ORAS_DOWSING_COLOR_SLOW RGB2GBA(56, 120, 255) +#define I_ORAS_DOWSING_COLOR_NORMAL RGB2GBA(24, 216, 24) +#define I_ORAS_DOWSING_COLOR_FAST RGB2GBA(255, 255, 40) +#define I_ORAS_DOWSING_COLOR_FASTER RGB_RED #endif // GUARD_CONFIG_ITEM_H diff --git a/include/config/name_box.h b/include/config/name_box.h new file mode 100644 index 0000000000..715b33cad9 --- /dev/null +++ b/include/config/name_box.h @@ -0,0 +1,17 @@ +#ifndef GUARD_CONFIG_NAME_BOX_H +#define GUARD_CONFIG_NAME_BOX_H + +#define OW_FLAG_SUPPRESS_NAME_BOX 0 // If this flag is set, any namebox (whether its from a macro or a code) will not show up until this flag is unset. + +// Namebox Speaker configs +#define OW_NAME_BOX_USE_DYNAMIC_WIDTH TRUE // When TRUE, the namebox window can use different width depending on the length of the speaker's name. +#define OW_NAME_BOX_NPC_TRAINER FALSE // When TRUE, any approaching NPC trainers will have a namebox shown automagically. The name will be taken from their trainer data. +#define OW_NAME_BOX_DEFAULT_WIDTH 8 // Maximum width of what OW_NAME_BOX_USE_DYNAMIC_WIDTH can set. Also the default width when the config above is set to FALSE (or the dynamic width exceeds this value). +#define OW_NAME_BOX_DEFAULT_HEIGHT 2 // Maximum height of the namebox window. + +// Text colors of Namebox. The numbers corresponds to the palette index. +// The BG color is not provided as it always needs to be 0. +#define OW_NAME_BOX_FOREGROUND_COLOR 1 +#define OW_NAME_BOX_SHADOW_COLOR 2 + +#endif // GUARD_CONFIG_NAME_BOX_H diff --git a/include/config/overworld.h b/include/config/overworld.h index 117d3b9eb5..8d060d7231 100644 --- a/include/config/overworld.h +++ b/include/config/overworld.h @@ -86,13 +86,13 @@ #define GEN_8_PLA GEN_LATEST + 2 #define TIME_DEBUG GEN_LATEST + 3 -//Time +// Time #define OW_TIMES_OF_DAY GEN_LATEST // Different generations have the times of day change at different times. #define OW_USE_FAKE_RTC FALSE // When TRUE, seconds on the in-game clock will only advance once every 60 playTimeVBlanks (every 60 frames). #define OW_ALTERED_TIME_RATIO GEN_LATEST // In GEN_8_PLA, the time in game moves forward 60 seconds for every second in the RTC. In GEN_9, it is 20 seconds. TIME_DEBUG is 1:1, and meant for debugging purposes. This has no effect if OW_USE_FAKE_RTC is FALSE. #define OW_TIME_OF_DAY_ENCOUNTERS FALSE // If TRUE, will allow the user to define and use different encounter tables based on the time of day. #define OW_TIME_OF_DAY_DISABLE_FALLBACK FALSE // If TRUE, if the encounter table for a specific map and time is empty, the area will have no encounters instead of falling back to the vanilla map and time. -#define OW_TIME_OF_DAY_FALLBACK TIME_MORNING // The time of day that encounter tables fall back to. +#define OW_TIME_OF_DAY_FALLBACK TIME_MORNING // The time of day that encounter tables fall back to. If you set OW_TIMES_OF_DAY to GEN_3, change this to TIME_DAY or you won't have any encounters! // Lighting #define OW_SHADOW_INTENSITY 4 // Ranges from 0 to 16, where 0 is fully transparent and 16 is black. diff --git a/include/config/species_enabled.h b/include/config/species_enabled.h index 23bb6d9d54..8b6b9d87b7 100644 --- a/include/config/species_enabled.h +++ b/include/config/species_enabled.h @@ -29,6 +29,8 @@ #define P_GIGANTAMAX_FORMS TRUE #define P_TERA_FORMS TRUE +#define P_GEN_9_MEGA_EVOLUTIONS P_MEGA_EVOLUTIONS // Mega Evolutions introduced in Z-A and its DLC + // Fusion forms #define P_FUSION_FORMS TRUE diff --git a/include/config/summary_screen.h b/include/config/summary_screen.h index 07bae63533..e76cd478b6 100644 --- a/include/config/summary_screen.h +++ b/include/config/summary_screen.h @@ -2,16 +2,16 @@ #define GUARD_CONFIG_SUMMARY_SCREEN_H // Settings -#define P_SUMMARY_SCREEN_MOVE_RELEARNER TRUE // If TRUE, shows an option for Pokémon to relearn moves on the summary screen moves page. -#define P_SUMMARY_SCREEN_NATURE_COLORS TRUE // If TRUE, nature-based stat boosts and reductions will be red and blue in the summary screen. -#define P_SUMMARY_MOVE_RELEARNER_FULL_PP TRUE // If TRUE, the move relearner in the summary screen restores relearned moves' PP to full. +#define P_SUMMARY_SCREEN_NATURE_COLORS TRUE // If TRUE, nature-based stat boosts and reductions will be red and blue in the summary screen. #define P_SUMMARY_SCREEN_RENAME TRUE // If TRUE, an option to change Pokémon nicknames replaces the cancel prompt on the summary screen info page. + +// IV/EV settings #define P_SUMMARY_SCREEN_IV_EV_INFO FALSE // If TRUE, will allow player to cycle through the Stats, IVs, and EVs in the summary screen skills page. #define P_SUMMARY_SCREEN_IV_EV_BOX_ONLY FALSE // If TRUE, will allow player to cycle through the Stats, IVs, and EVs in the summary screen skills page, but only in the PC storage box. #define P_SUMMARY_SCREEN_IV_HYPERTRAIN TRUE // If TRUE, stats that have been hyper trained will show as 31/S when viewing them in the summary screen #define P_SUMMARY_SCREEN_IV_EV_TILESET FALSE // If TRUE, loads an alternate tileset to allow changing the "STATS" label in the summary screen skills page. Note: if it's still loading the alternate tileset after changing this and recompiling, you may need a `make clean` before compilation. #define P_SUMMARY_SCREEN_IV_EV_VALUES FALSE // If TRUE, will show the actual IV value instead of the letter grade. -/* +/* LETTER GRADE GUIDE: F = 0 @@ -26,7 +26,32 @@ Info taken from https://bulbapedia.bulbagarden.net/wiki/Stats_judge. #define P_SUMMARY_SCREEN_IV_ONLY FALSE // If TRUE, will only show IV info in the summary screen. #define P_SUMMARY_SCREEN_EV_ONLY FALSE // If TRUE, will only show EV info in the summary screen. -// Flags +// IV/EV flags #define P_FLAG_SUMMARY_SCREEN_IV_EV_INFO 0 // If this flag is set, will allow player to cycle through the Stats, IVs, and EVs in the summary screen skills page. Note: if P_SUMMARY_SCREEN_IV_EV_INFO is TRUE, this flag does nothing. +// Move Relearner settings +#define P_ENABLE_MOVE_RELEARNERS FALSE // If TRUE, it enables move relearners for egg, TM and tutor. (see below for specific configs /flags) +#define P_SORT_MOVES FALSE // If TRUE, sorts all moves alphabetically in the relearner's list. + +// Level up Relearner +#define P_PRE_EVO_MOVES FALSE // If TRUE, it enables the Pokémon to learn moves from it's pre evolution. +#define P_ENABLE_ALL_LEVEL_UP_MOVES FALSE // If TRUE, it enables the Pokémon to learn all level up moves, regardless of its level. + +// TM Relearner +#define P_TM_MOVES_RELEARNER TRUE // If TRUE, enables machine move relearner. +#define P_ENABLE_ALL_TM_MOVES FALSE // If TRUE, it enables the Pokémon to learn all TMs its compatible with, regardless of it being in the bag. + +// Relearner flags - Redundant if P_ENABLE_MOVE_RELEARNERS is TRUE, but still added here incase you don't want all relearners unlocked at the same time. +// To use the following features in scripting, replace the 0s with the flag ID you're assigning it to. +// Eg: Replace with FLAG_UNUSED_0x264 so you can use that flag to toggle the feature. +#define P_FLAG_EGG_MOVES 0 // If this flag is set, enables egg move relearner. +#define P_FLAG_TUTOR_MOVES 0 // If this flag is set, enables tutor move relearner. + +// Move Relearner summary screen +#define P_SUMMARY_SCREEN_MOVE_RELEARNER TRUE // If TRUE, shows an option for Pokémon to relearn moves on the summary screen moves page. +#define P_SUMMARY_MOVE_RELEARNER_FULL_PP TRUE // If TRUE, the move relearner in the summary screen restores relearned moves' PP to full. + +// Move Relearner party menu +#define P_PARTY_MOVE_RELEARNER FALSE // If TRUE, it enables the move relearner in the party menu. + #endif // GUARD_CONFIG_SUMMARY_SCREEN_H diff --git a/include/config/text.h b/include/config/text.h new file mode 100644 index 0000000000..81438055a1 --- /dev/null +++ b/include/config/text.h @@ -0,0 +1,19 @@ +#ifndef GUARD_CONFIG_TEXT_H +#define GUARD_CONFIG_TEXT_H + +// Text settings: +#define AUTO_SCROLL_TEXT FALSE // If TRUE, text will automatically scroll to the next line after NUM_FRAMES_AUTO_SCROLL_DELAY. Players can still press A_BUTTON or B_BUTTON to scroll on their own. +#define NUM_FRAMES_AUTO_SCROLL_DELAY 49 + +// A note on the modifiers: they are roughly multiplicative, so having them set at 1 is vanilla speed. They also are used to calculate frame delays for the speed of the scroll effect and the animated down arrow, so to that end, they are capped at 31 to prevent the text printing from desyncing with A/B button inputs. +// From testing, a value of 18 to 20 is essentially equivalent to instant text. +#define TEXT_SPEED_SLOW_MODIFIER 1 // How fast the SLOW text speed option prints +#define TEXT_SPEED_MEDIUM_MODIFIER 1 // How fast the MID text speed option prints +#define TEXT_SPEED_FAST_MODIFIER 1 // How fast the FAST text speed option prints +#define TEXT_SPEED_INSTANT_MODIFIER 12 // Needed only for the animation delays +#define TEXT_SPEED_INSTANT FALSE // Renders all text as fast as it can, basically instant. Overrides FLAG_TEXT_SPEED_INSTANT and in-game player options menu setting. + +// Text speed flag: +#define FLAG_TEXT_SPEED_INSTANT 0 // Use this if you want to toggle instant text speed + +#endif // GUARD_CONFIG_TEXT_H diff --git a/include/constants/abilities.h b/include/constants/abilities.h index 8568206137..7e17fd5287 100644 --- a/include/constants/abilities.h +++ b/include/constants/abilities.h @@ -1,344 +1,339 @@ #ifndef GUARD_CONSTANTS_ABILITIES_H #define GUARD_CONSTANTS_ABILITIES_H -#define ABILITY_NONE 0 -#define ABILITY_STENCH 1 -#define ABILITY_DRIZZLE 2 -#define ABILITY_SPEED_BOOST 3 -#define ABILITY_BATTLE_ARMOR 4 -#define ABILITY_STURDY 5 -#define ABILITY_DAMP 6 -#define ABILITY_LIMBER 7 -#define ABILITY_SAND_VEIL 8 -#define ABILITY_STATIC 9 -#define ABILITY_VOLT_ABSORB 10 -#define ABILITY_WATER_ABSORB 11 -#define ABILITY_OBLIVIOUS 12 -#define ABILITY_CLOUD_NINE 13 -#define ABILITY_COMPOUND_EYES 14 -#define ABILITY_INSOMNIA 15 -#define ABILITY_COLOR_CHANGE 16 -#define ABILITY_IMMUNITY 17 -#define ABILITY_FLASH_FIRE 18 -#define ABILITY_SHIELD_DUST 19 -#define ABILITY_OWN_TEMPO 20 -#define ABILITY_SUCTION_CUPS 21 -#define ABILITY_INTIMIDATE 22 -#define ABILITY_SHADOW_TAG 23 -#define ABILITY_ROUGH_SKIN 24 -#define ABILITY_WONDER_GUARD 25 -#define ABILITY_LEVITATE 26 -#define ABILITY_EFFECT_SPORE 27 -#define ABILITY_SYNCHRONIZE 28 -#define ABILITY_CLEAR_BODY 29 -#define ABILITY_NATURAL_CURE 30 -#define ABILITY_LIGHTNING_ROD 31 -#define ABILITY_SERENE_GRACE 32 -#define ABILITY_SWIFT_SWIM 33 -#define ABILITY_CHLOROPHYLL 34 -#define ABILITY_ILLUMINATE 35 -#define ABILITY_TRACE 36 -#define ABILITY_HUGE_POWER 37 -#define ABILITY_POISON_POINT 38 -#define ABILITY_INNER_FOCUS 39 -#define ABILITY_MAGMA_ARMOR 40 -#define ABILITY_WATER_VEIL 41 -#define ABILITY_MAGNET_PULL 42 -#define ABILITY_SOUNDPROOF 43 -#define ABILITY_RAIN_DISH 44 -#define ABILITY_SAND_STREAM 45 -#define ABILITY_PRESSURE 46 -#define ABILITY_THICK_FAT 47 -#define ABILITY_EARLY_BIRD 48 -#define ABILITY_FLAME_BODY 49 -#define ABILITY_RUN_AWAY 50 -#define ABILITY_KEEN_EYE 51 -#define ABILITY_HYPER_CUTTER 52 -#define ABILITY_PICKUP 53 -#define ABILITY_TRUANT 54 -#define ABILITY_HUSTLE 55 -#define ABILITY_CUTE_CHARM 56 -#define ABILITY_PLUS 57 -#define ABILITY_MINUS 58 -#define ABILITY_FORECAST 59 -#define ABILITY_STICKY_HOLD 60 -#define ABILITY_SHED_SKIN 61 -#define ABILITY_GUTS 62 -#define ABILITY_MARVEL_SCALE 63 -#define ABILITY_LIQUID_OOZE 64 -#define ABILITY_OVERGROW 65 -#define ABILITY_BLAZE 66 -#define ABILITY_TORRENT 67 -#define ABILITY_SWARM 68 -#define ABILITY_ROCK_HEAD 69 -#define ABILITY_DROUGHT 70 -#define ABILITY_ARENA_TRAP 71 -#define ABILITY_VITAL_SPIRIT 72 -#define ABILITY_WHITE_SMOKE 73 -#define ABILITY_PURE_POWER 74 -#define ABILITY_SHELL_ARMOR 75 -#define ABILITY_AIR_LOCK 76 +enum __attribute__((packed)) Ability +{ + ABILITY_NONE = 0, + ABILITY_STENCH = 1, + ABILITY_DRIZZLE = 2, + ABILITY_SPEED_BOOST = 3, + ABILITY_BATTLE_ARMOR = 4, + ABILITY_STURDY = 5, + ABILITY_DAMP = 6, + ABILITY_LIMBER = 7, + ABILITY_SAND_VEIL = 8, + ABILITY_STATIC = 9, + ABILITY_VOLT_ABSORB = 10, + ABILITY_WATER_ABSORB = 11, + ABILITY_OBLIVIOUS = 12, + ABILITY_CLOUD_NINE = 13, + ABILITY_COMPOUND_EYES = 14, + ABILITY_INSOMNIA = 15, + ABILITY_COLOR_CHANGE = 16, + ABILITY_IMMUNITY = 17, + ABILITY_FLASH_FIRE = 18, + ABILITY_SHIELD_DUST = 19, + ABILITY_OWN_TEMPO = 20, + ABILITY_SUCTION_CUPS = 21, + ABILITY_INTIMIDATE = 22, + ABILITY_SHADOW_TAG = 23, + ABILITY_ROUGH_SKIN = 24, + ABILITY_WONDER_GUARD = 25, + ABILITY_LEVITATE = 26, + ABILITY_EFFECT_SPORE = 27, + ABILITY_SYNCHRONIZE = 28, + ABILITY_CLEAR_BODY = 29, + ABILITY_NATURAL_CURE = 30, + ABILITY_LIGHTNING_ROD = 31, + ABILITY_SERENE_GRACE = 32, + ABILITY_SWIFT_SWIM = 33, + ABILITY_CHLOROPHYLL = 34, + ABILITY_ILLUMINATE = 35, + ABILITY_TRACE = 36, + ABILITY_HUGE_POWER = 37, + ABILITY_POISON_POINT = 38, + ABILITY_INNER_FOCUS = 39, + ABILITY_MAGMA_ARMOR = 40, + ABILITY_WATER_VEIL = 41, + ABILITY_MAGNET_PULL = 42, + ABILITY_SOUNDPROOF = 43, + ABILITY_RAIN_DISH = 44, + ABILITY_SAND_STREAM = 45, + ABILITY_PRESSURE = 46, + ABILITY_THICK_FAT = 47, + ABILITY_EARLY_BIRD = 48, + ABILITY_FLAME_BODY = 49, + ABILITY_RUN_AWAY = 50, + ABILITY_KEEN_EYE = 51, + ABILITY_HYPER_CUTTER = 52, + ABILITY_PICKUP = 53, + ABILITY_TRUANT = 54, + ABILITY_HUSTLE = 55, + ABILITY_CUTE_CHARM = 56, + ABILITY_PLUS = 57, + ABILITY_MINUS = 58, + ABILITY_FORECAST = 59, + ABILITY_STICKY_HOLD = 60, + ABILITY_SHED_SKIN = 61, + ABILITY_GUTS = 62, + ABILITY_MARVEL_SCALE = 63, + ABILITY_LIQUID_OOZE = 64, + ABILITY_OVERGROW = 65, + ABILITY_BLAZE = 66, + ABILITY_TORRENT = 67, + ABILITY_SWARM = 68, + ABILITY_ROCK_HEAD = 69, + ABILITY_DROUGHT = 70, + ABILITY_ARENA_TRAP = 71, + ABILITY_VITAL_SPIRIT = 72, + ABILITY_WHITE_SMOKE = 73, + ABILITY_PURE_POWER = 74, + ABILITY_SHELL_ARMOR = 75, + ABILITY_AIR_LOCK = 76, + ABILITIES_COUNT_GEN3, -#define ABILITIES_COUNT_GEN3 77 + // Gen 4 + ABILITY_TANGLED_FEET = ABILITIES_COUNT_GEN3, + ABILITY_MOTOR_DRIVE = 78, + ABILITY_RIVALRY = 79, + ABILITY_STEADFAST = 80, + ABILITY_SNOW_CLOAK = 81, + ABILITY_GLUTTONY = 82, + ABILITY_ANGER_POINT = 83, + ABILITY_UNBURDEN = 84, + ABILITY_HEATPROOF = 85, + ABILITY_SIMPLE = 86, + ABILITY_DRY_SKIN = 87, + ABILITY_DOWNLOAD = 88, + ABILITY_IRON_FIST = 89, + ABILITY_POISON_HEAL = 90, + ABILITY_ADAPTABILITY = 91, + ABILITY_SKILL_LINK = 92, + ABILITY_HYDRATION = 93, + ABILITY_SOLAR_POWER = 94, + ABILITY_QUICK_FEET = 95, + ABILITY_NORMALIZE = 96, + ABILITY_SNIPER = 97, + ABILITY_MAGIC_GUARD = 98, + ABILITY_NO_GUARD = 99, + ABILITY_STALL = 100, + ABILITY_TECHNICIAN = 101, + ABILITY_LEAF_GUARD = 102, + ABILITY_KLUTZ = 103, + ABILITY_MOLD_BREAKER = 104, + ABILITY_SUPER_LUCK = 105, + ABILITY_AFTERMATH = 106, + ABILITY_ANTICIPATION = 107, + ABILITY_FOREWARN = 108, + ABILITY_UNAWARE = 109, + ABILITY_TINTED_LENS = 110, + ABILITY_FILTER = 111, + ABILITY_SLOW_START = 112, + ABILITY_SCRAPPY = 113, + ABILITY_STORM_DRAIN = 114, + ABILITY_ICE_BODY = 115, + ABILITY_SOLID_ROCK = 116, + ABILITY_SNOW_WARNING = 117, + ABILITY_HONEY_GATHER = 118, + ABILITY_FRISK = 119, + ABILITY_RECKLESS = 120, + ABILITY_MULTITYPE = 121, + ABILITY_FLOWER_GIFT = 122, + ABILITY_BAD_DREAMS = 123, + ABILITIES_COUNT_GEN4, -// Gen 4 -#define ABILITY_TANGLED_FEET 77 -#define ABILITY_MOTOR_DRIVE 78 -#define ABILITY_RIVALRY 79 -#define ABILITY_STEADFAST 80 -#define ABILITY_SNOW_CLOAK 81 -#define ABILITY_GLUTTONY 82 -#define ABILITY_ANGER_POINT 83 -#define ABILITY_UNBURDEN 84 -#define ABILITY_HEATPROOF 85 -#define ABILITY_SIMPLE 86 -#define ABILITY_DRY_SKIN 87 -#define ABILITY_DOWNLOAD 88 -#define ABILITY_IRON_FIST 89 -#define ABILITY_POISON_HEAL 90 -#define ABILITY_ADAPTABILITY 91 -#define ABILITY_SKILL_LINK 92 -#define ABILITY_HYDRATION 93 -#define ABILITY_SOLAR_POWER 94 -#define ABILITY_QUICK_FEET 95 -#define ABILITY_NORMALIZE 96 -#define ABILITY_SNIPER 97 -#define ABILITY_MAGIC_GUARD 98 -#define ABILITY_NO_GUARD 99 -#define ABILITY_STALL 100 -#define ABILITY_TECHNICIAN 101 -#define ABILITY_LEAF_GUARD 102 -#define ABILITY_KLUTZ 103 -#define ABILITY_MOLD_BREAKER 104 -#define ABILITY_SUPER_LUCK 105 -#define ABILITY_AFTERMATH 106 -#define ABILITY_ANTICIPATION 107 -#define ABILITY_FOREWARN 108 -#define ABILITY_UNAWARE 109 -#define ABILITY_TINTED_LENS 110 -#define ABILITY_FILTER 111 -#define ABILITY_SLOW_START 112 -#define ABILITY_SCRAPPY 113 -#define ABILITY_STORM_DRAIN 114 -#define ABILITY_ICE_BODY 115 -#define ABILITY_SOLID_ROCK 116 -#define ABILITY_SNOW_WARNING 117 -#define ABILITY_HONEY_GATHER 118 -#define ABILITY_FRISK 119 -#define ABILITY_RECKLESS 120 -#define ABILITY_MULTITYPE 121 -#define ABILITY_FLOWER_GIFT 122 -#define ABILITY_BAD_DREAMS 123 + // Gen 5 + ABILITY_PICKPOCKET = ABILITIES_COUNT_GEN4, + ABILITY_SHEER_FORCE = 125, + ABILITY_CONTRARY = 126, + ABILITY_UNNERVE = 127, + ABILITY_DEFIANT = 128, + ABILITY_DEFEATIST = 129, + ABILITY_CURSED_BODY = 130, + ABILITY_HEALER = 131, + ABILITY_FRIEND_GUARD = 132, + ABILITY_WEAK_ARMOR = 133, + ABILITY_HEAVY_METAL = 134, + ABILITY_LIGHT_METAL = 135, + ABILITY_MULTISCALE = 136, + ABILITY_TOXIC_BOOST = 137, + ABILITY_FLARE_BOOST = 138, + ABILITY_HARVEST = 139, + ABILITY_TELEPATHY = 140, + ABILITY_MOODY = 141, + ABILITY_OVERCOAT = 142, + ABILITY_POISON_TOUCH = 143, + ABILITY_REGENERATOR = 144, + ABILITY_BIG_PECKS = 145, + ABILITY_SAND_RUSH = 146, + ABILITY_WONDER_SKIN = 147, + ABILITY_ANALYTIC = 148, + ABILITY_ILLUSION = 149, + ABILITY_IMPOSTER = 150, + ABILITY_INFILTRATOR = 151, + ABILITY_MUMMY = 152, + ABILITY_MOXIE = 153, + ABILITY_JUSTIFIED = 154, + ABILITY_RATTLED = 155, + ABILITY_MAGIC_BOUNCE = 156, + ABILITY_SAP_SIPPER = 157, + ABILITY_PRANKSTER = 158, + ABILITY_SAND_FORCE = 159, + ABILITY_IRON_BARBS = 160, + ABILITY_ZEN_MODE = 161, + ABILITY_VICTORY_STAR = 162, + ABILITY_TURBOBLAZE = 163, + ABILITY_TERAVOLT = 164, + ABILITIES_COUNT_GEN5, -#define ABILITIES_COUNT_GEN4 124 + // Gen 6 + ABILITY_AROMA_VEIL = ABILITIES_COUNT_GEN5, + ABILITY_FLOWER_VEIL = 166, + ABILITY_CHEEK_POUCH = 167, + ABILITY_PROTEAN = 168, + ABILITY_FUR_COAT = 169, + ABILITY_MAGICIAN = 170, + ABILITY_BULLETPROOF = 171, + ABILITY_COMPETITIVE = 172, + ABILITY_STRONG_JAW = 173, + ABILITY_REFRIGERATE = 174, + ABILITY_SWEET_VEIL = 175, + ABILITY_STANCE_CHANGE = 176, + ABILITY_GALE_WINGS = 177, + ABILITY_MEGA_LAUNCHER = 178, + ABILITY_GRASS_PELT = 179, + ABILITY_SYMBIOSIS = 180, + ABILITY_TOUGH_CLAWS = 181, + ABILITY_PIXILATE = 182, + ABILITY_GOOEY = 183, + ABILITY_AERILATE = 184, + ABILITY_PARENTAL_BOND = 185, + ABILITY_DARK_AURA = 186, + ABILITY_FAIRY_AURA = 187, + ABILITY_AURA_BREAK = 188, + ABILITY_PRIMORDIAL_SEA = 189, + ABILITY_DESOLATE_LAND = 190, + ABILITY_DELTA_STREAM = 191, + ABILITIES_COUNT_GEN6, -// Gen 5 -#define ABILITY_PICKPOCKET 124 -#define ABILITY_SHEER_FORCE 125 -#define ABILITY_CONTRARY 126 -#define ABILITY_UNNERVE 127 -#define ABILITY_DEFIANT 128 -#define ABILITY_DEFEATIST 129 -#define ABILITY_CURSED_BODY 130 -#define ABILITY_HEALER 131 -#define ABILITY_FRIEND_GUARD 132 -#define ABILITY_WEAK_ARMOR 133 -#define ABILITY_HEAVY_METAL 134 -#define ABILITY_LIGHT_METAL 135 -#define ABILITY_MULTISCALE 136 -#define ABILITY_TOXIC_BOOST 137 -#define ABILITY_FLARE_BOOST 138 -#define ABILITY_HARVEST 139 -#define ABILITY_TELEPATHY 140 -#define ABILITY_MOODY 141 -#define ABILITY_OVERCOAT 142 -#define ABILITY_POISON_TOUCH 143 -#define ABILITY_REGENERATOR 144 -#define ABILITY_BIG_PECKS 145 -#define ABILITY_SAND_RUSH 146 -#define ABILITY_WONDER_SKIN 147 -#define ABILITY_ANALYTIC 148 -#define ABILITY_ILLUSION 149 -#define ABILITY_IMPOSTER 150 -#define ABILITY_INFILTRATOR 151 -#define ABILITY_MUMMY 152 -#define ABILITY_MOXIE 153 -#define ABILITY_JUSTIFIED 154 -#define ABILITY_RATTLED 155 -#define ABILITY_MAGIC_BOUNCE 156 -#define ABILITY_SAP_SIPPER 157 -#define ABILITY_PRANKSTER 158 -#define ABILITY_SAND_FORCE 159 -#define ABILITY_IRON_BARBS 160 -#define ABILITY_ZEN_MODE 161 -#define ABILITY_VICTORY_STAR 162 -#define ABILITY_TURBOBLAZE 163 -#define ABILITY_TERAVOLT 164 + // Gen 7 + ABILITY_STAMINA = ABILITIES_COUNT_GEN6, + ABILITY_WIMP_OUT = 193, + ABILITY_EMERGENCY_EXIT = 194, + ABILITY_WATER_COMPACTION = 195, + ABILITY_MERCILESS = 196, + ABILITY_SHIELDS_DOWN = 197, + ABILITY_STAKEOUT = 198, + ABILITY_WATER_BUBBLE = 199, + ABILITY_STEELWORKER = 200, + ABILITY_BERSERK = 201, + ABILITY_SLUSH_RUSH = 202, + ABILITY_LONG_REACH = 203, + ABILITY_LIQUID_VOICE = 204, + ABILITY_TRIAGE = 205, + ABILITY_GALVANIZE = 206, + ABILITY_SURGE_SURFER = 207, + ABILITY_SCHOOLING = 208, + ABILITY_DISGUISE = 209, + ABILITY_BATTLE_BOND = 210, + ABILITY_POWER_CONSTRUCT = 211, + ABILITY_CORROSION = 212, + ABILITY_COMATOSE = 213, + ABILITY_QUEENLY_MAJESTY = 214, + ABILITY_INNARDS_OUT = 215, + ABILITY_DANCER = 216, + ABILITY_BATTERY = 217, + ABILITY_FLUFFY = 218, + ABILITY_DAZZLING = 219, + ABILITY_SOUL_HEART = 220, + ABILITY_TANGLING_HAIR = 221, + ABILITY_RECEIVER = 222, + ABILITY_POWER_OF_ALCHEMY = 223, + ABILITY_BEAST_BOOST = 224, + ABILITY_RKS_SYSTEM = 225, + ABILITY_ELECTRIC_SURGE = 226, + ABILITY_PSYCHIC_SURGE = 227, + ABILITY_MISTY_SURGE = 228, + ABILITY_GRASSY_SURGE = 229, + ABILITY_FULL_METAL_BODY = 230, + ABILITY_SHADOW_SHIELD = 231, + ABILITY_PRISM_ARMOR = 232, + ABILITY_NEUROFORCE = 233, + ABILITIES_COUNT_GEN7, -#define ABILITIES_COUNT_GEN5 165 + // Gen 8 + ABILITY_INTREPID_SWORD = ABILITIES_COUNT_GEN7, + ABILITY_DAUNTLESS_SHIELD = 235, + ABILITY_LIBERO = 236, + ABILITY_BALL_FETCH = 237, + ABILITY_COTTON_DOWN = 238, + ABILITY_PROPELLER_TAIL = 239, + ABILITY_MIRROR_ARMOR = 240, + ABILITY_GULP_MISSILE = 241, + ABILITY_STALWART = 242, + ABILITY_STEAM_ENGINE = 243, + ABILITY_PUNK_ROCK = 244, + ABILITY_SAND_SPIT = 245, + ABILITY_ICE_SCALES = 246, + ABILITY_RIPEN = 247, + ABILITY_ICE_FACE = 248, + ABILITY_POWER_SPOT = 249, + ABILITY_MIMICRY = 250, + ABILITY_SCREEN_CLEANER = 251, + ABILITY_STEELY_SPIRIT = 252, + ABILITY_PERISH_BODY = 253, + ABILITY_WANDERING_SPIRIT = 254, + ABILITY_GORILLA_TACTICS = 255, + ABILITY_NEUTRALIZING_GAS = 256, + ABILITY_PASTEL_VEIL = 257, + ABILITY_HUNGER_SWITCH = 258, + ABILITY_QUICK_DRAW = 259, + ABILITY_UNSEEN_FIST = 260, + ABILITY_CURIOUS_MEDICINE = 261, + ABILITY_TRANSISTOR = 262, + ABILITY_DRAGONS_MAW = 263, + ABILITY_CHILLING_NEIGH = 264, + ABILITY_GRIM_NEIGH = 265, + ABILITY_AS_ONE_ICE_RIDER = 266, + ABILITY_AS_ONE_SHADOW_RIDER = 267, + ABILITIES_COUNT_GEN8, -// Gen 6 -#define ABILITY_AROMA_VEIL 165 -#define ABILITY_FLOWER_VEIL 166 -#define ABILITY_CHEEK_POUCH 167 -#define ABILITY_PROTEAN 168 -#define ABILITY_FUR_COAT 169 -#define ABILITY_MAGICIAN 170 -#define ABILITY_BULLETPROOF 171 -#define ABILITY_COMPETITIVE 172 -#define ABILITY_STRONG_JAW 173 -#define ABILITY_REFRIGERATE 174 -#define ABILITY_SWEET_VEIL 175 -#define ABILITY_STANCE_CHANGE 176 -#define ABILITY_GALE_WINGS 177 -#define ABILITY_MEGA_LAUNCHER 178 -#define ABILITY_GRASS_PELT 179 -#define ABILITY_SYMBIOSIS 180 -#define ABILITY_TOUGH_CLAWS 181 -#define ABILITY_PIXILATE 182 -#define ABILITY_GOOEY 183 -#define ABILITY_AERILATE 184 -#define ABILITY_PARENTAL_BOND 185 -#define ABILITY_DARK_AURA 186 -#define ABILITY_FAIRY_AURA 187 -#define ABILITY_AURA_BREAK 188 -#define ABILITY_PRIMORDIAL_SEA 189 -#define ABILITY_DESOLATE_LAND 190 -#define ABILITY_DELTA_STREAM 191 - -#define ABILITIES_COUNT_GEN6 192 - -// Gen 7 -#define ABILITY_STAMINA 192 -#define ABILITY_WIMP_OUT 193 -#define ABILITY_EMERGENCY_EXIT 194 -#define ABILITY_WATER_COMPACTION 195 -#define ABILITY_MERCILESS 196 -#define ABILITY_SHIELDS_DOWN 197 -#define ABILITY_STAKEOUT 198 -#define ABILITY_WATER_BUBBLE 199 -#define ABILITY_STEELWORKER 200 -#define ABILITY_BERSERK 201 -#define ABILITY_SLUSH_RUSH 202 -#define ABILITY_LONG_REACH 203 -#define ABILITY_LIQUID_VOICE 204 -#define ABILITY_TRIAGE 205 -#define ABILITY_GALVANIZE 206 -#define ABILITY_SURGE_SURFER 207 -#define ABILITY_SCHOOLING 208 -#define ABILITY_DISGUISE 209 -#define ABILITY_BATTLE_BOND 210 -#define ABILITY_POWER_CONSTRUCT 211 -#define ABILITY_CORROSION 212 -#define ABILITY_COMATOSE 213 -#define ABILITY_QUEENLY_MAJESTY 214 -#define ABILITY_INNARDS_OUT 215 -#define ABILITY_DANCER 216 -#define ABILITY_BATTERY 217 -#define ABILITY_FLUFFY 218 -#define ABILITY_DAZZLING 219 -#define ABILITY_SOUL_HEART 220 -#define ABILITY_TANGLING_HAIR 221 -#define ABILITY_RECEIVER 222 -#define ABILITY_POWER_OF_ALCHEMY 223 -#define ABILITY_BEAST_BOOST 224 -#define ABILITY_RKS_SYSTEM 225 -#define ABILITY_ELECTRIC_SURGE 226 -#define ABILITY_PSYCHIC_SURGE 227 -#define ABILITY_MISTY_SURGE 228 -#define ABILITY_GRASSY_SURGE 229 -#define ABILITY_FULL_METAL_BODY 230 -#define ABILITY_SHADOW_SHIELD 231 -#define ABILITY_PRISM_ARMOR 232 -#define ABILITY_NEUROFORCE 233 - -#define ABILITIES_COUNT_GEN7 234 - -// Gen 8 -#define ABILITY_INTREPID_SWORD 234 -#define ABILITY_DAUNTLESS_SHIELD 235 -#define ABILITY_LIBERO 236 -#define ABILITY_BALL_FETCH 237 -#define ABILITY_COTTON_DOWN 238 -#define ABILITY_PROPELLER_TAIL 239 -#define ABILITY_MIRROR_ARMOR 240 -#define ABILITY_GULP_MISSILE 241 -#define ABILITY_STALWART 242 -#define ABILITY_STEAM_ENGINE 243 -#define ABILITY_PUNK_ROCK 244 -#define ABILITY_SAND_SPIT 245 -#define ABILITY_ICE_SCALES 246 -#define ABILITY_RIPEN 247 -#define ABILITY_ICE_FACE 248 -#define ABILITY_POWER_SPOT 249 -#define ABILITY_MIMICRY 250 -#define ABILITY_SCREEN_CLEANER 251 -#define ABILITY_STEELY_SPIRIT 252 -#define ABILITY_PERISH_BODY 253 -#define ABILITY_WANDERING_SPIRIT 254 -#define ABILITY_GORILLA_TACTICS 255 -#define ABILITY_NEUTRALIZING_GAS 256 -#define ABILITY_PASTEL_VEIL 257 -#define ABILITY_HUNGER_SWITCH 258 -#define ABILITY_QUICK_DRAW 259 -#define ABILITY_UNSEEN_FIST 260 -#define ABILITY_CURIOUS_MEDICINE 261 -#define ABILITY_TRANSISTOR 262 -#define ABILITY_DRAGONS_MAW 263 -#define ABILITY_CHILLING_NEIGH 264 -#define ABILITY_GRIM_NEIGH 265 -#define ABILITY_AS_ONE_ICE_RIDER 266 -#define ABILITY_AS_ONE_SHADOW_RIDER 267 - -#define ABILITIES_COUNT_GEN8 268 - -// Gen 9 -#define ABILITY_LINGERING_AROMA 268 -#define ABILITY_SEED_SOWER 269 -#define ABILITY_THERMAL_EXCHANGE 270 -#define ABILITY_ANGER_SHELL 271 -#define ABILITY_PURIFYING_SALT 272 -#define ABILITY_WELL_BAKED_BODY 273 -#define ABILITY_WIND_RIDER 274 -#define ABILITY_GUARD_DOG 275 -#define ABILITY_ROCKY_PAYLOAD 276 -#define ABILITY_WIND_POWER 277 -#define ABILITY_ZERO_TO_HERO 278 -#define ABILITY_COMMANDER 279 -#define ABILITY_ELECTROMORPHOSIS 280 -#define ABILITY_PROTOSYNTHESIS 281 -#define ABILITY_QUARK_DRIVE 282 -#define ABILITY_GOOD_AS_GOLD 283 -#define ABILITY_VESSEL_OF_RUIN 284 -#define ABILITY_SWORD_OF_RUIN 285 -#define ABILITY_TABLETS_OF_RUIN 286 -#define ABILITY_BEADS_OF_RUIN 287 -#define ABILITY_ORICHALCUM_PULSE 288 -#define ABILITY_HADRON_ENGINE 289 -#define ABILITY_OPPORTUNIST 290 -#define ABILITY_CUD_CHEW 291 -#define ABILITY_SHARPNESS 292 -#define ABILITY_SUPREME_OVERLORD 293 -#define ABILITY_COSTAR 294 -#define ABILITY_TOXIC_DEBRIS 295 -#define ABILITY_ARMOR_TAIL 296 -#define ABILITY_EARTH_EATER 297 -#define ABILITY_MYCELIUM_MIGHT 298 -#define ABILITY_HOSPITALITY 299 -#define ABILITY_MINDS_EYE 300 -#define ABILITY_EMBODY_ASPECT_TEAL_MASK 301 -#define ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK 302 -#define ABILITY_EMBODY_ASPECT_WELLSPRING_MASK 303 -#define ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK 304 -#define ABILITY_TOXIC_CHAIN 305 -#define ABILITY_SUPERSWEET_SYRUP 306 -#define ABILITY_TERA_SHIFT 307 -#define ABILITY_TERA_SHELL 308 -#define ABILITY_TERAFORM_ZERO 309 -#define ABILITY_POISON_PUPPETEER 310 - -#define ABILITIES_COUNT_GEN9 311 - -#define ABILITIES_COUNT ABILITIES_COUNT_GEN9 + // Gen 9 + ABILITY_LINGERING_AROMA = ABILITIES_COUNT_GEN8, + ABILITY_SEED_SOWER = 269, + ABILITY_THERMAL_EXCHANGE = 270, + ABILITY_ANGER_SHELL = 271, + ABILITY_PURIFYING_SALT = 272, + ABILITY_WELL_BAKED_BODY = 273, + ABILITY_WIND_RIDER = 274, + ABILITY_GUARD_DOG = 275, + ABILITY_ROCKY_PAYLOAD = 276, + ABILITY_WIND_POWER = 277, + ABILITY_ZERO_TO_HERO = 278, + ABILITY_COMMANDER = 279, + ABILITY_ELECTROMORPHOSIS = 280, + ABILITY_PROTOSYNTHESIS = 281, + ABILITY_QUARK_DRIVE = 282, + ABILITY_GOOD_AS_GOLD = 283, + ABILITY_VESSEL_OF_RUIN = 284, + ABILITY_SWORD_OF_RUIN = 285, + ABILITY_TABLETS_OF_RUIN = 286, + ABILITY_BEADS_OF_RUIN = 287, + ABILITY_ORICHALCUM_PULSE = 288, + ABILITY_HADRON_ENGINE = 289, + ABILITY_OPPORTUNIST = 290, + ABILITY_CUD_CHEW = 291, + ABILITY_SHARPNESS = 292, + ABILITY_SUPREME_OVERLORD = 293, + ABILITY_COSTAR = 294, + ABILITY_TOXIC_DEBRIS = 295, + ABILITY_ARMOR_TAIL = 296, + ABILITY_EARTH_EATER = 297, + ABILITY_MYCELIUM_MIGHT = 298, + ABILITY_HOSPITALITY = 299, + ABILITY_MINDS_EYE = 300, + ABILITY_EMBODY_ASPECT_TEAL_MASK = 301, + ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK = 302, + ABILITY_EMBODY_ASPECT_WELLSPRING_MASK = 303, + ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK = 304, + ABILITY_TOXIC_CHAIN = 305, + ABILITY_SUPERSWEET_SYRUP = 306, + ABILITY_TERA_SHIFT = 307, + ABILITY_TERA_SHELL = 308, + ABILITY_TERAFORM_ZERO = 309, + ABILITY_POISON_PUPPETEER = 310, + ABILITIES_COUNT_GEN9, + ABILITIES_COUNT = ABILITIES_COUNT_GEN9, +}; #endif // GUARD_CONSTANTS_ABILITIES_H diff --git a/include/constants/apricorn_tree.h b/include/constants/apricorn_tree.h new file mode 100644 index 0000000000..14b111adbd --- /dev/null +++ b/include/constants/apricorn_tree.h @@ -0,0 +1,90 @@ +#ifndef GUARD_CONSTANTS_APRICORN_TREE_H +#define GUARD_CONSTANTS_APRICORN_TREE_H + +#include "constants/items.h" + +// Apricorn lookup table, added to allow adding new apricorns without being forced to rearrange the item constants. +enum ApricornType +{ + APRICORN_RED = ITEM_RED_APRICORN, + APRICORN_BLUE = ITEM_BLUE_APRICORN, + APRICORN_YELLOW = ITEM_YELLOW_APRICORN, + APRICORN_GREEN = ITEM_GREEN_APRICORN, + APRICORN_PINK = ITEM_PINK_APRICORN, + APRICORN_WHITE = ITEM_WHITE_APRICORN, + APRICORN_BLACK = ITEM_BLACK_APRICORN, + APRICORN_BERRY_CHERI = ITEM_CHERI_BERRY, + APRICORN_BERRY_CHESTO = ITEM_CHESTO_BERRY, + APRICORN_BERRY_PECHA = ITEM_PECHA_BERRY, + APRICORN_BERRY_RAWST = ITEM_RAWST_BERRY, + APRICORN_BERRY_ASPEAR = ITEM_ASPEAR_BERRY, + APRICORN_BERRY_LEPPA = ITEM_LEPPA_BERRY, + APRICORN_BERRY_ORAN = ITEM_ORAN_BERRY, + APRICORN_BERRY_PERSIM = ITEM_PERSIM_BERRY, + APRICORN_BERRY_LUM = ITEM_LUM_BERRY, + APRICORN_BERRY_SITRUS = ITEM_SITRUS_BERRY, + APRICORN_BERRY_FIGY = ITEM_FIGY_BERRY, + APRICORN_BERRY_WIKI = ITEM_WIKI_BERRY, + APRICORN_BERRY_MAGO = ITEM_MAGO_BERRY, + APRICORN_BERRY_AGUAV = ITEM_AGUAV_BERRY, + APRICORN_BERRY_IAPAPA = ITEM_IAPAPA_BERRY, + APRICORN_BERRY_RAZZ = ITEM_RAZZ_BERRY, + APRICORN_BERRY_BLUK = ITEM_BLUK_BERRY, + APRICORN_BERRY_NANAB = ITEM_NANAB_BERRY, + APRICORN_BERRY_WEPEAR = ITEM_WEPEAR_BERRY, + APRICORN_BERRY_PINAP = ITEM_PINAP_BERRY, + APRICORN_BERRY_POMEG = ITEM_POMEG_BERRY, + APRICORN_BERRY_KELPSY = ITEM_KELPSY_BERRY, + APRICORN_BERRY_QUALOT = ITEM_QUALOT_BERRY, + APRICORN_BERRY_HONDEW = ITEM_HONDEW_BERRY, + APRICORN_BERRY_GREPA = ITEM_GREPA_BERRY, + APRICORN_BERRY_TAMATO = ITEM_TAMATO_BERRY, + APRICORN_BERRY_CORNN = ITEM_CORNN_BERRY, + APRICORN_BERRY_MAGOST = ITEM_MAGOST_BERRY, + APRICORN_BERRY_RABUTA = ITEM_RABUTA_BERRY, + APRICORN_BERRY_NOMEL = ITEM_NOMEL_BERRY, + APRICORN_BERRY_SPELON = ITEM_SPELON_BERRY, + APRICORN_BERRY_PAMTRE = ITEM_PAMTRE_BERRY, + APRICORN_BERRY_WATMEL = ITEM_WATMEL_BERRY, + APRICORN_BERRY_DURIN = ITEM_DURIN_BERRY, + APRICORN_BERRY_BELUE = ITEM_BELUE_BERRY, + APRICORN_BERRY_OCCA = ITEM_OCCA_BERRY, + APRICORN_BERRY_PASSHO = ITEM_PASSHO_BERRY, + APRICORN_BERRY_WACAN = ITEM_WACAN_BERRY, + APRICORN_BERRY_RINDO = ITEM_RINDO_BERRY, + APRICORN_BERRY_YACHE = ITEM_YACHE_BERRY, + APRICORN_BERRY_CHOPLE = ITEM_CHOPLE_BERRY, + APRICORN_BERRY_KEBIA = ITEM_KEBIA_BERRY, + APRICORN_BERRY_SHUCA = ITEM_SHUCA_BERRY, + APRICORN_BERRY_COBA = ITEM_COBA_BERRY, + APRICORN_BERRY_PAYAPA = ITEM_PAYAPA_BERRY, + APRICORN_BERRY_TANGA = ITEM_TANGA_BERRY, + APRICORN_BERRY_CHARTI = ITEM_CHARTI_BERRY, + APRICORN_BERRY_KASIB = ITEM_KASIB_BERRY, + APRICORN_BERRY_HABAN = ITEM_HABAN_BERRY, + APRICORN_BERRY_COLBUR = ITEM_COLBUR_BERRY, + APRICORN_BERRY_BABIRI = ITEM_BABIRI_BERRY, + APRICORN_BERRY_CHILAN = ITEM_CHILAN_BERRY, + APRICORN_BERRY_LIECHI = ITEM_LIECHI_BERRY, + APRICORN_BERRY_GANLON = ITEM_GANLON_BERRY, + APRICORN_BERRY_SALAC = ITEM_SALAC_BERRY, + APRICORN_BERRY_PETAYA = ITEM_PETAYA_BERRY, + APRICORN_BERRY_APICOT = ITEM_APICOT_BERRY, + APRICORN_BERRY_LANSAT = ITEM_LANSAT_BERRY, + APRICORN_BERRY_STARF = ITEM_STARF_BERRY, + APRICORN_BERRY_ENIGMA = ITEM_ENIGMA_BERRY, + APRICORN_BERRY_MICLE = ITEM_MICLE_BERRY, + APRICORN_BERRY_CUSTAP = ITEM_CUSTAP_BERRY, + APRICORN_BERRY_JABOCA = ITEM_JABOCA_BERRY, + APRICORN_BERRY_ROWAP = ITEM_ROWAP_BERRY, + APRICORN_BERRY_ROSELI = ITEM_ROSELI_BERRY, + APRICORN_BERRY_KEE = ITEM_KEE_BERRY, + APRICORN_BERRY_MARANGA = ITEM_MARANGA_BERRY, +}; + +// Trees +#define APRICORN_TREE_NONE 0 + +#define APRICORN_TREE_COUNT 0 + +#endif //GUARD_CONSTANTS_APRICORN_TREE_H diff --git a/include/constants/battle.h b/include/constants/battle.h index 8527ec800f..8dacb7a60a 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -1,6 +1,8 @@ #ifndef GUARD_CONSTANTS_BATTLE_H #define GUARD_CONSTANTS_BATTLE_H +#include "constants/moves.h" + /* * A battler may be in one of four positions on the field. The first bit determines * what side the battler is on, either the player's side or the opponent's side. @@ -45,9 +47,17 @@ enum BattlerId #define BATTLE_OPPOSITE(id) ((id) ^ BIT_SIDE) #define BATTLE_PARTNER(id) ((id) ^ BIT_FLANK) -#define B_SIDE_PLAYER 0 -#define B_SIDE_OPPONENT 1 -#define NUM_BATTLE_SIDES 2 +// Left and right are determined by how they're referred to in tests and everywhere else. +// Left is battlers 0 and 1, right 2 and 3; if you assume the battler referencing them is south, left is to the northeast and right to the northwest. +#define LEFT_FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE) +#define RIGHT_FOE(battler) (((BATTLE_OPPOSITE(battler)) & BIT_SIDE) | BIT_FLANK) + +enum BattleSide +{ + B_SIDE_PLAYER = 0, + B_SIDE_OPPONENT = 1, + NUM_BATTLE_SIDES = 2, +}; #define B_FLANK_LEFT 0 #define B_FLANK_RIGHT 1 @@ -95,12 +105,17 @@ enum BattlerId | BATTLE_TYPE_LEGENDARY \ | BATTLE_TYPE_RECORDED | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE)) -#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))) -#define RECORDED_WILD_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_RECORDED) && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER))) -#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && TRAINER_BATTLE_PARAM.opponentB == 0xFFFF)) -#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER) +#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER)))) +#define RECORDED_WILD_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_RECORDED) && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER))) +#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && TRAINER_BATTLE_PARAM.opponentB == 0xFFFF)) +#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER) +#define BATTLE_TYPE_MORE_THAN_TWO_BATTLERS (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_TWO_OPPONENTS) #define BATTLE_TYPE_PLAYER_HAS_PARTNER (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_TOWER_LINK_MULTI) +// Multibattle test composite flags +#define BATTLE_MULTI_TEST (BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) +#define BATTLE_TWO_VS_ONE_TEST (BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI) + // Battle Outcome defines #define B_OUTCOME_WON 1 #define B_OUTCOME_LOST 2 @@ -155,6 +170,8 @@ enum VolatileFlags F(VOLATILE_LOCK_CONFUSE, lockConfusionTurns, (u32, 3)) \ F(VOLATILE_MULTIPLETURNS, multipleTurns, (u32, 1)) \ F(VOLATILE_WRAPPED, wrapped, (u32, 1)) \ + F(VOLATILE_WRAPPED_BY, wrappedBy, (enum BattlerId, MAX_BITS(4))) \ + F(VOLATILE_WRAPPED_MOVE, wrappedMove, (u32, MOVES_COUNT_ALL - 1)) \ F(VOLATILE_POWDER, powder, (u32, 1)) \ F(VOLATILE_UNUSED, padding, (u32, 1)) \ F(VOLATILE_INFATUATION, infatuation, (enum BattlerId, MAX_BITS(4))) \ @@ -162,7 +179,7 @@ enum VolatileFlags F(VOLATILE_TRANSFORMED, transformed, (u32, 1)) \ F(VOLATILE_RAGE, rage, (u32, 1)) \ F(VOLATILE_SUBSTITUTE, substitute, (u32, 1), V_BATON_PASSABLE) \ - F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 1)) \ + F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 2)) \ F(VOLATILE_ESCAPE_PREVENTION, escapePrevention, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_NIGHTMARE, nightmare, (u32, 1)) \ F(VOLATILE_CURSED, cursed, (u32, 1), V_BATON_PASSABLE) \ @@ -176,12 +193,13 @@ enum VolatileFlags F(VOLATILE_INFINITE_CONFUSION, infiniteConfusion, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_SALT_CURE, saltCure, (u32, 1)) \ F(VOLATILE_SYRUP_BOMB, syrupBomb, (u32, 1)) \ + F(VOLATILE_STICKY_SYRUPED_BY, stickySyrupedBy, (enum BattlerId, MAX_BITS(4))) \ F(VOLATILE_GLAIVE_RUSH, glaiveRush, (u32, 1)) \ F(VOLATILE_LEECH_SEED, leechSeed, (enum BattlerId, MAX_BITS(4)), V_BATON_PASSABLE) \ F(VOLATILE_LOCK_ON, lockOn, (u32, 2), V_BATON_PASSABLE) \ F(VOLATILE_PERISH_SONG, perishSong, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_MINIMIZE, minimize, (u32, 1)) \ - F(VOLATILE_CHARGE, charge, (u32, 1)) \ + F(VOLATILE_CHARGE_TIMER, chargeTimer, (u32, 2)) \ F(VOLATILE_ROOT, root, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_YAWN, yawn, (u32, 2)) \ F(VOLATILE_IMPRISON, imprison, (u32, 1)) \ @@ -195,7 +213,12 @@ enum VolatileFlags F(VOLATILE_HEAL_BLOCK, healBlock, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_AQUA_RING, aquaRing, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_LASER_FOCUS, laserFocus, (u32, 1)) \ - F(VOLATILE_POWER_TRICK, powerTrick, (u32, 1), V_BATON_PASSABLE) + F(VOLATILE_POWER_TRICK, powerTrick, (u32, 1), V_BATON_PASSABLE) \ + F(VOLATILE_NO_RETREAT, noRetreat, (u32, 1), V_BATON_PASSABLE) \ + F(VOLATILE_VESSEL_OF_RUIN, vesselOfRuin, (u32, 1)) \ + F(VOLATILE_SWORD_OF_RUIN, swordOfRuin, (u32, 1)) \ + F(VOLATILE_TABLETS_OF_RUIN, tabletsOfRuin, (u32, 1)) \ + F(VOLATILE_BEADS_OF_RUIN, beadsOfRuin, (u32, 1)) /* Use within a macro to get the maximum allowed value for a volatile. Requires _typeMaxValue as input. */ @@ -233,46 +256,41 @@ enum SemiInvulnerableExclusion EXCLUDE_COMMANDER, }; -#define HITMARKER_STRING_PRINTED (1 << 4) -#define HITMARKER_IGNORE_BIDE (1 << 5) -#define HITMARKER_DESTINYBOND (1 << 6) #define HITMARKER_NO_ANIMATIONS (1 << 7) // set from battleSceneOff. Never changed during battle -#define HITMARKER_IGNORE_SUBSTITUTE (1 << 8) -#define HITMARKER_NO_ATTACKSTRING (1 << 9) -#define HITMARKER_ATTACKSTRING_PRINTED (1 << 10) -#define HITMARKER_NO_PPDEDUCT (1 << 11) +#define HITMARKER_UNUSED_8 (1 << 8) +#define HITMARKER_UNUSED_9 (1 << 9) +#define HITMARKER_UNUSED_10 (1 << 10) +#define HITMARKER_UNUSED_11 (1 << 11) #define HITMARKER_UNUSED_12 (1 << 12) -#define HITMARKER_STATUS_ABILITY_EFFECT (1 << 13) +#define HITMARKER_UNUSED_13 (1 << 13) #define HITMARKER_UNUSED_14 (1 << 14) #define HITMARKER_RUN (1 << 15) -#define HITMARKER_IGNORE_DISGUISE (1 << 16) +#define HITMARKER_UNUSED_16 (1 << 16) #define HITMARKER_DISABLE_ANIMATION (1 << 17) // disable animations during battle scripts, e.g. for Bug Bite #define HITMARKER_UNUSED_18 (1 << 18) #define HITMARKER_UNABLE_TO_USE_MOVE (1 << 19) -#define HITMARKER_PASSIVE_HP_UPDATE (1 << 20) +#define HITMARKER_UNUSED_20 (1 << 20) #define HITMARKER_UNUSED_21 (1 << 21) #define HITMARKER_PLAYER_FAINTED (1 << 22) -#define HITMARKER_ALLOW_NO_PP (1 << 23) -#define HITMARKER_GRUDGE (1 << 24) +#define HITMARKER_UNUSED_23 (1 << 23) +#define HITMARKER_UNUSED_24 (1 << 24) #define HITMARKER_OBEYS (1 << 25) #define HITMARKER_UNUSED_26 (1 << 26) #define HITMARKER_UNUSED_27 (1 << 27) -#define HITMARKER_FAINTED(battler) (1u << (battler + 28)) -#define HITMARKER_FAINTED2(battler) HITMARKER_FAINTED(battler) +#define HITMARKER_FAINTED(battler) (1u << (battler + 28)) // Also uses bits 29, 30 and 31 // Per-side statuses that affect an entire party #define SIDE_STATUS_REFLECT (1 << 0) #define SIDE_STATUS_LIGHTSCREEN (1 << 1) #define SIDE_STATUS_SAFEGUARD (1 << 2) -#define SIDE_STATUS_FUTUREATTACK (1 << 3) -#define SIDE_STATUS_MIST (1 << 4) -#define SIDE_STATUS_TAILWIND (1 << 5) -#define SIDE_STATUS_AURORA_VEIL (1 << 6) -#define SIDE_STATUS_LUCKY_CHANT (1 << 7) -#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 8) -#define SIDE_STATUS_RAINBOW (1 << 9) -#define SIDE_STATUS_SEA_OF_FIRE (1 << 10) -#define SIDE_STATUS_SWAMP (1 << 11) +#define SIDE_STATUS_MIST (1 << 3) +#define SIDE_STATUS_TAILWIND (1 << 4) +#define SIDE_STATUS_AURORA_VEIL (1 << 5) +#define SIDE_STATUS_LUCKY_CHANT (1 << 6) +#define SIDE_STATUS_DAMAGE_NON_TYPES (1 << 7) +#define SIDE_STATUS_RAINBOW (1 << 8) +#define SIDE_STATUS_SEA_OF_FIRE (1 << 9) +#define SIDE_STATUS_SWAMP (1 << 10) #define SIDE_STATUS_SCREEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL) #define SIDE_STATUS_PLEDGE_ANY (SIDE_STATUS_RAINBOW | SIDE_STATUS_SEA_OF_FIRE | SIDE_STATUS_SWAMP) @@ -639,6 +657,17 @@ enum BattleEnvironments // Constants for Torment #define PERMANENT_TORMENT 0xF +enum FaintedActions +{ + FAINTED_ACTIONS_NO_MONS_TO_SWITCH, + FAINTED_ACTIONS_GIVE_EXP, + FAINTED_ACTIONS_SET_ABSENT_FLAGS, + FAINTED_ACTIONS_WAIT_STATE, + FAINTED_ACTIONS_HANDLE_FAINTED_MON, + FAINTED_ACTIONS_HANDLE_NEXT_BATTLER, + FAINTED_ACTIONS_MAX_CASE, +}; + // Constants for B_VAR_STARTING_STATUS // Timer value controlled by B_VAR_STARTING_STATUS_TIMER enum StartingStatus @@ -680,4 +709,11 @@ enum __attribute__((packed)) CalcDamageState CHECK_ACCURACY, }; +enum SubmoveState +{ + SUBMOVE_NO_EFFECT, + SUBMOVE_SUCCESS, + SUBMOVE_FAILURE, +}; + #endif // GUARD_CONSTANTS_BATTLE_H diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index c6277bf9b5..89cfd08ed0 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -38,6 +38,7 @@ #define AI_FLAG_ASSUME_STAB AI_FLAG(28) // AI knows player's STAB moves, but nothing else. Restricted version of AI_FLAG_OMNISCIENT. #define AI_FLAG_ASSUME_STATUS_MOVES AI_FLAG(29) // AI has a chance to know certain non-damaging moves, and also Fake Out and Super Fang. Restricted version of AI_FLAG_OMNISCIENT. #define AI_FLAG_ATTACKS_PARTNER AI_FLAG(30) // AI specific to double battles; AI can deliberately attack its 'partner.' +#define AI_FLAG_KNOW_OPPONENT_PARTY AI_FLAG(31) // AI knows all the species in the player's party, but not moves/items/abilities unless they've been seen. // The following options are enough to have a basic/smart trainer. Any other addtion could make the trainer worse/better depending on the flag #define AI_FLAG_BASIC_TRAINER (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY) diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index e169b29cf3..2ac2bc30f2 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -617,8 +617,9 @@ #define B_ANIM_STATUS_FRZ 6 #define B_ANIM_STATUS_CURSED 7 #define B_ANIM_STATUS_NIGHTMARE 8 +#define B_ANIM_STATUS_FRB 9 -#define NUM_B_ANIMS_STATUS 9 +#define NUM_B_ANIMS_STATUS 10 // Tasks with return values often assign them to gBattleAnimArgs[7]. #define ARG_RET_ID 7 diff --git a/include/constants/battle_end_turn.h b/include/constants/battle_end_turn.h new file mode 100644 index 0000000000..81c0409ecd --- /dev/null +++ b/include/constants/battle_end_turn.h @@ -0,0 +1,92 @@ +#ifndef GUARD_CONSTANTS_BATTLE_END_TURN_H +#define GUARD_CONSTANTS_BATTLE_END_TURN_H + +// General End Turn Effects based on research from smogon from vanilla games: +// https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179 +enum EndTurnResolutionOrder +{ + ENDTURN_ORDER, + ENDTURN_VARIOUS, + ENDTURN_WEATHER, + ENDTURN_WEATHER_DAMAGE, + ENDTURN_EMERGENCY_EXIT_1, + ENDTURN_AFFECTION, + ENDTURN_FUTURE_SIGHT, + ENDTURN_WISH, + ENDTURN_FIRST_EVENT_BLOCK, + ENDTURN_EMERGENCY_EXIT_2, + ENDTURN_AQUA_RING, + ENDTURN_INGRAIN, + ENDTURN_LEECH_SEED, + ENDTURN_POISON, + ENDTURN_BURN, + ENDTURN_FROSTBITE, + ENDTURN_NIGHTMARE, + ENDTURN_CURSE, + ENDTURN_WRAP, + ENDTURN_SALT_CURE, + ENDTURN_OCTOLOCK, + ENDTURN_SYRUP_BOMB, + ENDTURN_TAUNT, + ENDTURN_TORMENT, + ENDTURN_ENCORE, + ENDTURN_DISABLE, + ENDTURN_MAGNET_RISE, + ENDTURN_TELEKINESIS, + ENDTURN_HEAL_BLOCK, + ENDTURN_EMBARGO, + ENDTURN_YAWN, + ENDTURN_PERISH_SONG, + ENDTURN_ROOST, + ENDTURN_EMERGENCY_EXIT_3, + ENDTURN_SECOND_EVENT_BLOCK, + ENDTURN_TRICK_ROOM, + ENDTURN_GRAVITY, + ENDTURN_WATER_SPORT, + ENDTURN_MUD_SPORT, + ENDTURN_WONDER_ROOM, + ENDTURN_MAGIC_ROOM, + ENDTURN_TERRAIN, + ENDTURN_THIRD_EVENT_BLOCK, + ENDTURN_EMERGENCY_EXIT_4, + ENDTURN_FORM_CHANGE_ABILITIES, + ENDTURN_EJECT_PACK, + ENDTURN_DYNAMAX, + ENDTURN_COUNT, +}; + +// Block that handles effects for each individual battler on the field (eg residual damage) +enum FirstEventBlock +{ + FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL, // Needs to be split + FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE, + FIRST_EVENT_BLOCK_THRASH, // Thrash isn't handled here in vanilla but for now it is that best place for it. + FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL, + FIRST_EVENT_BLOCK_ABILITIES, + FIRST_EVENT_BLOCK_HEAL_ITEMS, +}; + +// Block that tries to remove side statuses +enum SecondEventBlock +{ + SECOND_EVENT_BLOCK_REFLECT, + SECOND_EVENT_BLOCK_LIGHT_SCREEN, + SECOND_EVENT_BLOCK_SAFEGUARD, + SECOND_EVENT_BLOCK_MIST, + SECOND_EVENT_BLOCK_TAILWIND, + SECOND_EVENT_BLOCK_LUCKY_CHANT, + SECOND_EVENT_BLOCK_RAINBOW, + SECOND_EVENT_BLOCK_SEA_OF_FIRE, + SECOND_EVENT_BLOCK_SWAMP, + SECOND_EVENT_BLOCK_AURORA_VEIL, +}; + +// Block that handles Uproar, items and non-form changing abilities +enum ThirdEventBlock +{ + THIRD_EVENT_BLOCK_UPROAR, + THIRD_EVENT_BLOCK_ABILITIES, + THIRD_EVENT_BLOCK_ITEMS, +}; + +#endif // GUARD_CONSTANTS_BATTLE_END_TURN_H diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 2ddb75adf6..f2ba76a551 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -133,7 +133,7 @@ enum __attribute__((packed)) BattleMoveEffects EFFECT_STOCKPILE, EFFECT_SPIT_UP, EFFECT_SWALLOW, - EFFECT_WORRY_SEED, + EFFECT_OVERWRITE_ABILITY, EFFECT_HAIL, EFFECT_TORMENT, EFFECT_FLATTER, @@ -218,7 +218,6 @@ enum __attribute__((packed)) BattleMoveEffects EFFECT_METAL_BURST, EFFECT_LUCKY_CHANT, EFFECT_SUCKER_PUNCH, - EFFECT_SIMPLE_BEAM, EFFECT_ENTRAINMENT, EFFECT_HEAL_PULSE, EFFECT_QUASH, @@ -311,7 +310,6 @@ enum __attribute__((packed)) BattleMoveEffects EFFECT_MAX_HP_50_RECOIL, EFFECT_CHLOROBLAST, // Same effect as EFFECT_MAX_HP_50_RECOIL but follows the same rules as EFFECT_RECOIL EFFECT_EXTREME_EVOBOOST, - EFFECT_HIT_SET_TERRAIN, EFFECT_DARK_VOID, EFFECT_VICTORY_DANCE, EFFECT_TEATIME, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 81dafd04df..234ebad0b2 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -33,7 +33,7 @@ #define sSAVED_DMG (gBattleScripting + 0x28) // savedDmg #define sUNUSED_0x2C (gBattleScripting + 0x2C) // unused_0x2c #define sMOVE_EFFECT (gBattleScripting + 0x2E) // moveEffect -#define sMULTIHIT_EFFECT (gBattleScripting + 0x30) // multihitMoveEffect +#define sUNUSED_0x30 (gBattleScripting + 0x30) // unused_0x30 #define sILLUSION_NICK_HACK (gBattleScripting + 0x32) // illusionNickHack #define sFIXED_ABILITY_POPUP (gBattleScripting + 0x33) // fixedPopup #define sABILITY_OVERWRITE (gBattleScripting + 0x34) // abilityPopupOverwrite @@ -124,47 +124,59 @@ enum CmdVarious #define PARTY_SCREEN_OPTIONAL (1 << 7) // Flag for first argument to openpartyscreen +enum SetMoveEffectFlags +{ + NO_FLAGS = 0, + EFFECT_PRIMARY = (1 << 0), + EFFECT_CERTAIN = (1 << 1), +}; + // cases for Cmd_moveend - Order matters! enum MoveEndEffects { - MOVEEND_SUM_DAMAGE, + MOVEEND_SET_VALUES, MOVEEND_PROTECT_LIKE_EFFECT, + MOVEEND_GRUDGE, + MOVEEND_DESTINY_BOND, MOVEEND_ABSORB, MOVEEND_RAGE, MOVEEND_SYNCHRONIZE_TARGET, MOVEEND_ABILITIES, MOVEEND_ABILITIES_ATTACKER, - MOVEEND_STATUS_IMMUNITY_ABILITIES, + MOVEEND_STATUS_IMMUNITY_ABILITIES, // TODO: Do berries come before???? MOVEEND_SYNCHRONIZE_ATTACKER, MOVEEND_ATTACKER_INVISIBLE, MOVEEND_ATTACKER_VISIBLE, MOVEEND_TARGET_VISIBLE, MOVEEND_ITEM_EFFECTS_TARGET, - MOVEEND_ITEM_EFFECTS_ALL, + MOVEEND_ITEM_EFFECTS_ATTACKER_1, MOVEEND_SYMBIOSIS, - MOVEEND_KINGSROCK, // These item effects will occur each strike of a multi-hit move MOVEEND_SUBSTITUTE, MOVEEND_SKY_DROP_CONFUSE, MOVEEND_UPDATE_LAST_MOVES, MOVEEND_MIRROR_MOVE, MOVEEND_DEFROST, MOVEEND_NEXT_TARGET, // Everything up until here is handled for each strike of a spread move + MOVEEND_HP_THRESHHOLD_ITEMS_TARGET, // Activation only during a multi hit move / ability (Parental Bond) MOVEEND_MULTIHIT_MOVE, MOVEEND_MOVE_BLOCK, - MOVEEND_ITEM_EFFECTS_ATTACKER, - MOVEEND_ITEM_THROAT_SPRAY, + MOVEEND_ITEM_EFFECTS_ATTACKER_2, MOVEEND_ABILITY_BLOCK, - MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Opportunist + MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip to Hit Escape + One + MOVEEND_COLOR_CHANGE, // Color Change / Berserk / Anger Shell + MOVEEND_KEE_MARANGA_HP_THRESHOLD_ITEM_TARGET, MOVEEND_RED_CARD, MOVEEND_EJECT_BUTTON, - MOVEEND_LIFEORB_SHELLBELL, + MOVEEND_LIFE_ORB_SHELL_BELL, MOVEEND_FORM_CHANGE, MOVEEND_EMERGENCY_EXIT, MOVEEND_EJECT_PACK, MOVEEND_HIT_ESCAPE, - MOVEEND_OPPORTUNIST, - MOVEEND_PICKPOCKET, + MOVEEND_ITEMS_EFFECTS_ALL, MOVEEND_WHITE_HERB, + MOVEEND_OPPORTUNIST, + MOVEEND_MIRROR_HERB, + MOVEEND_PICKPOCKET, MOVEEND_THIRD_MOVE_BLOCK, MOVEEND_CHANGED_ITEMS, MOVEEND_SAME_MOVE_TURNS, @@ -172,6 +184,9 @@ enum MoveEndEffects MOVEEND_DANCER, MOVEEND_PURSUIT_NEXT_ACTION, MOVEEND_COUNT, + + // This guarantees a correct jump if new moveends are added directly after MOVEEND_HIT_ESCAPE + MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE = (MOVEEND_HIT_ESCAPE + 1), }; // switch cases @@ -193,4 +208,10 @@ enum TriggerOnFieldStatus ON_WEATHER, }; +enum HealthUpdate +{ + PASSIVE_HP_UPDATE, + MOVE_DAMAGE_HP_UPDATE, +}; + #endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 22d63b119c..462c64cda1 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -28,8 +28,7 @@ enum StringID STRINGID_STATSWONTINCREASE2, STRINGID_AVOIDEDDAMAGE, STRINGID_ITDOESNTAFFECT, - STRINGID_ATTACKERFAINTED, - STRINGID_TARGETFAINTED, + STRINGID_BATTLERFAINTED, STRINGID_PLAYERGOTMONEY, STRINGID_PLAYERWHITEOUT, STRINGID_PLAYERWHITEOUT2_WILD, @@ -61,11 +60,8 @@ enum StringID STRINGID_PKMNISPARALYZED, STRINGID_PKMNISALREADYPARALYZED, STRINGID_PKMNHEALEDPARALYSIS, - STRINGID_PKMNDREAMEATEN, STRINGID_STATSWONTINCREASE, STRINGID_STATSWONTDECREASE, - STRINGID_TEAMSTOPPEDWORKING, - STRINGID_FOESTOPPEDWORKING, STRINGID_PKMNISCONFUSED, STRINGID_PKMNHEALEDCONFUSION, STRINGID_PKMNWASCONFUSED, @@ -73,7 +69,6 @@ enum StringID STRINGID_PKMNFELLINLOVE, STRINGID_PKMNINLOVE, STRINGID_PKMNIMMOBILIZEDBYLOVE, - STRINGID_PKMNBLOWNAWAY, STRINGID_PKMNCHANGEDTYPE, STRINGID_PKMNFLINCHED, STRINGID_PKMNREGAINEDHEALTH, @@ -117,7 +112,6 @@ enum StringID STRINGID_PKMNCALMEDDOWN, STRINGID_PKMNCANTSLEEPINUPROAR, STRINGID_PKMNSTOCKPILED, - STRINGID_PKMNCANTSTOCKPILE, STRINGID_PKMNCANTSLEEPINUPROAR2, STRINGID_UPROARKEPTPKMNAWAKE, STRINGID_PKMNSTAYEDAWAKEUSING, @@ -179,7 +173,6 @@ enum StringID STRINGID_PKMNREADYTOHELP, STRINGID_PKMNSWITCHEDITEMS, STRINGID_PKMNCOPIEDFOE, - STRINGID_PKMNMADEWISH, STRINGID_PKMNWISHCAMETRUE, STRINGID_PKMNPLANTEDROOTS, STRINGID_PKMNABSORBEDNUTRIENTS, @@ -196,14 +189,11 @@ enum StringID STRINGID_PKMNWAITSFORTARGET, STRINGID_PKMNSNATCHEDMOVE, STRINGID_PKMNMADEITRAIN, - STRINGID_PKMNRAISEDSPEED, STRINGID_PKMNPROTECTEDBY, STRINGID_PKMNPREVENTSUSAGE, STRINGID_PKMNRESTOREDHPUSING, STRINGID_PKMNCHANGEDTYPEWITH, - STRINGID_PKMNPREVENTSPARALYSISWITH, STRINGID_PKMNPREVENTSROMANCEWITH, - STRINGID_PKMNPREVENTSPOISONINGWITH, STRINGID_PKMNPREVENTSCONFUSIONWITH, STRINGID_PKMNRAISEDFIREPOWERWITH, STRINGID_PKMNANCHORSITSELFWITH, @@ -233,7 +223,6 @@ enum StringID STRINGID_BUTNOTHINGHAPPENED, STRINGID_BUTITFAILED, STRINGID_ITHURTCONFUSION, - STRINGID_MIRRORMOVEFAILED, STRINGID_STARTEDTORAIN, STRINGID_DOWNPOURSTARTED, STRINGID_RAINCONTINUES, @@ -248,9 +237,6 @@ enum StringID STRINGID_STARTEDHAIL, STRINGID_HAILCONTINUES, STRINGID_HAILSTOPPED, - STRINGID_FAILEDTOSPITUP, - STRINGID_FAILEDTOSWALLOW, - STRINGID_WINDBECAMEHEATWAVE, STRINGID_STATCHANGESGONE, STRINGID_COINSSCATTERED, STRINGID_TOOWEAKFORSUBSTITUTE, @@ -307,7 +293,6 @@ enum StringID STRINGID_ITEMALLOWSONLYYMOVE, STRINGID_PKMNHUNGONWITHX, STRINGID_EMPTYSTRING3, - STRINGID_PKMNSXPREVENTSBURNS, STRINGID_PKMNSXBLOCKSY, STRINGID_PKMNSXRESTOREDHPALITTLE2, STRINGID_PKMNSXWHIPPEDUPSANDSTORM, @@ -326,8 +311,8 @@ enum StringID STRINGID_PLAYERDEFEATEDTRAINER1, STRINGID_SOOTHINGAROMA, STRINGID_ITEMSCANTBEUSEDNOW, - STRINGID_FORXCOMMAYZ, STRINGID_USINGITEMSTATOFPKMNROSE, + STRINGID_USINGITEMSTATOFPKMNFELL, STRINGID_PKMNUSEDXTOGETPUMPED, STRINGID_PKMNSXMADEYUSELESS, STRINGID_PKMNTRAPPEDBYSANDTOMB, @@ -343,7 +328,6 @@ enum StringID STRINGID_PKMNFLEDUSINGITS, STRINGID_PKMNFLEDUSING, STRINGID_PKMNWASDRAGGEDOUT, - STRINGID_PREVENTEDFROMWORKING, STRINGID_PKMNSITEMNORMALIZEDSTATUS, STRINGID_TRAINER1USEDITEM, STRINGID_BOXISFULL, @@ -354,17 +338,13 @@ enum StringID STRINGID_STATSWONTDECREASE2, STRINGID_PKMNSXBLOCKSY2, STRINGID_PKMNSXWOREOFF, - STRINGID_PKMNRAISEDDEFALITTLE, - STRINGID_PKMNRAISEDSPDEFALITTLE, STRINGID_THEWALLSHATTERED, - STRINGID_PKMNSXPREVENTSYSZ, STRINGID_PKMNSXCUREDITSYPROBLEM, STRINGID_ATTACKERCANTESCAPE, STRINGID_PKMNOBTAINEDX, STRINGID_PKMNOBTAINEDX2, STRINGID_PKMNOBTAINEDXYOBTAINEDZ, STRINGID_BUTNOEFFECT, - STRINGID_PKMNSXHADNOEFFECTONY, STRINGID_TWOENEMIESDEFEATED, STRINGID_TRAINER2LOSETEXT, STRINGID_PKMNINCAPABLEOFPOWER, @@ -423,10 +403,8 @@ enum StringID STRINGID_FELLSTRAIGHTDOWN, STRINGID_TARGETCHANGEDTYPE, STRINGID_PKMNACQUIREDSIMPLE, - STRINGID_EMPTYSTRING5, STRINGID_KINDOFFER, STRINGID_RESETSTARGETSSTATLEVELS, - STRINGID_EMPTYSTRING6, STRINGID_ALLYSWITCHPOSITION, STRINGID_RESTORETARGETSHEALTH, STRINGID_TOOKPJMNINTOTHESKY, @@ -557,10 +535,8 @@ enum StringID STRINGID_COMATOSEENTERS, STRINGID_SCREENCLEANERENTERS, STRINGID_FETCHEDPOKEBALL, - STRINGID_BATTLERABILITYRAISEDSTAT, STRINGID_ASANDSTORMKICKEDUP, STRINGID_PKMNSWILLPERISHIN3TURNS, - STRINGID_ABILITYRAISEDSTATDRASTICALLY, STRINGID_AURAFLAREDTOLIFE, STRINGID_ASONEENTERS, STRINGID_CURIOUSMEDICINEENTERS, @@ -597,7 +573,6 @@ enum StringID STRINGID_BROKETHROUGHPROTECTION, STRINGID_ABILITYALLOWSONLYMOVE, STRINGID_SWAPPEDABILITIES, - STRINGID_PASTELVEILPROTECTED, STRINGID_PASTELVEILENTERS, STRINGID_BATTLERTYPECHANGEDTO, STRINGID_BOTHCANNOLONGERESCAPE, @@ -746,33 +721,24 @@ enum StringID // They are assigned to the MULTISTRING_CHOOSER byte of gBattleCommunication // and read when e.g. the command printfromtable is used. -// gStatUpStringIds -enum StatUpStringID +// gStatUpStringIds and gStatDownStringIds +enum StatChangedStringID { - B_MSG_ATTACKER_STAT_ROSE, - B_MSG_DEFENDER_STAT_ROSE, - B_MSG_STAT_WONT_INCREASE, - B_MSG_STAT_ROSE_EMPTY, - B_MSG_STAT_ROSE_ITEM, + B_MSG_ATTACKER_STAT_CHANGED, + B_MSG_DEFENDER_STAT_CHANGED, + B_MSG_STAT_WONT_CHANGE, + B_MSG_STAT_CHANGE_EMPTY, + B_MSG_STAT_CHANGED_ITEM, B_MSG_USED_DIRE_HIT, }; -// gStatDownStringIds -enum StatDownStringID -{ - B_MSG_ATTACKER_STAT_FELL = 0, - B_MSG_DEFENDER_STAT_FELL = 1, - B_MSG_STAT_WONT_DECREASE, - B_MSG_STAT_FELL_EMPTY, -}; - // gMissStringIds enum MissStringID { B_MSG_MISSED, B_MSG_PROTECTED, B_MSG_AVOIDED_ATK, - // Ability-related messages need to below this comment + // Ability-related messages need to be below this comment B_MSG_AVOIDED_DMG, B_MSG_GROUND_MISS, }; @@ -888,20 +854,6 @@ enum UproarOverTurnStringID B_MSG_UPROAR_ENDS, }; -// gStockpileUsedStringIds -enum StockpileUsedStringID -{ - B_MSG_STOCKPILED, - B_MSG_CANT_STOCKPILE, -}; - -// gSwallowFailStringIds -enum SwallowFailStringID -{ - B_MSG_SWALLOW_FAILED, - B_MSG_SWALLOW_FULL_HP, -}; - // gKOFailedStringIds enum KOFailedStringID { @@ -1024,9 +976,15 @@ enum FlashFireStringID B_MSG_FLASH_FIRE_NO_BOOST, }; -// gBerryEffectStringIds -enum BerryEffectStringID +// CureStatusBerryEffectStringID +enum CureStatusBerryEffectStringID { + B_MSG_CURED_PARALYSIS, + B_MSG_CURED_POISON, + B_MSG_CURED_BURN, + B_MSG_CURED_FREEEZE, + B_MSG_CURED_FROSTBITE, + B_MSG_CURED_SLEEP, B_MSG_CURED_PROBLEM, B_MSG_NORMALIZED_STATUS, }; @@ -1049,17 +1007,6 @@ enum GotStatusedStringID B_MSG_STATUSED_BY_ABILITY, }; -// gStatusPreventionStringIds -enum StatusPreventionStringID -{ - B_MSG_ABILITY_PREVENTS_MOVE_BURN, - B_MSG_ABILITY_PREVENTS_MOVE_PARALYSIS, - B_MSG_ABILITY_PREVENTS_MOVE_POISON, - B_MSG_ABILITY_PREVENTS_ABILITY_STATUS, - B_MSG_STATUS_HAD_NO_EFFECT, - B_MSG_ABILITY_PASTEL_VEIL, -}; - // gGotDefrostedStringIds enum GotDefrostedStringID { diff --git a/include/constants/characters.h b/include/constants/characters.h index 6ac3c5224c..0af7b110f0 100644 --- a/include/constants/characters.h +++ b/include/constants/characters.h @@ -232,6 +232,7 @@ #define EXT_CTRL_CODE_ENG 0x16 #define EXT_CTRL_CODE_PAUSE_MUSIC 0x17 #define EXT_CTRL_CODE_RESUME_MUSIC 0x18 +#define EXT_CTRL_CODE_SPEAKER 0x19 #define TEXT_COLOR_TRANSPARENT 0x0 #define TEXT_COLOR_WHITE 0x1 diff --git a/include/constants/contest.h b/include/constants/contest.h index 3b83d4f1c3..70531f5406 100644 --- a/include/constants/contest.h +++ b/include/constants/contest.h @@ -103,29 +103,29 @@ #define CONTEST_EFFECT_REPETITION_NOT_BORING 3 #define CONTEST_EFFECT_AVOID_STARTLE_ONCE 4 #define CONTEST_EFFECT_AVOID_STARTLE 5 -#define CONTEST_EFFECT_AVOID_STARTLE_SLIGHTLY 6 -#define CONTEST_EFFECT_USER_LESS_EASILY_STARTLED 7 -#define CONTEST_EFFECT_STARTLE_FRONT_MON 8 -#define CONTEST_EFFECT_SLIGHTLY_STARTLE_PREV_MONS 9 +#define CONTEST_EFFECT_AVOID_STARTLE_SLIGHTLY 6 // Unused +#define CONTEST_EFFECT_USER_LESS_EASILY_STARTLED 7 // Unused +#define CONTEST_EFFECT_STARTLE_FRONT_MON 8 // Unused +#define CONTEST_EFFECT_SLIGHTLY_STARTLE_PREV_MONS 9 // Unused #define CONTEST_EFFECT_STARTLE_PREV_MON 10 #define CONTEST_EFFECT_STARTLE_PREV_MONS 11 #define CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON 12 #define CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS 13 -#define CONTEST_EFFECT_STARTLE_PREV_MON_2 14 -#define CONTEST_EFFECT_STARTLE_PREV_MONS_2 15 +#define CONTEST_EFFECT_STARTLE_PREV_MON_2 14 // Unused +#define CONTEST_EFFECT_STARTLE_PREV_MONS_2 15 // Unused #define CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION 16 #define CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION 17 #define CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN 18 #define CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL 19 -#define CONTEST_EFFECT_STARTLE_MONS_COOL_APPEAL 20 -#define CONTEST_EFFECT_STARTLE_MONS_BEAUTY_APPEAL 21 -#define CONTEST_EFFECT_STARTLE_MONS_CUTE_APPEAL 22 -#define CONTEST_EFFECT_STARTLE_MONS_SMART_APPEAL 23 -#define CONTEST_EFFECT_STARTLE_MONS_TOUGH_APPEAL 24 -#define CONTEST_EFFECT_MAKE_FOLLOWING_MON_NERVOUS 25 +#define CONTEST_EFFECT_STARTLE_MONS_COOL_APPEAL 20 // Unused +#define CONTEST_EFFECT_STARTLE_MONS_BEAUTY_APPEAL 21 // Unused +#define CONTEST_EFFECT_STARTLE_MONS_CUTE_APPEAL 22 // Unused +#define CONTEST_EFFECT_STARTLE_MONS_SMART_APPEAL 23 // Unused +#define CONTEST_EFFECT_STARTLE_MONS_TOUGH_APPEAL 24 // Unused +#define CONTEST_EFFECT_MAKE_FOLLOWING_MON_NERVOUS 25 // Unused #define CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS 26 #define CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS 27 -#define CONTEST_EFFECT_BADLY_STARTLES_MONS_IN_GOOD_CONDITION 28 +#define CONTEST_EFFECT_BADLY_STARTLES_MONS_IN_GOOD_CONDITION 28 // Unused #define CONTEST_EFFECT_BETTER_IF_FIRST 29 #define CONTEST_EFFECT_BETTER_IF_LAST 30 #define CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES 31 @@ -133,18 +133,21 @@ #define CONTEST_EFFECT_BETTER_WHEN_LATER 33 #define CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING 34 #define CONTEST_EFFECT_BETTER_IF_SAME_TYPE 35 -#define CONTEST_EFFECT_BETTER_IF_DIFF_TYPE 36 +#define CONTEST_EFFECT_BETTER_IF_DIFF_TYPE 36 // Unused #define CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL 37 #define CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS 38 #define CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION 39 #define CONTEST_EFFECT_NEXT_APPEAL_EARLIER 40 #define CONTEST_EFFECT_NEXT_APPEAL_LATER 41 -#define CONTEST_EFFECT_MAKE_SCRAMBLING_TURN_ORDER_EASIER 42 +#define CONTEST_EFFECT_MAKE_SCRAMBLING_TURN_ORDER_EASIER 42 // Unused #define CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER 43 #define CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST 44 #define CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS 45 #define CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED 46 #define CONTEST_EFFECT_DONT_EXCITE_AUDIENCE 47 +//#define CONTEST_EFFECT_QUICKLY_GROW_BORED 48 // New in Gen 6 +//#define CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST 49 // New in Gen 6 +//#define CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST 50 // New in Gen 6 // Each of the above effects is grouped into one of these effect type categories // Only a few of these get checked by the AI, the rest go unused @@ -157,93 +160,127 @@ #define CONTEST_EFFECT_TYPE_TURN_ORDER 6 #define CONTEST_EFFECT_TYPE_UNKNOWN 8 -#define COMBO_STARTER_POUND 1 -#define COMBO_STARTER_FIRE_PUNCH 2 -#define COMBO_STARTER_ICE_PUNCH 3 -#define COMBO_STARTER_THUNDER_PUNCH 4 -#define COMBO_STARTER_SCRATCH 5 -#define COMBO_STARTER_VICE_GRIP 6 -#define COMBO_STARTER_SWORDS_DANCE 7 -#define COMBO_STARTER_SAND_ATTACK 8 -#define COMBO_STARTER_HORN_ATTACK 9 -#define COMBO_STARTER_LEER 10 -#define COMBO_STARTER_SING 11 -#define COMBO_STARTER_SURF 12 -#define COMBO_STARTER_PECK 13 -#define COMBO_STARTER_LEECH_SEED 14 -#define COMBO_STARTER_GROWTH 15 -#define COMBO_STARTER_STRING_SHOT 16 -#define COMBO_STARTER_DRAGON_RAGE 17 -#define COMBO_STARTER_ROCK_THROW 18 -#define COMBO_STARTER_EARTHQUAKE 19 -#define COMBO_STARTER_TOXIC 20 -#define COMBO_STARTER_CONFUSION 21 -#define COMBO_STARTER_PSYCHIC 22 -#define COMBO_STARTER_HYPNOSIS 23 -#define COMBO_STARTER_RAGE 24 -#define COMBO_STARTER_DOUBLE_TEAM 25 -#define COMBO_STARTER_HARDEN 26 -#define COMBO_STARTER_DEFENSE_CURL 27 -#define COMBO_STARTER_FOCUS_ENERGY 28 -#define COMBO_STARTER_SMOG 29 -#define COMBO_STARTER_SLUDGE 30 -#define COMBO_STARTER_BONE_CLUB 31 -#define COMBO_STARTER_KINESIS 32 -#define COMBO_STARTER_SOFT_BOILED 33 -#define COMBO_STARTER_BONEMERANG 34 -#define COMBO_STARTER_REST 35 -#define COMBO_STARTER_MIND_READER 36 -#define COMBO_STARTER_CURSE 37 -#define COMBO_STARTER_POWDER_SNOW 38 -#define COMBO_STARTER_SCARY_FACE 39 -#define COMBO_STARTER_BELLY_DRUM 40 -#define COMBO_STARTER_SLUDGE_BOMB 41 -#define COMBO_STARTER_MUD_SLAP 42 -#define COMBO_STARTER_BONE_RUSH 43 -#define COMBO_STARTER_LOCK_ON 44 -#define COMBO_STARTER_SANDSTORM 45 -#define COMBO_STARTER_ENDURE 46 -#define COMBO_STARTER_CHARM 47 -#define COMBO_STARTER_MEAN_LOOK 48 -#define COMBO_STARTER_HEAL_BELL 49 -#define COMBO_STARTER_DRAGON_BREATH 50 -#define COMBO_STARTER_SWEET_SCENT 51 -#define COMBO_STARTER_RAIN_DANCE 52 -#define COMBO_STARTER_SUNNY_DAY 53 -#define COMBO_STARTER_FAKE_OUT 54 -#define COMBO_STARTER_STOCKPILE 55 -#define COMBO_STARTER_HAIL 56 -#define COMBO_STARTER_CHARGE 57 -#define COMBO_STARTER_TAUNT 58 -#define COMBO_STARTER_REVENGE 59 -#define COMBO_STARTER_YAWN 60 -#define COMBO_STARTER_DIVE 61 -#define COMBO_STARTER_MUD_SPORT 62 -#define COMBO_STARTER_METAL_SOUND 63 -#define COMBO_STARTER_WATER_SPORT 64 -#define COMBO_STARTER_CALM_MIND 65 -#define COMBO_STARTER_DRAGON_DANCE 66 -#define COMBO_STARTER_PAYBACK 67 -#define COMBO_STARTER_LUCKY_CHANT 68 -#define COMBO_STARTER_WORRY_SEED 69 -#define COMBO_STARTER_DRAGON_RUSH 70 -#define COMBO_STARTER_BRAVE_BIRD 71 -#define COMBO_STARTER_THUNDER_FANG 72 -#define COMBO_STARTER_ICE_FANG 73 -#define COMBO_STARTER_FIRE_FANG 74 -#define COMBO_STARTER_ATTACK_ORDER 75 -#define COMBO_STARTER_DEFEND_ORDER 76 -#define COMBO_STARTER_HEAL_ORDER 77 -#define COMBO_STARTER_SCALD 78 -#define COMBO_STARTER_DRAGON_TAIL 79 -#define COMBO_STARTER_HYPERSPACE_HOLE 80 -#define COMBO_STARTER_THOUSAND_ARROWS 81 -#define COMBO_STARTER_THOUSAND_WAVES 82 -#define COMBO_STARTER_HYPERSPACE_FURY 83 -#define COMBO_STARTER_SHADOW_BONE 84 -#define COMBO_STARTER_ELECTRIC_TERRAIN 85 -#define COMBO_STARTER_MISTY_TERRAIN 86 -#define COMBO_STARTER_GRASSY_TERRAIN 87 -#define COMBO_STARTER_PSYCHIC_TERRAIN 88 +enum { + COMBO_STARTER_POUND, + COMBO_STARTER_FIRE_PUNCH, + COMBO_STARTER_ICE_PUNCH, + COMBO_STARTER_THUNDER_PUNCH, + COMBO_STARTER_SCRATCH, + COMBO_STARTER_VICE_GRIP, + COMBO_STARTER_SWORDS_DANCE, + COMBO_STARTER_SAND_ATTACK, + COMBO_STARTER_HORN_ATTACK, + COMBO_STARTER_LEER, + COMBO_STARTER_SING, + COMBO_STARTER_SURF, + COMBO_STARTER_PECK, + COMBO_STARTER_LEECH_SEED, + COMBO_STARTER_GROWTH, + COMBO_STARTER_STRING_SHOT, + COMBO_STARTER_DRAGON_RAGE, + COMBO_STARTER_ROCK_THROW, + COMBO_STARTER_EARTHQUAKE, + COMBO_STARTER_TOXIC, + COMBO_STARTER_CONFUSION, + COMBO_STARTER_PSYCHIC, + COMBO_STARTER_HYPNOSIS, + COMBO_STARTER_RAGE, + COMBO_STARTER_DOUBLE_TEAM, + COMBO_STARTER_HARDEN, + COMBO_STARTER_DEFENSE_CURL, + COMBO_STARTER_FOCUS_ENERGY, + COMBO_STARTER_SMOG, + COMBO_STARTER_SLUDGE, + COMBO_STARTER_BONE_CLUB, + COMBO_STARTER_KINESIS, + COMBO_STARTER_SOFT_BOILED, + COMBO_STARTER_BONEMERANG, + COMBO_STARTER_REST, + COMBO_STARTER_MIND_READER, + COMBO_STARTER_CURSE, + COMBO_STARTER_POWDER_SNOW, + COMBO_STARTER_SCARY_FACE, + COMBO_STARTER_BELLY_DRUM, + COMBO_STARTER_SLUDGE_BOMB, + COMBO_STARTER_MUD_SLAP, + COMBO_STARTER_BONE_RUSH, + COMBO_STARTER_LOCK_ON, + COMBO_STARTER_SANDSTORM, + COMBO_STARTER_ENDURE, + COMBO_STARTER_CHARM, + COMBO_STARTER_MEAN_LOOK, + COMBO_STARTER_HEAL_BELL, + COMBO_STARTER_DRAGON_BREATH, + COMBO_STARTER_SWEET_SCENT, + COMBO_STARTER_RAIN_DANCE, + COMBO_STARTER_SUNNY_DAY, + COMBO_STARTER_FAKE_OUT, + COMBO_STARTER_STOCKPILE, + COMBO_STARTER_HAIL, + COMBO_STARTER_CHARGE, + COMBO_STARTER_TAUNT, + COMBO_STARTER_REVENGE, + COMBO_STARTER_YAWN, + COMBO_STARTER_DIVE, + COMBO_STARTER_MUD_SPORT, + COMBO_STARTER_METAL_SOUND, + COMBO_STARTER_WATER_SPORT, + COMBO_STARTER_CALM_MIND, + COMBO_STARTER_DRAGON_DANCE, + COMBO_STARTER_PAYBACK, + COMBO_STARTER_LUCKY_CHANT, + COMBO_STARTER_WORRY_SEED, + COMBO_STARTER_DRAGON_RUSH, + COMBO_STARTER_BRAVE_BIRD, + COMBO_STARTER_THUNDER_FANG, + COMBO_STARTER_ICE_FANG, + COMBO_STARTER_FIRE_FANG, + COMBO_STARTER_ATTACK_ORDER, + COMBO_STARTER_DEFEND_ORDER, + COMBO_STARTER_HEAL_ORDER, + COMBO_STARTER_SCALD, + COMBO_STARTER_DRAGON_TAIL, + COMBO_STARTER_HYPERSPACE_HOLE, + COMBO_STARTER_THOUSAND_ARROWS, + COMBO_STARTER_THOUSAND_WAVES, + COMBO_STARTER_HYPERSPACE_FURY, + COMBO_STARTER_SHADOW_BONE, + COMBO_STARTER_ELECTRIC_TERRAIN, + COMBO_STARTER_MISTY_TERRAIN, + COMBO_STARTER_GRASSY_TERRAIN, + COMBO_STARTER_PSYCHIC_TERRAIN, + COMBO_STARTER_FORCE_PALM, + COMBO_STARTER_THUNDER_WAVE, + COMBO_STARTER_AGILITY, + COMBO_STARTER_STEALTH_ROCK, + COMBO_STARTER_INFERNO, + COMBO_STARTER_WILL_O_WISP, + COMBO_STARTER_LOVELY_KISS, + COMBO_STARTER_SPORE, + COMBO_STARTER_CELEBRATE, + COMBO_STARTER_COVET, + COMBO_STARTER_HAPPY_HOUR, + COMBO_STARTER_WISH, + COMBO_STARTER_AMNESIA, + COMBO_STARTER_HONE_CLAWS, + COMBO_STARTER_ENTRAINMENT, + COMBO_STARTER_PLAY_NICE, + COMBO_STARTER_BLOCK, + COMBO_STARTER_ENCORE, + COMBO_STARTER_DARK_VOID, + COMBO_STARTER_GRASS_WHISTLE, + COMBO_STARTER_SLEEP_POWDER, + COMBO_STARTER_POISON_GAS, + COMBO_STARTER_POISON_POWDER, + COMBO_STARTER_NASTY_PLOT, + COMBO_STARTER_PARABOLIC_CHARGE, + COMBO_STARTER_SHIFT_GEAR, + COMBO_STARTER_SPIKES, + COMBO_STARTER_TOXIC_SPIKES, + COMBO_STARTER_GLARE, + COMBO_STARTER_ROCK_POLISH, + COMBO_STARTER_ROTOTILLER, + COMBO_STARTER_TORMENT, +}; #endif // GUARD_CONSTANTS_CONTEST_H diff --git a/include/constants/event_objects.h b/include/constants/event_objects.h index eacd3b3a2a..c20c2c79c3 100644 --- a/include/constants/event_objects.h +++ b/include/constants/event_objects.h @@ -246,11 +246,12 @@ #define OBJ_EVENT_GFX_POKE_BALL 239 #define OBJ_EVENT_GFX_OW_MON 240 #define OBJ_EVENT_GFX_LIGHT_SPRITE 241 +#define OBJ_EVENT_GFX_APRICORN_TREE 242 // NOTE: The maximum amount of object events has been expanded from 255 to 65535. // Since dynamic graphics ids still require at least 16 free values, the actual limit // is 65519, but even considering follower Pokémon, this should be more than enough :) -#define NUM_OBJ_EVENT_GFX 242 +#define NUM_OBJ_EVENT_GFX 243 // These are dynamic object gfx ids. diff --git a/include/constants/expansion.h b/include/constants/expansion.h index 1b9fba88a1..85e8aba189 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -1,10 +1,10 @@ #ifndef GUARD_CONSTANTS_EXPANSION_H #define GUARD_CONSTANTS_EXPANSION_H -// Last version: 1.13.3 +// Last version: 1.14.0 #define EXPANSION_VERSION_MAJOR 1 -#define EXPANSION_VERSION_MINOR 13 -#define EXPANSION_VERSION_PATCH 4 +#define EXPANSION_VERSION_MINOR 14 +#define EXPANSION_VERSION_PATCH 1 // FALSE if this this version of Expansion is not a tagged commit, i.e. // it contains unreleased changes. diff --git a/include/constants/field_effects.h b/include/constants/field_effects.h index e38b25cac7..71978fc64f 100644 --- a/include/constants/field_effects.h +++ b/include/constants/field_effects.h @@ -79,6 +79,7 @@ #define FLDEFF_DEFOG 74 #define FLDEFF_USE_ROCK_CLIMB 75 #define FLDEFF_ROCK_CLIMB_DUST 76 +#define FLDEFF_ORAS_DOWSE 77 #define FLDEFFOBJ_SHADOW_S 0 #define FLDEFFOBJ_SHADOW_M 1 @@ -123,6 +124,8 @@ #define FLDEFFOBJ_CAVE_DUST 40 #define FLDEFFOBJ_ROCK_CLIMB_BLOB 41 #define FLDEFFOBJ_ROCK_CLIMB_DUST 42 +#define FLDEFFOBJ_ORAS_DOWSE_BRENDAN 43 +#define FLDEFFOBJ_ORAS_DOWSE_MAY 44 #define FLDEFF_PAL_TAG_CUT_GRASS 0x1000 #define FLDEFF_PAL_TAG_SECRET_POWER_TREE 0x1003 @@ -138,6 +141,7 @@ #define FLDEFF_PAL_TAG_UNKNOWN 0x1011 #define FLDEFF_PAL_TAG_CAVE_DUST 0x1012 #define FLDEFF_PAL_TAG_DUST_CLOUD 0x1013 +#define FLDEFF_PAL_TAG_ORAS_DOWSE 0x1014 #define FLDEFF_PAL_TAG_FIELD_MOVE_MON 0x8400 // tile tags, for field effects that may have many copies on screen at once diff --git a/include/constants/field_specials.h b/include/constants/field_specials.h index 72966adeb8..6973f9e14f 100644 --- a/include/constants/field_specials.h +++ b/include/constants/field_specials.h @@ -2,65 +2,80 @@ #define GUARD_CONSTANTS_FIELD_SPECIALS_H // PC Locations -#define PC_LOCATION_OTHER 0 -#define PC_LOCATION_BRENDANS_HOUSE 1 -#define PC_LOCATION_MAYS_HOUSE 2 +enum PCLocation +{ + PC_LOCATION_OTHER, + PC_LOCATION_BRENDANS_HOUSE, + PC_LOCATION_MAYS_HOUSE, +}; // SS Tidal Locations -#define SS_TIDAL_LOCATION_CURRENTS 0 -#define SS_TIDAL_LOCATION_SLATEPORT 1 -#define SS_TIDAL_LOCATION_LILYCOVE 2 -#define SS_TIDAL_LOCATION_ROUTE124 3 -#define SS_TIDAL_LOCATION_ROUTE131 4 +enum SSTidalLocation +{ + SS_TIDAL_LOCATION_CURRENTS, + SS_TIDAL_LOCATION_SLATEPORT, + SS_TIDAL_LOCATION_LILYCOVE, + SS_TIDAL_LOCATION_ROUTE124, + SS_TIDAL_LOCATION_ROUTE131, +}; -#define SS_TIDAL_BOARD_SLATEPORT 1 -#define SS_TIDAL_DEPART_SLATEPORT 2 -#define SS_TIDAL_HALFWAY_LILYCOVE 3 -#define SS_TIDAL_LAND_LILYCOVE 4 -#define SS_TIDAL_BOARD_LILYCOVE 5 -#define SS_TIDAL_DEPART_LILYCOVE 6 -#define SS_TIDAL_HALFWAY_SLATEPORT 7 -#define SS_TIDAL_LAND_SLATEPORT 8 -#define SS_TIDAL_EXIT_CURRENTS_RIGHT 9 -#define SS_TIDAL_EXIT_CURRENTS_LEFT 10 +enum SSTidalState +{ + SS_TIDAL_BOARD_SLATEPORT = 1, + SS_TIDAL_DEPART_SLATEPORT, + SS_TIDAL_HALFWAY_LILYCOVE, + SS_TIDAL_LAND_LILYCOVE, + SS_TIDAL_BOARD_LILYCOVE, + SS_TIDAL_DEPART_LILYCOVE, + SS_TIDAL_HALFWAY_SLATEPORT, + SS_TIDAL_LAND_SLATEPORT, + SS_TIDAL_EXIT_CURRENTS_RIGHT, + SS_TIDAL_EXIT_CURRENTS_LEFT, +}; #define SS_TIDAL_MAX_STEPS 205 // Scrollable Multichoice Menus -#define SCROLL_MULTI_NONE 0 -#define SCROLL_MULTI_GLASS_WORKSHOP_VENDOR 1 -#define SCROLL_MULTI_POKEMON_FAN_CLUB_RATER 2 -#define SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1 3 -#define SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_2 4 -#define SCROLL_MULTI_BF_EXCHANGE_CORNER_VITAMIN_VENDOR 5 -#define SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR 6 -#define SCROLL_MULTI_BERRY_POWDER_VENDOR 7 -#define SCROLL_MULTI_BF_RECEPTIONIST 8 -#define SCROLL_MULTI_BF_MOVE_TUTOR_1 9 -#define SCROLL_MULTI_BF_MOVE_TUTOR_2 10 -#define SCROLL_MULTI_SS_TIDAL_DESTINATION 11 -#define SCROLL_MULTI_BATTLE_TENT_RULES 12 +enum ScrollMulti +{ + SCROLL_MULTI_NONE, + SCROLL_MULTI_GLASS_WORKSHOP_VENDOR, + SCROLL_MULTI_POKEMON_FAN_CLUB_RATER, + SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1, + SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_2, + SCROLL_MULTI_BF_EXCHANGE_CORNER_VITAMIN_VENDOR, + SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR, + SCROLL_MULTI_BERRY_POWDER_VENDOR, + SCROLL_MULTI_BF_RECEPTIONIST, + SCROLL_MULTI_BF_MOVE_TUTOR_1, + SCROLL_MULTI_BF_MOVE_TUTOR_2, + SCROLL_MULTI_SS_TIDAL_DESTINATION, + SCROLL_MULTI_BATTLE_TENT_RULES, +}; #define MAX_SCROLL_MULTI_ON_SCREEN 6 #define MAX_SCROLL_MULTI_LENGTH 16 // Dept Store Floor Numbers -#define DEPT_STORE_FLOORNUM_B4F 0 -#define DEPT_STORE_FLOORNUM_B3F 1 -#define DEPT_STORE_FLOORNUM_B2F 2 -#define DEPT_STORE_FLOORNUM_B1F 3 -#define DEPT_STORE_FLOORNUM_1F 4 -#define DEPT_STORE_FLOORNUM_2F 5 -#define DEPT_STORE_FLOORNUM_3F 6 -#define DEPT_STORE_FLOORNUM_4F 7 -#define DEPT_STORE_FLOORNUM_5F 8 -#define DEPT_STORE_FLOORNUM_6F 9 -#define DEPT_STORE_FLOORNUM_7F 10 -#define DEPT_STORE_FLOORNUM_8F 11 -#define DEPT_STORE_FLOORNUM_9F 12 -#define DEPT_STORE_FLOORNUM_10F 13 -#define DEPT_STORE_FLOORNUM_11F 14 -#define DEPT_STORE_FLOORNUM_ROOFTOP 15 +enum DeptStoreFloorNumber +{ + DEPT_STORE_FLOORNUM_B4F, + DEPT_STORE_FLOORNUM_B3F, + DEPT_STORE_FLOORNUM_B2F, + DEPT_STORE_FLOORNUM_B1F, + DEPT_STORE_FLOORNUM_1F, + DEPT_STORE_FLOORNUM_2F, + DEPT_STORE_FLOORNUM_3F, + DEPT_STORE_FLOORNUM_4F, + DEPT_STORE_FLOORNUM_5F, + DEPT_STORE_FLOORNUM_6F, + DEPT_STORE_FLOORNUM_7F, + DEPT_STORE_FLOORNUM_8F, + DEPT_STORE_FLOORNUM_9F, + DEPT_STORE_FLOORNUM_10F, + DEPT_STORE_FLOORNUM_11F, + DEPT_STORE_FLOORNUM_ROOFTOP, +}; // Lilycove Pokémon Trainer Fan Club #define NUM_TRAINER_FAN_CLUB_MEMBERS 8 @@ -81,10 +96,13 @@ #define FANCOUNTER_USED_BATTLE_TOWER 3 // Return values for DoDeoxysRockInteraction -#define DEOXYS_ROCK_FAILED 0 -#define DEOXYS_ROCK_PROGRESSED 1 -#define DEOXYS_ROCK_SOLVED 2 -#define DEOXYS_ROCK_COMPLETE 3 +enum DeoxysRockResult +{ + DEOXYS_ROCK_FAILED, + DEOXYS_ROCK_PROGRESSED, + DEOXYS_ROCK_SOLVED, + DEOXYS_ROCK_COMPLETE, +}; enum { OPEN_PARTY_SCREEN, diff --git a/include/constants/global.h b/include/constants/global.h index b2d892014c..fa0ebbcc0f 100644 --- a/include/constants/global.h +++ b/include/constants/global.h @@ -1,17 +1,33 @@ #ifndef GUARD_CONSTANTS_GLOBAL_H #define GUARD_CONSTANTS_GLOBAL_H -#include "config/general.h" -#include "config/battle.h" -#include "config/debug.h" -#include "config/item.h" -#include "config/caps.h" -#include "config/pokemon.h" -#include "config/overworld.h" -#include "config/dexnav.h" -#include "config/summary_screen.h" +// You can use the ENABLED_ON_RELEASE and DISABLED_ON_RELEASE macros to +// control whether a feature is enabled or disabled when making a release build. +// +// For example, the overworld debug menu is enabled by default, but when using +// `make release`, it will be automatically disabled. +// +// #define DEBUG_OVERWORLD_MENU DISABLED_ON_RELEASE +#ifdef RELEASE +#define ENABLED_ON_RELEASE TRUE +#define DISABLED_ON_RELEASE FALSE +#else +#define ENABLED_ON_RELEASE FALSE +#define DISABLED_ON_RELEASE TRUE +#endif + #include "config/ai.h" +#include "config/battle.h" +#include "config/caps.h" +#include "config/contest.h" +#include "config/debug.h" +#include "config/dexnav.h" #include "config/follower_npc.h" +#include "config/general.h" +#include "config/item.h" +#include "config/overworld.h" +#include "config/pokemon.h" +#include "config/summary_screen.h" // Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen. // In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen. @@ -101,12 +117,14 @@ #define ALL_MOVES_MASK ((1 << MAX_MON_MOVES) - 1) #define CONTESTANT_COUNT 4 -#define CONTEST_CATEGORY_COOL 0 -#define CONTEST_CATEGORY_BEAUTY 1 -#define CONTEST_CATEGORY_CUTE 2 -#define CONTEST_CATEGORY_SMART 3 -#define CONTEST_CATEGORY_TOUGH 4 -#define CONTEST_CATEGORIES_COUNT 5 +#define CONTEST_CATEGORY_COOL 0 +#define CONTEST_CATEGORY_BEAUTIFUL 1 +#define CONTEST_CATEGORY_BEAUTY CONTEST_CATEGORY_BEAUTIFUL +#define CONTEST_CATEGORY_CUTE 2 +#define CONTEST_CATEGORY_CLEVER 3 +#define CONTEST_CATEGORY_SMART CONTEST_CATEGORY_CLEVER +#define CONTEST_CATEGORY_TOUGH 4 +#define CONTEST_CATEGORIES_COUNT 5 // string lengths #define ITEM_NAME_LENGTH 20 @@ -148,6 +166,7 @@ #define OPTIONS_TEXT_SPEED_SLOW 0 #define OPTIONS_TEXT_SPEED_MID 1 #define OPTIONS_TEXT_SPEED_FAST 2 +#define OPTIONS_TEXT_SPEED_INSTANT 3 #define OPTIONS_SOUND_MONO 0 #define OPTIONS_SOUND_STEREO 1 diff --git a/include/constants/hold_effects.h b/include/constants/hold_effects.h index 101a198b81..32dacc36d3 100644 --- a/include/constants/hold_effects.h +++ b/include/constants/hold_effects.h @@ -1,7 +1,7 @@ #ifndef GUARD_HOLD_EFFECTS_H #define GUARD_HOLD_EFFECTS_H -enum ItemHoldEffect +enum __attribute__((packed)) HoldEffect { HOLD_EFFECT_NONE, HOLD_EFFECT_RESTORE_HP, @@ -120,7 +120,7 @@ enum ItemHoldEffect // Gen7 hold effects HOLD_EFFECT_PROTECTIVE_PADS, HOLD_EFFECT_TERRAIN_EXTENDER, - HOLD_EFFECT_SEEDS, + HOLD_EFFECT_TERRAIN_SEED, HOLD_EFFECT_ADRENALINE_ORB, HOLD_EFFECT_MEMORY, HOLD_EFFECT_Z_CRYSTAL, @@ -151,4 +151,12 @@ enum ItemHoldEffect #define HOLD_EFFECT_PARAM_MISTY_TERRAIN 2 #define HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN 3 +enum ItemActivationState +{ + ACTIVATION_ON_USABLE_AGAIN, + ACTIVATION_ON_PICK_UP, + ACTIVATION_ON_HARVEST, + ACTIVATION_ON_HP_THRESHOLD, +}; + #endif // GUARD_HOLD_EFFECTS_H diff --git a/include/constants/items.h b/include/constants/items.h index 58f453414f..ca25c57c3c 100644 --- a/include/constants/items.h +++ b/include/constants/items.h @@ -994,10 +994,34 @@ #define ITEM_STRANGE_BALL 828 -// HOPO BERRY -// LEGEND PLATE +#define ITEM_CLEFABLITE 829 +#define ITEM_VICTREEBELITE 830 +#define ITEM_STARMINITE 831 +#define ITEM_DRAGONINITE 832 +#define ITEM_MEGANIUMITE 833 +#define ITEM_FERALIGITE 834 +#define ITEM_SKARMORITE 835 +#define ITEM_FROSLASSITE 836 +#define ITEM_EMBOARITE 837 +#define ITEM_EXCADRITE 838 +#define ITEM_SCOLIPITE 839 +#define ITEM_SCRAFTINITE 840 +#define ITEM_EELEKTROSSITE 841 +#define ITEM_CHANDELURITE 842 +#define ITEM_CHESNAUGHTITE 843 +#define ITEM_DELPHOXITE 844 +#define ITEM_GRENINJITE 845 +#define ITEM_PYROARITE 846 +#define ITEM_FLOETTITE 847 +#define ITEM_MALAMARITE 848 +#define ITEM_BARBARACITE 849 +#define ITEM_DRAGALGITE 850 +#define ITEM_HAWLUCHANITE 851 +#define ITEM_ZYGARDITE 852 +#define ITEM_DRAMPANITE 853 +#define ITEM_FALINKSITE 854 -#define ITEMS_COUNT 829 +#define ITEMS_COUNT 855 #define ITEM_FIELD_ARROW ITEMS_COUNT // A special item id associated with "Cancel"/"Exit" etc. in a list of items or decorations diff --git a/include/constants/move_relearner.h b/include/constants/move_relearner.h new file mode 100644 index 0000000000..0229cb7f17 --- /dev/null +++ b/include/constants/move_relearner.h @@ -0,0 +1,29 @@ +#ifndef GUARD_CONSTANTS_MOVE_RELEARNER_H +#define GUARD_CONSTANTS_MOVE_RELEARNER_H + +// Max number of moves shown by the move relearner. +// Increased from 25 to 60 so Mew can display all TMs/HMs. +// If you plan on adding more TMs, increase this number too. +#define MAX_RELEARNER_MOVES 60 + +// Move Relearner menu change constants +enum MoveRelearnerStates +{ + MOVE_RELEARNER_LEVEL_UP_MOVES, + MOVE_RELEARNER_EGG_MOVES, + MOVE_RELEARNER_TM_MOVES, + MOVE_RELEARNER_TUTOR_MOVES, + MOVE_RELEARNER_COUNT, +}; + +enum RelearnMode +{ + RELEARN_MODE_NONE = 0, + RELEARN_MODE_SCRIPT = 1, // Relearning moves through an event script + // These two must stay 2 and 3, they are tied to the summary screen pages + RELEARN_MODE_PSS_PAGE_BATTLE_MOVES = 2, // Relearning moves through the summary screen's battle moves page + RELEARN_MODE_PSS_PAGE_CONTEST_MOVES = 3, // Relearning moves through the summary screen's contest moves page (defaults to contest page on relearner screen) + RELEARN_MODE_PARTY_MENU = 4, // Relearning moves through the party menu's moves submenu +}; + +#endif // GUARD_CONSTANTS_MOVE_RELEARNER_H diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index b2e6b23ead..59bf27d823 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -2,28 +2,31 @@ #define GUARD_CONSTANTS_POKEMON_H // Pokémon types -#define TYPE_NONE 0 -#define TYPE_NORMAL 1 -#define TYPE_FIGHTING 2 -#define TYPE_FLYING 3 -#define TYPE_POISON 4 -#define TYPE_GROUND 5 -#define TYPE_ROCK 6 -#define TYPE_BUG 7 -#define TYPE_GHOST 8 -#define TYPE_STEEL 9 -#define TYPE_MYSTERY 10 -#define TYPE_FIRE 11 -#define TYPE_WATER 12 -#define TYPE_GRASS 13 -#define TYPE_ELECTRIC 14 -#define TYPE_PSYCHIC 15 -#define TYPE_ICE 16 -#define TYPE_DRAGON 17 -#define TYPE_DARK 18 -#define TYPE_FAIRY 19 -#define TYPE_STELLAR 20 -#define NUMBER_OF_MON_TYPES 21 +enum __attribute__((packed)) Type +{ + TYPE_NONE = 0, + TYPE_NORMAL = 1, + TYPE_FIGHTING = 2, + TYPE_FLYING = 3, + TYPE_POISON = 4, + TYPE_GROUND = 5, + TYPE_ROCK = 6, + TYPE_BUG = 7, + TYPE_GHOST = 8, + TYPE_STEEL = 9, + TYPE_MYSTERY = 10, + TYPE_FIRE = 11, + TYPE_WATER = 12, + TYPE_GRASS = 13, + TYPE_ELECTRIC = 14, + TYPE_PSYCHIC = 15, + TYPE_ICE = 16, + TYPE_DRAGON = 17, + TYPE_DARK = 18, + TYPE_FAIRY = 19, + TYPE_STELLAR = 20, + NUMBER_OF_MON_TYPES +}; // Pokémon egg groups #define EGG_GROUP_NONE 0 @@ -74,16 +77,18 @@ #define NUM_NATURES 25 // Pokémon Stats -#define STAT_HP 0 -#define STAT_ATK 1 -#define STAT_DEF 2 -#define STAT_SPEED 3 -#define STAT_SPATK 4 -#define STAT_SPDEF 5 -#define NUM_STATS 6 - -#define STAT_ACC 6 // Only in battles. -#define STAT_EVASION 7 // Only in battles. +enum __attribute__((packed)) Stat +{ + STAT_HP, + STAT_ATK, + STAT_DEF, + STAT_SPEED, + STAT_SPATK, + STAT_SPDEF, + NUM_STATS, + STAT_ACC = NUM_STATS, // Only in battles. + STAT_EVASION, // Only in battles. +}; #define NUM_NATURE_STATS (NUM_STATS - 1) // excludes HP #define NUM_BATTLE_STATS (NUM_STATS + 2) // includes Accuracy and Evasion @@ -169,7 +174,6 @@ #define LEVEL_UP_MOVE_END 0xFFFF #define MAX_LEVEL_UP_MOVES 20 -#define MAX_RELEARNER_MOVES max(MAX_LEVEL_UP_MOVES, 25) #define MON_MALE 0x00 #define MON_FEMALE 0xFE @@ -218,7 +222,7 @@ #define EV_ITEM_RAISE_LIMIT ((I_VITAMIN_EV_CAP >= GEN_8) ? MAX_PER_STAT_EVS : 100) // Move category defines. -enum DamageCategory +enum __attribute__((packed)) DamageCategory { DAMAGE_CATEGORY_PHYSICAL, DAMAGE_CATEGORY_SPECIAL, @@ -300,6 +304,8 @@ enum EvolutionConditions { IF_PID_MODULO_100_LT, // The Pokémon's personality value's modulo by 100 is lower than the defined value. IF_MIN_OVERWORLD_STEPS, // The Player has taken a specific amount of steps in the overworld with the Pokémon following them or in the first slot of the party. IF_BAG_ITEM_COUNT, // The Player has the specific amount of an item in the bag. It then removes those items. + IF_REGION, // The Player is in the specific region. + IF_NOT_REGION, // The Player is NOT in the specific region. CONDITIONS_END }; diff --git a/include/constants/rtc.h b/include/constants/rtc.h index 65ee9c35ed..ea0748b506 100644 --- a/include/constants/rtc.h +++ b/include/constants/rtc.h @@ -81,7 +81,7 @@ #define NIGHT_HOUR_END 6 #endif -// TIMES_OF_DAY_COUNT must be last +// TIMES_OF_DAY_COUNT must be last or things will break enum TimeOfDay { TIME_MORNING, @@ -91,6 +91,10 @@ enum TimeOfDay TIMES_OF_DAY_COUNT, }; +// for incrementing/decrementing +#define TIME_FIRST 0 +#define TIME_LAST (TIMES_OF_DAY_COUNT - 1) + #define TIME_OF_DAY_DEFAULT 0 #endif // GUARD_CONSTANTS_RTC_H diff --git a/include/constants/script_commands.h b/include/constants/script_commands.h new file mode 100644 index 0000000000..4adf99ccef --- /dev/null +++ b/include/constants/script_commands.h @@ -0,0 +1,238 @@ +// +// DO NOT MODIFY THIS FILE! It is auto-generated by tools/misc/make_scr_cmd_constants.py +// +#ifndef GUARD_SCR_CMD_CONSTANTS_H +#define GUARD_SCR_CMD_CONSTANTS_H + +#define SCR_OP_NOP 0x00 +#define SCR_OP_NOP1 0x01 +#define SCR_OP_END 0x02 +#define SCR_OP_RETURN 0x03 +#define SCR_OP_CALL 0x04 +#define SCR_OP_GOTO 0x05 +#define SCR_OP_GOTO_IF 0x06 +#define SCR_OP_CALL_IF 0x07 +#define SCR_OP_GOTO_STD 0x08 +#define SCR_OP_CALL_STD 0x09 +#define SCR_OP_GOTO_STD_IF 0x0a +#define SCR_OP_CALL_STD_IF 0x0b +#define SCR_OP_RETURNRAM 0x0c +#define SCR_OP_ENDRAM 0x0d +#define SCR_OP_SETMYSTERYEVENTSTATUS 0x0e +#define SCR_OP_LOAD_WORD 0x0f +#define SCR_OP_LOAD_BYTE 0x10 +#define SCR_OP_SETPTR 0x11 +#define SCR_OP_LOADBYTEFROMPTR 0x12 +#define SCR_OP_SETPTRBYTE 0x13 +#define SCR_OP_COPYLOCAL 0x14 +#define SCR_OP_COPYBYTE 0x15 +#define SCR_OP_SETVAR 0x16 +#define SCR_OP_ADDVAR 0x17 +#define SCR_OP_SUBVAR 0x18 +#define SCR_OP_COPYVAR 0x19 +#define SCR_OP_SETORCOPYVAR 0x1a +#define SCR_OP_COMPARE_LOCAL_TO_LOCAL 0x1b +#define SCR_OP_COMPARE_LOCAL_TO_VALUE 0x1c +#define SCR_OP_COMPARE_LOCAL_TO_PTR 0x1d +#define SCR_OP_COMPARE_PTR_TO_LOCAL 0x1e +#define SCR_OP_COMPARE_PTR_TO_VALUE 0x1f +#define SCR_OP_COMPARE_PTR_TO_PTR 0x20 +#define SCR_OP_COMPARE_VAR_TO_VALUE 0x21 +#define SCR_OP_COMPARE_VAR_TO_VAR 0x22 +#define SCR_OP_CALLNATIVE 0x23 +#define SCR_OP_GOTONATIVE 0x24 +#define SCR_OP_SPECIAL 0x25 +#define SCR_OP_SPECIALVAR 0x26 +#define SCR_OP_WAITSTATE 0x27 +#define SCR_OP_DELAY 0x28 +#define SCR_OP_SETFLAG 0x29 +#define SCR_OP_CLEARFLAG 0x2a +#define SCR_OP_CHECKFLAG 0x2b +#define SCR_OP_INITCLOCK 0x2c +#define SCR_OP_DOTIMEBASEDEVENTS 0x2d +#define SCR_OP_GETTIME 0x2e +#define SCR_OP_PLAYSE 0x2f +#define SCR_OP_WAITSE 0x30 +#define SCR_OP_PLAYFANFARE 0x31 +#define SCR_OP_WAITFANFARE 0x32 +#define SCR_OP_PLAYBGM 0x33 +#define SCR_OP_SAVEBGM 0x34 +#define SCR_OP_FADEDEFAULTBGM 0x35 +#define SCR_OP_FADENEWBGM 0x36 +#define SCR_OP_FADEOUTBGM 0x37 +#define SCR_OP_FADEINBGM 0x38 +#define SCR_OP_WARP 0x39 +#define SCR_OP_WARPSILENT 0x3a +#define SCR_OP_WARPDOOR 0x3b +#define SCR_OP_WARPHOLE 0x3c +#define SCR_OP_WARPTELEPORT 0x3d +#define SCR_OP_SETWARP 0x3e +#define SCR_OP_SETDYNAMICWARP 0x3f +#define SCR_OP_SETDIVEWARP 0x40 +#define SCR_OP_SETHOLEWARP 0x41 +#define SCR_OP_GETPLAYERXY 0x42 +#define SCR_OP_GETPARTYSIZE 0x43 +#define SCR_OP_ADDITEM 0x44 +#define SCR_OP_REMOVEITEM 0x45 +#define SCR_OP_CHECKITEMSPACE 0x46 +#define SCR_OP_CHECKITEM 0x47 +#define SCR_OP_CHECKITEMTYPE 0x48 +#define SCR_OP_ADDPCITEM 0x49 +#define SCR_OP_CHECKPCITEM 0x4a +#define SCR_OP_ADDDECORATION 0x4b +#define SCR_OP_REMOVEDECORATION 0x4c +#define SCR_OP_CHECKDECOR 0x4d +#define SCR_OP_CHECKDECORSPACE 0x4e +#define SCR_OP_APPLYMOVEMENT 0x4f +#define SCR_OP_APPLYMOVEMENTAT 0x50 +#define SCR_OP_WAITMOVEMENT 0x51 +#define SCR_OP_WAITMOVEMENTAT 0x52 +#define SCR_OP_REMOVEOBJECT 0x53 +#define SCR_OP_REMOVEOBJECTAT 0x54 +#define SCR_OP_ADDOBJECT 0x55 +#define SCR_OP_ADDOBJECTAT 0x56 +#define SCR_OP_SETOBJECTXY 0x57 +#define SCR_OP_SHOWOBJECTAT 0x58 +#define SCR_OP_HIDEOBJECTAT 0x59 +#define SCR_OP_FACEPLAYER 0x5a +#define SCR_OP_TURNOBJECT 0x5b +#define SCR_OP_TRAINERBATTLE 0x5c +#define SCR_OP_DOTRAINERBATTLE 0x5d +#define SCR_OP_GOTOPOSTBATTLESCRIPT 0x5e +#define SCR_OP_GOTOBEATENSCRIPT 0x5f +#define SCR_OP_CHECKTRAINERFLAG 0x60 +#define SCR_OP_SETTRAINERFLAG 0x61 +#define SCR_OP_CLEARTRAINERFLAG 0x62 +#define SCR_OP_SETOBJECTXYPERM 0x63 +#define SCR_OP_COPYOBJECTXYTOPERM 0x64 +#define SCR_OP_SETOBJECTMOVEMENTTYPE 0x65 +#define SCR_OP_WAITMESSAGE 0x66 +#define SCR_OP_MESSAGE 0x67 +#define SCR_OP_CLOSEMESSAGE 0x68 +#define SCR_OP_LOCKALL 0x69 +#define SCR_OP_LOCK 0x6a +#define SCR_OP_RELEASEALL 0x6b +#define SCR_OP_RELEASE 0x6c +#define SCR_OP_WAITBUTTONPRESS 0x6d +#define SCR_OP_YESNOBOX 0x6e +#define SCR_OP_MULTICHOICE 0x6f +#define SCR_OP_MULTICHOICEDEFAULT 0x70 +#define SCR_OP_MULTICHOICEGRID 0x71 +#define SCR_OP_DRAWBOX 0x72 +#define SCR_OP_ERASEBOX 0x73 +#define SCR_OP_DRAWBOXTEXT 0x74 +#define SCR_OP_SHOWMONPIC 0x75 +#define SCR_OP_HIDEMONPIC 0x76 +#define SCR_OP_SHOWCONTESTPAINTING 0x77 +#define SCR_OP_BRAILLEMESSAGE 0x78 +#define SCR_OP_GIVEMON 0x79 +#define SCR_OP_GIVEEGG 0x7a +#define SCR_OP_SETMONMOVE 0x7b +#define SCR_OP_CHECKFIELDMOVE 0x7c +#define SCR_OP_BUFFERSPECIESNAME 0x7d +#define SCR_OP_BUFFERLEADMONSPECIESNAME 0x7e +#define SCR_OP_BUFFERPARTYMONNICK 0x7f +#define SCR_OP_BUFFERITEMNAME 0x80 +#define SCR_OP_BUFFERDECORATIONNAME 0x81 +#define SCR_OP_BUFFERMOVENAME 0x82 +#define SCR_OP_BUFFERNUMBERSTRING 0x83 +#define SCR_OP_BUFFERSTDSTRING 0x84 +#define SCR_OP_BUFFERSTRING 0x85 +#define SCR_OP_POKEMART 0x86 +#define SCR_OP_POKEMARTDECORATION 0x87 +#define SCR_OP_POKEMARTDECORATION2 0x88 +#define SCR_OP_PLAYSLOTMACHINE 0x89 +#define SCR_OP_SETBERRYTREE 0x8a +#define SCR_OP_CHOOSECONTESTMON 0x8b +#define SCR_OP_STARTCONTEST 0x8c +#define SCR_OP_SHOWCONTESTRESULTS 0x8d +#define SCR_OP_CONTESTLINKTRANSFER 0x8e +#define SCR_OP_RANDOM 0x8f +#define SCR_OP_ADDMONEY 0x90 +#define SCR_OP_REMOVEMONEY 0x91 +#define SCR_OP_CHECKMONEY 0x92 +#define SCR_OP_SHOWMONEYBOX 0x93 +#define SCR_OP_HIDEMONEYBOX 0x94 +#define SCR_OP_UPDATEMONEYBOX 0x95 +#define SCR_OP_GETPOKENEWSACTIVE 0x96 +#define SCR_OP_FADESCREEN 0x97 +#define SCR_OP_FADESCREENSPEED 0x98 +#define SCR_OP_SETFLASHLEVEL 0x99 +#define SCR_OP_ANIMATEFLASH 0x9a +#define SCR_OP_MESSAGEAUTOSCROLL 0x9b +#define SCR_OP_DOFIELDEFFECT 0x9c +#define SCR_OP_SETFIELDEFFECTARGUMENT 0x9d +#define SCR_OP_WAITFIELDEFFECT 0x9e +#define SCR_OP_SETRESPAWN 0x9f +#define SCR_OP_CHECKPLAYERGENDER 0xa0 +#define SCR_OP_PLAYMONCRY 0xa1 +#define SCR_OP_SETMETATILE 0xa2 +#define SCR_OP_RESETWEATHER 0xa3 +#define SCR_OP_SETWEATHER 0xa4 +#define SCR_OP_DOWEATHER 0xa5 +#define SCR_OP_SETSTEPCALLBACK 0xa6 +#define SCR_OP_SETMAPLAYOUTINDEX 0xa7 +#define SCR_OP_SETOBJECTSUBPRIORITY 0xa8 +#define SCR_OP_RESETOBJECTSUBPRIORITY 0xa9 +#define SCR_OP_CREATEVOBJECT 0xaa +#define SCR_OP_TURNVOBJECT 0xab +#define SCR_OP_OPENDOOR 0xac +#define SCR_OP_CLOSEDOOR 0xad +#define SCR_OP_WAITDOORANIM 0xae +#define SCR_OP_SETDOOROPEN 0xaf +#define SCR_OP_SETDOORCLOSED 0xb0 +#define SCR_OP_ADDELEVMENUITEM 0xb1 +#define SCR_OP_SHOWELEVMENU 0xb2 +#define SCR_OP_CHECKCOINS 0xb3 +#define SCR_OP_ADDCOINS 0xb4 +#define SCR_OP_REMOVECOINS 0xb5 +#define SCR_OP_SETWILDBATTLE 0xb6 +#define SCR_OP_DOWILDBATTLE 0xb7 +#define SCR_OP_SETVADDRESS 0xb8 +#define SCR_OP_VGOTO 0xb9 +#define SCR_OP_VCALL 0xba +#define SCR_OP_VGOTO_IF 0xbb +#define SCR_OP_VCALL_IF 0xbc +#define SCR_OP_VMESSAGE 0xbd +#define SCR_OP_VBUFFERMESSAGE 0xbe +#define SCR_OP_VBUFFERSTRING 0xbf +#define SCR_OP_SHOWCOINSBOX 0xc0 +#define SCR_OP_HIDECOINSBOX 0xc1 +#define SCR_OP_UPDATECOINSBOX 0xc2 +#define SCR_OP_INCREMENTGAMESTAT 0xc3 +#define SCR_OP_SETESCAPEWARP 0xc4 +#define SCR_OP_WAITMONCRY 0xc5 +#define SCR_OP_BUFFERBOXNAME 0xc6 +#define SCR_OP_TEXTCOLOR 0xc7 +#define SCR_OP_LOADHELP 0xc8 +#define SCR_OP_UNLOADHELP 0xc9 +#define SCR_OP_SIGNMSG 0xca +#define SCR_OP_NORMALMSG 0xcb +#define SCR_OP_COMPAREHIDDENVAR 0xcc +#define SCR_OP_SETMODERNFATEFULENCOUNTER 0xcd +#define SCR_OP_CHECKMODERNFATEFULENCOUNTER 0xce +#define SCR_OP_TRYWONDERCARDSCRIPT 0xcf +#define SCR_OP_SETWORLDMAPFLAG 0xd0 +#define SCR_OP_WARPSPINENTER 0xd1 +#define SCR_OP_SETMONMETLOCATION 0xd2 +#define SCR_OP_MOVEROTATINGTILEOBJECTS 0xd3 +#define SCR_OP_TURNROTATINGTILEOBJECTS 0xd4 +#define SCR_OP_INITROTATINGTILEPUZZLE 0xd5 +#define SCR_OP_FREEROTATINGTILEPUZZLE 0xd6 +#define SCR_OP_WARPMOSSDEEPGYM 0xd7 +#define SCR_OP_SELECTAPPROACHINGTRAINER 0xd8 +#define SCR_OP_LOCKFORTRAINER 0xd9 +#define SCR_OP_CLOSEBRAILLEMESSAGE 0xda +#define SCR_OP_MESSAGEINSTANT 0xdb +#define SCR_OP_FADESCREENSWAPBUFFERS 0xdc +#define SCR_OP_BUFFERTRAINERCLASSNAME 0xdd +#define SCR_OP_BUFFERTRAINERNAME 0xde +#define SCR_OP_POKENAVCALL 0xdf +#define SCR_OP_WARPWHITEFADE 0xe0 +#define SCR_OP_BUFFERCONTESTNAME 0xe1 +#define SCR_OP_BUFFERITEMNAMEPLURAL 0xe2 +#define SCR_OP_DYNMULTICHOICE 0xe3 +#define SCR_OP_DYNMULTIPUSH 0xe4 +#define SCR_OP_HIDEFOLLOWER 0xe5 + +#endif // GUARD_SCR_CMD_CONSTANTS_H diff --git a/include/constants/speaker_names.h b/include/constants/speaker_names.h new file mode 100644 index 0000000000..1f4f399e75 --- /dev/null +++ b/include/constants/speaker_names.h @@ -0,0 +1,11 @@ +#ifndef GUARD_CONSTANTS_SPEAKER_NAMES_H +#define GUARD_CONSTANTS_SPEAKER_NAMES_H + +enum SpeakerNames { + SP_NAME_NONE = 0, + SP_NAME_MOM, + SP_NAME_PLAYER, + SP_NAME_COUNT +}; + +#endif // GUARD_CONSTANTS_SPEAKER_NAMES_H diff --git a/include/constants/species.h b/include/constants/species.h index 3656d7664e..ed31317c36 100644 --- a/include/constants/species.h +++ b/include/constants/species.h @@ -2,7 +2,7 @@ #define GUARD_CONSTANTS_SPECIES_H // NOTE: The defines here are named in order to match Pokémon Showdown's naming conventions. This is done to avoid issues with trainerproc parsing species names. If a Pokémon does not have an entry on Showdown, use your best judgement. -// Additionally, we have tried to reduce down to as few defines as possible, because programs like porymap does not always properly handle having multiple defines. +// Additionally, we have tried to reduce down to as few defines as possible, because programs like porymap do not always properly handle having multiple defines. // Discussion: https://github.com/rh-hideout/pokeemerald-expansion/pull/5075#issuecomment-2384088602 // Showdown: https://github.com/smogon/Pokemon-Showdown/blob/master/data/pokedex.ts @@ -1637,8 +1637,35 @@ #define SPECIES_URSHIFU_RAPID_STRIKE_STYLE_GMAX SPECIES_URSHIFU_RAPID_STRIKE_GMAX #define SPECIES_MIMIKYU_BUSTED_TOTEM 1523 #define SPECIES_MIMIKYU_TOTEM_BUSTED SPECIES_MIMIKYU_BUSTED_TOTEM +// Legends Z-A +#define SPECIES_CLEFABLE_MEGA 1524 +#define SPECIES_VICTREEBEL_MEGA 1525 +#define SPECIES_STARMIE_MEGA 1526 +#define SPECIES_DRAGONITE_MEGA 1527 +#define SPECIES_MEGANIUM_MEGA 1528 +#define SPECIES_FERALIGATR_MEGA 1529 +#define SPECIES_SKARMORY_MEGA 1530 +#define SPECIES_FROSLASS_MEGA 1531 +#define SPECIES_EMBOAR_MEGA 1532 +#define SPECIES_EXCADRILL_MEGA 1533 +#define SPECIES_SCOLIPEDE_MEGA 1534 +#define SPECIES_SCRAFTY_MEGA 1535 +#define SPECIES_EELEKTROSS_MEGA 1536 +#define SPECIES_CHANDELURE_MEGA 1537 +#define SPECIES_CHESNAUGHT_MEGA 1538 +#define SPECIES_DELPHOX_MEGA 1539 +#define SPECIES_GRENINJA_MEGA 1540 +#define SPECIES_PYROAR_MEGA 1541 +#define SPECIES_MALAMAR_MEGA 1542 +#define SPECIES_DRAGALGE_MEGA 1543 +#define SPECIES_HAWLUCHA_MEGA 1544 +#define SPECIES_FLOETTE_MEGA 1545 +#define SPECIES_BARBARACLE_MEGA 1546 +#define SPECIES_ZYGARDE_MEGA 1547 +#define SPECIES_DRAMPA_MEGA 1548 +#define SPECIES_FALINKS_MEGA 1549 -#define SPECIES_EGG (SPECIES_MIMIKYU_BUSTED_TOTEM + 1) +#define SPECIES_EGG (SPECIES_FALINKS_MEGA + 1) #define NUM_SPECIES SPECIES_EGG diff --git a/include/constants/wild_encounter.h b/include/constants/wild_encounter.h index 364d18350f..364dc7b35a 100644 --- a/include/constants/wild_encounter.h +++ b/include/constants/wild_encounter.h @@ -9,7 +9,4 @@ #define NUM_ALTERING_CAVE_TABLES 9 -#define FISHING_CHAIN_LENGTH_MAX 200 -#define FISHING_CHAIN_SHINY_STREAK_MAX 20 - #endif // GUARD_CONSTANTS_WILD_ENCOUNTER_H diff --git a/include/contest.h b/include/contest.h index 80a1370541..278efaa4ac 100644 --- a/include/contest.h +++ b/include/contest.h @@ -302,6 +302,17 @@ struct ContestResources void *animBgTileBuffer; }; +struct ContestCategory +{ + const u8 *name; + const u8 *condition; + const u8 *generic; + const u8 *negativeTrait; + u8 palette; +}; + +extern const struct ContestCategory gContestCategoryInfo[CONTEST_CATEGORIES_COUNT + 1]; + #define eContest (*gContestResources->contest) #define eContestantStatus (gContestResources->status) #define eContestAppealResults (*gContestResources->appealResults) diff --git a/include/contest_effect.h b/include/contest_effect.h index 87129bd792..7db929031b 100644 --- a/include/contest_effect.h +++ b/include/contest_effect.h @@ -1,17 +1,17 @@ #ifndef GUARD_CONTEST_EFFECT_H #define GUARD_CONTEST_EFFECT_H -#define MAX_COMBO_MOVES 5 +#define MAX_COMBO_MOVES 17 struct ContestEffect { u8 effectType; u8 appeal; u8 jam; + const u8 *description; + void (*function)(void); }; extern const struct ContestEffect gContestEffects[]; -extern const u8 *const gContestEffectDescriptionPointers[]; -extern const u8 *const gContestMoveTypeTextPointers[]; bool8 AreMovesContestCombo(u16 lastMove, u16 nextMove); diff --git a/include/data.h b/include/data.h index 2128685e19..fbca022f97 100644 --- a/include/data.h +++ b/include/data.h @@ -64,14 +64,14 @@ struct TrainerMon u16 moves[4]; u16 species; u16 heldItem; - u16 ability; + enum Ability ability; u8 lvl; u8 ball; u8 friendship; u8 nature:5; bool8 gender:2; bool8 isShiny:1; - u8 teraType:5; + enum Type teraType:5; bool8 gigantamaxFactor:1; u8 shouldUseDynamax:1; u8 padding1:1; @@ -82,7 +82,7 @@ struct TrainerMon #define TRAINER_PARTY(partyArray) partyArray, .partySize = ARRAY_COUNT(partyArray) -enum TrainerBattleType +enum TrainerBattleType { TRAINER_BATTLE_TYPE_SINGLES, TRAINER_BATTLE_TYPE_DOUBLES, diff --git a/include/debug.h b/include/debug.h index 11212ce97f..01be269c4d 100644 --- a/include/debug.h +++ b/include/debug.h @@ -6,6 +6,9 @@ extern const u8 Debug_FlagsAndVarNotSetBattleConfigMessage[]; const u8 *GetWeatherName(u32 weatherId); const struct Trainer* GetDebugAiTrainer(void); +void DebugNative_GetAbilityNames(void); +void DebugNative_Party_SetFriendship(void); + extern EWRAM_DATA bool8 gIsDebugBattle; extern EWRAM_DATA u64 gDebugAIFlags; diff --git a/include/event_object_movement.h b/include/event_object_movement.h index a9d1e61277..4ec46709e3 100644 --- a/include/event_object_movement.h +++ b/include/event_object_movement.h @@ -512,4 +512,6 @@ bool8 MovementAction_EmoteX_Step0(struct ObjectEvent *, struct Sprite *); bool8 MovementAction_EmoteDoubleExclamationMark_Step0(struct ObjectEvent *, struct Sprite *); bool8 PlayerIsUnderWaterfall(struct ObjectEvent *objectEvent); +u8 GetObjectEventApricornTreeId(u8 objectEventId); + #endif //GUARD_EVENT_OBJECT_MOVEMENT_H diff --git a/include/field_name_box.h b/include/field_name_box.h new file mode 100644 index 0000000000..983ac09d09 --- /dev/null +++ b/include/field_name_box.h @@ -0,0 +1,22 @@ +#ifndef GUARD_FIELD_NAME_BOX_H +#define GUARD_FIELD_NAME_BOX_H + +#include "config/name_box.h" + +#define NAME_BOX_BASE_TILES_TOTAL (6) // Total tiles within the namebox's .png, best practice to make all images uses the same total tiles. +#define NAME_BOX_BASE_TILE_NUM (0x194 - (OW_NAME_BOX_DEFAULT_WIDTH * OW_NAME_BOX_DEFAULT_HEIGHT)) + +extern EWRAM_DATA const u8 *gSpeakerName; +extern const u8 *const gSpeakerNamesTable[]; + +void TrySpawnNamebox(u32 tileNum); +u32 GetNameboxWindowId(void); +void ResetNameboxData(void); +void DestroyNamebox(void); +void FillNamebox(void); +void DrawNamebox(u32 windowId, u32 tileNum, bool32 copyToVram); +void ClearNamebox(u32 windowId, bool32 copyToVram); +u32 GetNameboxWidth(void); +void TrySpawnAndShowNamebox(const u8 *speaker, u32 tileNum); + +#endif // GUARD_FIELD_NAME_BOX_H diff --git a/include/field_player_avatar.h b/include/field_player_avatar.h index cb7128f203..a6d56f62f7 100644 --- a/include/field_player_avatar.h +++ b/include/field_player_avatar.h @@ -64,7 +64,7 @@ bool32 IsPlayerSpinEntranceActive(void); bool32 IsPlayerSpinExitActive(void); void SetPlayerInvisibility(bool8 invisible); u8 player_get_pos_including_state_based_drift(s16 *x, s16 *y); -void StartFishing(u8 rod); +void SetPlayerAvatarFishing(u8 direction); bool8 ObjectMovingOnRockStairs(struct ObjectEvent *objectEvent, u8 direction); //sideways stairs u8 GetRightSideStairsDirection(u8 direction); diff --git a/include/field_specials.h b/include/field_specials.h index 50afecf2fb..c6bc40143f 100644 --- a/include/field_specials.h +++ b/include/field_specials.h @@ -19,7 +19,7 @@ bool32 ShouldDoScottBattleFrontierCall(void); bool32 ShouldDoRoxanneCall(void); bool32 ShouldDoRivalRayquazaCall(void); bool32 CountSSTidalStep(u16 delta); -u8 GetSSTidalLocation(s8 *mapGroup, s8 *mapNum, s16 *x, s16 *y); +enum SSTidalLocation GetSSTidalLocation(s8 *mapGroup, s8 *mapNum, s16 *x, s16 *y); void ShowScrollableMultichoice(void); void FrontierGamblerSetWonOrLost(bool8 won); u8 TryGainNewFanFromCounter(u8 incrementId); diff --git a/include/fishing.h b/include/fishing.h new file mode 100644 index 0000000000..05ee236604 --- /dev/null +++ b/include/fishing.h @@ -0,0 +1,9 @@ +#ifndef GUARD_FISHING_H +#define GUARD_FISHING_H + +void StartFishing(u8 rod); +void UpdateChainFishingStreak(); +u32 CalculateChainFishingShinyRolls(void); +bool32 ShouldUseFishingEnvironmentInBattle(); + +#endif // GUARD_FISHING_H \ No newline at end of file diff --git a/include/follower_npc.h b/include/follower_npc.h index 5a2ab0e545..680a3b6799 100644 --- a/include/follower_npc.h +++ b/include/follower_npc.h @@ -81,6 +81,13 @@ enum FollowerNPCHandleEscalatorFinishTaskStates MOVEMENT_FINISH }; +enum FollowerNPCForcedMovementStates +{ + FNPC_FORCED_NONE, + FNPC_FORCED_FOLLOW, + FNPC_FORCED_STAY +}; + #define FOLLOWER_NPC_FLAG_HAS_RUNNING_FRAMES 0x1 #define FNPC_NONE 0 diff --git a/include/frontier_util.h b/include/frontier_util.h index 5494aa5f0b..cd99f7a181 100644 --- a/include/frontier_util.h +++ b/include/frontier_util.h @@ -25,5 +25,6 @@ u8 GetFrontierBrainMonNature(u8 monId); u8 GetFrontierBrainMonEvs(u8 monId, u8 evStatId); s32 GetFronterBrainSymbol(void); void ClearEnemyPartyAfterChallenge(void); +void ShowBattleFrontierCaughtBannedSpecies(void); #endif // GUARD_FRONTIER_UTIL_H diff --git a/include/global.h b/include/global.h index a3dacfb3d4..3135542e02 100644 --- a/include/global.h +++ b/include/global.h @@ -14,6 +14,7 @@ #include "constants/vars.h" #include "constants/species.h" #include "constants/pokedex.h" +#include "constants/apricorn_tree.h" #include "constants/berry.h" #include "constants/maps.h" #include "constants/pokemon.h" @@ -134,6 +135,8 @@ #define NUM_FLAG_BYTES ROUND_BITS_TO_BYTES(FLAGS_COUNT) #define NUM_TRENDY_SAYING_BYTES ROUND_BITS_TO_BYTES(NUM_TRENDY_SAYINGS) +#define NUM_APRICORN_TREE_BYTES ROUND_BITS_TO_BYTES(APRICORN_TREE_COUNT) + // This produces an error at compile-time if expr is zero. // It looks like file.c:line: size of array `id' is negative #define STATIC_ASSERT(expr, id) typedef char id[(expr) ? 1 : -1]; @@ -219,9 +222,9 @@ struct NPCFollower { u8 inProgress:1; u8 warpEnd:1; - u8 createSurfBlob:3; + u8 createSurfBlob:2; u8 comeOutDoorStairs:2; - u8 forcedMovement:1; + u8 forcedMovement:2; u8 objId; u8 currentSprite; u8 delayedState; @@ -252,6 +255,9 @@ struct SaveBlock3 u8 dexNavSearchLevels[NUM_SPECIES]; #endif u8 dexNavChain; +#if APRICORN_TREE_COUNT > 0 + u8 apricornTrees[NUM_APRICORN_TREE_BYTES]; +#endif }; /* max size 1624 bytes */ extern struct SaveBlock3 *gSaveBlock3Ptr; diff --git a/include/item.h b/include/item.h index 56fe152720..7d446e0fbc 100644 --- a/include/item.h +++ b/include/item.h @@ -180,6 +180,8 @@ static inline u16 GetTMHMMoveId(enum TMHMIndex index) return gTMHMItemMoveIds[index].moveId; } +enum TMHMItemId GetTMHMItemIdFromMoveId(u16 move); + void BagPocket_SetSlotData(struct BagPocket *pocket, u32 pocketPos, struct ItemSlot newSlot); struct ItemSlot BagPocket_GetSlotData(struct BagPocket *pocket, u32 pocketPos); @@ -232,7 +234,7 @@ bool32 RemovePyramidBagItem(u16 itemId, u16 count); const u8 *GetItemName(u16 itemId); u32 GetItemPrice(u16 itemId); const u8 *GetItemEffect(u32 itemId); -u32 GetItemHoldEffect(u32 itemId); +enum HoldEffect GetItemHoldEffect(u32 itemId); u32 GetItemHoldEffectParam(u32 itemId); const u8 *GetItemDescription(u16 itemId); u8 GetItemImportance(u16 itemId); @@ -246,6 +248,6 @@ u32 GetItemFlingPower(u32 itemId); u32 GetItemStatus1Mask(u16 itemId); bool32 ItemHasVolatileFlag(u16 itemId, enum Volatile volatile); u32 GetItemSellPrice(u32 itemId); -bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect); +bool32 IsHoldEffectChoice(enum HoldEffect holdEffect); #endif // GUARD_ITEM_H diff --git a/include/item_use.h b/include/item_use.h index ad8018d67d..ccb0f4f3df 100644 --- a/include/item_use.h +++ b/include/item_use.h @@ -49,6 +49,8 @@ void Task_ItemUse_CloseMessageBoxAndReturnToField_VsSeeker(u8 taskId); void DisplayDadsAdviceCannotUseItemMessage(u8 taskId, bool8 isUsingRegisteredKeyItemOnField); void ItemUseOutOfBattle_PokeFlute(u8 taskId); void ItemUseOutOfBattle_TownMap(u8 taskId); +bool8 ItemfinderCheckForHiddenItems(const struct MapEvents *, u8); +u8 GetDirectionToHiddenItem(s16, s16); enum { BALL_THROW_UNABLE_TWO_MONS, diff --git a/include/list_menu.h b/include/list_menu.h index 184b9c416f..8d472320d6 100644 --- a/include/list_menu.h +++ b/include/list_menu.h @@ -76,8 +76,9 @@ struct ListMenuTemplate u8 lettersSpacing:3; u8 itemVerticalPadding:3; u8 scrollMultiple:2; // x40, x80 = xC0 - u8 fontId:6; // x1, x2, x4, x8, x10, x20 = x3F - u8 cursorKind:2; // x40, x80 + u8 fontId:5; // x1, x2, x4, x8, x10 = x1F + u8 cursorKind:2; // x20, x40 + u8 isDynamic:1; //Dynamic list doesn't store all items in memory but load them from ROM when necessary }; struct ListMenu diff --git a/include/match_call.h b/include/match_call.h index ed2cf506c5..468a977a13 100644 --- a/include/match_call.h +++ b/include/match_call.h @@ -19,5 +19,6 @@ void BufferPokedexRatingForMatchCall(u8 *destStr); bool32 SelectMatchCallMessage(int trainerId, u8 *str); void LoadMatchCallWindowGfx(u32 windowId, u32 destOffset, u32 paletteId); void DrawMatchCallTextBoxBorder(u32 windowId, u32 tileOffset, u32 paletteId); +void RedrawMatchCallTextBoxBorder(void); #endif //GUARD_MATCH_CALL_H diff --git a/include/menu.h b/include/menu.h index ca7f8d008c..6702552331 100644 --- a/include/menu.h +++ b/include/menu.h @@ -61,8 +61,6 @@ void PrintPlayerNameOnWindow(u8 windowId, const u8 *src, u16 x, u16 y); void ClearDialogWindowAndFrame(u8 windowId, bool8 copyToVram); void SetStandardWindowBorderStyle(u8 windowId, bool8 copyToVram); void DisplayYesNoMenuDefaultYes(void); -u32 GetPlayerTextSpeed(void); -u8 GetPlayerTextSpeedDelay(void); void Menu_LoadStdPalAt(u16 offset); void AddTextPrinterWithCallbackForMessage(bool8 canSpeedUp, void (*callback)(struct TextPrinterTemplate *, u16)); void BgDmaFill(u32 bg, u8 value, int offset, int size); @@ -106,7 +104,6 @@ void DrawStdWindowFrame(u8 windowId, bool8 copyToVram); u8 AddStartMenuWindow(u8 numActions); u8 InitMenuNormal(u8 windowId, u8 fontId, u8 left, u8 top, u8 cursorHeight, u8 numChoices, u8 initialCursorPos); void LoadMessageBoxAndFrameGfx(u8 windowId, bool8 copyToVram); -void AddTextPrinterForMessage_2(bool8 allowSkippingDelayWithButtonPress); void RemoveStartMenuWindow(void); void DisplayYesNoMenuWithDefault(u8 initialCursorPos); void BufferSaveMenuText(u8 textId, u8 *dest, u8 color); @@ -135,5 +132,6 @@ u8 AddSecondaryPopUpWindow(void); u8 GetSecondaryPopUpWindowId(void); void RemoveSecondaryPopUpWindow(void); void HBlankCB_DoublePopupWindow(void); +void RedrawDialogueFrame(void); #endif // GUARD_MENU_H diff --git a/include/move.h b/include/move.h index b1e8cba99f..fe2587a225 100644 --- a/include/move.h +++ b/include/move.h @@ -65,7 +65,7 @@ struct MoveInfo const u8 *name; const u8 *description; enum BattleMoveEffects effect; - u16 type:5; // Up to 32 + enum Type type:5; // Up to 32 enum DamageCategory category:2; u16 power:9; // up to 511 // end of word @@ -81,7 +81,7 @@ struct MoveInfo u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit. u32 criticalHitStage:2; bool32 alwaysCriticalHit:1; - u32 numAdditionalEffects:2; // limited to 3 - don't want to get too crazy + u32 numAdditionalEffects:3; // limited to 7 // Flags bool32 makesContact:1; bool32 ignoresProtect:1; @@ -101,8 +101,8 @@ struct MoveInfo bool32 minimizeDoubleDamage:1; bool32 ignoresTargetAbility:1; bool32 ignoresTargetDefenseEvasionStages:1; - bool32 damagesUnderground:1; // end of word + bool32 damagesUnderground:1; bool32 damagesUnderwater:1; bool32 damagesAirborne:1; bool32 damagesAirborneDoubleDamage:1; @@ -131,7 +131,7 @@ struct MoveInfo bool32 dampBanned:1; //Other bool32 validApprenticeMove:1; - u32 padding:6; + u32 padding:5; // end of word union { @@ -149,6 +149,7 @@ struct MoveInfo u32 absorbPercentage; u32 recoilPercentage; u32 nonVolatileStatus; + u32 overwriteAbility; } argument; // primary/secondary effects @@ -192,7 +193,7 @@ static inline const u8 *GetMoveDescription(u32 moveId) return gMovesInfo[moveId].description; } -static inline u32 GetMoveType(u32 moveId) +static inline enum Type GetMoveType(u32 moveId) { return gMovesInfo[SanitizeMoveId(moveId)].type; } @@ -564,6 +565,11 @@ static inline u32 GetMoveDamagePercentage(u32 move) return gMovesInfo[SanitizeMoveId(move)].argument.damagePercentage; } +static inline u32 GetMoveOverwriteAbility(u32 move) +{ + return gMovesInfo[SanitizeMoveId(move)].argument.overwriteAbility; +} + static inline const struct AdditionalEffect *GetMoveAdditionalEffectById(u32 moveId, u32 effect) { return &gMovesInfo[SanitizeMoveId(moveId)].additionalEffects[effect]; diff --git a/include/move_relearner.h b/include/move_relearner.h index 9aab3974df..1d22d82a79 100644 --- a/include/move_relearner.h +++ b/include/move_relearner.h @@ -1,11 +1,14 @@ #ifndef GUARD_MOVE_RELEARNER_H #define GUARD_MOVE_RELEARNER_H +#include "constants/move_relearner.h" + void TeachMoveRelearnerMove(void); void MoveRelearnerShowHideHearts(s32 move); void MoveRelearnerShowHideCategoryIcon(s32); void CB2_InitLearnMove(void); -extern u8 gOriginSummaryScreenPage; +extern enum MoveRelearnerStates gMoveRelearnerState; +extern enum RelearnMode gRelearnMode; #endif //GUARD_MOVE_RELEARNER_H diff --git a/include/oras_dowse.h b/include/oras_dowse.h new file mode 100644 index 0000000000..8b490cf6c7 --- /dev/null +++ b/include/oras_dowse.h @@ -0,0 +1,39 @@ +#ifndef GUARD_ORAS_DOWSE_H +#define GUARD_ORAS_DOWSE_H + +// States for ORAS Dowsing +enum +{ + ORASD_WIGGLE_NONE, + ORASD_WIGGLE_SLOW, + ORASD_WIGGLE_NORMAL, + ORASD_WIGGLE_FAST, + ORASD_WIGGLE_FASTER +}; + +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH_SLOW (ANIM_STD_FACE_EAST + 1) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH_SLOW (ANIM_STD_FACE_EAST + 2) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST_SLOW (ANIM_STD_FACE_EAST + 3) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST_SLOW (ANIM_STD_FACE_EAST + 4) +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH (ANIM_STD_FACE_EAST + 5) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH (ANIM_STD_FACE_EAST + 6) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST (ANIM_STD_FACE_EAST + 7) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST (ANIM_STD_FACE_EAST + 8) +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FAST (ANIM_STD_FACE_EAST + 9) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH_FAST (ANIM_STD_FACE_EAST + 10) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST_FAST (ANIM_STD_FACE_EAST + 11) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST_FAST (ANIM_STD_FACE_EAST + 12) +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FASTER (ANIM_STD_FACE_EAST + 13) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH_FASTER (ANIM_STD_FACE_EAST + 14) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST_FASTER (ANIM_STD_FACE_EAST + 15) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST_FASTER (ANIM_STD_FACE_EAST + 16) + +extern const u16 gFieldEffectPal_ORASDowsing[]; + +void Task_UseORASDowsingMachine(u8 taskId); +void ResumeORASDowseFieldEffect(void); +void UpdateDowseState(struct Sprite *sprite); +void UpdateDowsingAnimDirection(struct Sprite *sprite, struct ObjectEvent *playerObj); +void EndORASDowsing(void); + +#endif // GUARD_ORAS_DOWSE_H diff --git a/include/overworld.h b/include/overworld.h index 28cd4c93f7..e0df9c3b89 100644 --- a/include/overworld.h +++ b/include/overworld.h @@ -143,7 +143,7 @@ bool32 IsOverworldLinkActive(void); void CB1_Overworld(void); void CB2_OverworldBasic(void); void UpdateTimeOfDay(void); -bool32 MapHasNaturalLight(u8 mapType); +bool32 MapHasNaturalLight(enum MapType mapType); bool32 CurrentMapHasShadows(void); void UpdateAltBgPalettes(u16 palettes); void UpdatePalettesWithTime(u32); diff --git a/include/party_menu.h b/include/party_menu.h index 38ba5202b5..acae4e0c0b 100644 --- a/include/party_menu.h +++ b/include/party_menu.h @@ -96,6 +96,7 @@ u8 GetPartyIdFromBattlePartyId(u8 battlePartyId); void ShowPartyMenuToShowcaseMultiBattleParty(void); void ChooseMonForDaycare(void); bool8 CB2_FadeFromPartyMenu(void); +void CB2_ReturnToPartyMenuFromSummaryScreen(void); void ChooseContestMon(void); void ChoosePartyMon(void); void ChooseMonForMoveRelearner(void); diff --git a/include/pokemon.h b/include/pokemon.h index bee162b4f7..99e510634a 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -11,6 +11,10 @@ #include "constants/map_groups.h" #include "constants/regions.h" #include "constants/region_map_sections.h" +#include "constants/map_groups.h" +#include "constants/battle.h" +#include "constants/abilities.h" +#include "contest_effect.h" #include "constants/trainers.h" #define GET_BASE_SPECIES_ID(speciesId) (GetFormSpeciesId(speciesId, 0)) @@ -127,7 +131,7 @@ enum MonData { struct PokemonSubstruct0 { u16 species:11; // 2047 species. - u16 teraType:5; // 30 types. + enum Type teraType:5; // 30 types. u16 heldItem:10; // 1023 items. u16 unused_02:6; u32 experience:21; @@ -368,8 +372,8 @@ struct BattlePokemon /*0x17*/ u32 spDefenseIV:5; /*0x17*/ u32 abilityNum:2; /*0x18*/ s8 statStages[NUM_BATTLE_STATS]; - /*0x20*/ u16 ability; - /*0x22*/ u8 types[3]; + /*0x20*/ enum Ability ability; + /*0x22*/ enum Type types[3]; /*0x25*/ u8 pp[MAX_MON_MOVES]; /*0x29*/ u16 hp; /*0x2B*/ u8 level; @@ -412,7 +416,7 @@ struct SpeciesInfo /*0xC4*/ u8 baseSpeed; u8 baseSpAttack; u8 baseSpDefense; - u8 types[2]; + enum Type types[2]; u8 catchRate; u8 forceTeraType; u16 expYield; // expYield was changed from u8 to u16 for the new Exp System. @@ -430,7 +434,7 @@ struct SpeciesInfo /*0xC4*/ u8 friendship; u8 growthRate; u8 eggGroups[2]; - u16 abilities[NUM_ABILITY_SLOTS]; // 3 abilities, no longer u8 because we have over 255 abilities now. + enum Ability abilities[NUM_ABILITY_SLOTS]; // 3 abilities, no longer u8 because we have over 255 abilities now. u8 safariZoneFleeRate; // Pokédex data @@ -534,7 +538,7 @@ struct SpeciesInfo /*0xC4*/ #endif //OW_POKEMON_OBJECT_EVENTS }; -struct Ability +struct AbilityInfo { u8 name[ABILITY_NAME_LENGTH + 1]; const u8 *description; @@ -598,8 +602,8 @@ enum { struct NatureInfo { const u8 *name; - u8 statUp; - u8 statDown; + enum Stat statUp; + enum Stat statDown; u8 backAnim; u8 pokeBlockAnim[2]; u8 battlePalacePercents[4]; @@ -695,7 +699,7 @@ extern const u8 gStatStageRatios[MAX_STAT_STAGE + 1][2]; extern const u16 gUnionRoomFacilityClasses[]; extern const struct SpriteTemplate gBattlerSpriteTemplates[]; extern const u32 sExpCandyExperienceTable[]; -extern const struct Ability gAbilitiesInfo[]; +extern const struct AbilityInfo gAbilitiesInfo[]; extern const struct NatureInfo gNaturesInfo[]; #if P_TUTOR_MOVES_ARRAY extern const u16 gTutorMoves[]; @@ -770,8 +774,8 @@ u8 CalculateEnemyPartyCount(void); u8 CalculateEnemyPartyCountInSide(u32 battler); u8 GetMonsStateToDoubles(void); u8 GetMonsStateToDoubles_2(void); -u16 GetAbilityBySpecies(u16 species, u8 abilityNum); -u16 GetMonAbility(struct Pokemon *mon); +enum Ability GetAbilityBySpecies(u16 species, u8 abilityNum); +enum Ability GetMonAbility(struct Pokemon *mon); void CreateSecretBaseEnemyParty(struct SecretBase *secretBaseRecord); u8 GetSecretBaseTrainerPicIndex(void); enum TrainerClassID GetSecretBaseTrainerClass(void); @@ -782,8 +786,8 @@ const u8 *GetSpeciesCategory(u16 species); const u8 *GetSpeciesPokedexDescription(u16 species); u32 GetSpeciesHeight(u16 species); u32 GetSpeciesWeight(u16 species); -u32 GetSpeciesType(u16 species, u8 slot); -u32 GetSpeciesAbility(u16 species, u8 slot); +enum Type GetSpeciesType(u16 species, u8 slot); +enum Ability GetSpeciesAbility(u16 species, u8 slot); u32 GetSpeciesBaseHP(u16 species); u32 GetSpeciesBaseAttack(u16 species); u32 GetSpeciesBaseDefense(u16 species); @@ -824,9 +828,9 @@ u8 GetPlayerFlankId(void); u16 GetLinkTrainerFlankId(u8 linkPlayerId); s32 GetBattlerMultiplayerId(u16 id); u8 GetTrainerEncounterMusicId(u16 trainerOpponentId); -u16 ModifyStatByNature(u8 nature, u16 stat, u8 statIndex); +u16 ModifyStatByNature(u8 nature, u16 stat, enum Stat statIndex); void AdjustFriendship(struct Pokemon *mon, u8 event); -u8 CalculateFriendshipBonuses(struct Pokemon *mon, u32 modifier, enum ItemHoldEffect itemHoldEffect); +u8 CalculateFriendshipBonuses(struct Pokemon *mon, u32 modifier, enum HoldEffect itemHoldEffect); void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies); u16 GetMonEVCount(struct Pokemon *mon); void RandomlyGivePartyPokerus(struct Pokemon *party); @@ -836,9 +840,15 @@ void UpdatePartyPokerusTime(u16 days); void PartySpreadPokerus(struct Pokemon *party); bool8 TryIncrementMonLevel(struct Pokemon *mon); u8 CanLearnTeachableMove(u16 species, u16 move); -u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves); +u8 GetRelearnerLevelUpMoves(struct Pokemon *mon, u16 *moves); +u8 GetRelearnerEggMoves(struct Pokemon *mon, u16 *moves); +u8 GetRelearnerTMMoves(struct Pokemon *mon, u16 *moves); +u8 GetRelearnerTutorMoves(struct Pokemon *mon, u16 *moves); +u8 GetNumberOfLevelUpMoves(struct Pokemon *mon); +u8 GetNumberOfEggMoves(struct Pokemon *mon); +u8 GetNumberOfTMMoves(struct Pokemon *mon); +u8 GetNumberOfTutorMoves(struct Pokemon *mon); u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves); -u8 GetNumberOfRelearnableMoves(struct Pokemon *mon); u16 SpeciesToPokedexNum(u16 species); bool32 IsSpeciesInHoennDex(u16 species); u16 GetBattleBGM(void); @@ -884,7 +894,7 @@ u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove); void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); void TrySpecialOverworldEvo(void); bool32 SpeciesHasGenderDifferences(u16 species); -bool32 TryFormChange(u32 monId, u32 side, enum FormChanges method); +bool32 TryFormChange(u32 monId, enum BattleSide side, enum FormChanges method); void TryToSetBattleFormChangeMoves(struct Pokemon *mon, enum FormChanges method); u32 GetMonFriendshipScore(struct Pokemon *pokemon); u32 GetMonAffectionHearts(struct Pokemon *pokemon); @@ -898,15 +908,15 @@ void HealPokemon(struct Pokemon *mon); void HealBoxPokemon(struct BoxPokemon *boxMon); void UpdateDaysPassedSinceFormChange(u16 days); void TrySetDayLimitToFormChange(struct Pokemon *mon); -u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state); +enum Type CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state); uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier); u32 GetRegionalFormByRegion(u32 species, u32 region); bool32 IsSpeciesForeignRegionalForm(u32 species, u32 currentRegion); -u32 GetTeraTypeFromPersonality(struct Pokemon *mon); +enum Type GetTeraTypeFromPersonality(struct Pokemon *mon); bool8 ShouldSkipFriendshipChange(void); struct Pokemon *GetSavedPlayerPartyMon(u32 index); u8 *GetSavedPlayerPartyCount(void); void SavePlayerPartyMon(u32 index, struct Pokemon *mon); -u32 IsSpeciesOfType(u32 species, u32 type); +bool32 IsSpeciesOfType(u32 species, enum Type type); #endif // GUARD_POKEMON_H diff --git a/include/pokemon_summary_screen.h b/include/pokemon_summary_screen.h index 3aa8460a17..db4c0e89ad 100755 --- a/include/pokemon_summary_screen.h +++ b/include/pokemon_summary_screen.h @@ -3,6 +3,7 @@ #include "main.h" #include "config/summary_screen.h" +#include "constants/move_relearner.h" extern u8 gLastViewedMonIndex; @@ -13,11 +14,12 @@ extern const struct SpritePalette gSpritePal_CategoryIcons; extern const struct SpriteTemplate gSpriteTemplate_CategoryIcons; extern MainCallback gInitialSummaryScreenCallback; -void ShowPokemonSummaryScreen(u8 mode, void *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void)); -void ShowSelectMovePokemonSummaryScreen(struct Pokemon *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void), u16 newMove); -void ShowPokemonSummaryScreenHandleDeoxys(u8 mode, struct BoxPokemon *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void)); -u8 GetMoveSlotToReplace(void); -void SummaryScreen_SetAnimDelayTaskId(u8 taskId); +enum IncrDecrUpdateValues +{ + TRY_SET_UPDATE, + TRY_INCREMENT, + TRY_DECREMENT, +}; // The Pokémon Summary Screen can operate in different modes. Certain features, // such as move re-ordering, are available in the different modes. @@ -48,4 +50,14 @@ enum PokemonSummarySkillsMode SUMMARY_SKILLS_MODE_EVS, }; +void ShowPokemonSummaryScreen(u8 mode, void *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void)); +void ShowSelectMovePokemonSummaryScreen(struct Pokemon *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void), u16 newMove); +void ShowPokemonSummaryScreenHandleDeoxys(u8 mode, struct BoxPokemon *mons, u8 monIndex, u8 maxMonIndex, void (*callback)(void)); +u8 GetMoveSlotToReplace(void); +void SummaryScreen_SetAnimDelayTaskId(u8 taskId); +void ShowRelearnPrompt(void); +void TryUpdateRelearnType(enum IncrDecrUpdateValues delta); +u32 GetCurrentRelearnMovesCount(void); +u32 GetRelearnMovesCount(enum MoveRelearnerStates state); + #endif // GUARD_POKEMON_SUMMARY_SCREEN_H diff --git a/include/random.h b/include/random.h index 816cf9b40a..84318bedc0 100644 --- a/include/random.h +++ b/include/random.h @@ -218,6 +218,10 @@ enum RandomTag RNG_BALLTHROW_CRITICAL, RNG_BALLTHROW_SHAKE, RNG_PROTECT_FAIL, + RNG_PRESENT, + RNG_MAGNITUDE, + RNG_FISHING_BITE, + RNG_FISHING_GEN3_STICKY, }; #define RandomWeighted(tag, ...) \ @@ -267,4 +271,13 @@ const void *RandomElementArrayDefault(enum RandomTag, const void *array, size_t u8 RandomWeightedIndex(u8 *weights, u8 length); +#if TESTING +u32 RandomUniformTrials(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller); +u32 RandomUniformDefaultValue(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller); +u32 RandomWeightedArrayTrials(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller); +u32 RandomWeightedArrayDefaultValue(enum RandomTag tag, u32 n, const u8 *weights, void *caller); +const void *RandomElementArrayTrials(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller); +const void *RandomElementArrayDefaultValue(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller); +#endif + #endif // GUARD_RANDOM_H diff --git a/include/recorded_battle.h b/include/recorded_battle.h index faf966109f..787cf4606c 100644 --- a/include/recorded_battle.h +++ b/include/recorded_battle.h @@ -27,7 +27,7 @@ struct RecordedBattleSave u8 frontierBrainSymbol; u8 battleScene:1; u8 textSpeed:3; - u64 AI_scripts; + u64 AI_scripts[MAX_BATTLERS_COUNT]; u8 recordMixFriendName[PLAYER_NAME_LENGTH + 1]; u8 recordMixFriendClass; u8 apprenticeId; @@ -81,7 +81,7 @@ u8 GetBattleSceneInRecordedBattle(void); u8 GetTextSpeedInRecordedBattle(void); void RecordedBattle_CopyBattlerMoves(u32 battler); void RecordedBattle_CheckMovesetChanges(u8 mode); -u64 GetAiScriptsInRecordedBattle(void); +u64 GetAiScriptsInRecordedBattle(u32 battler); void RecordedBattle_SetPlaybackFinished(void); bool8 RecordedBattle_CanStopPlayback(void); void GetRecordedBattleRecordMixFriendName(u8 *dst); diff --git a/include/rtc.h b/include/rtc.h index 8ee3071615..d0bb6a43de 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -43,6 +43,7 @@ u16 GetFullYear(void); enum Month GetMonth(void); u8 GetDay(void); enum Weekday GetDayOfWeek(void); +enum TimeOfDay GenConfigTimeOfDay(enum TimeOfDay timeOfDay); enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay); enum TimeOfDay TryDecrementTimeOfDay(enum TimeOfDay timeOfDay); diff --git a/include/strings.h b/include/strings.h index ec0072f062..a9264b69fd 100644 --- a/include/strings.h +++ b/include/strings.h @@ -246,31 +246,6 @@ extern const u8 gText_SavingTime[]; extern const u8 gText_BattlePyramidConfirmRest[]; extern const u8 gText_BattlePyramidConfirmRetire[]; -// option menu texts -extern const u8 gText_TextSpeedSlow[]; -extern const u8 gText_TextSpeedMid[]; -extern const u8 gText_TextSpeedFast[]; -extern const u8 gText_BattleSceneOn[]; -extern const u8 gText_BattleSceneOff[]; -extern const u8 gText_BattleStyleShift[]; -extern const u8 gText_BattleStyleSet[]; -extern const u8 gText_SoundMono[]; -extern const u8 gText_SoundStereo[]; -extern const u8 gText_FrameTypeNumber[]; -extern const u8 gText_FrameType[]; -extern const u8 gText_ButtonTypeNormal[]; -extern const u8 gText_ButtonTypeLR[]; -extern const u8 gText_ButtonTypeLEqualsA[]; -extern const u8 gText_Option[]; -extern const u8 gText_OptionMenu[]; -extern const u8 gText_TextSpeed[]; -extern const u8 gText_BattleScene[]; -extern const u8 gText_BattleStyle[]; -extern const u8 gText_Sound[]; -extern const u8 gText_Frame[]; -extern const u8 gText_OptionMenuCancel[]; -extern const u8 gText_ButtonMode[]; - extern const u8 gText_MaleSymbol[]; extern const u8 gText_FemaleSymbol[]; @@ -942,6 +917,9 @@ extern const u8 gText_FrontierFacilityClearStreak[]; extern const u8 gText_FrontierFacilityRoomsCleared[]; extern const u8 gText_FrontierFacilityKOsStreak[]; extern const u8 gText_FrontierFacilityFloorsCleared[]; +extern const u8 gText_FrontierFacilityTotalCaughtSpeciesBanned[]; +extern const u8 gText_FrontierFacilityIncluding[]; +extern const u8 gText_FrontierFacilityAreInelegible[]; // Battle Tower. extern const u8 BattleFrontier_BattleTowerMultiPartnerRoom_Text_Apprentice1Intro[]; @@ -2421,8 +2399,17 @@ extern const u8 gText_PlayerRegroupCenter[]; extern const u8 gText_PlayerRegroupHome[]; extern const u8 gText_Relearn[]; // move relearner from summary screen +extern const u8 gText_Relearn_LevelUp[]; +extern const u8 gText_Relearn_Egg[]; +extern const u8 gText_Relearn_TM[]; +extern const u8 gText_Relearn_Tutor[]; extern const u8 gText_Rename[]; // change nickname from summary screen +extern const u8 MoveRelearner_Text_LevelUpMoveLWR[]; +extern const u8 MoveRelearner_Text_EggMoveLWR[]; +extern const u8 MoveRelearner_Text_TMMoveLWR[]; +extern const u8 MoveRelearner_Text_TutorMoveLWR[]; + // Switch Caught Mon into Party extern const u8 gText_CannotSendMonToBoxHM[]; extern const u8 gText_CannotSendMonToBoxActive[]; diff --git a/include/test/battle.h b/include/test/battle.h index 9cd1d23b1f..245b15fa0d 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -194,21 +194,22 @@ * ASSUME(GetMoveEffect(MOVE_POISON_STING) == EFFECT_POISON_HIT); * } * - * SINGLE_BATTLE_TEST(name, results...) and DOUBLE_BATTLE_TEST(name, results...) - * Define single- and double- battles. The names should start with the - * name of the mechanic being tested so that it is easier to run all the - * related tests. results contains variable declarations to be placed - * into the results array which is available in PARAMETRIZEd tests. - * The main differences for doubles are: + * SINGLE_BATTLE_TEST(name, results...), DOUBLE_BATTLE_TEST(name, results...), MULTI_BATTLE_TEST(name, results...), + * TWO_VS_ONE_BATTLE_TEST(name, results...), and ONE_VS_TWO_BATTLE_TEST(name, results...) + * Define single-, double-, 2v2-multi-, 2v1-multi-, and 1v2- battles. The names should start with + * the name of the mechanic being tested so that it is easier to run all the related tests. results contains variable + * declarations to be placed into the `results` array which is available in tests using `PARAMETRIZE` commands. + * The main differences for doubles, 2v2, 2v1, and 1v2 are: * - Move targets sometimes need to be explicit. * - Instead of player and opponent there is playerLeft, playerRight, * opponentLeft, and opponentRight. * - * AI_SINGLE_BATTLE_TEST(name, results...) and AI_DOUBLE_BATTLE_TEST(name, results...) + * AI_SINGLE_BATTLE_TEST(name, results...), AI_DOUBLE_BATTLE_TEST(name, results...), + * AI_MULTI_BATTLE_TEST(name, results...), AI_TWO_VS_ONE_BATTLE_TEST(name, results...), and AI_ONE_VS_TWO_BATTLE_TEST(name, results...) * Define battles where opponent mons are controlled by AI, the same that runs * when battling regular Trainers. The flags for AI should be specified by * the AI_FLAGS command. - * The rules remain the same as with the SINGLE and DOUBLE battle tests + * The rules remain the same as with the SINGLE, DOUBLE, MULTI, TWO_VS_ONE, and ONE_VS_TWO battle tests with some differences: * with some differences: * - opponent's action is specified by the EXPECT_MOVE(s) / EXPECT_SEND_OUT / EXPECT_SWITCH commands * - we don't control what opponent actually does, instead we make sure the opponent does what we expect it to do @@ -333,11 +334,40 @@ * Note if Moves is specified then MOVE will not automatically add moves * to the moveset. * + * For tests using MULTI_BATTLE_TEST, AI_MULTI_BATTLE_TEST, TWO_VS_ONE_BATTLE_TEST, + * AI_TWO_VS_ONE_BATTLE_TEST, ONE_VS_TWO_BATTLE_TEST, and AI_ONE_VS_TWO_BATTLE_TEST, + * the below must be used instead of PLAYER(species) and OPPONENT(species). + * MULTI_PLAYER(species), MULTI_PARTNER(species), MULTI_OPPONENT_A(species), and + * MULTI_OPPONENT_B(species) Adds the species to the player's, player partner's, + * opponent A's, or opponent B's party, respectively. + * Pokemon can be customised as per the guidance for PLAYER(species) and OPPONENT(species). + * The functions assign the Pokémon to the party of the trainer at B_POSITION_PLAYER_LEFT, + * B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_LEFT, and B_POSITION_OPPONENT_RIGHT, respectively. + * MULTI_PLAYER(species) and MULTI_OPPONENT_A(species) set Pokémon starting at party index 0, + * while MULTI_PARTNER(species) and MULTI_OPPONENT_B(species) set Pokémon starting at party + * index 3. + * For ONE_VS_TWO tests, MULTI_PLAYER(species) must be used for all player-side Pokémon, + * and for TWO_VS_ONE tests, MULTI_OPPONENT_A(species) must be used for all opponent-side + * Pokémon. + * All MULTI_PLAYER(species) Pokémon must be set before any MULTI_PARTNER(species) Pokémon, + * and all MULTI_OPPONENT_A(species) must be set before any MULTI_OPPONENT_B(species) Pokémon, + * else Pokémon will be set in the incorrect parties in the test. + * Note where a side in a test has two trainers, the test setup manages the assigning of correct + * multi-party orders, therefore when using functions such as SEND_OUT, Player and Opponent A + * Pokémon may be referenced using indexes 0, 1, and 2, and Player's Partner and Opponent B + * Pokémon may be referenced using indexes 3, 4, and 5. + * * AI_FLAGS - * Specifies which AI flags are run during the test. Has use only for AI tests. + * Specifies which AI flags are run for all battlers during the test. Has use only for AI tests. * The most common combination is AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT) * which is the general 'smart' AI. * + * BATTLER_AI_FLAGS + * Specifies additional AI flags to be applied to specific battlers (battler 0/1/2/3). Has use only for AI tests. + * Must be used strictly after AI_FLAGS(flags), which overwrites all existing flags. + * Example: BATTLER_AI_FLAGS(3, AI_FLAG_RISKY) used after AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT) + * will set AI_FLAG_RISKY to only battler3 (Opponent B), in addition to the flags set by AI_FLAGS. + * * WHEN * Contains the choices that battlers make during the battle. * @@ -537,10 +567,25 @@ #define MAX_QUEUED_EVENTS 30 #define MAX_EXPECTED_ACTIONS 10 -enum { BATTLE_TEST_SINGLES, BATTLE_TEST_DOUBLES, BATTLE_TEST_WILD, BATTLE_TEST_AI_SINGLES, BATTLE_TEST_AI_DOUBLES }; +enum { + BATTLE_TEST_SINGLES, + BATTLE_TEST_DOUBLES, + BATTLE_TEST_WILD, + BATTLE_TEST_MULTI, + BATTLE_TEST_TWO_VS_ONE, + BATTLE_TEST_ONE_VS_TWO, + BATTLE_TEST_AI_SINGLES, + BATTLE_TEST_AI_DOUBLES, + BATTLE_TEST_AI_MULTI, + BATTLE_TEST_AI_TWO_VS_ONE, + BATTLE_TEST_AI_ONE_VS_TWO +}; typedef void (*SingleBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *); typedef void (*DoubleBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); +typedef void (*MultiBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); +typedef void (*TwoVsOneBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); +typedef void (*OneVsTwoBattleTestFunction)(void *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); struct BattleTest { @@ -549,6 +594,9 @@ struct BattleTest { SingleBattleTestFunction singles; DoubleBattleTestFunction doubles; + MultiBattleTestFunction multi; + TwoVsOneBattleTestFunction two_vs_one; + OneVsTwoBattleTestFunction one_vs_two; } function; size_t resultsSize; }; @@ -566,7 +614,7 @@ enum struct QueuedAbilityEvent { u8 battlerId; - u16 ability; + enum Ability ability; }; struct QueuedAnimationEvent @@ -622,23 +670,18 @@ struct QueuedEvent } as; }; -struct TurnRNG -{ - u16 tag; - u16 value; -}; - struct BattlerTurn { u8 hit:2; u8 criticalHit:2; u8 secondaryEffect:2; - struct TurnRNG rng; + struct RiggedRNG rng; }; struct ExpectedAIAction { - u16 sourceLine; + u16 sourceLine:13; // TODO: Avoid stealing these bits. + enum Gimmick gimmick:3; u8 type:4; // which action u8 moveSlots:4; // Expected move(s) to be chosen or not, marked as bits. u8 target:4; // move target or id of mon which gets sent out @@ -687,17 +730,19 @@ struct BattleTestData u8 playerPartySize; u8 opponentPartySize; - u8 explicitMoves[NUM_BATTLE_SIDES]; + u8 explicitMoves[MAX_BATTLERS_COUNT]; bool8 hasExplicitSpeeds; - u8 explicitSpeeds[NUM_BATTLE_SIDES]; + u8 explicitSpeeds[MAX_BATTLERS_COUNT]; u16 slowerThan[NUM_BATTLE_SIDES][PARTY_SIZE]; - u8 currentSide; + u8 currentPosition; u8 currentPartyIndex; struct Pokemon *currentMon; u8 gender; u8 nature; - u16 forcedAbilities[NUM_BATTLE_SIDES][PARTY_SIZE]; + bool8 isShiny; + enum Ability forcedAbilities[NUM_BATTLE_SIDES][PARTY_SIZE]; u8 chosenGimmick[NUM_BATTLE_SIDES][PARTY_SIZE]; + u8 forcedEnvironment; u8 currentMonIndexes[MAX_BATTLERS_COUNT]; u8 turnState; @@ -765,6 +810,8 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState; #define R_APPEND_TRUE(...) __VA_OPT__(FIRST(__VA_ARGS__), TRUE RECURSIVELY(R_FOR_EACH(APPEND_COMMA_TRUE, EXCEPT_1(__VA_ARGS__)))) #define AI_TRAINER_NAME "{PKMN} TRAINER LEAF" +#define AI_TRAINER_2_NAME "{PKMN} TRAINER RED" +#define AI_PARTNER_NAME "{PKMN} TRAINER 1" /* Test */ @@ -810,6 +857,60 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState; }; \ static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + #define BATTLE_TEST_ARGS_MULTI(_name, _type, ...) \ + struct CAT(Result, __LINE__) { RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \ + __attribute__((section(".tests"), used)) static const struct Test CAT(sTest, __LINE__) = \ + { \ + .name = _name, \ + .filename = __FILE__, \ + .runner = &gBattleTestRunner, \ + .sourceLine = __LINE__, \ + .data = (void *)&(const struct BattleTest) \ + { \ + .type = _type, \ + .function = { .multi = (MultiBattleTestFunction)CAT(Test, __LINE__) }, \ + .resultsSize = sizeof(struct CAT(Result, __LINE__)), \ + }, \ + }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + +#define BATTLE_TEST_ARGS_TWO_VS_ONE(_name, _type, ...) \ + struct CAT(Result, __LINE__) { RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \ + __attribute__((section(".tests"), used)) static const struct Test CAT(sTest, __LINE__) = \ + { \ + .name = _name, \ + .filename = __FILE__, \ + .runner = &gBattleTestRunner, \ + .sourceLine = __LINE__, \ + .data = (void *)&(const struct BattleTest) \ + { \ + .type = _type, \ + .function = { .two_vs_one = (TwoVsOneBattleTestFunction)CAT(Test, __LINE__) }, \ + .resultsSize = sizeof(struct CAT(Result, __LINE__)), \ + }, \ + }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + +#define BATTLE_TEST_ARGS_ONE_VS_TWO(_name, _type, ...) \ + struct CAT(Result, __LINE__) { RECURSIVELY(R_FOR_EACH(APPEND_SEMICOLON, __VA_ARGS__)) }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *, const u32, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *, struct BattlePokemon *); \ + __attribute__((section(".tests"), used)) static const struct Test CAT(sTest, __LINE__) = \ + { \ + .name = _name, \ + .filename = __FILE__, \ + .runner = &gBattleTestRunner, \ + .sourceLine = __LINE__, \ + .data = (void *)&(const struct BattleTest) \ + { \ + .type = _type, \ + .function = { .one_vs_two = (OneVsTwoBattleTestFunction)CAT(Test, __LINE__) }, \ + .resultsSize = sizeof(struct CAT(Result, __LINE__)), \ + }, \ + }; \ + static void CAT(Test, __LINE__)(struct CAT(Result, __LINE__) *results, const u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight) + #define SINGLE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_SINGLE(_name, BATTLE_TEST_SINGLES, __VA_ARGS__) #define WILD_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_SINGLE(_name, BATTLE_TEST_WILD, __VA_ARGS__) @@ -818,6 +919,15 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState; #define DOUBLE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_DOUBLE(_name, BATTLE_TEST_DOUBLES, __VA_ARGS__) #define AI_DOUBLE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_DOUBLE(_name, BATTLE_TEST_AI_DOUBLES, __VA_ARGS__) +#define MULTI_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_MULTI(_name, BATTLE_TEST_MULTI, __VA_ARGS__) +#define AI_MULTI_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_MULTI(_name, BATTLE_TEST_AI_MULTI, __VA_ARGS__) + +#define TWO_VS_ONE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_TWO_VS_ONE(_name, BATTLE_TEST_TWO_VS_ONE, __VA_ARGS__) +#define AI_TWO_VS_ONE_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_TWO_VS_ONE(_name, BATTLE_TEST_AI_TWO_VS_ONE, __VA_ARGS__) + +#define ONE_VS_TWO_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_ONE_VS_TWO(_name, BATTLE_TEST_ONE_VS_TWO, __VA_ARGS__) +#define AI_ONE_VS_TWO_BATTLE_TEST(_name, ...) BATTLE_TEST_ARGS_ONE_VS_TWO(_name, BATTLE_TEST_AI_ONE_VS_TWO, __VA_ARGS__) + /* Parametrize */ #undef PARAMETRIZE // Override test/test.h's implementation. @@ -846,13 +956,18 @@ struct moveWithPP { #define RNGSeed(seed) RNGSeed_(__LINE__, seed) #define AI_FLAGS(flags) AIFlags_(__LINE__, flags) +#define BATTLER_AI_FLAGS(battler, flags) BattlerAIFlags_(__LINE__, battler, flags) #define AI_LOG AILogScores(__LINE__) #define FLAG_SET(flagId) SetFlagForTest(__LINE__, flagId) #define WITH_CONFIG(configTag, value) TestSetConfig(__LINE__, configTag, value) -#define PLAYER(species) for (OpenPokemon(__LINE__, B_SIDE_PLAYER, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) -#define OPPONENT(species) for (OpenPokemon(__LINE__, B_SIDE_OPPONENT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define PLAYER(species) for (OpenPokemon(__LINE__, B_POSITION_PLAYER_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define OPPONENT(species) for (OpenPokemon(__LINE__, B_POSITION_OPPONENT_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_PLAYER(species) for (OpenPokemonMulti(__LINE__, B_POSITION_PLAYER_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_OPPONENT_A(species) for (OpenPokemonMulti(__LINE__, B_POSITION_OPPONENT_LEFT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_PARTNER(species) for (OpenPokemonMulti(__LINE__, B_POSITION_PLAYER_RIGHT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) +#define MULTI_OPPONENT_B(species) for (OpenPokemonMulti(__LINE__, B_POSITION_OPPONENT_RIGHT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__)) #define Gender(gender) Gender_(__LINE__, gender) #define Nature(nature) Nature_(__LINE__, nature) @@ -880,20 +995,24 @@ struct moveWithPP { #define DynamaxLevel(dynamaxLevel) DynamaxLevel_(__LINE__, dynamaxLevel) #define GigantamaxFactor(gigantamaxFactor) GigantamaxFactor_(__LINE__, gigantamaxFactor) #define TeraType(teraType) TeraType_(__LINE__, teraType) -#define Shadow(isShadow) Shadow_(__LINE__, shadow) +#define Shadow(isShadow) Shadow_(__LINE__, isShadow) +#define Shiny(isShiny) Shiny_(__LINE__, isShiny) +#define Environment(environment) Environment_(__LINE__, environment) void SetFlagForTest(u32 sourceLine, u16 flagId); void TestSetConfig(u32 sourceLine, enum GenConfigTag configTag, u32 value); void ClearFlagAfterTest(void); -void OpenPokemon(u32 sourceLine, u32 side, u32 species); +void OpenPokemon(u32 sourceLine, enum BattlerPosition position, u32 species); +void OpenPokemonMulti(u32 sourceLine, enum BattlerPosition position, u32 species); void ClosePokemon(u32 sourceLine); void RNGSeed_(u32 sourceLine, rng_value_t seed); void AIFlags_(u32 sourceLine, u64 flags); +void BattlerAIFlags_(u32 sourceLine, u32 battler, u64 flags); void AILogScores(u32 sourceLine); void Gender_(u32 sourceLine, u32 gender); void Nature_(u32 sourceLine, u32 nature); -void Ability_(u32 sourceLine, u32 ability); +void Ability_(u32 sourceLine, enum Ability ability); void Level_(u32 sourceLine, u32 level); void MaxHP_(u32 sourceLine, u32 maxHP); void HP_(u32 sourceLine, u32 hp); @@ -916,8 +1035,26 @@ void Status1_(u32 sourceLine, u32 status1); void OTName_(u32 sourceLine, const u8 *otName); void DynamaxLevel_(u32 sourceLine, u32 dynamaxLevel); void GigantamaxFactor_(u32 sourceLine, bool32 gigantamaxFactor); -void TeraType_(u32 sourceLine, u32 teraType); +void TeraType_(u32 sourceLine, enum Type teraType); void Shadow_(u32 sourceLine, bool32 isShadow); +void Shiny_(u32 sourceLine, bool32 isShiny); +void Environment_(u32 sourceLine, u32 environment); + +static inline bool8 IsMultibattleTest(void) +{ + if (TESTING) + { + if (((gBattleTypeFlags & BATTLE_MULTI_TEST) == BATTLE_MULTI_TEST) + || ((gBattleTypeFlags & BATTLE_TWO_VS_ONE_TEST) == BATTLE_TWO_VS_ONE_TEST)) + return TRUE; + else + return FALSE; + } + else + { + return FALSE; + } +} // Created for easy use of EXPECT_MOVES, so the user can provide 1, 2, 3 or 4 moves for AI which can pass the test. struct FourMoves @@ -968,7 +1105,7 @@ enum { TURN_CLOSED, TURN_OPEN, TURN_CLOSING }; #define SKIP_TURN(battler) SkipTurn(__LINE__, battler) #define SEND_OUT(battler, partyIndex) SendOut(__LINE__, battler, partyIndex) #define USE_ITEM(battler, ...) UseItem(__LINE__, battler, (struct ItemContext) { R_APPEND_TRUE(__VA_ARGS__) }) -#define WITH_RNG(tag, value) rng: ((struct TurnRNG) { tag, value }) +#define WITH_RNG(tag, value) rng: ((struct RiggedRNG) { tag, value }) struct MoveContext { @@ -993,7 +1130,7 @@ struct MoveContext u16 explicitNotExpected:1; struct BattlePokemon *target; bool8 explicitTarget; - struct TurnRNG rng; + struct RiggedRNG rng; bool8 explicitRNG; }; @@ -1005,7 +1142,7 @@ struct ItemContext u16 explicitPartyIndex:1; u16 move; u16 explicitMove:1; - struct TurnRNG rng; + struct RiggedRNG rng; u16 explicitRNG:1; }; @@ -1066,7 +1203,7 @@ enum QueueGroupType struct AbilityEventContext { - u16 ability; + enum Ability ability; }; struct AnimationEventContext diff --git a/include/test/test.h b/include/test/test.h index 7b3225934d..15f71d50b1 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -2,8 +2,10 @@ #define GUARD_TEST_H #include "test_runner.h" +#include "random.h" #define MAX_PROCESSES 32 // See also tools/mgba-rom-test-hydra/main.c +#define RIGGED_RNG_COUNT 8 enum TestResult { @@ -26,6 +28,9 @@ struct TestRunner void (*tearDown)(void *); bool32 (*checkProgress)(void *); bool32 (*handleExitWithResult)(void *, enum TestResult); + u32 (*randomUniform)(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller); + u32 (*randomWeightedArray)(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller); + const void* (*randomElementArray)(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller); }; struct Test @@ -76,11 +81,18 @@ extern const char gTestRunnerArgv[256]; extern const struct TestRunner gAssumptionsRunner; +struct RiggedRNG +{ + u16 tag; + u16 value; +}; + struct FunctionTestRunnerState { u16 parameters; u16 runParameter; u16 checkProgressParameter; + struct RiggedRNG rngList[RIGGED_RNG_COUNT]; }; extern const struct TestRunner gFunctionTestRunner; @@ -97,6 +109,8 @@ void Test_ExpectCrash(bool32); void Test_ExitWithResult(enum TestResult, u32 stopLine, const char *fmt, ...); u32 SourceLine(u32 sourceLineOffset); u32 SourceLineOffset(u32 sourceLine); +void SetupRiggedRng(u32 sourceLine, enum RandomTag randomTag, u32 value); +void ClearRiggedRng(); s32 Test_MgbaPrintf(const char *fmt, ...); @@ -245,6 +259,8 @@ static inline struct Benchmark BenchmarkStop(void) #define PARAMETRIZE_LABEL(f, label) if (gFunctionTestRunnerState->parameters++ == gFunctionTestRunnerState->runParameter && (Test_MgbaPrintf(":N%s: " f " (%d/%d)", gTestRunnerState.test->name, label, gFunctionTestRunnerState->runParameter + 1, gFunctionTestRunnerState->parameters), 1)) +#define SET_RNG(tag, value) SetupRiggedRng(__LINE__, tag, value) + #define TO_DO \ do { \ Test_ExpectedResult(TEST_RESULT_TODO); \ diff --git a/include/test/test_runner_battle.h b/include/test/test_runner_battle.h new file mode 100644 index 0000000000..8a2c0dc64b --- /dev/null +++ b/include/test/test_runner_battle.h @@ -0,0 +1,6 @@ +#ifndef GUARD_BATTLE_TEST_RUNNER_H +#define GUARD_BATTLE_TEST_RUNNER_H + +bool8 IsMultibattleTest(void); + +#endif diff --git a/include/test_runner.h b/include/test_runner.h index b7aa69a076..b1d90889fb 100644 --- a/include/test_runner.h +++ b/include/test_runner.h @@ -11,14 +11,16 @@ extern const bool8 gTestRunnerSkipIsFail; #if TESTING -void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability); +enum Gimmick; + +void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, enum Ability ability); void TestRunner_Battle_RecordAnimation(u32 animType, u32 animId); void TestRunner_Battle_RecordHP(u32 battlerId, u32 oldHP, u32 newHP); void TestRunner_Battle_RecordExp(u32 battlerId, u32 oldExp, u32 newExp); void TestRunner_Battle_RecordMessage(const u8 *message); void TestRunner_Battle_RecordStatus1(u32 battlerId, u32 status1); void TestRunner_Battle_AfterLastTurn(void); -void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target); +void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target, enum Gimmick gimmick); void TestRunner_Battle_CheckSwitch(u32 battlerId, u32 partyIndex); void TestRunner_Battle_CheckAiMoveScores(u32 battlerId); void TestRunner_Battle_AISetScore(const char *file, u32 line, u32 battlerId, u32 moveIndex, s32 score); @@ -30,6 +32,7 @@ void TestRunner_Battle_CheckBattleRecordActionType(u32 battlerId, u32 recordInde u32 TestRunner_Battle_GetForcedAbility(u32 side, u32 partyIndex); u32 TestRunner_Battle_GetChosenGimmick(u32 side, u32 partyIndex); +u32 TestRunner_Battle_GetForcedEnvironment(void); #else @@ -53,6 +56,8 @@ u32 TestRunner_Battle_GetChosenGimmick(u32 side, u32 partyIndex); #define TestRunner_Battle_GetChosenGimmick(...) (u32)0 +#define TestRunner_Battle_GetForcedEnvironment(...) (u8)0 + #endif #endif diff --git a/include/text.h b/include/text.h index 040fe49f13..294bff94c7 100644 --- a/include/text.h +++ b/include/text.h @@ -1,8 +1,15 @@ #ifndef GUARD_TEXT_H #define GUARD_TEXT_H +#include "config/text.h" #include "constants/characters.h" +// This is to prevent the user from having a higher text speed modifier than the printing system can handle. +STATIC_ASSERT( TEXT_SPEED_SLOW_MODIFIER <= 31 + && TEXT_SPEED_MEDIUM_MODIFIER <= 31 + && TEXT_SPEED_FAST_MODIFIER <= 31 + && TEXT_SPEED_INSTANT_MODIFIER <= 31, TextSpeedModifiersCantGoPast31) + // Given as a text speed when all the text should be // loaded at once but not copied to vram yet. #define TEXT_SKIP_DRAW 0xFF @@ -59,9 +66,9 @@ struct TextPrinterSubStruct u8 fontId:4; // 0x14 bool8 hasPrintBeenSpedUp:1; u8 unk:3; - u8 downArrowDelay:5; - u8 downArrowYPosIdx:2; - bool8 hasFontIdBeenSet:1; + u16 utilityCounter:13; + u16 downArrowYPosIdx:2; + bool16 hasFontIdBeenSet:1; u8 autoScrollDelay; }; @@ -135,7 +142,6 @@ struct TextGlyph }; extern TextFlags gTextFlags; - extern u8 gDisableTextPrinters; extern struct TextGlyph gCurGlyph; @@ -178,4 +184,11 @@ u32 GetFontIdToFit(const u8 *string, u32 widestFontId, u32 letterSpacing, u32 wi u8 *PrependFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width); u8 *WrapFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width); +// player text speed +u32 GetPlayerTextSpeed(void); +u32 GetPlayerTextSpeedDelay(void); +u32 GetPlayerTextSpeedModifier(void); +u32 GetPlayerTextScrollSpeed(void); +bool32 IsPlayerTextSpeedInstant(void); + #endif // GUARD_TEXT_H diff --git a/include/trade.h b/include/trade.h index 24de69b036..553d5ab334 100644 --- a/include/trade.h +++ b/include/trade.h @@ -14,7 +14,7 @@ s32 GetGameProgressForLinkTrade(void); void CB2_StartCreateTradeMenu(void); void CB2_LinkTrade(void); int CanRegisterMonForTradingBoard(struct RfuGameCompatibilityData player, u16 species2, u16 species, bool8 isModernFatefulEncounter); -int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData player, struct RfuGameCompatibilityData partner, u16 playerSpecies2, u16 partnerSpecies, u8 requestedType, u16 playerSpecies, bool8 isModernFatefulEncounter); +int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData player, struct RfuGameCompatibilityData partner, u16 playerSpecies2, u16 partnerSpecies, enum Type requestedType, u16 playerSpecies, bool8 isModernFatefulEncounter); int CanSpinTradeMon(struct Pokemon *mon, u16 monIdx); void InitTradeSequenceBgGpuRegs(void); void LinkTradeDrawWindow(void); diff --git a/include/trainer_pools.h b/include/trainer_pools.h index 196657a55f..72df3e765c 100644 --- a/include/trainer_pools.h +++ b/include/trainer_pools.h @@ -56,10 +56,12 @@ enum PoolTags { struct PoolRules { - bool8 speciesClause; - bool8 excludeForms; - bool8 itemClause; - bool8 itemClauseExclusions; + u8 speciesClause:1; + u8 excludeForms:1; + u8 itemClause:1; + u8 itemClauseExclusions:1; + u8 megaStoneClause:1; + u8 zCrystalClause:1; u8 tagMaxMembers[POOL_NUM_TAGS]; bool8 tagRequired[POOL_NUM_TAGS]; }; diff --git a/include/trainer_slide.h b/include/trainer_slide.h index 19fdf7c24a..a8f1988fb8 100644 --- a/include/trainer_slide.h +++ b/include/trainer_slide.h @@ -12,7 +12,7 @@ struct MessageStatus void SetTrainerSlideMessage(enum DifficultyLevel difficulty, u32 trainerId, u32 slideId); enum TrainerSlideTargets ShouldDoTrainerSlide(u32 battler, enum TrainerSlideType slideId); -void TryInitializeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, u32 moveType); +void TryInitializeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, enum Type moveType); void TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(u32 target); void TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(u32 target); void TryInitializeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32 target); diff --git a/include/union_room.h b/include/union_room.h index 514a159850..5616c106d3 100644 --- a/include/union_room.h +++ b/include/union_room.h @@ -149,7 +149,7 @@ extern u8 gPlayerCurrActivity; extern struct RfuGameCompatibilityData gRfuPartnerCompatibilityData; extern u16 gUnionRoomOfferedSpecies; -extern u8 gUnionRoomRequestedMonType; +extern enum Type gUnionRoomRequestedMonType; u8 CreateTask_CreateTradeMenu(void); void SetUsingUnionRoomStartMenu(void); diff --git a/include/window.h b/include/window.h index 2dd67b123f..fc35f724d9 100644 --- a/include/window.h +++ b/include/window.h @@ -45,7 +45,7 @@ struct WindowTemplate struct Window { struct WindowTemplate window; - u8 *tileData; + ALIGNED(4) u8 *tileData; }; bool32 InitWindows(const struct WindowTemplate *templates); diff --git a/migration_scripts/1.11/consolidate_contest_opponent_filters.py b/migration_scripts/1.11/consolidate_contest_opponent_filters.py index 240152cea2..0f273f7b1d 100644 --- a/migration_scripts/1.11/consolidate_contest_opponent_filters.py +++ b/migration_scripts/1.11/consolidate_contest_opponent_filters.py @@ -30,7 +30,6 @@ def add_filter_data(match): if trainer_name in source_data: contest_filter = source_data[trainer_name] print(f"Updating {trainer_name}: adding {contest_filter}") - #return f'{trainer_name} = {{\n .filter = {contest_filter}' return f'{match.group(0)}\n .filter = {contest_filter}' else: return match.group(0) diff --git a/migration_scripts/1.14/consolidate_contest_effects.py b/migration_scripts/1.14/consolidate_contest_effects.py new file mode 100644 index 0000000000..b517a45d2c --- /dev/null +++ b/migration_scripts/1.14/consolidate_contest_effects.py @@ -0,0 +1,44 @@ +import glob +import re +import os + +if not os.path.exists("Makefile"): + print("Please run this script from your root folder.") + quit() + +# Read contest.c and extract the party information +for file in glob.glob('./src/contest.c'): + with open(file, 'r') as f: + source_content = f.read() + +# Extract party info from contest.c +source_pattern = re.compile(r'(\[CONTEST_EFFECT_.*\])\s*=\s(COMPOUND_STRING.*),') +source_data = {} +for match in source_pattern.findall(source_content): + if len(match) == 2: + contest_effect, effect_description = match + source_data[contest_effect] = (effect_description) + +# Read contest_moves.h content +for file in glob.glob('./src/data/contest_moves.h'): + with open(file, 'r') as f: + destination_content = f.read() + +# Modify contest_moves.h content +def add_description(match): + contest_effect = match.group(1) + if contest_effect in source_data: + effect_description = source_data[contest_effect] + print(f"Updating {contest_effect}: adding {effect_description}") + return f"{match.group(0)}\n .description = {effect_description}," + else: + return match.group(0) + +destination_pattern = re.compile(r'(\[CONTEST_EFFECT_.*\]) =\s*\n\s*{') +modified_content = destination_pattern.sub(add_description, destination_content) + +# Write the modified content back to contest_moves.h +for file in glob.glob('./src/data/contest_moves.h'): + with open(file, 'w') as f: + f.write(modified_content) + print("contest_moves.h has been updated") diff --git a/migration_scripts/add_time_based_encounters.py b/migration_scripts/add_time_based_encounters.py index aebdafc2b2..b036e46e41 100644 --- a/migration_scripts/add_time_based_encounters.py +++ b/migration_scripts/add_time_based_encounters.py @@ -7,7 +7,7 @@ try: print("Please run this script from the project's root folder.") quit() sys.path.append("./tools/wild_encounters/") - from wild_encounters_to_header import TimeOfDay, SetupUserTimeEnum + from wild_encounters_to_header import Config except ImportError: print("Could not import the file tools/wild_encounters/wild_encounters_to_header.py") quit() @@ -24,11 +24,13 @@ def GetWildEncounterFile(): print("Please run this script from the project's root folder.") quit() - timeOfDay = SetupUserTimeEnum(TimeOfDay()) - wFile = open("src/data/wild_encounters.json") wData = json.load(wFile) + config = Config('include/config/overworld.h', 'include/constants/rtc.h', wData) + timeOfDay = config.times_of_day + + wBackupData = json.dumps(wData, indent=2) wBackupFile = open("src/data/wild_encounters.json.bak", mode="w", encoding="utf-8") wBackupFile.write(wBackupData) @@ -49,7 +51,7 @@ def GetWildEncounterFile(): wEncounters_New = list() for map in wEncounters: - for suffix in timeOfDay.fvals: + for suffix in timeOfDay.values(): tempSuffix = "_" + suffix if tempSuffix in map["base_label"]: editMap = False @@ -59,7 +61,7 @@ def GetWildEncounterFile(): if editMap: k = 0 - for suffix in timeOfDay.fvals: + for suffix in timeOfDay.values(): tempDict = dict() if k == TIME_OF_DAY_DEFAULT or COPY_FULL_ENCOUNTER: tempDict = map.copy() diff --git a/spritesheet_rules.mk b/spritesheet_rules.mk index 7c05219f8a..a14fd18813 100644 --- a/spritesheet_rules.mk +++ b/spritesheet_rules.mk @@ -612,6 +612,8 @@ $(OBJEVENTGFXDIR)/berry_trees/rowap.4bpp: %.4bpp: %.png $(OBJEVENTGFXDIR)/berry_trees/micle.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 2 -mheight 4 +$(OBJEVENTGFXDIR)/misc/apricorn_tree.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 2 -mheight 2 $(OBJEVENTGFXDIR)/misc/breakable_rock.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 2 -mheight 2 @@ -694,6 +696,12 @@ $(FLDEFFGFXDIR)/surf_blob.4bpp: %.4bpp: %.png $(FLDEFFGFXDIR)/rock_climb_blob.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 +$(FLDEFFGFXDIR)/oras_dowsing_brendan.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 2 -mheight 4 + +$(FLDEFFGFXDIR)/oras_dowsing_may.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 2 -mheight 4 + $(FLDEFFGFXDIR)/tall_grass.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 2 -mheight 2 diff --git a/src/apricorn_tree.c b/src/apricorn_tree.c new file mode 100644 index 0000000000..b7784a6a85 --- /dev/null +++ b/src/apricorn_tree.c @@ -0,0 +1,86 @@ +#include "global.h" +#include "apricorn_tree.h" +#include "event_data.h" +#include "event_object_movement.h" +#include "event_scripts.h" +#include "item.h" +#include "random.h" +#include "string_util.h" +#include "data/apricorns.h" + +void DailyResetApricornTrees(void) +{ +#if (APRICORN_TREE_COUNT > 0) + memset(&gSaveBlock3Ptr->apricornTrees[0], 0, NUM_APRICORN_TREE_BYTES); +#endif +} + +void ObjectEventInteractionGetApricornTreeData(void) +{ + u32 id = GetObjectEventApricornTreeId(gSelectedObjectEvent); + gSpecialVar_0x8004 = GetApricornTypeByApricornTreeId(id); + gSpecialVar_0x8005 = GetApricornCountByApricornTreeId(id); + + CopyItemNameHandlePlural(gSpecialVar_0x8004, gStringVar1, gSpecialVar_0x8005); +} + +void ObjectEventInteractionPickApricornTree(void) +{ + u32 id = GetObjectEventApricornTreeId(gSelectedObjectEvent); + enum ApricornType apricorn = GetApricornTypeByApricornTreeId(id); + gSpecialVar_0x8006 = CheckBagHasSpace(apricorn, GetApricornCountByApricornTreeId(id)); + + if (gSpecialVar_0x8006) + { + AddBagItem(apricorn, GetApricornCountByApricornTreeId(id)); + SetApricornTreePicked(id); + } + gSpecialVar_Result = GetItemPocket(apricorn); +} + +enum ApricornType GetApricornTypeByApricornTreeId(u32 id) +{ + if (APRICORN_TREE_COUNT > 0) + return gApricornTrees[id].apricornType; + else + return 0; +} + +u8 GetApricornCountByApricornTreeId(u32 id) +{ + if (IsApricornTreePicked(id)) + return 0; + + if (APRICORN_TREE_COUNT > 0) + { + if (gApricornTrees[id].maximum > gApricornTrees[id].minimum) + return gApricornTrees[id].minimum + Random() % (gApricornTrees[id].maximum - gApricornTrees[id].minimum); + else + return gApricornTrees[id].minimum; + } + else + return 0; +} + +bool8 IsApricornTreePicked(u32 id) +{ + if (id > APRICORN_TREE_COUNT) + return TRUE; + +#if (APRICORN_TREE_COUNT > 0) + return gSaveBlock3Ptr->apricornTrees[id / 8] & (1 << (id % 8)); +#else + return TRUE; +#endif +} + +void SetApricornTreePicked(u32 id) +{ + if (id > APRICORN_TREE_COUNT) + return; + +#if (APRICORN_TREE_COUNT > 0) + u8 *flagByte = &gSaveBlock3Ptr->apricornTrees[id / 8]; + *flagByte = (*flagByte) | (1 << (id % 8)); +#endif +} diff --git a/src/battle_ai_field_statuses.c b/src/battle_ai_field_statuses.c index bd7bdd8e17..030d99a94e 100644 --- a/src/battle_ai_field_statuses.c +++ b/src/battle_ai_field_statuses.c @@ -20,12 +20,11 @@ #include "constants/abilities.h" #include "constants/battle_ai.h" #include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" #include "constants/moves.h" #include "constants/items.h" -static bool32 DoesAbilityBenefitFromWeather(u32 ability, u32 weather); -static bool32 DoesAbilityBenefitFromFieldStatus(u32 ability, u32 fieldStatus); +static bool32 DoesAbilityBenefitFromWeather(enum Ability ability, u32 weather); +static bool32 DoesAbilityBenefitFromFieldStatus(enum Ability ability, u32 fieldStatus); // A move is light sensitive if it is boosted by Sunny Day and weakened by low light weathers. static bool32 IsLightSensitiveMove(u32 move); static bool32 HasLightSensitiveMove(u32 battler); @@ -44,6 +43,7 @@ static enum FieldEffectOutcome BenefitsFromElectricTerrain(u32 battler); static enum FieldEffectOutcome BenefitsFromGrassyTerrain(u32 battler); static enum FieldEffectOutcome BenefitsFromMistyTerrain(u32 battler); static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler); +static enum FieldEffectOutcome BenefitsFromGravity(u32 battler); static enum FieldEffectOutcome BenefitsFromTrickRoom(u32 battler); bool32 WeatherChecker(u32 battler, u32 weather, enum FieldEffectOutcome desiredResult) @@ -108,6 +108,8 @@ bool32 FieldStatusChecker(u32 battler, u32 fieldStatus, enum FieldEffectOutcome result = BenefitsFromPsychicTerrain(battler); // other field statuses + if (fieldStatus & STATUS_FIELD_GRAVITY) + result = BenefitsFromGravity(battler); if (fieldStatus & STATUS_FIELD_TRICK_ROOM) result = BenefitsFromTrickRoom(battler); @@ -125,7 +127,7 @@ bool32 FieldStatusChecker(u32 battler, u32 fieldStatus, enum FieldEffectOutcome return (result == desiredResult); } -static bool32 DoesAbilityBenefitFromWeather(u32 ability, u32 weather) +static bool32 DoesAbilityBenefitFromWeather(enum Ability ability, u32 weather) { switch (ability) { @@ -163,7 +165,7 @@ static bool32 DoesAbilityBenefitFromWeather(u32 ability, u32 weather) return FALSE; } -static bool32 DoesAbilityBenefitFromFieldStatus(u32 ability, u32 fieldStatus) +static bool32 DoesAbilityBenefitFromFieldStatus(enum Ability ability, u32 fieldStatus) { switch (ability) { @@ -217,7 +219,7 @@ static bool32 HasLightSensitiveMove(u32 battler) // Utility Umbrella does NOT block Ancient Pokemon from their stat boosts. static enum FieldEffectOutcome BenefitsFromSun(u32 battler) { - u32 ability = gAiLogicData->abilities[battler]; + enum Ability ability = gAiLogicData->abilities[battler]; if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_UTILITY_UMBRELLA) { @@ -248,9 +250,9 @@ static enum FieldEffectOutcome BenefitsFromSandstorm(u32 battler) if (gAiLogicData->holdEffects[battler] == HOLD_EFFECT_SAFETY_GOGGLES || IS_BATTLER_ANY_TYPE(battler, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL)) { - if (!(IS_BATTLER_ANY_TYPE(FOE(battler), TYPE_ROCK, TYPE_GROUND, TYPE_STEEL)) - || gAiLogicData->holdEffects[FOE(battler)] == HOLD_EFFECT_SAFETY_GOGGLES - || DoesAbilityBenefitFromWeather(gAiLogicData->abilities[FOE(battler)], B_WEATHER_SANDSTORM)) + if (!(IS_BATTLER_ANY_TYPE(LEFT_FOE(battler), TYPE_ROCK, TYPE_GROUND, TYPE_STEEL)) + || gAiLogicData->holdEffects[LEFT_FOE(battler)] == HOLD_EFFECT_SAFETY_GOGGLES + || DoesAbilityBenefitFromWeather(gAiLogicData->abilities[LEFT_FOE(battler)], B_WEATHER_SANDSTORM)) return FIELD_EFFECT_POSITIVE; else return FIELD_EFFECT_NEUTRAL; @@ -274,7 +276,7 @@ static enum FieldEffectOutcome BenefitsFromHailOrSnow(u32 battler, u32 weather) if (HasLightSensitiveMove(battler)) return FIELD_EFFECT_NEGATIVE; - if (HasMoveWithFlag(FOE(battler), MoveAlwaysHitsInHailSnow)) + if (HasMoveWithFlag(LEFT_FOE(battler), MoveAlwaysHitsInHailSnow)) return FIELD_EFFECT_NEGATIVE; return FIELD_EFFECT_NEUTRAL; @@ -294,7 +296,7 @@ static enum FieldEffectOutcome BenefitsFromRain(u32 battler) if (HasLightSensitiveMove(battler) || HasDamagingMoveOfType(battler, TYPE_FIRE)) return FIELD_EFFECT_NEGATIVE; - if (HasMoveWithFlag(FOE(battler), MoveAlwaysHitsInRain)) + if (HasMoveWithFlag(LEFT_FOE(battler), MoveAlwaysHitsInRain)) return FIELD_EFFECT_NEGATIVE; return FIELD_EFFECT_NEUTRAL; @@ -309,11 +311,12 @@ static enum FieldEffectOutcome BenefitsFromElectricTerrain(u32 battler) if (HasMoveWithEffect(battler, EFFECT_RISING_VOLTAGE)) return FIELD_EFFECT_POSITIVE; - if (HasMoveWithEffect(FOE(battler), EFFECT_REST) && IsBattlerGrounded(FOE(battler))) + if ((HasMoveWithEffect(LEFT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(LEFT_FOE(battler))) + || (HasMoveWithEffect(RIGHT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(RIGHT_FOE(battler)))) return FIELD_EFFECT_POSITIVE; - bool32 grounded = IsBattlerGrounded(battler); - if (grounded && HasBattlerSideMoveWithAdditionalEffect(FOE(battler), MOVE_EFFECT_SLEEP)) + bool32 grounded = AI_IsBattlerGrounded(battler); + if (grounded && HasBattlerSideMoveWithAdditionalEffect(LEFT_FOE(battler), MOVE_EFFECT_SLEEP)) return FIELD_EFFECT_POSITIVE; if (grounded && ((gBattleMons[battler].status1 & STATUS1_SLEEP) @@ -321,7 +324,7 @@ static enum FieldEffectOutcome BenefitsFromElectricTerrain(u32 battler) || HasDamagingMoveOfType(battler, TYPE_ELECTRIC))) return FIELD_EFFECT_POSITIVE; - if (HasBattlerSideMoveWithEffect(FOE(battler), EFFECT_RISING_VOLTAGE)) + if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_RISING_VOLTAGE)) return FIELD_EFFECT_NEGATIVE; @@ -334,22 +337,22 @@ static enum FieldEffectOutcome BenefitsFromGrassyTerrain(u32 battler) if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_GRASSY_TERRAIN)) return FIELD_EFFECT_POSITIVE; - if (HasMoveWithEffect(battler, EFFECT_GRASSY_GLIDE)) + if (HasBattlerSideMoveWithEffect(battler, EFFECT_GRASSY_GLIDE)) return FIELD_EFFECT_POSITIVE; if (HasMoveWithAdditionalEffect(battler, MOVE_EFFECT_FLORAL_HEALING)) return FIELD_EFFECT_POSITIVE; - bool32 grounded = IsBattlerGrounded(battler); + bool32 grounded = AI_IsBattlerGrounded(battler); // Weaken spamming Earthquake, Magnitude, and Bulldoze. - if (grounded && (HasBattlerSideMoveWithEffect(FOE(battler), EFFECT_EARTHQUAKE) - || HasBattlerSideMoveWithEffect(FOE(battler), EFFECT_MAGNITUDE))) + if (grounded && (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_EARTHQUAKE) + || HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_MAGNITUDE))) return FIELD_EFFECT_POSITIVE; if (grounded && HasDamagingMoveOfType(battler, TYPE_GRASS)) return FIELD_EFFECT_POSITIVE; - if (HasBattlerSideMoveWithEffect(FOE(battler), EFFECT_GRASSY_GLIDE)) + if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_GRASSY_GLIDE)) return FIELD_EFFECT_NEGATIVE; @@ -365,21 +368,22 @@ static enum FieldEffectOutcome BenefitsFromMistyTerrain(u32 battler) if (HasBattlerSideMoveWithEffect(battler, EFFECT_MISTY_EXPLOSION)) return FIELD_EFFECT_POSITIVE; - bool32 grounded = IsBattlerGrounded(battler); + bool32 grounded = AI_IsBattlerGrounded(battler); bool32 allyGrounded = FALSE; if (HasPartner(battler)) - allyGrounded = IsBattlerGrounded(BATTLE_PARTNER(battler)); + allyGrounded = AI_IsBattlerGrounded(BATTLE_PARTNER(battler)); - if (HasMoveWithEffect(FOE(battler), EFFECT_REST) && IsBattlerGrounded(FOE(battler))) + if ((HasMoveWithEffect(LEFT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(LEFT_FOE(battler))) + || (HasMoveWithEffect(RIGHT_FOE(battler), EFFECT_REST) && AI_IsBattlerGrounded(RIGHT_FOE(battler)))) return FIELD_EFFECT_POSITIVE; // harass dragons - if ((grounded || allyGrounded) - && (HasDamagingMoveOfType(FOE(battler), TYPE_DRAGON) || HasDamagingMoveOfType(BATTLE_PARTNER(FOE(battler)), TYPE_DRAGON))) + if ((grounded || allyGrounded) + && (HasDamagingMoveOfType(LEFT_FOE(battler), TYPE_DRAGON) || HasDamagingMoveOfType(RIGHT_FOE(battler), TYPE_DRAGON))) return FIELD_EFFECT_POSITIVE; - if ((grounded || allyGrounded) - && (HasNonVolatileMoveEffect(FOE(battler), MOVE_EFFECT_SLEEP) || HasNonVolatileMoveEffect(BATTLE_PARTNER(FOE(battler)), MOVE_EFFECT_SLEEP))) + if ((grounded || allyGrounded) + && (HasNonVolatileMoveEffect(LEFT_FOE(battler), MOVE_EFFECT_SLEEP) || HasNonVolatileMoveEffect(RIGHT_FOE(battler), MOVE_EFFECT_SLEEP))) return FIELD_EFFECT_POSITIVE; if (grounded && (gBattleMons[battler].status1 & STATUS1_SLEEP || gBattleMons[battler].volatiles.yawn)) @@ -394,48 +398,77 @@ static enum FieldEffectOutcome BenefitsFromPsychicTerrain(u32 battler) if (DoesAbilityBenefitFromFieldStatus(gAiLogicData->abilities[battler], STATUS_FIELD_PSYCHIC_TERRAIN)) return FIELD_EFFECT_POSITIVE; - if (HasMoveWithEffect(battler, EFFECT_EXPANDING_FORCE)) + if (HasBattlerSideMoveWithEffect(battler, EFFECT_EXPANDING_FORCE)) return FIELD_EFFECT_POSITIVE; - bool32 grounded = IsBattlerGrounded(battler); + bool32 grounded = AI_IsBattlerGrounded(battler); bool32 allyGrounded = FALSE; if (HasPartner(battler)) - allyGrounded = IsBattlerGrounded(BATTLE_PARTNER(battler)); + allyGrounded = AI_IsBattlerGrounded(BATTLE_PARTNER(battler)); // don't bother if we're not grounded if (grounded || allyGrounded) { // harass priority - if (HasBattlerSideAbility(FOE(battler), ABILITY_GALE_WINGS, gAiLogicData) - || HasBattlerSideAbility(FOE(battler), ABILITY_TRIAGE, gAiLogicData) - || HasBattlerSideAbility(FOE(battler), ABILITY_PRANKSTER, gAiLogicData)) + if (AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_GALE_WINGS) + || AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_TRIAGE) + || AI_IsAbilityOnSide(LEFT_FOE(battler), ABILITY_PRANKSTER)) return FIELD_EFFECT_POSITIVE; } - if (grounded && (HasDamagingMoveOfType(battler, TYPE_PSYCHIC))) + if (grounded && HasDamagingMoveOfType(battler, TYPE_PSYCHIC)) return FIELD_EFFECT_POSITIVE; - if (HasBattlerSideMoveWithEffect(FOE(battler), EFFECT_EXPANDING_FORCE)) + if (HasBattlerSideMoveWithEffect(LEFT_FOE(battler), EFFECT_EXPANDING_FORCE)) return FIELD_EFFECT_NEGATIVE; - if (HasBattlerSideAbility(battler, ABILITY_GALE_WINGS, gAiLogicData) - || HasBattlerSideAbility(battler, ABILITY_TRIAGE, gAiLogicData) - || HasBattlerSideAbility(battler, ABILITY_PRANKSTER, gAiLogicData)) + if (AI_IsAbilityOnSide(battler, ABILITY_GALE_WINGS) + || AI_IsAbilityOnSide(battler, ABILITY_TRIAGE) + || AI_IsAbilityOnSide(battler, ABILITY_PRANKSTER)) return FIELD_EFFECT_NEGATIVE; return FIELD_EFFECT_NEUTRAL; } +static enum FieldEffectOutcome BenefitsFromGravity(u32 battler) +{ + if (!AI_IsBattlerGrounded(battler)) + return FIELD_EFFECT_NEGATIVE; + + if (AI_IsAbilityOnSide(battler, ABILITY_HUSTLE)) + return FIELD_EFFECT_POSITIVE; + + if (HasMoveWithFlag(battler, IsMoveGravityBanned)) + return FIELD_EFFECT_NEGATIVE; + + if (IsBattlerAlive(LEFT_FOE(battler))) + { + if (HasMoveWithLowAccuracy(battler, LEFT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE) + || (!AI_IsBattlerGrounded(LEFT_FOE(battler)) && HasDamagingMoveOfType(battler, TYPE_GROUND))) + return FIELD_EFFECT_POSITIVE; + } + + if (IsBattlerAlive(RIGHT_FOE(battler))) + { + if (HasMoveWithLowAccuracy(battler, RIGHT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE) + || (!AI_IsBattlerGrounded(RIGHT_FOE(battler)) && HasDamagingMoveOfType(battler, TYPE_GROUND))) + return FIELD_EFFECT_POSITIVE; + } + + return FIELD_EFFECT_NEUTRAL; +} + + static enum FieldEffectOutcome BenefitsFromTrickRoom(u32 battler) { // If we're in singles, we literally only care about speed. if (IsBattle1v1()) { - if (gAiLogicData->speedStats[battler] < gAiLogicData->speedStats[FOE(battler)]) + if (gAiLogicData->speedStats[battler] < gAiLogicData->speedStats[LEFT_FOE(battler)]) return FIELD_EFFECT_POSITIVE; // If we tie, we shouldn't change trick room state. - else if (gAiLogicData->speedStats[battler] == gAiLogicData->speedStats[FOE(battler)]) - return FIELD_EFFECT_NEUTRAL; + else if (gAiLogicData->speedStats[battler] == gAiLogicData->speedStats[LEFT_FOE(battler)]) + return FIELD_EFFECT_NEUTRAL; else return FIELD_EFFECT_NEGATIVE; } @@ -455,7 +488,7 @@ static enum FieldEffectOutcome BenefitsFromTrickRoom(u32 battler) } // If we are faster or tie, we don't want trick room. - if ((gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[FOE(battler)]) || (gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[BATTLE_PARTNER(FOE(battler))])) + if ((gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[LEFT_FOE(battler)]) || (gAiLogicData->speedStats[battler] >= gAiLogicData->speedStats[RIGHT_FOE(battler)])) return FIELD_EFFECT_NEGATIVE; return FIELD_EFFECT_POSITIVE; diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index d2d81c2a53..abe8cbf696 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1,5 +1,3 @@ -// Note that FOE specifically returns the left-side battler; BATTLE_OPPOSITE is the diagonal. - #include "global.h" #include "main.h" #include "malloc.h" @@ -25,7 +23,6 @@ #include "constants/abilities.h" #include "constants/battle_ai.h" #include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" #include "constants/moves.h" #include "constants/items.h" #include "constants/trainers.h" @@ -40,7 +37,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battler); static u32 ChooseMoveOrAction_Doubles(u32 battler); static inline void BattleAI_DoAIProcessing(struct AiThinkingStruct *aiThink, u32 battlerAtk, u32 battlerDef); static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AiThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef); -static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect); +static bool32 IsPinchBerryItemEffect(enum HoldEffect holdEffect); static void AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef); // ewram @@ -185,7 +182,7 @@ static u64 GetWildAiFlags(void) return flags; } -static u64 GetAiFlags(u16 trainerId) +static u64 GetAiFlags(u16 trainerId, u32 battler) { u64 flags = 0; @@ -198,7 +195,7 @@ static u64 GetAiFlags(u16 trainerId) else { if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) - flags = GetAiScriptsInRecordedBattle(); + flags = GetAiScriptsInRecordedBattle(battler); else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) flags = AI_FLAG_SAFARI; else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) @@ -235,7 +232,7 @@ static u64 GetAiFlags(u16 trainerId) void BattleAI_SetupFlags(void) { if (IsAiVsAiBattle()) - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId); + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId, B_POSITION_PLAYER_LEFT); else gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI @@ -249,8 +246,8 @@ void BattleAI_SetupFlags(void) if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))) { // smart wild AI - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF); - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF, B_POSITION_OPPONENT_LEFT); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF, B_POSITION_OPPONENT_RIGHT); // The check is here because wild natural enemies are not symmetrical. if (B_WILD_NATURAL_ENEMIES && IsDoubleBattle()) @@ -262,20 +259,19 @@ void BattleAI_SetupFlags(void) if (IsNaturalEnemy(speciesRight, speciesLeft)) gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] |= AI_FLAG_ATTACKS_PARTNER; } - } else { - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA); - if (TRAINER_BATTLE_PARAM.opponentB != 0 && TRAINER_BATTLE_PARAM.opponentB != 0xFFFF) - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA, B_POSITION_OPPONENT_LEFT); + if ((TRAINER_BATTLE_PARAM.opponentB != 0) && (TRAINER_BATTLE_PARAM.opponentB != 0xFFFF)) + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB, B_POSITION_OPPONENT_RIGHT); else gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; } if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId); + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId, B_POSITION_PLAYER_RIGHT); } else if (IsDoubleBattle() && IsAiVsAiBattle()) { @@ -283,7 +279,8 @@ void BattleAI_SetupFlags(void) } else // Assign ai flags for player for prediction { - u64 aiFlags = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA) | GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); + u64 aiFlags = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA, B_POSITION_OPPONENT_LEFT) + | GetAiFlags(TRAINER_BATTLE_PARAM.opponentB, B_POSITION_OPPONENT_RIGHT); gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = aiFlags; gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = aiFlags; } @@ -362,13 +359,13 @@ void ComputeBattlerDecisions(u32 battler) if (isAiBattler || CanAiPredictMove()) { // Risky AI switches aggressively even mid battle - enum SwitchType switchType = (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE; + enum SwitchType switchType = (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE_OPTIONAL; gAiLogicData->aiCalcInProgress = TRUE; // Setup battler and prediction data BattleAI_SetupAIData(0xF, battler); - SetupAIPredictionData(battler, switchType); + SetupAIPredictionData(battler, SWITCH_MID_BATTLE_OPTIONAL); // AI's own switching data if (isAiBattler) @@ -450,6 +447,7 @@ void Ai_InitPartyStruct(void) { u32 i; bool32 isOmniscient = (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT); + bool32 hasPartyKnowledge = (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_KNOW_OPPONENT_PARTY) || (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_KNOW_OPPONENT_PARTY); struct Pokemon *mon; gAiPartyData->count[B_SIDE_PLAYER] = CalculatePlayerPartyCount(); @@ -470,13 +468,16 @@ void Ai_InitPartyStruct(void) // Find fainted mons for (i = 0; i < gAiPartyData->count[B_SIDE_PLAYER]; i++) { + mon = &gPlayerParty[i]; if (GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) gAiPartyData->mons[B_SIDE_PLAYER][i].isFainted = TRUE; + if (isOmniscient || hasPartyKnowledge) + gAiPartyData->mons[B_SIDE_PLAYER][i].species = GetMonData(mon, MON_DATA_SPECIES); + if (isOmniscient) { u32 j; - mon = &gPlayerParty[i]; gAiPartyData->mons[B_SIDE_PLAYER][i].item = GetMonData(mon, MON_DATA_HELD_ITEM); gAiPartyData->mons[B_SIDE_PLAYER][i].heldEffect = GetItemHoldEffect(gAiPartyData->mons[B_SIDE_PLAYER][i].item); gAiPartyData->mons[B_SIDE_PLAYER][i].ability = GetMonAbility(mon); @@ -549,15 +550,17 @@ void RecordStatusMoves(u32 battler) void SetBattlerAiData(u32 battler, struct AiLogicData *aiData) { - u32 ability, holdEffect; + enum Ability ability; + u32 holdEffect; + ability = aiData->abilities[battler] = AI_DecideKnownAbilityForTurn(battler); aiData->items[battler] = gBattleMons[battler].item; holdEffect = aiData->holdEffects[battler] = AI_DecideHoldEffectForTurn(battler); aiData->holdEffectParams[battler] = GetBattlerHoldEffectParam(battler); - aiData->lastUsedMove[battler] = gLastMoves[battler]; + aiData->lastUsedMove[battler] = (gLastMoves[battler] == MOVE_UNAVAILABLE) ? MOVE_NONE : gLastMoves[battler]; aiData->hpPercents[battler] = GetHealthPercentage(battler); aiData->moveLimitations[battler] = CheckMoveLimitations(battler, 0, MOVE_LIMITATIONS_ALL); - aiData->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); + aiData->speedStats[battler] = GetBattlerTotalSpeedStat(battler, ability, holdEffect); if (IsAiBattlerAssumingStab()) RecordMovesBasedOnStab(battler); @@ -570,8 +573,8 @@ void SetBattlerAiData(u32 battler, struct AiLogicData *aiData) static u32 Ai_SetMoveAccuracy(struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef, u32 move) { u32 accuracy; - u32 abilityAtk = aiData->abilities[battlerAtk]; - u32 abilityDef = aiData->abilities[battlerDef]; + enum Ability abilityAtk = aiData->abilities[battlerAtk]; + enum Ability abilityDef = aiData->abilities[battlerDef]; if (CanMoveSkipAccuracyCalc(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_CHECK)) { accuracy = BYPASSES_ACCURACY_CALC; @@ -637,6 +640,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData) u32 battlerAtk, battlersCount, weather; memset(aiData, 0, sizeof(struct AiLogicData)); + gAiBattleData->aiUsingGimmick = 0; if (!(gBattleTypeFlags & BATTLE_TYPE_HAS_AI) && !IsWildMonSmart()) return; @@ -691,7 +695,7 @@ u32 GetPartyMonAbility(struct Pokemon *mon) { // Doesn't have any special handling yet u32 species = GetMonData(mon, MON_DATA_SPECIES); - u32 ability = GetSpeciesAbility(species, GetMonData(mon, MON_DATA_ABILITY_NUM)); + enum Ability ability = GetSpeciesAbility(species, GetMonData(mon, MON_DATA_ABILITY_NUM)); return ability; } @@ -711,9 +715,9 @@ static u32 PpStallReduction(u32 move, u32 battlerAtk) continue; PokemonToBattleMon(&gPlayerParty[partyIndex], &gBattleMons[tempBattleMonIndex]); u32 species = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES); - u32 abilityAtk = ABILITY_NONE; - u32 abilityDef = GetPartyMonAbility(&gPlayerParty[partyIndex]); - u32 moveType = GetBattleMoveType(move); // Probably doesn't handle dynamic types right now + enum Ability abilityAtk = ABILITY_NONE; + enum Ability abilityDef = GetPartyMonAbility(&gPlayerParty[partyIndex]); + enum Type moveType = GetBattleMoveType(move); // Probably doesn't handle dynamic types right now if (CanAbilityAbsorbMove(battlerAtk, tempBattleMonIndex, abilityDef, move, moveType, CHECK_TRIGGER) || CanAbilityBlockMove(battlerAtk, tempBattleMonIndex, abilityAtk, abilityDef, move, CHECK_TRIGGER) || (CalcPartyMonTypeEffectivenessMultiplier(move, species, abilityDef) == 0)) @@ -1071,7 +1075,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // move data enum BattleMoveEffects moveEffect = GetMoveEffect(move); u32 nonVolatileStatus = GetMoveNonVolatileStatus(move); - s32 moveType; + enum Type moveType; u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); struct AiLogicData *aiData = gAiLogicData; uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; @@ -1082,8 +1086,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) u32 weather; u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, gAiLogicData); u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, gAiLogicData); - u32 abilityAtk = aiData->abilities[battlerAtk]; - u32 abilityDef = aiData->abilities[battlerDef]; + enum Ability abilityAtk = aiData->abilities[battlerAtk]; + enum Ability abilityDef = aiData->abilities[battlerDef]; s32 atkPriority = GetBattleMovePriority(battlerAtk, abilityAtk, move); SetTypeBeforeUsingMove(move, battlerAtk); @@ -1141,6 +1145,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // check non-user target if (!(moveTarget & MOVE_TARGET_USER)) { + if (Ai_IsPriorityBlocked(battlerAtk, battlerDef, move, aiData)) + RETURN_SCORE_MINUS(20); + if (CanAbilityBlockMove(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_CHECK)) RETURN_SCORE_MINUS(20); @@ -1221,6 +1228,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) && IsNonVolatileStatusMove(move)) RETURN_SCORE_MINUS(10); break; + default: + break; } // def ability checks // target partner ability checks & not attacking partner @@ -1252,6 +1261,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IsAromaVeilProtectedEffect(moveEffect)) RETURN_SCORE_MINUS(10); break; + default: + break; } } // def partner ability checks @@ -1262,19 +1273,19 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) RETURN_SCORE_MINUS(10); // terrain & effect checks - if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_ELECTRIC_TERRAIN)) + if (IsBattlerTerrainAffected(battlerDef, abilityDef, aiData->holdEffects[battlerDef], STATUS_FIELD_ELECTRIC_TERRAIN)) { if (nonVolatileStatus == MOVE_EFFECT_SLEEP) RETURN_SCORE_MINUS(20); } - if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN)) + if (IsBattlerTerrainAffected(battlerDef, abilityDef, aiData->holdEffects[battlerDef], STATUS_FIELD_MISTY_TERRAIN)) { if (IsNonVolatileStatusMove(move) || IsConfusionMoveEffect(moveEffect)) RETURN_SCORE_MINUS(20); } - if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && atkPriority > 0) + if (IsBattlerTerrainAffected(battlerAtk, abilityAtk, aiData->holdEffects[battlerAtk], STATUS_FIELD_PSYCHIC_TERRAIN) && atkPriority > 0) { RETURN_SCORE_MINUS(20); } @@ -1283,7 +1294,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // the following checks apply to any target (including user) // throat chop check - if (gDisableStructs[battlerAtk].throatChopTimer > gBattleTurnCounter && IsSoundMove(move)) + if (gDisableStructs[battlerAtk].throatChopTimer > 0 && IsSoundMove(move)) return 0; // Can't even select move at all // heal block check if (gBattleMons[battlerAtk].volatiles.healBlock && IsHealBlockPreventingMove(battlerAtk, move)) @@ -1437,7 +1448,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case EFFECT_CHARGE: - if (gBattleMons[battlerAtk].volatiles.charge) + if (gBattleMons[battlerAtk].volatiles.chargeTimer > 0) ADJUST_SCORE(-20); else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) ADJUST_SCORE(-10); @@ -1447,7 +1458,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_QUIVER_DANCE: case EFFECT_GEOMANCY: - if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, aiData)) + if (AI_IsAbilityOnSide(battlerDef, ABILITY_UNAWARE)) ADJUST_SCORE(-10); if (gBattleMons[battlerAtk].statStages[STAT_SPATK] >= MAX_STAT_STAGE || !HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) ADJUST_SCORE(-10); @@ -1498,10 +1509,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (hasPartner) { if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) - && IsBattlerGrounded(battlerAtk) + && AI_IsBattlerGrounded(battlerAtk) && (BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK))) && !(IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS) - && IsBattlerGrounded(BATTLE_PARTNER(battlerAtk)) + && AI_IsBattlerGrounded(BATTLE_PARTNER(battlerAtk)) && aiData->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_CONTRARY && (BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_ATK) || BattlerStatCanRise(BATTLE_PARTNER(battlerAtk), aiData->abilities[BATTLE_PARTNER(battlerAtk)], STAT_SPATK)))) @@ -1510,7 +1521,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } } else if (!(IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) - && IsBattlerGrounded(battlerAtk) + && AI_IsBattlerGrounded(battlerAtk) && (BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_ATK) || BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK)))) { ADJUST_SCORE(-10); @@ -1526,12 +1537,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-8); break; } - else if (!hasPartner) - { - ADJUST_SCORE(-10); // no partner and our stats wont rise, so don't use - } - - if (hasPartner) + else if (hasPartner) { if (aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS) { @@ -1544,6 +1550,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); // nor our or our partner's ability is plus/minus } } + else + { + ADJUST_SCORE(-10); // no partner and our stats wont rise, so don't use + } break; case EFFECT_ACUPRESSURE: if (DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || AreBattlersStatsMaxed(battlerDef)) @@ -1557,12 +1567,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) else if (!BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) ADJUST_SCORE(-8); } - else if (!hasPartner) - { - ADJUST_SCORE(-10); // our stats wont rise from this move - } - - if (hasPartner) + else if (hasPartner) { if (aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS) { @@ -1576,6 +1581,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); // nor our or our partner's ability is plus/minus } } + else + { + ADJUST_SCORE(-10); // our stats wont rise from this move + } break; // stat lowering effects case EFFECT_ATTACK_DOWN: @@ -1784,7 +1793,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Attacker should go first { - if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); // no anticipated move to disable } else if (predictedMove == MOVE_NONE) @@ -1806,7 +1815,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Attacker should go first { - if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); // no anticipated move to encore } else if (predictedMove == MOVE_NONE) @@ -1892,15 +1901,15 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (CountUsablePartyMons(battlerAtk) == 0 && aiData->abilities[battlerAtk] != ABILITY_SOUNDPROOF - && aiData->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_SOUNDPROOF - && CountUsablePartyMons(FOE(battlerAtk)) >= 1) + && CountUsablePartyMons(battlerDef) >= 1 + && (aiData->abilities[BATTLE_PARTNER(battlerAtk)] != ABILITY_SOUNDPROOF || !IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))) { ADJUST_SCORE(-10); //Don't wipe your team if you're going to lose } - else if ((!IsBattlerAlive(FOE(battlerAtk)) || aiData->abilities[FOE(battlerAtk)] == ABILITY_SOUNDPROOF - || gBattleMons[FOE(battlerAtk)].volatiles.perishSong) - && (!IsBattlerAlive(BATTLE_PARTNER(FOE(battlerAtk))) || aiData->abilities[BATTLE_PARTNER(FOE(battlerAtk))] == ABILITY_SOUNDPROOF - || gBattleMons[BATTLE_PARTNER(FOE(battlerAtk))].volatiles.perishSong)) + else if ((!IsBattlerAlive(LEFT_FOE(battlerAtk)) || aiData->abilities[LEFT_FOE(battlerAtk)] == ABILITY_SOUNDPROOF + || gBattleMons[LEFT_FOE(battlerAtk)].volatiles.perishSong) + && (!IsBattlerAlive(RIGHT_FOE(battlerAtk)) || aiData->abilities[RIGHT_FOE(battlerAtk)] == ABILITY_SOUNDPROOF + || gBattleMons[RIGHT_FOE(battlerAtk)].volatiles.perishSong)) { ADJUST_SCORE(-10); //Both enemies are perish songed } @@ -1915,7 +1924,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) && CountUsablePartyMons(battlerDef) >= 1) ADJUST_SCORE(-10); - if (gBattleMons[FOE(battlerAtk)].volatiles.perishSong || aiData->abilities[FOE(battlerAtk)] == ABILITY_SOUNDPROOF) + if (gBattleMons[battlerDef].volatiles.perishSong || aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF) ADJUST_SCORE(-10); } break; @@ -1981,16 +1990,16 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_BELLY_DRUM: case EFFECT_FILLET_AWAY: - if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, aiData)) + if (AI_IsAbilityOnSide(battlerDef, ABILITY_UNAWARE)) ADJUST_SCORE(-10); if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY) ADJUST_SCORE(-10); - else if (aiData->hpPercents[battlerAtk] <= 60) + else if (aiData->hpPercents[battlerAtk] <= 60 && !IsConsideringZMove(battlerAtk, battlerDef, move)) ADJUST_SCORE(-10); break; case EFFECT_FUTURE_SIGHT: - if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_FUTUREATTACK - || gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_FUTUREATTACK) + if (gWishFutureKnock.futureSightCounter[LEFT_FOE(battlerAtk)] > 0 + || gWishFutureKnock.futureSightCounter[RIGHT_FOE(battlerAtk)] > 0) ADJUST_SCORE(-12); else ADJUST_SCORE(GOOD_EFFECT); @@ -2062,7 +2071,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_RECYCLE: - if (GetUsedHeldItem(battlerAtk) == 0 || gBattleMons[battlerAtk].item != 0) + if (GetBattlerPartyState(battlerAtk)->usedHeldItem == 0 || gBattleMons[battlerAtk].item != 0) ADJUST_SCORE(-10); break; case EFFECT_IMPRISON: @@ -2168,15 +2177,32 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) else if ((AI_GetWeather() & (B_WEATHER_LOW_LIGHT))) ADJUST_SCORE(-3); break; + case EFFECT_LIFE_DEW: + if (AI_BattlerAtMaxHp(battlerAtk)) + { + if (hasPartner) + { + if (AI_BattlerAtMaxHp(BATTLE_PARTNER(battlerAtk))) + ADJUST_SCORE(-10); + } + else + { + ADJUST_SCORE(-10); + } + } + break; case EFFECT_PURIFY: if (!(gBattleMons[battlerDef].status1 & STATUS1_ANY)) ADJUST_SCORE(-10); else if (battlerDef == BATTLE_PARTNER(battlerAtk)) break; //Always heal your ally - else if (AI_BattlerAtMaxHp(battlerAtk)) - ADJUST_SCORE(-10); - else if (aiData->hpPercents[battlerAtk] >= 90) - ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better + else if (!ShouldCureStatus(battlerAtk, battlerDef, aiData)) + { + if (AI_BattlerAtMaxHp(battlerAtk)) + ADJUST_SCORE(-10); + else if (aiData->hpPercents[battlerAtk] >= 90) + ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better + } break; case EFFECT_RECOIL_IF_MISS: if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] < 75 @@ -2193,13 +2219,12 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_MIMIC: if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Attacker should go first { - if (gLastMoves[battlerDef] == MOVE_NONE - || gLastMoves[battlerDef] == 0xFFFF) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); } else if (predictedMove == MOVE_NONE) { - // TODO predicted move separate from gLastMoves + // TODO predicted move separate from aiData->lastUsedMove ADJUST_SCORE(-10); } break; @@ -2223,13 +2248,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-8); break; case EFFECT_SKETCH: - if (gLastMoves[battlerDef] == MOVE_NONE) + if (aiData->lastUsedMove[battlerDef] == MOVE_NONE) ADJUST_SCORE(-10); break; case EFFECT_DESTINY_BOND: if (DoesDestinyBondFail(battlerAtk)) ADJUST_SCORE(-10); - if (gBattleMons[battlerDef].volatiles.destinyBond) + if (gBattleMons[battlerAtk].volatiles.destinyBond) ADJUST_SCORE(-10); else if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) ADJUST_SCORE(-10); @@ -2256,7 +2281,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case PROTECT_WIDE_GUARD: - if(!(GetBattlerMoveTargetType(battlerAtk, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH))) + if (!(GetBattlerMoveTargetType(battlerAtk, predictedMove) & (MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_BOTH))) { ADJUST_SCORE(-10); decreased = TRUE; @@ -2331,11 +2356,11 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-9); break; case EFFECT_COURT_CHANGE: - if (gSideStatuses[GetBattlerSide(FOE(battlerAtk))] & SIDE_STATUS_BAD_COURT) + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_BAD_COURT) ADJUST_SCORE(BAD_EFFECT); if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_GOOD_COURT) ADJUST_SCORE(BAD_EFFECT); - if (AreAnyHazardsOnSide(GetBattlerSide(FOE(battlerAtk))) && CountUsablePartyMons(battlerAtk) != 0) + if (AreAnyHazardsOnSide(GetBattlerSide(battlerDef)) && CountUsablePartyMons(battlerAtk) != 0) ADJUST_SCORE(WORST_EFFECT); if (hasPartner) { @@ -2429,7 +2454,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_WISH: - if (gWishFutureKnock.wishCounter[battlerAtk] > gBattleTurnCounter) + if (gWishFutureKnock.wishCounter[battlerAtk] > 0) ADJUST_SCORE(-10); break; case EFFECT_ASSIST: @@ -2452,10 +2477,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: - if (!CanEffectChangeAbility(battlerAtk, battlerDef, moveEffect, aiData) + case EFFECT_OVERWRITE_ABILITY: + if (!CanEffectChangeAbility(battlerAtk, battlerDef, move, aiData) || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) ADJUST_AND_RETURN_SCORE(NO_DAMAGE_OR_FAILS); break; @@ -2600,7 +2624,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { // This only happens if the ally already rolled on double trick room on final turn. // Both Pokemon use Trick Room on the final turn of Trick Room to anticipate both opponents Protecting to stall out. - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1)) + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1) ADJUST_SCORE(PERFECT_EFFECT); else ADJUST_SCORE(-10); @@ -2611,7 +2635,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) ADJUST_SCORE(-10); // Don't unset a trick room that doesn't harm you unless it's about to expire. - else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1) && !ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) + else if ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && gFieldTimers.trickRoomTimer > 1 && !ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) ADJUST_SCORE(-10); } break; @@ -2687,7 +2711,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_SOAK: { - u32 types[3]; + enum Type types[3]; u32 typeArg = GetMoveArgType(move); GetBattlerTypes(battlerDef, FALSE, types); @@ -2746,6 +2770,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_HOLD_HANDS: case EFFECT_CELEBRATE: case EFFECT_HAPPY_HOUR: + if (IsConsideringZMove(battlerAtk, battlerDef, move)) + break; ADJUST_SCORE(-10); break; case EFFECT_INSTRUCT: @@ -2754,13 +2780,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (AI_IsSlower(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) instructedMove = predictedMove; else - instructedMove = gLastMoves[battlerDef]; + instructedMove = aiData->lastUsedMove[battlerDef]; if (instructedMove == MOVE_NONE || IsMoveInstructBanned(instructedMove) || MoveHasAdditionalEffectSelf(instructedMove, MOVE_EFFECT_RECHARGE) || IsZMove(instructedMove) - || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) + || (gLockedMoves[battlerDef] != MOVE_NONE && gLockedMoves[battlerDef] != MOVE_UNAVAILABLE) || gBattleMons[battlerDef].volatiles.multipleTurns || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) { @@ -2808,7 +2834,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_TAILWIND: if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_TAILWIND || PartnerMoveEffectIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, EFFECT_TAILWIND) - || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1))) + || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1)) ADJUST_SCORE(-10); break; case EFFECT_LUCKY_CHANT: @@ -2818,12 +2844,12 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_MAGNET_RISE: if (gFieldStatuses & STATUS_FIELD_GRAVITY - || gDisableStructs[battlerAtk].magnetRiseTimer > gBattleTurnCounter + || gDisableStructs[battlerAtk].magnetRiseTimer > 0 || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_IRON_BALL || gBattleMons[battlerAtk].volatiles.smackDown || gBattleMons[battlerAtk].volatiles.root || gBattleMons[battlerAtk].volatiles.magnetRise - || !IsBattlerGrounded(battlerAtk)) + || !AI_IsBattlerGrounded(battlerAtk)) ADJUST_SCORE(-10); break; case EFFECT_CAMOUFLAGE: @@ -2857,7 +2883,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_NO_RETREAT: - if (gDisableStructs[battlerAtk].noRetreat) + if (gBattleMons[battlerAtk].volatiles.noRetreat) ADJUST_SCORE(-10); break; case EFFECT_EXTREME_EVOBOOST: @@ -2969,7 +2995,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) else if (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_STATUS && (CountUsablePartyMons(battlerAtk) < 1 || gAiLogicData->mostSuitableMonId[battlerAtk] == PARTY_SIZE - || (!AI_CanBattlerEscape(battlerAtk) && IsBattlerTrapped(battlerDef, battlerAtk)))) + || IsBattlerTrapped(battlerDef, battlerAtk))) ADJUST_SCORE(-30); } @@ -2979,6 +3005,19 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return score; } +static s32 AI_GetWhichBattlerFasterOrTies(u32 battlerAtk, u32 battlerDef, bool32 ignoreChosenMoves) +{ + struct BattleContext ctx = {0}; + ctx.battlerAtk = battlerAtk; + ctx.battlerDef = battlerDef; + ctx.abilities[battlerAtk] = gAiLogicData->abilities[battlerAtk]; + ctx.abilities[battlerDef] = gAiLogicData->abilities[battlerDef]; + ctx.holdEffects[battlerAtk] = gAiLogicData->holdEffects[battlerAtk]; + ctx.holdEffects[battlerDef] = gAiLogicData->holdEffects[battlerDef]; + + return GetWhichBattlerFasterOrTies(&ctx, ignoreChosenMoves); +} + static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { u32 movesetIndex = gAiThinkingStruct->movesetIndex; @@ -3000,7 +3039,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(SLOW_KILL); } else if (CanTargetFaintAi(battlerDef, battlerAtk) - && GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER + && AI_GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER && GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], move) > 0) { if (RandomPercentage(RNG_AI_PRIORITIZE_LAST_CHANCE, PRIORITIZE_LAST_CHANCE_CHANCE)) @@ -3016,7 +3055,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { // move data - u32 moveType = GetMoveType(move); + enum Type moveType = GetMoveType(move); enum BattleMoveEffects effect = GetMoveEffect(move); u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); // ally data @@ -3100,38 +3139,38 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } else { - u32 ownHitsToKOFoe1 = GetBestNoOfHitsToKO(battlerAtk, BATTLE_OPPOSITE(battlerAtk), AI_ATTACKING); - u32 partnerHitsToKOFoe1 = GetBestNoOfHitsToKO(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtk), AI_ATTACKING); - u32 ownHitsToKOFoe2 = GetBestNoOfHitsToKO(battlerAtk, BATTLE_OPPOSITE(battlerAtkPartner), AI_ATTACKING); - u32 partnerHitsToKOFoe2 = GetBestNoOfHitsToKO(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtkPartner), AI_ATTACKING); + u32 ownHitsToKOFoe1 = GetBestNoOfHitsToKO(battlerAtk, LEFT_FOE(battlerAtk), AI_ATTACKING); + u32 partnerHitsToKOFoe1 = GetBestNoOfHitsToKO(battlerAtkPartner, LEFT_FOE(battlerAtk), AI_ATTACKING); + u32 ownHitsToKOFoe2 = GetBestNoOfHitsToKO(battlerAtk, RIGHT_FOE(battlerAtk), AI_ATTACKING); + u32 partnerHitsToKOFoe2 = GetBestNoOfHitsToKO(battlerAtkPartner, RIGHT_FOE(battlerAtk), AI_ATTACKING); if (hasTwoOpponents) { // Might be about to die - if (CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtk), battlerAtk) && CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtkPartner), battlerAtk) - && AI_IsSlower(battlerAtk, BATTLE_OPPOSITE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY) - && AI_IsSlower(battlerAtk, BATTLE_OPPOSITE(battlerAtkPartner), move, predictedMove, DONT_CONSIDER_PRIORITY)) + if (CanTargetFaintAi(LEFT_FOE(battlerAtk), battlerAtk) && CanTargetFaintAi(RIGHT_FOE(battlerAtk), battlerAtk) + && AI_IsSlower(battlerAtk, LEFT_FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY) + && AI_IsSlower(battlerAtk, RIGHT_FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY)) ADJUST_SCORE(GOOD_EFFECT); if (ownHitsToKOFoe1 > partnerHitsToKOFoe1 && partnerHitsToKOFoe1 > 1 && ownHitsToKOFoe2 > partnerHitsToKOFoe2 && partnerHitsToKOFoe2 > 1) ADJUST_SCORE(GOOD_EFFECT); } - else if (IsBattlerAlive(BATTLE_OPPOSITE(battlerAtk))) + else if (IsBattlerAlive(LEFT_FOE(battlerAtk))) { // Might be about to die - if (CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtk), battlerAtk) - && AI_IsSlower(battlerAtk, BATTLE_OPPOSITE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY)) + if (CanTargetFaintAi(LEFT_FOE(battlerAtk), battlerAtk) + && AI_IsSlower(battlerAtk, LEFT_FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY)) ADJUST_SCORE(GOOD_EFFECT); if (ownHitsToKOFoe1 > partnerHitsToKOFoe1 && partnerHitsToKOFoe1 > 1) ADJUST_SCORE(GOOD_EFFECT); } - else if (IsBattlerAlive(BATTLE_OPPOSITE(battlerAtkPartner))) + else if (IsBattlerAlive(RIGHT_FOE(battlerAtk))) { // Might be about to die - if (CanTargetFaintAi(BATTLE_OPPOSITE(battlerAtkPartner), battlerAtk) - && AI_IsSlower(battlerAtk, BATTLE_OPPOSITE(battlerAtkPartner), move, predictedMove, DONT_CONSIDER_PRIORITY)) + if (CanTargetFaintAi(RIGHT_FOE(battlerAtk), battlerAtk) + && AI_IsSlower(battlerAtk, RIGHT_FOE(battlerAtk), move, predictedMove, DONT_CONSIDER_PRIORITY)) ADJUST_SCORE(GOOD_EFFECT); if (ownHitsToKOFoe2 > partnerHitsToKOFoe2 && partnerHitsToKOFoe2 > 1) @@ -3145,7 +3184,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(WEAK_EFFECT); break; case EFFECT_MAGNET_RISE: - if (IsBattlerGrounded(battlerAtk) + if (AI_IsBattlerGrounded(battlerAtk) && (HasMoveWithEffect(battlerAtkPartner, EFFECT_EARTHQUAKE) || HasMoveWithEffect(battlerAtkPartner, EFFECT_MAGNITUDE)) && (AI_GetMoveEffectiveness(MOVE_EARTHQUAKE, battlerAtk, battlerAtkPartner) != UQ_4_12(0.0))) // Doesn't resist ground move { @@ -3163,6 +3202,20 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) || HasMoveWithCriticalHitChance(battlerAtkPartner)) ADJUST_SCORE(GOOD_EFFECT); break; + case EFFECT_COACHING: + if (!hasPartner + || !HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL)) + { + ADJUST_SCORE(WORST_EFFECT); + } + else + { + ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtk), STAT_CHANGE_ATK)); + ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtk), STAT_CHANGE_DEF)); + ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtkPartner), STAT_CHANGE_ATK)); + ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtkPartner), STAT_CHANGE_DEF)); + } + break; default: break; } // our effect relative to partner @@ -3173,7 +3226,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // Both Pokemon use Trick Room on the final turn of Trick Room to anticipate both opponents Protecting to stall out. // This unsets Trick Room and resets it with a full timer. case EFFECT_TRICK_ROOM: - if (hasPartner && gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1) + if (hasPartner && gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1 && ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM) && HasMoveWithEffect(battlerAtkPartner, EFFECT_TRICK_ROOM) && RandomPercentage(RNG_AI_REFRESH_TRICK_ROOM_ON_LAST_TURN, DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE)) @@ -3181,7 +3234,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_TAILWIND: // Anticipate both opponents protecting to stall out Trick Room, and apply Tailwind. - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == (gBattleTurnCounter + 1) + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == 1 && RandomPercentage(RNG_AI_APPLY_TAILWIND_ON_LAST_TURN_OF_TRICK_ROOM, TAILWIND_IN_TRICK_ROOM_CHANCE)) ADJUST_SCORE(BEST_EFFECT); break; @@ -3550,10 +3603,9 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: - AbilityChangeScore(battlerAtk, battlerAtkPartner, effect, &score, aiData); + case EFFECT_OVERWRITE_ABILITY: + AbilityChangeScore(battlerAtk, battlerAtkPartner, move, &score, aiData); return score; case EFFECT_SPICY_EXTRACT: if (AI_ShouldSpicyExtract(battlerAtk, battlerAtkPartner, move, aiData)) @@ -3565,8 +3617,18 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (gBattleMons[battlerAtkPartner].status1 & STATUS1_ANY) { if (gBattleMons[battlerAtkPartner].status1 & STATUS1_CAN_MOVE) + { + if (ShouldCureStatus(battlerAtk, battlerAtkPartner, aiData)) + ADJUST_SCORE(DECENT_EFFECT); + } + else + { + ADJUST_SCORE(DECENT_EFFECT); + } + + if ((!IsBattlerAlive(LEFT_FOE(battlerAtk)) || ShouldRecover(battlerAtk, LEFT_FOE(battlerAtk), move, 50)) + && (!IsBattlerAlive(RIGHT_FOE(battlerAtk)) || ShouldRecover(battlerAtk, RIGHT_FOE(battlerAtk), move, 50))) RETURN_SCORE_PLUS(WEAK_EFFECT); - RETURN_SCORE_PLUS(GOOD_EFFECT); } break; case EFFECT_SWAGGER: @@ -3619,7 +3681,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (AI_IsFaster(battlerAtk, battlerAtkPartner, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) instructedMove = aiData->partnerMove; else - instructedMove = gLastMoves[battlerAtkPartner]; + instructedMove = aiData->lastUsedMove[battlerAtkPartner]; if (instructedMove != MOVE_NONE && !IsBattleMoveStatus(instructedMove) @@ -3633,8 +3695,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && HasMoveWithEffect(battlerAtkPartner, EFFECT_TRICK_ROOM)) ADJUST_SCORE(DECENT_EFFECT); - if (AI_IsSlower(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove, predictedMoveSpeedCheck, CONSIDER_PRIORITY) // Opponent mon 1 goes before partner - && AI_IsSlower(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Opponent mon 2 goes before partner + if (AI_IsSlower(battlerAtkPartner, LEFT_FOE(battlerAtk), aiData->partnerMove, predictedMoveSpeedCheck, CONSIDER_PRIORITY) // Opponent mon 1 goes before partner + && AI_IsSlower(battlerAtkPartner, RIGHT_FOE(battlerAtk), aiData->partnerMove, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Opponent mon 2 goes before partner { if (partnerEffect == EFFECT_COUNTER || partnerEffect == EFFECT_MIRROR_COAT) break; // These moves need to go last @@ -3643,8 +3705,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_HEAL_PULSE: case EFFECT_HIT_ENEMY_HEAL_ALLY: - if (AI_IsFaster(battlerAtk, FOE(battlerAtk), move, predictedMoveSpeedCheck, CONSIDER_PRIORITY) - && AI_IsFaster(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move, predictedMoveSpeedCheck, CONSIDER_PRIORITY) + if (AI_IsFaster(battlerAtk, LEFT_FOE(battlerAtk), move, predictedMoveSpeedCheck, CONSIDER_PRIORITY) + && AI_IsFaster(battlerAtk, RIGHT_FOE(battlerAtk), move, predictedMoveSpeedCheck, CONSIDER_PRIORITY) && gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2) RETURN_SCORE_PLUS(WEAK_EFFECT); break; @@ -3731,7 +3793,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) return score; } -static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect) +static bool32 IsPinchBerryItemEffect(enum HoldEffect holdEffect) { switch (holdEffect) { @@ -3962,10 +4024,9 @@ static void AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef) } } -static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) +static s32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) { - struct AiLogicData *aiData = gAiLogicData; - enum ItemHoldEffect holdEffect = aiData->holdEffects[battlerAtk]; + enum HoldEffect holdEffect = aiData->holdEffects[battlerAtk]; s32 score = 0; @@ -3992,18 +4053,17 @@ static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) return score; } -static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) +static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) { // move data enum BattleMoveEffects moveEffect = GetMoveEffect(move); - struct AiLogicData *aiData = gAiLogicData; u32 movesetIndex = gAiThinkingStruct->movesetIndex; uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex]; s32 score = 0; - u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, gAiLogicData); - u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, gAiLogicData); - u32 predictedType = GetMoveType(predictedMove); + u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, aiData); + u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, aiData); + enum Type predictedType = GetMoveType(predictedMove); u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove); bool32 isBattle1v1 = IsBattle1v1(); bool32 hasTwoOpponents = HasTwoOpponents(battlerAtk); @@ -4019,12 +4079,25 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0)) ADJUST_SCORE(10); + // don't get baited into encore + if (gBattleMoveEffects[moveEffect].encourageEncore + && HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE) + && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerAtk] != HOLD_EFFECT_MENTAL_HERB)) + { + if (!AI_IsAbilityOnSide(battlerAtk, ABILITY_AROMA_VEIL) + || IsMoldBreakerTypeAbility(battlerDef, aiData->abilities[battlerDef]) + || aiData->abilities[battlerDef] == ABILITY_MYCELIUM_MIGHT + || IsMoldBreakerTypeAbility(BATTLE_PARTNER(battlerDef), aiData->abilities[BATTLE_PARTNER(battlerDef)]) + || aiData->abilities[BATTLE_PARTNER(battlerDef)] == ABILITY_MYCELIUM_MIGHT) + return score; + } + // check thawing moves if (gBattleMons[battlerAtk].status1 & STATUS1_ICY_ANY && MoveThawsUser(move)) ADJUST_SCORE(10); // check burn / frostbite - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && gAiLogicData->abilities[battlerAtk] == ABILITY_NATURAL_CURE) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && aiData->abilities[battlerAtk] == ABILITY_NATURAL_CURE) { if ((gBattleMons[battlerAtk].status1 & STATUS1_BURN && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL, TRUE)) || (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL, TRUE))) @@ -4108,13 +4181,15 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK_2)); break; case EFFECT_DEFENSE_UP: - case EFFECT_DEFENSE_UP_3: ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF)); break; case EFFECT_STUFF_CHEEKS: case EFFECT_DEFENSE_UP_2: ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF_2)); break; + case EFFECT_DEFENSE_UP_3: + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF_3)); + break; case EFFECT_SPEED_UP: ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED)); break; @@ -4126,9 +4201,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK)); break; case EFFECT_SPECIAL_ATTACK_UP_2: - case EFFECT_SPECIAL_ATTACK_UP_3: ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK_2)); break; + case EFFECT_SPECIAL_ATTACK_UP_3: + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK_3)); + break; case EFFECT_SPECIAL_DEFENSE_UP: ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF)); break; @@ -4177,7 +4254,34 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_BIDE: if (aiData->hpPercents[battlerAtk] < 90) ADJUST_SCORE(-2); // Should be either removed or turned into increasing score + // treat as offense booster case EFFECT_ACUPRESSURE: + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK_2)); + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK_2)); + break; + case EFFECT_GEAR_UP: + if (aiData->abilities[battlerAtk] == ABILITY_PLUS || aiData->abilities[battlerAtk] == ABILITY_MINUS) + { + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK)); + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK)); + } + if (hasPartner && (aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS)) + { + ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, STAT_CHANGE_ATK)); + ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, STAT_CHANGE_SPATK)); + } + break; + case EFFECT_MAGNETIC_FLUX: + if (aiData->abilities[battlerAtk] == ABILITY_PLUS || aiData->abilities[battlerAtk] == ABILITY_MINUS) + { + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF)); + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF)); + } + if (hasPartner && (aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_PLUS || aiData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_MINUS)) + { + ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, STAT_CHANGE_DEF)); + ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, STAT_CHANGE_SPDEF)); + } break; case EFFECT_ATTACK_ACCURACY_UP: // hone claws ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK)); @@ -4189,31 +4293,55 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK)); break; case EFFECT_ROTOTILLER: - if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && IsBattlerGrounded(battlerAtk)) + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS) && AI_IsBattlerGrounded(battlerAtk)) { ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK)); ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK)); } - if (hasPartner && IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS) && IsBattlerGrounded(BATTLE_PARTNER(battlerAtk))) + if (hasPartner && IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS) && AI_IsBattlerGrounded(BATTLE_PARTNER(battlerAtk))) { ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, STAT_CHANGE_ATK)); ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, STAT_CHANGE_SPATK)); } - if (IS_BATTLER_OF_TYPE(FOE(battlerAtk), TYPE_GRASS) && IsBattlerGrounded(FOE(battlerAtk))) + if (IS_BATTLER_OF_TYPE(LEFT_FOE(battlerAtk), TYPE_GRASS) && AI_IsBattlerGrounded(LEFT_FOE(battlerAtk))) { - if (aiData->abilities[FOE(battlerAtk)] == ABILITY_CONTRARY) + if (aiData->abilities[LEFT_FOE(battlerAtk)] == ABILITY_CONTRARY) ADJUST_SCORE(WEAK_EFFECT); else ADJUST_SCORE(AWFUL_EFFECT); } - if (IS_BATTLER_OF_TYPE(BATTLE_PARTNER(FOE(battlerAtk)), TYPE_GRASS) && IsBattlerGrounded(BATTLE_PARTNER(FOE(battlerAtk)))) + if (IS_BATTLER_OF_TYPE(RIGHT_FOE(battlerAtk), TYPE_GRASS) && AI_IsBattlerGrounded(RIGHT_FOE(battlerAtk))) { - if (aiData->abilities[BATTLE_PARTNER(FOE(battlerAtk))] == ABILITY_CONTRARY) + if (aiData->abilities[RIGHT_FOE(battlerAtk)] == ABILITY_CONTRARY) ADJUST_SCORE(WEAK_EFFECT); else ADJUST_SCORE(AWFUL_EFFECT); } break; + case EFFECT_FLOWER_SHIELD: + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GRASS)) + { + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF)); + } + if (hasPartner && IS_BATTLER_OF_TYPE(BATTLE_PARTNER(battlerAtk), TYPE_GRASS)) + { + ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, STAT_CHANGE_DEF)); + } + if (IS_BATTLER_OF_TYPE(LEFT_FOE(battlerAtk), TYPE_GRASS)) + { + if (aiData->abilities[LEFT_FOE(battlerAtk)] == ABILITY_CONTRARY) + ADJUST_SCORE(WEAK_EFFECT); + else + ADJUST_SCORE(AWFUL_EFFECT); + } + if (IS_BATTLER_OF_TYPE(RIGHT_FOE(battlerAtk), TYPE_GRASS)) + { + if (aiData->abilities[RIGHT_FOE(battlerAtk)] == ABILITY_CONTRARY) + ADJUST_SCORE(WEAK_EFFECT); + else + ADJUST_SCORE(AWFUL_EFFECT); + } + break; case EFFECT_HAZE: if (AnyStatIsRaised(BATTLE_PARTNER(battlerAtk)) || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) @@ -4238,7 +4366,13 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case EFFECT_CONVERSION: if (!IS_BATTLER_OF_TYPE(battlerAtk, GetMoveType(gBattleMons[battlerAtk].moves[0]))) + { ADJUST_SCORE(WEAK_EFFECT); + if (aiData->abilities[battlerAtk] == ABILITY_ADAPTABILITY) + ADJUST_SCORE(WEAK_EFFECT); + if (IsConsideringZMove(battlerAtk, battlerDef, move)) + ADJUST_SCORE(BEST_EFFECT); + } break; case EFFECT_SWALLOW: if (gDisableStructs[battlerAtk].stockpileCounter == 0) @@ -4276,6 +4410,12 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (ShouldRecover(battlerAtk, battlerDef, move, 50)) ADJUST_SCORE(GOOD_EFFECT); break; + case EFFECT_LIFE_DEW: + if (ShouldRecover(battlerAtk, battlerDef, move, 25)) + ADJUST_SCORE(GOOD_EFFECT); + if (ShouldRecover(BATTLE_PARTNER(battlerAtk), battlerDef, move, 25)) + ADJUST_SCORE(GOOD_EFFECT); + break; case EFFECT_LIGHT_SCREEN: case EFFECT_REFLECT: case EFFECT_AURORA_VEIL: @@ -4332,9 +4472,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_MIMIC: if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) { - if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF - && (GetMoveEffect(gLastMoves[battlerDef]) != GetMoveEffect(move))) - return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); + if (aiData->lastUsedMove[battlerDef] != MOVE_NONE + && (GetMoveEffect(aiData->lastUsedMove[battlerDef]) != GetMoveEffect(move))) + return AI_CheckViability(battlerAtk, battlerDef, aiData->lastUsedMove[battlerDef], score); } break; case EFFECT_LEECH_SEED: @@ -4346,7 +4486,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; ADJUST_SCORE(GOOD_EFFECT); if (!HasDamagingMove(battlerDef) - || (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef)) + || IsBattlerTrapped(battlerAtk, battlerDef) || aiData->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT) ADJUST_SCORE(DECENT_EFFECT); break; @@ -4354,7 +4494,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_HOLD_HANDS: case EFFECT_CELEBRATE: case EFFECT_HAPPY_HOUR: - //todo - check z splash, z celebrate, z happy hour (lol) + case EFFECT_LAST_RESORT: + if (IsConsideringZMove(battlerAtk, battlerDef, move)) + ADJUST_SCORE(BEST_EFFECT); break; case EFFECT_TELEPORT: // Either remove or add better logic if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) || !IsOnPlayerSide(battlerAtk)) @@ -4387,7 +4529,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case EFFECT_BATON_PASS: - if ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].volatiles.substitute + if ((aiData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].volatiles.substitute || gBattleMons[battlerAtk].volatiles.powerTrick || gBattleMons[battlerAtk].volatiles.magnetRise || gBattleMons[battlerAtk].volatiles.aquaRing @@ -4399,12 +4541,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) break; else if (gDisableStructs[battlerDef].disableTimer == 0 - && (gLastMoves[battlerDef] != MOVE_NONE) - && (gLastMoves[battlerDef] != 0xFFFF) + && (aiData->lastUsedMove[battlerDef] != MOVE_NONE) && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY))) { - if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1)) + if (CanTargetMoveFaintAi(aiData->lastUsedMove[battlerDef], battlerDef, battlerAtk, 1)) ADJUST_SCORE(GOOD_EFFECT); // Disable move that can kill attacker } break; @@ -4413,9 +4554,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) break; - bool32 encourage = gBattleMoveEffects[GetMoveEffect(gLastMoves[battlerDef])].encourageEncore; + bool32 encourage = gBattleMoveEffects[GetMoveEffect(aiData->lastUsedMove[battlerDef])].encourageEncore; - switch(GetMoveNonVolatileStatus(gLastMoves[battlerDef])) + switch(GetMoveNonVolatileStatus(aiData->lastUsedMove[battlerDef])) { case MOVE_EFFECT_POISON: case MOVE_EFFECT_PARALYSIS: @@ -4436,7 +4577,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_LOCK_ON: if (HasMoveWithEffect(battlerAtk, EFFECT_OHKO) || HasMoveWithEffect(battlerAtk, EFFECT_SHEER_COLD)) ADJUST_SCORE(GOOD_EFFECT); - else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 85, TRUE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef])) + else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 85, TRUE)) ADJUST_SCORE(GOOD_EFFECT); break; case EFFECT_DESTINY_BOND: @@ -4453,10 +4594,19 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (ShouldUseWishAromatherapy(battlerAtk, battlerDef, move)) ADJUST_SCORE(DECENT_EFFECT); break; + case EFFECT_PURIFY: + if (gBattleMons[battlerDef].status1 & STATUS1_ANY) + { + if (ShouldCureStatus(battlerAtk, battlerDef, aiData)) + ADJUST_SCORE(GOOD_EFFECT); + if (ShouldRecover(battlerAtk, battlerDef, move, 50)) + RETURN_SCORE_PLUS(WEAK_EFFECT); + } + break; case EFFECT_CURSE: if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) { - if (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef)) + if (IsBattlerTrapped(battlerAtk, battlerDef)) ADJUST_SCORE(GOOD_EFFECT); else ADJUST_SCORE(WEAK_EFFECT); @@ -4468,7 +4618,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case EFFECT_PROTECT: - if (predictedMove == 0xFFFF) + if (predictedMove == MOVE_UNAVAILABLE) predictedMove = MOVE_NONE; enum ProtectMethod protectMethod = GetMoveProtectMethod(move); switch (protectMethod) @@ -4554,7 +4704,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_PERISH_SONG: - if (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef)) + if (IsBattlerTrapped(battlerAtk, battlerDef)) ADJUST_SCORE(GOOD_EFFECT); break; case EFFECT_SANDSTORM: @@ -4713,19 +4863,19 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; // Don't use if the attract won't have a change to activate if (gBattleMons[battlerDef].status1 & STATUS1_ANY || gBattleMons[battlerDef].volatiles.confusionTurns > 0 - || (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef))) + || IsBattlerTrapped(battlerAtk, battlerDef)) ADJUST_SCORE(GOOD_EFFECT); else ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_SAFEGUARD: - if (!IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_MISTY_TERRAIN) || !IsBattlerGrounded(battlerAtk)) + if (!IsBattlerTerrainAffected(battlerAtk, aiData->abilities[battlerAtk], aiData->holdEffects[battlerAtk], STATUS_FIELD_MISTY_TERRAIN) || !AI_IsBattlerGrounded(battlerAtk)) ADJUST_SCORE(DECENT_EFFECT); // TODO: check if opp has status move? //if (CountUsablePartyMons(battlerDef) != 0) //ADJUST_SCORE(8); break; case EFFECT_COURT_CHANGE: - if (gSideStatuses[GetBattlerSide(FOE(battlerAtk))] & SIDE_STATUS_GOOD_COURT) + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_GOOD_COURT) ADJUST_SCORE(WEAK_EFFECT); if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_BAD_COURT) ADJUST_SCORE(WEAK_EFFECT); @@ -4771,7 +4921,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) && (!IsPowderMove(move) || IsAffectedByPowderMove(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))) // Rage Powder doesn't affect powder immunities { - u32 predictedMoveOnPartner = gLastMoves[BATTLE_PARTNER(battlerAtk)]; + u32 predictedMoveOnPartner = aiData->lastUsedMove[BATTLE_PARTNER(battlerAtk)]; if (predictedMoveOnPartner != MOVE_NONE && !IsBattleMoveStatus(predictedMoveOnPartner)) ADJUST_SCORE(GOOD_EFFECT); } @@ -4816,7 +4966,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(DECENT_EFFECT); break; case HOLD_EFFECT_IRON_BALL: - if (!HasMoveWithEffect(battlerDef, EFFECT_FLING) || !IsBattlerGrounded(battlerDef)) + if (!HasMoveWithEffect(battlerDef, EFFECT_FLING) || !AI_IsBattlerGrounded(battlerDef)) ADJUST_SCORE(DECENT_EFFECT); break; case HOLD_EFFECT_LAGGING_TAIL: @@ -4837,6 +4987,8 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (AI_GetWeather() & B_WEATHER_SUN) ADJUST_SCORE(DECENT_EFFECT); // Slow 'em down break; + default: + break; } } break; @@ -4907,19 +5059,19 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(GOOD_EFFECT); break; case EFFECT_RECYCLE: - if (GetUsedHeldItem(battlerAtk) != ITEM_NONE) + if (GetBattlerPartyState(battlerAtk)->usedHeldItem != ITEM_NONE) ADJUST_SCORE(WEAK_EFFECT); - if (IsRecycleEncouragedItem(GetUsedHeldItem(battlerAtk))) + if (IsRecycleEncouragedItem(GetBattlerPartyState(battlerAtk)->usedHeldItem)) ADJUST_SCORE(WEAK_EFFECT); if (aiData->abilities[battlerAtk] == ABILITY_RIPEN) { - u32 item = GetUsedHeldItem(battlerAtk); + u32 item = GetBattlerPartyState(battlerAtk)->usedHeldItem; u32 toHeal = (GetItemHoldEffectParam(item) == 10) ? 10 : gBattleMons[battlerAtk].maxHP / GetItemHoldEffectParam(item); if (IsStatBoostingBerry(item) && aiData->hpPercents[battlerAtk] > 60) ADJUST_SCORE(WEAK_EFFECT); else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0) - && ((GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) == 1 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) + && ((AI_GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) == 1 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0)) || !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toHeal, 0))) ADJUST_SCORE(WEAK_EFFECT); // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry } @@ -4937,10 +5089,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: - AbilityChangeScore(battlerAtk, battlerDef, moveEffect, &score, aiData); + case EFFECT_OVERWRITE_ABILITY: + AbilityChangeScore(battlerAtk, battlerDef, move, &score, aiData); return score; case EFFECT_IMPRISON: if (predictedMove != MOVE_NONE && HasMove(battlerAtk, predictedMove)) @@ -5122,7 +5273,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_ELECTRIC_TERRAIN)) { ADJUST_SCORE(GOOD_EFFECT); - if (gBattleMons[battlerAtk].volatiles.yawn && IsBattlerGrounded(battlerAtk)) + if (gBattleMons[battlerAtk].volatiles.yawn && AI_IsBattlerGrounded(battlerAtk)) ADJUST_SCORE(BEST_EFFECT); if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_TERRAIN_EXTENDER || HasBattlerSideMoveWithEffect(battlerAtk, EFFECT_TERRAIN_PULSE)) ADJUST_SCORE(WEAK_EFFECT); @@ -5132,7 +5283,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_MISTY_TERRAIN)) { ADJUST_SCORE(GOOD_EFFECT); - if (gBattleMons[battlerAtk].volatiles.yawn && IsBattlerGrounded(battlerAtk)) + if (gBattleMons[battlerAtk].volatiles.yawn && AI_IsBattlerGrounded(battlerAtk)) ADJUST_SCORE(BEST_EFFECT); if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_TERRAIN_EXTENDER || HasBattlerSideMoveWithEffect(battlerAtk, EFFECT_TERRAIN_PULSE)) ADJUST_SCORE(WEAK_EFFECT); @@ -5185,7 +5336,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) else if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && !hasPartner && (CountUsablePartyMons(battlerAtk) != 0)) ADJUST_SCORE(DECENT_EFFECT); // Don't unset it on last turn. - else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1) && ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) + else if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1 && ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_TRICK_ROOM)) ADJUST_SCORE(GOOD_EFFECT); } break; @@ -5202,11 +5353,16 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_GRAVITY: - if (!(gFieldStatuses & STATUS_FIELD_GRAVITY)) + if (!(gFieldStatuses & STATUS_FIELD_GRAVITY || ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_GRAVITY))) { - if (HasSleepMoveWithLowAccuracy(battlerAtk, battlerDef)) // Has Gravity for a move like Hypnosis + // improve accuracy of Hypnosis + if (HasSleepMoveWithLowAccuracy(battlerAtk, battlerDef) + || HasSleepMoveWithLowAccuracy(BATTLE_PARTNER(battlerAtk), battlerDef)) IncreaseSleepScore(battlerAtk, battlerDef, move, &score); - if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef])) + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE) + || HasMoveWithLowAccuracy(BATTLE_PARTNER(battlerAtk), battlerDef, 90, TRUE)) + ADJUST_SCORE(WEAK_EFFECT); + if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_GRAVITY)) ADJUST_SCORE(DECENT_EFFECT); } break; @@ -5249,8 +5405,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_TELEKINESIS: - if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef]) - || !IsBattlerGrounded(battlerDef)) + if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, FALSE) || !AI_IsBattlerGrounded(battlerDef)) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_HEAL_BLOCK: @@ -5293,7 +5448,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case EFFECT_TAILWIND: { - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer != (gBattleTurnCounter + 1)) + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1) break; if (HasBattlerSideMoveWithEffect(battlerAtk, EFFECT_ELECTRO_BALL)) @@ -5312,8 +5467,8 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) u32 tailwindScore = 0; u32 speed = aiData->speedStats[battlerAtk]; u32 partnerSpeed = aiData->speedStats[BATTLE_PARTNER(battlerAtk)]; - u32 foe1Speed = aiData->speedStats[FOE(battlerAtk)]; - u32 foe2Speed = aiData->speedStats[BATTLE_PARTNER(FOE(battlerAtk))]; + u32 foe1Speed = aiData->speedStats[LEFT_FOE(battlerAtk)]; + u32 foe2Speed = aiData->speedStats[RIGHT_FOE(battlerAtk)]; if (speed <= foe1Speed && (speed * 2) > foe1Speed) tailwindScore += 1; @@ -5336,7 +5491,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(GOOD_EFFECT); break; case EFFECT_MAGNET_RISE: - if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC) + if (AI_IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC) && !(effectiveness == UQ_4_12(0.0))) // Doesn't resist ground move { if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) // Attacker goes first @@ -5388,9 +5543,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (GetFirstFaintedPartyIndex(battlerAtk) != PARTY_SIZE) { ADJUST_SCORE(DECENT_EFFECT); - if (gAiLogicData->shouldSwitch & (1u << battlerAtk)) // Bad matchup + if (aiData->shouldSwitch & (1u << battlerAtk)) // Bad matchup ADJUST_SCORE(WEAK_EFFECT); - if (gAiLogicData->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after + if (aiData->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after ADJUST_SCORE(WEAK_EFFECT); } break; @@ -5418,7 +5573,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(AI_ShouldCopyStatChanges(battlerAtk, battlerDef)); break; case EFFECT_SMACK_DOWN: - if (!IsBattlerGrounded(battlerDef) && HasDamagingMoveOfType(battlerAtk, TYPE_GROUND) && !CanTargetFaintAi(battlerDef, battlerAtk)) + if (!AI_IsBattlerGrounded(battlerDef) && HasDamagingMoveOfType(battlerAtk, TYPE_GROUND) && !CanTargetFaintAi(battlerDef, battlerAtk)) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_KNOCK_OFF: @@ -5496,11 +5651,30 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; } // move effect checks + return score; +} + +static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) +{ + // move data + s32 score = 0; + + u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, aiData); + bool32 hasPartner = HasPartner(battlerAtk); + u32 i; u32 additionalEffectCount = GetMoveAdditionalEffectCount(move); + // check move additional effects that are likely to happen for (i = 0; i < additionalEffectCount; i++) { const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i); + + if (aiData->abilities[battlerAtk] == ABILITY_SHEER_FORCE) + { + if ((additionalEffect->chance > 0) != additionalEffect->sheerForceOverride) + continue; + } + // Only consider effects with a guaranteed chance to happen if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], additionalEffect)) continue; @@ -5600,32 +5774,74 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case MOVE_EFFECT_SPD_MINUS_1: case MOVE_EFFECT_SPD_MINUS_2: - ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_SPEED)); + if (CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPEED)) + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_SPEED)); + break; + case MOVE_EFFECT_ACC_MINUS_1: + case MOVE_EFFECT_ACC_MINUS_2: + if (CanLowerStat(battlerAtk, battlerDef, aiData, STAT_ACC)) + { + u32 scoreIncrease = IncreaseStatDownScore(battlerAtk, battlerDef, STAT_ACC); + if (scoreIncrease == WEAK_EFFECT) + scoreIncrease = DECENT_EFFECT; + ADJUST_SCORE(scoreIncrease); + } break; case MOVE_EFFECT_ATK_MINUS_1: case MOVE_EFFECT_DEF_MINUS_1: case MOVE_EFFECT_SP_ATK_MINUS_1: case MOVE_EFFECT_SP_DEF_MINUS_1: - case MOVE_EFFECT_ACC_MINUS_1: case MOVE_EFFECT_EVS_MINUS_1: - if (aiData->abilities[battlerDef] != ABILITY_CONTRARY) - ADJUST_SCORE(DECENT_EFFECT); + { + u32 statId = STAT_ATK + additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1; + if (CanLowerStat(battlerAtk, battlerDef, aiData, statId)) + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, statId)); break; + } case MOVE_EFFECT_ATK_MINUS_2: case MOVE_EFFECT_DEF_MINUS_2: case MOVE_EFFECT_SP_ATK_MINUS_2: case MOVE_EFFECT_SP_DEF_MINUS_2: - case MOVE_EFFECT_ACC_MINUS_2: case MOVE_EFFECT_EVS_MINUS_2: - if (aiData->abilities[battlerDef] != ABILITY_CONTRARY) - ADJUST_SCORE(DECENT_EFFECT); + { + u32 statId = STAT_ATK + additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2; + if (CanLowerStat(battlerAtk, battlerDef, aiData, statId)) + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, statId)); break; + } + case MOVE_EFFECT_RAISE_TEAM_ATTACK: + case MOVE_EFFECT_RAISE_TEAM_DEFENSE: + case MOVE_EFFECT_RAISE_TEAM_SPEED: + case MOVE_EFFECT_RAISE_TEAM_SP_ATK: + case MOVE_EFFECT_RAISE_TEAM_SP_DEF: + { + enum StatChange StageStatId = STAT_CHANGE_ATK + additionalEffect->moveEffect - MOVE_EFFECT_RAISE_TEAM_ATTACK; + ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, StageStatId)); + if (hasPartner) + ADJUST_SCORE(IncreaseStatUpScore(BATTLE_PARTNER(battlerAtk), battlerDef, StageStatId)); + break; + } + case MOVE_EFFECT_LOWER_ATTACK_SIDE: + case MOVE_EFFECT_LOWER_DEFENSE_SIDE: + case MOVE_EFFECT_LOWER_SPEED_SIDE: + case MOVE_EFFECT_LOWER_SP_ATK_SIDE: + case MOVE_EFFECT_LOWER_SP_DEF_SIDE: + { + u32 statId = STAT_ATK + additionalEffect->moveEffect - MOVE_EFFECT_LOWER_ATTACK_SIDE; + if (CanLowerStat(battlerAtk, battlerDef, aiData, statId)) + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, statId)); + break; + } case MOVE_EFFECT_POISON: IncreasePoisonScore(battlerAtk, battlerDef, move, &score); break; case MOVE_EFFECT_CLEAR_SMOG: + { + bool32 moveTargetsBothOpponents = HasTwoOpponents(battlerAtk) && (gMovesInfo[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_ALL_BATTLERS)); + score += AI_TryToClearStats(battlerAtk, battlerDef, moveTargetsBothOpponents); break; + } case MOVE_EFFECT_BUG_BITE: // And pluck if (gBattleMons[battlerDef].volatiles.substitute || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) break; @@ -5654,6 +5870,8 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case MOVE_EFFECT_THROAT_CHOP: if (IsSoundMove(GetBestDmgMoveFromBattler(battlerDef, battlerAtk, AI_DEFENDING))) { + u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, aiData); + if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) ADJUST_SCORE(GOOD_EFFECT); else @@ -5668,18 +5886,102 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_WATER) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL)) ADJUST_SCORE(DECENT_EFFECT); break; + case MOVE_EFFECT_SUN: + if (ShouldSetWeather(battlerAtk, B_WEATHER_SUN)) + ADJUST_SCORE(DECENT_EFFECT); + if (ShouldClearWeather(battlerAtk, B_WEATHER_SUN)) + ADJUST_SCORE(BAD_EFFECT); + break; + case MOVE_EFFECT_RAIN: + if (ShouldSetWeather(battlerAtk, B_WEATHER_RAIN)) + ADJUST_SCORE(DECENT_EFFECT); + if (ShouldClearWeather(battlerAtk, B_WEATHER_RAIN)) + ADJUST_SCORE(BAD_EFFECT); + break; + case MOVE_EFFECT_SANDSTORM: + if (ShouldSetWeather(battlerAtk, B_WEATHER_SANDSTORM)) + ADJUST_SCORE(DECENT_EFFECT); + if (ShouldClearWeather(battlerAtk, B_WEATHER_SANDSTORM)) + ADJUST_SCORE(BAD_EFFECT); + break; + case MOVE_EFFECT_HAIL: + if (ShouldSetWeather(battlerAtk, B_WEATHER_HAIL)) + ADJUST_SCORE(DECENT_EFFECT); + if (ShouldClearWeather(battlerAtk, B_WEATHER_HAIL)) + ADJUST_SCORE(BAD_EFFECT); + break; + case MOVE_EFFECT_MISTY_TERRAIN: + if (ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_MISTY_TERRAIN)) + { + ADJUST_SCORE(BAD_EFFECT); + break; + } + if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_MISTY_TERRAIN) + || ShouldClearFieldStatus(battlerAtk, gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_GRASSY_TERRAIN: + if (ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_GRASSY_TERRAIN)) + { + ADJUST_SCORE(BAD_EFFECT); + break; + } + if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_GRASSY_TERRAIN) + || ShouldClearFieldStatus(battlerAtk, gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_ELECTRIC_TERRAIN: + if (ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_ELECTRIC_TERRAIN)) + { + ADJUST_SCORE(BAD_EFFECT); + break; + } + if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_ELECTRIC_TERRAIN) + || ShouldClearFieldStatus(battlerAtk, gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_PSYCHIC_TERRAIN: + if (ShouldClearFieldStatus(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN)) + { + ADJUST_SCORE(BAD_EFFECT); + break; + } + if (ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) + || ShouldClearFieldStatus(battlerAtk, gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_GRAVITY: + if (!(gFieldStatuses & STATUS_FIELD_GRAVITY) && ShouldSetFieldStatus(battlerAtk, STATUS_FIELD_GRAVITY)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_AURORA_VEIL: + if (ShouldSetScreen(battlerAtk, battlerDef, EFFECT_AURORA_VEIL)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case MOVE_EFFECT_REMOVE_STATUS: + if (gBattleMons[battlerDef].status1 & GetMoveEffectArg_Status(move)) + { + if (ShouldCureStatus(battlerAtk, battlerDef, aiData)) + ADJUST_SCORE(DECENT_EFFECT); + else if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_FLAME_ORB || aiData->holdEffects[battlerDef] == HOLD_EFFECT_TOXIC_ORB) + ADJUST_SCORE(WEAK_EFFECT); + else + ADJUST_SCORE(BAD_EFFECT); + } + break; default: break; } } } - return score; } // AI_FLAG_CHECK_VIABILITY - Chooses best possible move to hit player static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { + struct AiLogicData *aiData = gAiLogicData; + // Targeting partner, check benefits of doing that instead if (IsTargetingPartner(battlerAtk, battlerDef)) return score; @@ -5696,8 +5998,9 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score } } - ADJUST_SCORE(AI_CalcMoveEffectScore(battlerAtk, battlerDef, move)); - ADJUST_SCORE(AI_CalcHoldEffectMoveScore(battlerAtk, battlerDef, move)); + ADJUST_SCORE(AI_CalcMoveEffectScore(battlerAtk, battlerDef, move, aiData)); + ADJUST_SCORE(AI_CalcAdditionalEffectScore(battlerAtk, battlerDef, move, aiData)); + ADJUST_SCORE(AI_CalcHoldEffectMoveScore(battlerAtk, battlerDef, move, aiData)); return score; } @@ -5921,7 +6224,7 @@ static s32 AI_AttacksPartner(u32 battlerAtk, u32 battlerDef, u32 move, s32 score u32 hitsToKO = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING); if (GetMoveTarget(move) == MOVE_TARGET_FOES_AND_ALLY && hitsToKO > 0 && - (GetNoOfHitsToKOBattler(battlerAtk, FOE(battlerAtk), gAiThinkingStruct->movesetIndex, AI_ATTACKING) > 0 || GetNoOfHitsToKOBattler(battlerAtk, FOE(battlerDef), gAiThinkingStruct->movesetIndex, AI_ATTACKING) > 0)) + (GetNoOfHitsToKOBattler(battlerAtk, LEFT_FOE(battlerAtk), gAiThinkingStruct->movesetIndex, AI_ATTACKING) > 0 || GetNoOfHitsToKOBattler(battlerAtk, LEFT_FOE(battlerDef), gAiThinkingStruct->movesetIndex, AI_ATTACKING) > 0)) ADJUST_SCORE(BEST_EFFECT); if (hitsToKO > 0) @@ -5937,7 +6240,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor || CountUsablePartyMons(battlerAtk) == 0 || !IsBattleMoveStatus(move) || !HasMoveWithEffect(battlerAtk, EFFECT_BATON_PASS) - || (!AI_CanBattlerEscape(battlerAtk) && IsBattlerTrapped(battlerDef, battlerAtk))) + || IsBattlerTrapped(battlerAtk, battlerDef)) return score; enum BattleMoveEffects effect = GetMoveEffect(move); @@ -5964,7 +6267,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_PROTECT: - if (GetProtectType(GetMoveProtectMethod(gLastMoves[battlerAtk])) == PROTECT_TYPE_SINGLE) + if (GetProtectType(GetMoveProtectMethod(gAiLogicData->lastUsedMove[battlerAtk])) == PROTECT_TYPE_SINGLE) ADJUST_SCORE(-2); else ADJUST_SCORE(DECENT_EFFECT); @@ -5986,7 +6289,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { enum BattleMoveEffects effect = GetMoveEffect(move); - u32 moveType = 0; + enum Type moveType = 0; SetTypeBeforeUsingMove(move, battlerAtk); moveType = GetBattleMoveType(move); @@ -6001,8 +6304,8 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (gBattleMons[battlerDef].volatiles.healBlock) return 0; - if (CanTargetFaintAi(FOE(battlerAtk), BATTLE_PARTNER(battlerAtk)) - || (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), BATTLE_PARTNER(battlerAtk)))) + if (CanTargetFaintAi(LEFT_FOE(battlerAtk), BATTLE_PARTNER(battlerAtk)) + || CanTargetFaintAi(RIGHT_FOE(battlerAtk), BATTLE_PARTNER(battlerAtk))) ADJUST_SCORE(-1); if (gAiLogicData->hpPercents[battlerDef] <= 50) @@ -6295,7 +6598,7 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { u32 i; u32 unmodifiedScore = score; - u32 ability = gBattleMons[battlerAtk].ability; + enum Ability ability = gBattleMons[battlerAtk].ability; bool32 opposingHazardFlags = DoesSideHaveDamagingHazards(GetBattlerSide(battlerDef)); bool32 aiHazardFlags = AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)); enum BattleMoveEffects moveEffect = GetMoveEffect(move); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 02cc668d14..b1e61e3493 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -7,7 +7,6 @@ #include "battle_anim.h" #include "battle_controllers.h" #include "battle_main.h" -#include "constants/hold_effects.h" #include "battle_setup.h" #include "data.h" #include "item.h" @@ -29,7 +28,7 @@ static bool32 AiExpectsToFaintPlayer(u32 battler); static bool32 AI_ShouldHeal(u32 battler, u32 healAmount); static bool32 AI_OpponentCanFaintAiWithMod(u32 battler, u32 healAmount); static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon); -static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent); +static bool32 CanAbilityTrapOpponent(enum Ability ability, u32 opponent); static u32 GetHPHealAmount(u8 itemEffectParam, struct Pokemon *mon); static u32 GetBattleMonTypeMatchup(struct BattlePokemon opposingBattleMon, struct BattlePokemon battleMon); @@ -165,7 +164,7 @@ static bool32 AI_DoesChoiceEffectBlockMove(u32 battler, u32 move) { // Choice locked into something else if (gAiLogicData->lastUsedMove[battler] != MOVE_NONE && gAiLogicData->lastUsedMove[battler] != move - && ((IsHoldEffectChoice(GetBattlerHoldEffect(battler, FALSE)) && IsBattlerItemEnabled(battler)) + && (IsHoldEffectChoice(GetBattlerHoldEffect(battler) && IsBattlerItemEnabled(battler)) || gBattleMons[battler].ability == ABILITY_GORILLA_TACTICS)) return TRUE; return FALSE; @@ -276,7 +275,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) if (!IsBattleMoveStatus(aiMove) && !AI_DoesChoiceEffectBlockMove(battler, aiMove)) { // Check if mon has a super effective move - if (AI_GetMoveEffectiveness(aiMove, battler, opposingBattler) >= UQ_4_12(2.0)) + if (gAiLogicData->effectiveness[battler][opposingBattler][i] >= UQ_4_12(2.0)) hasSuperEffectiveMove = TRUE; // Get maximum damage mon can deal @@ -408,9 +407,10 @@ static bool32 ShouldSwitchIfAllMovesBad(u32 battler) for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { aiMove = gBattleMons[battler].moves[moveIndex]; - if ((AI_GetMoveEffectiveness(aiMove, battler, opposingBattler) > UQ_4_12(0.0) - || AI_GetMoveEffectiveness(aiMove, battler, opposingPartner) > UQ_4_12(0.0)) - && aiMove != MOVE_NONE) + if (aiMove == MOVE_NONE) + continue; + if (gAiLogicData->effectiveness[battler][opposingBattler][moveIndex] > UQ_4_12(0.0) + || gAiLogicData->effectiveness[battler][opposingPartner][moveIndex] > UQ_4_12(0.0)) return FALSE; } } @@ -419,7 +419,7 @@ static bool32 ShouldSwitchIfAllMovesBad(u32 battler) for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { aiMove = gBattleMons[battler].moves[moveIndex]; - if (AI_GetMoveEffectiveness(aiMove, battler, opposingBattler) > UQ_4_12(0.0) && aiMove != MOVE_NONE + if (gAiLogicData->effectiveness[battler][opposingBattler][moveIndex] > UQ_4_12(0.0) && aiMove != MOVE_NONE && !CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], aiMove, GetBattleMoveType(aiMove), AI_CHECK) && !CanAbilityBlockMove(battler, opposingBattler, gBattleMons[battler].ability, gAiLogicData->abilities[opposingBattler], aiMove, AI_CHECK) && (!ALL_MOVES_BAD_STATUS_MOVES_BAD || GetMovePower(aiMove) != 0)) // If using ALL_MOVES_BAD_STATUS_MOVES_BAD, then need power to be non-zero @@ -441,7 +441,7 @@ static bool32 ShouldSwitchIfAllMovesBad(u32 battler) static bool32 ShouldSwitchIfWonderGuard(u32 battler) { u32 opposingBattler = GetOppositeBattler(battler); - u32 i, move; + u32 i; if (IsDoubleBattle()) return FALSE; @@ -452,12 +452,8 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler) // Check if Pokémon has a super effective move. for (i = 0; i < MAX_MON_MOVES; i++) { - move = gBattleMons[battler].moves[i]; - if (move != MOVE_NONE) - { - if (AI_GetMoveEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0)) - return FALSE; - } + if (gBattleMons[battler].moves[i] != MOVE_NONE && gAiLogicData->effectiveness[battler][opposingBattler][i] >= UQ_4_12(2.0)) + return FALSE; } if (RandomPercentage(RNG_AI_SWITCH_WONDER_GUARD, GetSwitchChance(SHOULD_SWITCH_WONDER_GUARD))) @@ -475,14 +471,15 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) { u8 battlerIn1, battlerIn2; u8 numAbsorbingAbilities = 0; - u16 absorbingTypeAbilities[3]; // Array size is maximum number of absorbing abilities for a single type + enum Ability absorbingTypeAbilities[3]; // Array size is maximum number of absorbing abilities for a single type s32 firstId; s32 lastId; struct Pokemon *party; - u16 monAbility, aiMove; + enum Ability monAbility; + u16 aiMove; u32 opposingBattler = GetOppositeBattler(battler); u32 incomingMove = GetIncomingMove(battler, opposingBattler, gAiLogicData); - u32 incomingType = CheckDynamicMoveType(GetBattlerMon(opposingBattler), incomingMove, opposingBattler, MON_IN_BATTLE); + enum Type incomingType = CheckDynamicMoveType(GetBattlerMon(opposingBattler), incomingMove, opposingBattler, MON_IN_BATTLE); bool32 isOpposingBattlerChargingOrInvulnerable = !BreaksThroughSemiInvulnerablity(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove); s32 i, j; @@ -621,6 +618,7 @@ static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler) if (IsDoubleBattle() || !(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) return FALSE; + // In a world with a unified ShouldSwitch function, also want to check whether we already win 1v1 and if we do don't switch; not worth doubling the HasBadOdds computation for now if (isOpposingBattlerChargingOrInvulnerable && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); @@ -633,7 +631,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) s32 lastId; struct Pokemon *party; s32 i; - u16 monAbility; + enum Ability monAbility; s32 opposingBattler = GetOppositeBattler(battler); // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer @@ -658,7 +656,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) if (CanAbilityTrapOpponent(monAbility, opposingBattler) || (CanAbilityTrapOpponent(gAiLogicData->abilities[opposingBattler], opposingBattler) && monAbility == ABILITY_TRACE)) { // If mon in slot i is the most suitable switchin candidate, then it's a trapper than wins 1v1 - if (i == gAiLogicData->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) + if (i == gAiLogicData->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_TRAPPER, GetSwitchChance(SHOULD_SWITCH_TRAPPER))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } } @@ -668,8 +666,8 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) static bool32 ShouldSwitchIfBadlyStatused(u32 battler) { bool32 switchMon = FALSE; - u16 monAbility = gAiLogicData->abilities[battler]; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; + enum Ability monAbility = gAiLogicData->abilities[battler]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler]; u8 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); u8 opposingBattler = GetBattlerAtPosition(opposingPosition); bool32 hasStatRaised = AnyStatIsRaised(battler); @@ -706,8 +704,8 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) || monAbility == ABILITY_EARLY_BIRD) || holdEffect == (HOLD_EFFECT_CURE_SLP | HOLD_EFFECT_CURE_STATUS) || HasMove(battler, MOVE_SLEEP_TALK) - || (HasMoveWithEffect(battler, MOVE_SNORE) && AI_GetMoveEffectiveness(MOVE_SNORE, battler, opposingBattler) >= UQ_4_12(2.0)) - || (IsBattlerGrounded(battler) + || (HasMove(battler, MOVE_SNORE) && gAiLogicData->effectiveness[battler][opposingBattler][GetIndexInMoveArray(battler, MOVE_SNORE)] >= UQ_4_12(2.0)) + || (IsBattlerGrounded(battler, monAbility, gAiLogicData->holdEffects[battler]) && (HasMove(battler, MOVE_MISTY_TERRAIN) || HasMove(battler, MOVE_ELECTRIC_TERRAIN))) ) switchMon = FALSE; @@ -830,10 +828,8 @@ static bool32 CanUseSuperEffectiveMoveAgainstOpponents(u32 battler) if (move == MOVE_NONE || AI_DoesChoiceEffectBlockMove(battler, move)) continue; - if (AI_GetMoveEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0)) - { + if (gAiLogicData->effectiveness[battler][opposingBattler][i] >= UQ_4_12(2.0)) return TRUE; - } } } if (!IsDoubleBattle()) @@ -849,10 +845,8 @@ static bool32 CanUseSuperEffectiveMoveAgainstOpponents(u32 battler) if (move == MOVE_NONE || AI_DoesChoiceEffectBlockMove(battler, move)) continue; - if (AI_GetMoveEffectiveness(move, battler, opposingBattler) >= UQ_4_12(2.0)) - { + if (gAiLogicData->effectiveness[battler][opposingBattler][i] >= UQ_4_12(2.0)) return TRUE; - } } } @@ -900,7 +894,8 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc for (i = firstId; i < lastId; i++) { - u16 species, monAbility; + u16 species; + enum Ability monAbility; uq4_12_t typeMultiplier; u16 moveFlags = 0; @@ -928,7 +923,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc for (j = 0; j < MAX_MON_MOVES; j++) { move = GetMonData(&party[i], MON_DATA_MOVE1 + j); - if (move == 0) + if (move == MOVE_NONE) continue; if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= UQ_4_12(2.0) && (RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance) || gAiLogicData->aiPredictionInProgress)) @@ -944,7 +939,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler) { u32 battlerIn1, battlerIn2; u32 hazardDamage = 0, battlerHp = gBattleMons[battler].hp; - u32 ability = gAiLogicData->abilities[battler], aiMove; + enum Ability ability = gAiLogicData->abilities[battler], aiMove; s32 firstId, lastId, i, j; struct Pokemon *party; @@ -1019,7 +1014,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) return SetSwitchinAndSwitch(battler, PARTY_SIZE); // Stay in if effective move - else if (AI_GetMoveEffectiveness(encoredMove, battler, opposingBattler) >= UQ_4_12(2.0)) + else if (gAiLogicData->effectiveness[battler][opposingBattler][GetIndexInMoveArray(battler, encoredMove)] >= UQ_4_12(2.0)) return FALSE; // Switch out 50% of the time otherwise @@ -1031,7 +1026,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) static bool32 ShouldSwitchIfBadChoiceLock(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); u32 lastUsedMove = gAiLogicData->lastUsedMove[battler]; u32 opposingBattler = GetOppositeBattler(battler); bool32 moveAffectsTarget = TRUE; @@ -1356,6 +1351,7 @@ void AI_TrySwitchOrUseItem(u32 battler) if (gAiLogicData->shouldSwitch & (1u << battler) && IsSwitchinValid(battler)) { BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_SWITCH, 0); + SetAIUsingGimmick(battler, NO_GIMMICK); if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE) { s32 monToSwitchId = gAiLogicData->mostSuitableMonId[battler]; @@ -1402,6 +1398,7 @@ void AI_TrySwitchOrUseItem(u32 battler) } else if (ShouldUseItem(battler)) { + SetAIUsingGimmick(battler, NO_GIMMICK); return; } } @@ -1494,8 +1491,8 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva int i, j; int dmg, bestDmg = 0; int bestMonId = PARTY_SIZE; - u32 aiMove; + uq4_12_t effectiveness; // If we couldn't find the best mon in terms of typing, find the one that deals most damage. for (i = firstId; i < lastId; i++) @@ -1509,7 +1506,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove)) { aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j); - dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING); + dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, &effectiveness, AI_ATTACKING); if (bestDmg < dmg) { bestDmg = dmg; @@ -1522,25 +1519,22 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva return bestMonId; } -static u32 GetFirstNonInvalidMon(u32 firstId, u32 lastId, u32 invalidMons, u32 battlerIn1, u32 battlerIn2) +static u32 GetFirstNonInvalidMon(u32 firstId, u32 lastId, u32 invalidMons) { - if (!IsDoubleBattle()) - return PARTY_SIZE; - - if (PARTY_SIZE != gBattleStruct->monToSwitchIntoId[battlerIn1] - && PARTY_SIZE != gBattleStruct->monToSwitchIntoId[battlerIn2]) - return PARTY_SIZE; - - for (u32 chosenMonId = (lastId-1); chosenMonId >= firstId; chosenMonId--) + u32 chosenMonId = PARTY_SIZE; + for (u32 i = (lastId-1); i > firstId; i--) { - if ((1 << (chosenMonId)) & invalidMons) - continue; - return chosenMonId; // first non invalid mon found + if (!((1 << i) & invalidMons)) + { + // first non invalid mon found + chosenMonId = i; + break; + } } - return PARTY_SIZE; + return chosenMonId; } -bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2) +bool32 IsMonGrounded(enum HoldEffect heldItemEffect, enum Ability ability, enum Type type1, enum Type type2) { // List that makes mon not grounded if (type1 == TYPE_FLYING || type2 == TYPE_FLYING || ability == ABILITY_LEVITATE @@ -1559,9 +1553,11 @@ bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2) // Gets hazard damage static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon) { - u8 defType1 = battleMon->types[0], defType2 = battleMon->types[1], tSpikesLayers; + enum Type defType1 = battleMon->types[0], defType2 = battleMon->types[1]; + u8 tSpikesLayers; u16 heldItemEffect = GetItemHoldEffect(battleMon->item); - u32 maxHP = battleMon->maxHP, ability = battleMon->ability, status = battleMon->status1; + u32 maxHP = battleMon->maxHP; + enum Ability ability = battleMon->ability, status = battleMon->status1; u32 spikesDamage = 0, tSpikesDamage = 0, hazardDamage = 0; u32 side = GetBattlerSide(battler); @@ -1590,7 +1586,7 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon && status == 0 && !(gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) && !IsAbilityOnSide(battler, ABILITY_PASTEL_VEIL) - && !IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN) + && !IsBattlerTerrainAffected(battler, ability, gAiLogicData->holdEffects[battler], STATUS_FIELD_MISTY_TERRAIN) && !IsAbilityStatusProtected(battler, ability) && heldItemEffect != HOLD_EFFECT_CURE_PSN && heldItemEffect != HOLD_EFFECT_CURE_STATUS && IsMonGrounded(heldItemEffect, ability, defType1, defType2))) @@ -1617,8 +1613,9 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon // Gets damage / healing from weather static s32 GetSwitchinWeatherImpact(void) { - s32 weatherImpact = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); + s32 weatherImpact = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; + enum Ability ability = gAiLogicData->switchinCandidate.battleMon.ability; + enum HoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); if (HasWeatherEffect()) { @@ -1681,8 +1678,9 @@ static s32 GetSwitchinWeatherImpact(void) // Gets one turn of recurring healing static u32 GetSwitchinRecurringHealing(void) { - u32 recurringHealing = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); + u32 recurringHealing = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; + enum Ability ability = gAiLogicData->switchinCandidate.battleMon.ability; + enum HoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); // Items if (ability != ABILITY_KLUTZ) @@ -1715,8 +1713,9 @@ static u32 GetSwitchinRecurringHealing(void) // Gets one turn of recurring damage static u32 GetSwitchinRecurringDamage(void) { - u32 passiveDamage = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); + u32 passiveDamage = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; + enum Ability ability = gAiLogicData->switchinCandidate.battleMon.ability; + enum HoldEffect holdEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); // Items if (ability != ABILITY_MAGIC_GUARD && ability != ABILITY_KLUTZ) @@ -1746,10 +1745,11 @@ static u32 GetSwitchinRecurringDamage(void) // Gets one turn of status damage static u32 GetSwitchinStatusDamage(u32 battler) { - u8 defType1 = gAiLogicData->switchinCandidate.battleMon.types[0], defType2 = gAiLogicData->switchinCandidate.battleMon.types[1]; + enum Type defType1 = gAiLogicData->switchinCandidate.battleMon.types[0], defType2 = gAiLogicData->switchinCandidate.battleMon.types[1]; u8 tSpikesLayers = gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount; u16 heldItemEffect = GetItemHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); - u32 status = gAiLogicData->switchinCandidate.battleMon.status1, ability = gAiLogicData->switchinCandidate.battleMon.ability, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; + u32 status = gAiLogicData->switchinCandidate.battleMon.status1; + enum Ability ability = gAiLogicData->switchinCandidate.battleMon.ability, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; u32 statusDamage = 0; // Status condition damage @@ -1829,7 +1829,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) u16 maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, item = gAiLogicData->switchinCandidate.battleMon.item, heldItemEffect = GetItemHoldEffect(item); u8 weatherDuration = gWishFutureKnock.weatherDuration, holdEffectParam = GetItemHoldEffectParam(item); u32 opposingBattler = GetOppositeBattler(battler); - u32 opposingAbility = gAiLogicData->abilities[opposingBattler], ability = gAiLogicData->switchinCandidate.battleMon.ability; + enum Ability opposingAbility = gAiLogicData->abilities[opposingBattler], ability = gAiLogicData->switchinCandidate.battleMon.ability; bool32 usedSingleUseHealingItem = FALSE, opponentCanBreakMold = IsMoldBreakerTypeAbility(opposingBattler, opposingAbility); s32 currentHP = startingHP, singleUseItemHeal = 0; @@ -1934,8 +1934,8 @@ static u32 GetBattleMonTypeMatchup(struct BattlePokemon opposingBattleMon, struc { // Check type matchup u32 typeEffectiveness1 = UQ_4_12(1.0), typeEffectiveness2 = UQ_4_12(1.0); - u8 atkType1 = opposingBattleMon.types[0], atkType2 = opposingBattleMon.types[1], - defType1 = battleMon.types[0], defType2 = battleMon.types[1]; + enum Type atkType1 = opposingBattleMon.types[0], atkType2 = opposingBattleMon.types[1]; + enum Type defType1 = battleMon.types[0], defType2 = battleMon.types[1]; // Add each independent defensive type matchup together typeEffectiveness1 = uq4_12_multiply(typeEffectiveness1, (GetTypeModifier(atkType1, defType1))); @@ -1986,13 +1986,14 @@ static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattle u32 playerMove; u16 *playerMoves = GetMovesArray(opposingBattler); s32 damageTaken = 0, maxDamageTaken = 0; + uq4_12_t effectiveness; for (i = 0; i < MAX_MON_MOVES; i++) { playerMove = SMART_SWITCHING_OMNISCIENT ? gBattleMons[opposingBattler].moves[i] : playerMoves[i]; if (playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove) && GetMoveEffect(playerMove) != EFFECT_FOCUS_PUNCH && gBattleMons[opposingBattler].pp[i] > 0) { - damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, AI_DEFENDING); + damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, &effectiveness, AI_DEFENDING); if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move { *bestPlayerMove = playerMove; @@ -2014,6 +2015,7 @@ static s32 GetMaxPriorityDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposi u32 playerMove; u16 *playerMoves = GetMovesArray(opposingBattler); s32 damageTaken = 0, maxDamageTaken = 0; + uq4_12_t effectiveness = UQ_4_12(1.0); for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2024,7 +2026,7 @@ static s32 GetMaxPriorityDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposi if (GetBattleMovePriority(opposingBattler, gAiLogicData->abilities[opposingBattler], playerMove) > 0 && playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove) && GetMoveEffect(playerMove) != EFFECT_FOCUS_PUNCH && gBattleMons[opposingBattler].pp[i] > 0) { - damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, AI_DEFENDING); + damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, &effectiveness, AI_DEFENDING); if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move { *bestPlayerPriorityMove = playerMove; @@ -2040,7 +2042,7 @@ static s32 GetMaxPriorityDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposi return maxDamageTaken; } -static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent) +static bool32 CanAbilityTrapOpponent(enum Ability ability, u32 opponent) { if ((B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(opponent, TYPE_GHOST))) return FALSE; @@ -2051,7 +2053,7 @@ static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent) else return TRUE; } - else if (ability == ABILITY_ARENA_TRAP && IsBattlerGrounded(opponent)) + else if (ability == ABILITY_ARENA_TRAP && IsBattlerGrounded(opponent, gAiLogicData->abilities[opponent], gAiLogicData->holdEffects[opponent])) return TRUE; else if (ability == ABILITY_MAGNET_PULL && IS_BATTLER_OF_TYPE(opponent, TYPE_STEEL)) return TRUE; @@ -2072,7 +2074,7 @@ static inline bool32 IsFreeSwitch(enum SwitchType switchType, u32 battlerSwitchi return TRUE; if (gAiLogicData->ejectPackSwitch) { - u32 opposingAbility = GetBattlerAbilityIgnoreMoldBreaker(opposingBattler); + enum Ability opposingAbility = GetBattlerAbilityIgnoreMoldBreaker(opposingBattler); // If faster, not a free switch; likely lowered own stats if (!movedSecond && opposingAbility != ABILITY_INTIMIDATE && opposingAbility != ABILITY_SUPERSWEET_SYRUP) // Intimidate triggers switches before turn starts return FALSE; @@ -2122,11 +2124,12 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, int batonPassId = PARTY_SIZE, typeMatchupId = PARTY_SIZE, typeMatchupEffectiveId = PARTY_SIZE, defensiveMonId = PARTY_SIZE, aceMonId = PARTY_SIZE, trapperId = PARTY_SIZE; int i, j, aliveCount = 0, bits = 0, aceMonCount = 0; s32 defensiveMonHitKOThreshold = 3; // 3HKO threshold that candidate defensive mons must exceed - s32 playerMonHP = gBattleMons[opposingBattler].hp, maxDamageDealt = 0, damageDealt = 0; + s32 playerMonHP = gBattleMons[opposingBattler].hp, maxDamageDealt = 0, damageDealt = 0, monMaxDamage = 0; u32 aiMove, hitsToKOAI, hitsToKOPlayer, hitsToKOAIPriority, bestPlayerMove = MOVE_NONE, bestPlayerPriorityMove = MOVE_NONE, maxHitsToKO = 0; u32 bestResist = UQ_4_12(2.0), bestResistEffective = UQ_4_12(2.0), typeMatchup; // 2.0 is the default "Neutral" matchup from GetBattleMonTypeMatchup bool32 isFreeSwitch = IsFreeSwitch(switchType, battlerIn1, opposingBattler), isSwitchinFirst, isSwitchinFirstPriority, canSwitchinWin1v1; u32 invalidMons = 0; + uq4_12_t effectiveness = UQ_4_12(1.0); // Iterate through mons for (i = firstId; i < lastId; i++) @@ -2163,6 +2166,8 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, hitsToKOAIPriority = GetSwitchinHitsToKO(GetMaxPriorityDamagePlayerCouldDealToSwitchin(battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, &bestPlayerPriorityMove), battler); typeMatchup = GetBattleMonTypeMatchup(gBattleMons[opposingBattler], gAiLogicData->switchinCandidate.battleMon); + monMaxDamage = 0; + // Check through current mon's moves for (j = 0; j < MAX_MON_MOVES; j++) { @@ -2171,7 +2176,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, continue; aiMove = gAiLogicData->switchinCandidate.battleMon.moves[j]; - damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING); + damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, &effectiveness, AI_ATTACKING); hitsToKOPlayer = GetNoOfHitsToKOBattlerDmg(damageDealt, opposingBattler); // Offensive switchin decisions are based on which whether switchin moves first and whether it can win a 1v1 @@ -2212,7 +2217,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, { if (typeMatchup < bestResistEffective) { - if (AI_GetMoveEffectiveness(aiMove, battler, opposingBattler) >= UQ_4_12(2.0)) + if (effectiveness >= UQ_4_12(2.0)) { if (canSwitchinWin1v1) { @@ -2228,6 +2233,8 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, && damageDealt < playerMonHP) continue; + if (damageDealt > monMaxDamage) + monMaxDamage = damageDealt; // Check that mon isn't one shot and set best damage mon if (damageDealt > maxDamageDealt) { @@ -2271,6 +2278,8 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, trapperId = i; } } + if (monMaxDamage == 0) + invalidMons |= 1u << i; } batonPassId = GetRandomSwitchinWithBatonPass(aliveCount, bits, firstId, lastId, i); @@ -2300,16 +2309,19 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, else if (batonPassId != PARTY_SIZE) return batonPassId; else if (generic1v1MonId != PARTY_SIZE) return generic1v1MonId; } - // If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon. - if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount - && (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch)) - return aceMonId; + + if (switchType == SWITCH_MID_BATTLE_OPTIONAL) + return PARTY_SIZE; // Fallback - u32 bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2); + u32 bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons); if (bestMonId != PARTY_SIZE) return bestMonId; + // If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon. + if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount) + return aceMonId; + return PARTY_SIZE; } @@ -2425,16 +2437,17 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType) if (bestMonId != PARTY_SIZE) return bestMonId; - // If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon. - if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount - && (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch)) - return aceMonId; + if (switchType == SWITCH_MID_BATTLE_OPTIONAL) + return PARTY_SIZE; // Fallback - bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2); + bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons); if (bestMonId != PARTY_SIZE) return bestMonId; + if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount) + return aceMonId; + return PARTY_SIZE; } } @@ -2513,18 +2526,13 @@ static bool32 ShouldUseItem(u32 battler) shouldUse = AI_ShouldHeal(battler, healAmount); break; case EFFECT_ITEM_CURE_STATUS: - if (itemEffects[3] & ITEM3_SLEEP && gBattleMons[battler].status1 & STATUS1_SLEEP) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_POISON && gBattleMons[battler].status1 & STATUS1_PSN_ANY) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_BURN && gBattleMons[battler].status1 & STATUS1_BURN) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_FREEZE && gBattleMons[battler].status1 & STATUS1_ICY_ANY) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[battler].status1 & STATUS1_PARALYSIS) - shouldUse = TRUE; - if (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[battler].volatiles.confusionTurns > 0) - shouldUse = TRUE; + if ((itemEffects[3] & ITEM3_SLEEP && gBattleMons[battler].status1 & STATUS1_SLEEP) + || (itemEffects[3] & ITEM3_POISON && gBattleMons[battler].status1 & STATUS1_PSN_ANY) + || (itemEffects[3] & ITEM3_BURN && gBattleMons[battler].status1 & STATUS1_BURN) + || (itemEffects[3] & ITEM3_FREEZE && gBattleMons[battler].status1 & STATUS1_ICY_ANY) + || (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[battler].status1 & STATUS1_PARALYSIS) + || (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[battler].volatiles.confusionTurns > 0)) + shouldUse = ShouldCureStatusWithItem(battler, battler, gAiLogicData); break; case EFFECT_ITEM_INCREASE_STAT: case EFFECT_ITEM_INCREASE_ALL_STATS: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 0a9bd476c4..08879ce403 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -20,7 +20,6 @@ #include "constants/abilities.h" #include "constants/battle_ai.h" #include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" #include "constants/moves.h" #include "constants/items.h" @@ -28,7 +27,7 @@ static u32 GetAIEffectGroup(enum BattleMoveEffects effect); static u32 GetAIEffectGroupFromMove(u32 battler, u32 move); // Functions -static u32 AI_GetMoldBreakerSanitizedAbility(u32 battlerAtk, u32 abilityAtk, u32 abilityDef, u32 holdEffectDef, u32 move) +static u32 AI_GetMoldBreakerSanitizedAbility(u32 battlerAtk, enum Ability abilityAtk, enum Ability abilityDef, u32 holdEffectDef, u32 move) { if (MoveIgnoresTargetAbility(move)) return ABILITY_NONE; @@ -65,6 +64,11 @@ static bool32 AI_IsDoubleSpreadMove(u32 battlerAtk, u32 move) return FALSE; } +bool32 AI_IsBattlerGrounded(u32 battler) +{ + return IsBattlerGrounded(battler, gAiLogicData->abilities[battler], gAiLogicData->holdEffects[battler]); +} + u32 AI_GetDamage(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcContext calcContext, struct AiLogicData *aiData) { if (calcContext == AI_ATTACKING && BattlerHasAi(battlerAtk)) @@ -256,7 +260,7 @@ void RecordAllMoves(u32 battler) memcpy(gAiPartyData->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].moves, gBattleMons[battler].moves, MAX_MON_MOVES * sizeof(u16)); } -void RecordAbilityBattle(u32 battlerId, u32 abilityId) +void RecordAbilityBattle(u32 battlerId, enum Ability abilityId) { gBattleHistory->abilities[battlerId] = abilityId; gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability = abilityId; @@ -267,7 +271,7 @@ void ClearBattlerAbilityHistory(u32 battlerId) gBattleHistory->abilities[battlerId] = ABILITY_NONE; } -void RecordItemEffectBattle(u32 battlerId, u32 itemEffect) +void RecordItemEffectBattle(u32 battlerId, enum HoldEffect itemEffect) { gBattleHistory->itemEffects[battlerId] = itemEffect; gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect = itemEffect; @@ -468,7 +472,7 @@ bool32 AI_BattlerAtMaxHp(u32 battlerId) bool32 AI_CanBattlerEscape(u32 battler) { - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler]; if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; @@ -480,6 +484,9 @@ bool32 AI_CanBattlerEscape(u32 battler) bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef) { + if (AI_CanBattlerEscape(battlerDef)) + return FALSE; + if (gBattleMons[battlerDef].volatiles.wrapped) return TRUE; if (gBattleMons[battlerDef].volatiles.escapePrevention) @@ -494,23 +501,26 @@ bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef) && (B_SHADOW_TAG_ESCAPE >= GEN_4 && gAiLogicData->abilities[battlerDef] != ABILITY_SHADOW_TAG)) return TRUE; if (AI_IsAbilityOnSide(battlerAtk, ABILITY_ARENA_TRAP) - && IsBattlerGrounded(battlerAtk)) + && AI_IsBattlerGrounded(battlerAtk)) return TRUE; if (AI_IsAbilityOnSide(battlerAtk, ABILITY_MAGNET_PULL) && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_STEEL)) return TRUE; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && CountUsablePartyMons(battlerDef) == 0) + return TRUE; + return FALSE; } u32 GetTotalBaseStat(u32 species) { return GetSpeciesBaseHP(species) - + GetSpeciesBaseAttack(species) - + GetSpeciesBaseDefense(species) - + GetSpeciesBaseSpeed(species) - + GetSpeciesBaseSpAttack(species) - + GetSpeciesBaseSpDefense(species); + + GetSpeciesBaseAttack(species) + + GetSpeciesBaseDefense(species) + + GetSpeciesBaseSpeed(species) + + GetSpeciesBaseSpAttack(species) + + GetSpeciesBaseSpDefense(species); } bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) @@ -530,6 +540,25 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) return FALSE; } +bool32 Ai_IsPriorityBlocked(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) +{ + s32 atkPriority = GetBattleMovePriority(battlerAtk, aiData->abilities[battlerAtk], move); + + if (atkPriority <= 0 || IsBattlerAlly(battlerAtk, battlerDef)) + return FALSE; + + if (IsMoldBreakerTypeAbility(battlerAtk, aiData->abilities[battlerAtk]) || MoveIgnoresTargetAbility(move)) + return FALSE; + + if (IsDazzlingAbility(aiData->abilities[battlerDef])) + return TRUE; + + if (IsDoubleBattle() && IsDazzlingAbility(aiData->abilities[BATTLE_PARTNER(battlerDef)])) + return TRUE; + + return FALSE; +} + // This function checks if all physical/special moves are either unusable or unreasonable to use. // Consider a pokemon boosting their attack against a ghost pokemon having only normal-type physical attacks. bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category) @@ -555,7 +584,7 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory c if (GetBattleMoveCategory(moves[i]) == category) { SetTypeBeforeUsingMove(moves[i], attacker); - ctx.move = moves[i]; + ctx.move = ctx.chosenMove = moves[i]; ctx.moveType = GetBattleMoveType(moves[i]); if (CalcTypeEffectivenessMultiplier(&ctx)) @@ -604,8 +633,8 @@ static inline s32 DmgRoll(s32 dmg) bool32 IsDamageMoveUnusable(struct DamageContext *ctx) { - u32 battlerDefAbility; - u32 partnerDefAbility; + enum Ability battlerDefAbility; + enum Ability partnerDefAbility; struct AiLogicData *aiData = gAiLogicData; if (ctx->typeEffectivenessModifier == UQ_4_12(0.0)) @@ -625,6 +654,9 @@ bool32 IsDamageMoveUnusable(struct DamageContext *ctx) partnerDefAbility = aiData->abilities[BATTLE_PARTNER(ctx->battlerDef)]; } + if (Ai_IsPriorityBlocked(ctx->battlerAtk, ctx->battlerDef, ctx->move, aiData)) + return TRUE; + if (CanAbilityBlockMove(ctx->battlerAtk, ctx->battlerDef, ctx->abilityAtk, battlerDefAbility, ctx->move, AI_CHECK)) return TRUE; @@ -660,7 +692,7 @@ bool32 IsDamageMoveUnusable(struct DamageContext *ctx) return TRUE; break; case EFFECT_LAST_RESORT: - if (!CanUseLastResort(ctx->battlerAtk)) + if (!CanUseLastResort(ctx->battlerAtk) && !IsConsideringZMove(ctx->battlerAtk, ctx->battlerDef, ctx->move)) return TRUE; break; case EFFECT_LOW_KICK: @@ -731,14 +763,14 @@ static inline s32 SetFixedMoveBasePower(u32 battlerAtk, u32 move) return fixedBasePower; } -static inline void AI_StoreBattlerTypes(u32 battlerAtk, u32 *types) +static inline void AI_StoreBattlerTypes(u32 battlerAtk, enum Type *types) { types[0] = gBattleMons[battlerAtk].types[0]; types[1] = gBattleMons[battlerAtk].types[1]; types[2] = gBattleMons[battlerAtk].types[2]; } -static inline void AI_RestoreBattlerTypes(u32 battlerAtk, u32 *types) +static inline void AI_RestoreBattlerTypes(u32 battlerAtk, enum Type *types) { gBattleMons[battlerAtk].types[0] = types[0]; gBattleMons[battlerAtk].types[1] = types[1]; @@ -861,7 +893,7 @@ static inline bool32 ShouldCalcCritDamage(u32 battlerAtk, u32 battlerDef, u32 mo struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef, u32 weather) { - struct SimulatedDamage simDamage; + struct SimulatedDamage simDamage = {0}; enum BattleMoveEffects moveEffect = GetMoveEffect(move); bool32 isDamageMoveUnusable = FALSE; bool32 toggledGimmickAtk = FALSE; @@ -876,10 +908,6 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u if (gBattleStruct->gimmick.usableGimmick[battlerAtk] && GetActiveGimmick(battlerAtk) == GIMMICK_NONE && gBattleStruct->gimmick.usableGimmick[battlerAtk] != GIMMICK_NONE && considerGimmickAtk == USE_GIMMICK) { - // Set Z-Move variables if needed - if (gBattleStruct->gimmick.usableGimmick[battlerAtk] == GIMMICK_Z_MOVE && IsViableZMove(battlerAtk, move)) - gBattleStruct->zmove.baseMoves[battlerAtk] = move; - toggledGimmickAtk = TRUE; SetActiveGimmick(battlerAtk, gBattleStruct->gimmick.usableGimmick[battlerAtk]); } @@ -901,7 +929,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = GetBattleMoveType(move); ctx.isCrit = ShouldCalcCritDamage(battlerAtk, battlerDef, move, aiData); ctx.randomFactor = FALSE; @@ -920,7 +948,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u if (movePower && !isDamageMoveUnusable) { - u32 types[3]; + enum Type types[3]; AI_StoreBattlerTypes(battlerAtk, types); ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, ctx.moveType); @@ -979,7 +1007,6 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u // Undo temporary settings gBattleStruct->dynamicMoveType = 0; gBattleStruct->swapDamageCategory = FALSE; - gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE; if (toggledGimmickAtk) SetActiveGimmick(battlerAtk, GIMMICK_NONE); if (toggledGimmickDef) @@ -990,7 +1017,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u bool32 AI_IsDamagedByRecoil(u32 battler) { - u32 ability = gAiLogicData->abilities[battler]; + enum Ability ability = gAiLogicData->abilities[battler]; if (ability == ABILITY_MAGIC_GUARD || ability == ABILITY_ROCK_HEAD) return FALSE; return TRUE; @@ -1000,8 +1027,8 @@ bool32 AI_IsDamagedByRecoil(u32 battler) static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s32 noOfHitsToKo) { u32 i; - u32 abilityDef = gAiLogicData->abilities[battlerDef]; - u32 abilityAtk = gAiLogicData->abilities[battlerAtk]; + enum Ability abilityDef = gAiLogicData->abilities[battlerDef]; + enum Ability abilityAtk = gAiLogicData->abilities[battlerAtk]; switch (GetMoveEffect(move)) { @@ -1178,8 +1205,8 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s32 noOfHitsToKo) { - u32 abilityAtk = gAiLogicData->abilities[battlerAtk]; - u32 abilityDef = gAiLogicData->abilities[battlerDef]; + enum Ability abilityAtk = gAiLogicData->abilities[battlerAtk]; + enum Ability abilityDef = gAiLogicData->abilities[battlerDef]; u8 i; switch (GetMoveEffect(move)) @@ -1259,8 +1286,8 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo) { bool32 effect1, effect2; - u32 defAbility = gAiLogicData->abilities[battlerDef]; - u32 atkAbility = gAiLogicData->abilities[battlerAtk]; + enum Ability defAbility = gAiLogicData->abilities[battlerDef]; + enum Ability atkAbility = gAiLogicData->abilities[battlerAtk]; // Check if physical moves hurt. if (gAiLogicData->holdEffects[battlerAtk] != HOLD_EFFECT_PROTECTIVE_PADS && atkAbility != ABILITY_LONG_REACH @@ -1355,7 +1382,7 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = GetBattleMoveType(move); ctx.updateFlags = FALSE; ctx.abilityAtk = gAiLogicData->abilities[battlerAtk]; @@ -1379,10 +1406,10 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 aiMoveConsidered, u32 playerMoveConsidered, enum ConsiderPriority considerPriority) { u32 speedBattlerAI, speedBattler; - enum ItemHoldEffect holdEffectAI = gAiLogicData->holdEffects[battlerAI]; - enum ItemHoldEffect holdEffectPlayer = gAiLogicData->holdEffects[battler]; - u32 abilityAI = gAiLogicData->abilities[battlerAI]; - u32 abilityPlayer = gAiLogicData->abilities[battler]; + enum HoldEffect holdEffectAI = gAiLogicData->holdEffects[battlerAI]; + enum HoldEffect holdEffectPlayer = gAiLogicData->holdEffects[battler]; + enum Ability abilityAI = gAiLogicData->abilities[battlerAI]; + enum Ability abilityPlayer = gAiLogicData->abilities[battler]; if (considerPriority == CONSIDER_PRIORITY) { @@ -1395,8 +1422,8 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 aiMoveConsidered, u32 pla return AI_IS_SLOWER; } - speedBattlerAI = GetBattlerTotalSpeedStatArgs(battlerAI, abilityAI, holdEffectAI); - speedBattler = GetBattlerTotalSpeedStatArgs(battler, abilityPlayer, holdEffectPlayer); + speedBattlerAI = GetBattlerTotalSpeedStat(battlerAI, abilityAI, holdEffectAI); + speedBattler = GetBattlerTotalSpeedStat(battler, abilityPlayer, holdEffectPlayer); if (holdEffectAI == HOLD_EFFECT_LAGGING_TAIL && holdEffectPlayer != HOLD_EFFECT_LAGGING_TAIL) return AI_IS_SLOWER; @@ -1444,7 +1471,7 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move) { if (B_STURDY >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY) return TRUE; - if (gBattleMons[battlerTarget].species == SPECIES_MIMIKYU_DISGUISED) + if (IsMimikyuDisguised(battlerTarget)) return TRUE; } @@ -1661,7 +1688,7 @@ bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dm return FALSE; } -bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) +bool32 AI_IsAbilityOnSide(u32 battlerId, enum Ability ability) { if (IsBattlerAlive(battlerId) && gAiLogicData->abilities[battlerId] == ability) return TRUE; @@ -1672,13 +1699,13 @@ bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) } // does NOT include ability suppression checks -s32 AI_DecideKnownAbilityForTurn(u32 battlerId) +enum Ability AI_DecideKnownAbilityForTurn(u32 battlerId) { u32 validAbilities[NUM_ABILITY_SLOTS]; u8 i, numValidAbilities = 0; - u32 knownAbility = GetBattlerAbilityIgnoreMoldBreaker(battlerId); // during ai checking for mold breaker could lead to inaccuracies - u32 indexAbility; - u32 abilityAiRatings[NUM_ABILITY_SLOTS] = {0}; + enum Ability knownAbility = GetBattlerAbilityIgnoreMoldBreaker(battlerId); + enum Ability indexAbility; + enum Ability abilityAiRatings[NUM_ABILITY_SLOTS] = {0}; // We've had ability overwritten by e.g. Worry Seed. It is not part of gAiPartyData in case of switching if (gDisableStructs[battlerId].overwrittenAbility) @@ -1718,9 +1745,9 @@ s32 AI_DecideKnownAbilityForTurn(u32 battlerId) return ABILITY_NONE; // Unknown. } -enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) +enum HoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) { - enum ItemHoldEffect holdEffect = HOLD_EFFECT_NONE; + enum HoldEffect holdEffect = HOLD_EFFECT_NONE; if (gBattleMons[battlerId].item == ITEM_NONE) // Failsafe for when user recorded an item but it was consumed return holdEffect; @@ -1728,7 +1755,7 @@ enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) if (!IsAiBattlerAware(battlerId)) holdEffect = gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; else - holdEffect = GetBattlerHoldEffect(battlerId, FALSE); + holdEffect = GetBattlerHoldEffectIgnoreNegation(battlerId); if (gAiThinkingStruct->aiFlags[battlerId] & AI_FLAG_NEGATE_UNAWARE) return holdEffect; @@ -1743,7 +1770,7 @@ enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) return holdEffect; } -bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move) +bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, enum Ability atkAbility, u32 move) { if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) return FALSE; // AI handicap flag: doesn't understand ability suppression concept @@ -1777,7 +1804,7 @@ u32 AI_GetWeather(void) u32 AI_GetSwitchinWeather(struct BattlePokemon battleMon) { - u32 ability = battleMon.ability; + enum Ability ability = battleMon.ability; // Forced weather behaviour if (!AI_WeatherHasEffect()) return B_WEATHER_NONE; @@ -1963,7 +1990,7 @@ bool32 IsAllyProtectingFromMove(u32 battlerAtk, u32 attackerMove, u32 allyMove) } } -bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility) +bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, enum Ability atkAbility) { if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) return FALSE; @@ -1977,9 +2004,9 @@ bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility) return FALSE; } -bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) +bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, enum Ability defAbility, u32 move) { - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battlerDef]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battlerDef]; u32 accuracy = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; gPotentialItemEffectBattler = battlerDef; @@ -2009,8 +2036,44 @@ bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbil return FALSE; } +bool32 ShouldRaiseAnyStat(u32 battlerAtk, u32 battlerDef) +{ + if (AreBattlersStatsMaxed(battlerAtk)) + return FALSE; + + // Don't increase stats if opposing battler has Unaware + if (AI_IsAbilityOnSide(battlerDef, ABILITY_UNAWARE)) + return FALSE; + + // Don't set up if AI is dead to residual damage from weather + if (GetBattlerSecondaryDamage(battlerAtk) >= gBattleMons[battlerAtk].hp) + return FALSE; + + // Don't increase stats if opposing battler has Opportunist + if (AI_IsAbilityOnSide(battlerDef, ABILITY_OPPORTUNIST)) + return FALSE; + + // Don't increase stats if opposing battler has used Haze effect or AI effect + if (!RandomPercentage(RNG_AI_BOOST_INTO_HAZE, BOOST_INTO_HAZE_CHANCE) + && HasBattlerSideUsedMoveWithEffect(battlerDef, EFFECT_HAZE)) + return FALSE; + + if (CountPositiveStatStages(battlerAtk) > 0 + && HasBattlerSideMoveWithAIEffect(battlerDef, AI_EFFECT_RESET_STATS)) + return FALSE; + + // Don't increase stats if AI could KO target through Sturdy effect, as otherwise it always 2HKOs + if (CanBattlerKOTargetIgnoringSturdy(battlerAtk, battlerDef)) + return FALSE; + + return TRUE; +} + bool32 ShouldSetWeather(u32 battler, u32 weather) { + if (AI_GetWeather() & weather) + return FALSE; + return WeatherChecker(battler, weather, FIELD_EFFECT_POSITIVE); } @@ -2021,6 +2084,15 @@ bool32 ShouldClearWeather(u32 battler, u32 weather) bool32 ShouldSetFieldStatus(u32 battler, u32 fieldStatus) { + if (gFieldStatuses & fieldStatus) + { + if (!(fieldStatus & STATUS_FIELD_TRICK_ROOM)) + return FALSE; + // DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE + else if (gFieldTimers.trickRoomTimer != 1) + return FALSE; + } + return FieldStatusChecker(battler, fieldStatus, FIELD_EFFECT_POSITIVE); } @@ -2083,7 +2155,7 @@ s32 ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove) } // stat stages -bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, u32 stat) +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, enum Stat stat) { if (gBattleMons[battlerDef].statStages[stat] == MIN_STAT_STAGE) return FALSE; @@ -2092,7 +2164,7 @@ bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, return FALSE; u32 move = gAiThinkingStruct->moveConsidered; - u32 abilityAtk = aiData->abilities[battlerAtk]; + enum Ability abilityAtk = aiData->abilities[battlerAtk]; if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_MIST && abilityAtk != ABILITY_INFILTRATOR) return FALSE; @@ -2125,6 +2197,10 @@ bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, case ABILITY_WHITE_SMOKE: case ABILITY_FULL_METAL_BODY: return FALSE; + case ABILITY_SHIELD_DUST: + if (!IsBattleMoveStatus(move) && GetActiveGimmick(battlerAtk) != GIMMICK_DYNAMAX) + return FALSE; + break; default: break; } @@ -2142,7 +2218,7 @@ bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, return TRUE; } -u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) +u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, enum Stat stat) { u32 tempScore = NO_INCREASE; @@ -2154,10 +2230,6 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) if (GetBattlerSecondaryDamage(battlerDef) >= gBattleMons[battlerDef].hp) return NO_INCREASE; - // Don't decrease stat if opposing battler has Encore - if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE)) - return NO_INCREASE; - if (DoesAbilityRaiseStatsWhenLowered(gAiLogicData->abilities[battlerDef])) return NO_INCREASE; @@ -2172,13 +2244,15 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) tempScore += DECENT_EFFECT; break; case STAT_DEF: - if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) + || HasMoveWithCategory(BATTLE_PARTNER(battlerAtk), DAMAGE_CATEGORY_PHYSICAL)) tempScore += DECENT_EFFECT; break; case STAT_SPEED: { u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, gAiLogicData); - if (AI_IsSlower(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered, predictedMoveSpeedCheck, DONT_CONSIDER_PRIORITY)) + if (AI_IsSlower(battlerAtk, battlerDef, MOVE_NONE, predictedMoveSpeedCheck, DONT_CONSIDER_PRIORITY) + || AI_IsSlower(BATTLE_PARTNER(battlerAtk), battlerDef, MOVE_NONE, predictedMoveSpeedCheck, DONT_CONSIDER_PRIORITY)) tempScore += DECENT_EFFECT; break; } @@ -2187,16 +2261,16 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) tempScore += DECENT_EFFECT; break; case STAT_SPDEF: - if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL) + || HasMoveWithCategory(BATTLE_PARTNER(battlerAtk), DAMAGE_CATEGORY_SPECIAL)) tempScore += DECENT_EFFECT; break; case STAT_ACC: - if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) - tempScore += WEAK_EFFECT; + tempScore += WEAK_EFFECT; + if (IsBattlerTrapped(battlerAtk, battlerDef)) + tempScore += DECENT_EFFECT; if (gBattleMons[battlerDef].volatiles.leechSeed) tempScore += WEAK_EFFECT; - if (gBattleMons[battlerDef].volatiles.root) - tempScore += WEAK_EFFECT; if (gBattleMons[battlerDef].volatiles.cursed) tempScore += WEAK_EFFECT; break; @@ -2210,12 +2284,14 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) if (gBattleMons[battlerDef].volatiles.cursed) tempScore += WEAK_EFFECT; break; + default: + break; } return (tempScore > BEST_EFFECT) ? BEST_EFFECT : tempScore; // don't inflate score so only max +4 } -bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat) +bool32 BattlerStatCanRise(u32 battler, enum Ability battlerAbility, enum Stat stat) { if ((gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE)) @@ -2225,7 +2301,7 @@ bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat) bool32 AreBattlersStatsMaxed(u32 battlerId) { - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] < MAX_STAT_STAGE) @@ -2236,7 +2312,7 @@ bool32 AreBattlersStatsMaxed(u32 battlerId) bool32 AnyStatIsRaised(u32 battlerId) { - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { @@ -2249,7 +2325,7 @@ bool32 AnyStatIsRaised(u32 battlerId) u32 CountPositiveStatStages(u32 battlerId) { u32 count = 0; - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] > DEFAULT_STAT_STAGE) @@ -2261,7 +2337,7 @@ u32 CountPositiveStatStages(u32 battlerId) u32 CountNegativeStatStages(u32 battlerId) { u32 count = 0; - u32 i; + enum Stat i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { if (gBattleMons[battlerId].statStages[i] < DEFAULT_STAT_STAGE) @@ -2293,6 +2369,18 @@ u16 *GetMovesArray(u32 battler) return gBattleHistory->usedMoves[battler]; } +u32 GetIndexInMoveArray(u32 battler, u32 move) +{ + u16 *moves = GetMovesArray(battler); + u32 i; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] == move) + return i; + } + return MAX_MON_MOVES; +} + bool32 HasOnlyMovesWithCategory(u32 battlerId, enum DamageCategory category, bool32 onlyOffensive) { u32 i; @@ -2322,7 +2410,7 @@ bool32 HasMoveWithCategory(u32 battler, enum DamageCategory category) return FALSE; } -bool32 HasMoveWithType(u32 battler, u32 type) +bool32 HasMoveWithType(u32 battler, enum Type type) { s32 i; u16 *moves = GetMovesArray(battler); @@ -2575,7 +2663,7 @@ bool32 HasMoveThatRaisesOwnStats(u32 battlerId) return FALSE; } -bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect) +bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus) { s32 i; u16 *moves = GetMovesArray(battlerAtk); @@ -2914,30 +3002,38 @@ static inline bool32 IsMoveSleepClauseTrigger(u32 move) return FALSE; } -bool32 HasDamagingMove(u32 battlerId) +bool32 HasDamagingMove(u32 battler) { u32 i; - u16 *moves = GetMovesArray(battlerId); + u16 *moves = GetMovesArray(battler); for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !IsBattleMoveStatus(moves[i])) + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMovePower(moves[i]) > 0) return TRUE; } return FALSE; } -bool32 HasDamagingMoveOfType(u32 battlerId, u32 type) +bool32 HasDamagingMoveOfType(u32 battler, enum Type type) { s32 i; - u16 *moves = GetMovesArray(battlerId); + u16 *moves = GetMovesArray(battler); for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE - && GetMoveType(moves[i]) == type && !IsBattleMoveStatus(moves[i])) - return TRUE; + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMovePower(moves[i]) > 0) + { + enum Type moveType = GetDynamicMoveType(GetBattlerMon(battler), moves[i], battler, MON_IN_BATTLE); + + if (moveType != TYPE_NONE && type == moveType) + return TRUE; + if (GetMoveType(moves[i]) == type) + return TRUE; + if (GetMoveEffect(moves[i]) == EFFECT_NATURE_POWER && GetMoveType(GetNaturePowerMove(moves[i])) == type) + return TRUE; + } } return FALSE; @@ -3009,17 +3105,16 @@ static u32 GetCurseDamage(u32 battlerId) return damage; } -static u32 GetTrapDamage(u32 battlerId) +static u32 GetTrapDamage(u32 battler) { // ai has no knowledge about turns remaining u32 damage = 0; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[gBattleStruct->wrappedBy[battlerId]]; - if (gBattleMons[battlerId].volatiles.wrapped) + if (gBattleMons[battler].volatiles.wrapped) { - if (holdEffect == HOLD_EFFECT_BINDING_BAND) - damage = GetNonDynamaxMaxHP(battlerId) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); + if (gAiLogicData->holdEffects[gBattleMons[battler].volatiles.wrappedBy] == HOLD_EFFECT_BINDING_BAND) + damage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); else - damage = GetNonDynamaxMaxHP(battlerId) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); + damage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); if (damage == 0) damage = 1; @@ -3053,7 +3148,7 @@ static u32 GetPoisonDamage(u32 battlerId) return damage; } -static bool32 BattlerAffectedBySandstorm(u32 battlerId, u32 ability) +static bool32 BattlerAffectedBySandstorm(u32 battlerId, enum Ability ability) { if (!IS_BATTLER_ANY_TYPE(battlerId, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL) && ability != ABILITY_SAND_VEIL @@ -3064,7 +3159,7 @@ static bool32 BattlerAffectedBySandstorm(u32 battlerId, u32 ability) return FALSE; } -static bool32 BattlerAffectedByHail(u32 battlerId, u32 ability) +static bool32 BattlerAffectedByHail(u32 battlerId, enum Ability ability) { if (!IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) && ability != ABILITY_SNOW_CLOAK @@ -3076,8 +3171,8 @@ static bool32 BattlerAffectedByHail(u32 battlerId, u32 ability) static u32 GetWeatherDamage(u32 battlerId) { - u32 ability = gAiLogicData->abilities[battlerId]; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battlerId]; + enum Ability ability = gAiLogicData->abilities[battlerId]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battlerId]; u32 damage = 0; u32 weather = AI_GetWeather(); if (!weather) @@ -3127,7 +3222,7 @@ u32 GetBattlerSecondaryDamage(u32 battlerId) return secondaryDamage; } -bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability) +bool32 BattlerWillFaintFromWeather(u32 battler, enum Ability ability) { if ((BattlerAffectedBySandstorm(battler, ability) || BattlerAffectedByHail(battler, ability)) && gBattleMons[battler].hp <= max(1, gBattleMons[battler].maxHP / 16)) @@ -3136,7 +3231,7 @@ bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability) return FALSE; } -bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability) +bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, enum Ability ability) { if (GetBattlerSecondaryDamage(battler) != 0 && gBattleMons[battler].hp <= max(1, gBattleMons[battler].maxHP / 16)) @@ -3146,7 +3241,7 @@ bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability) static bool32 AnyUsefulStatIsRaised(u32 battler) { - u32 statId; + enum Stat statId; for (statId = STAT_ATK; statId < NUM_BATTLE_STATS; statId++) { @@ -3164,6 +3259,8 @@ static bool32 AnyUsefulStatIsRaised(u32 battler) break; case STAT_SPEED: return TRUE; + default: + break; } } } @@ -3174,12 +3271,12 @@ static bool32 AnyUsefulStatIsRaised(u32 battler) static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler) { struct Pokemon *mon = &GetBattlerParty(currBattler)[switchBattler]; - u32 ability = GetMonAbility(mon); // we know our own party data - enum ItemHoldEffect holdEffect; + enum Ability ability = GetMonAbility(mon); // we know our own party data + enum HoldEffect holdEffect; u32 species = GetMonData(mon, MON_DATA_SPECIES); s32 hazardDamage = 0; - u32 type1 = GetSpeciesType(species, 0); - u32 type2 = GetSpeciesType(species, 1); + enum Type type1 = GetSpeciesType(species, 0); + enum Type type2 = GetSpeciesType(species, 1); u32 maxHp = GetMonData(mon, MON_DATA_MAX_HP); u32 side = GetBattlerSide(currBattler); @@ -3215,7 +3312,7 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler) return FALSE; } -enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex) +enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 moveIndex) { bool32 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class u32 battlerToSwitch; @@ -3417,7 +3514,7 @@ bool32 CanKnockOffItem(u32 battler, u32 item) } // status checks -bool32 IsBattlerIncapacitated(u32 battler, u32 ability) +bool32 IsBattlerIncapacitated(u32 battler, enum Ability ability) { if ((gBattleMons[battler].status1 & STATUS1_FREEZE) && !HasThawingMove(battler)) return TRUE; // if battler has thawing move we assume they will definitely use it, and thus being frozen should be neglected @@ -3431,7 +3528,7 @@ bool32 IsBattlerIncapacitated(u32 battler, u32 ability) return FALSE; } -bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) +bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove) { if (!CanBeSlept(battlerAtk, battlerDef, defAbility, BLOCKED_BY_SLEEP_CLAUSE) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) @@ -3440,7 +3537,7 @@ bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move return TRUE; } -static inline bool32 DoesBattlerBenefitFromAllVolatileStatus(u32 battler, u32 ability) +static inline bool32 DoesBattlerBenefitFromAllVolatileStatus(u32 battler, enum Ability ability) { if (ability == ABILITY_MARVEL_SCALE || ability == ABILITY_QUICK_FEET @@ -3454,7 +3551,7 @@ static inline bool32 DoesBattlerBenefitFromAllVolatileStatus(u32 battler, u32 ab bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef) { - u32 abilityDef = gAiLogicData->abilities[battlerDef]; + enum Ability abilityDef = gAiLogicData->abilities[battlerDef]; // Battler can be poisoned and has move/ability that synergizes with being poisoned if (CanBePoisoned(battlerAtk, battlerDef, gAiLogicData->abilities[battlerAtk], abilityDef) && ( DoesBattlerBenefitFromAllVolatileStatus(battlerDef, abilityDef) @@ -3472,7 +3569,7 @@ bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef) return TRUE; } -bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef, u32 abilityDef) +bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef) { // Battler can be burned and has move/ability that synergizes with being burned if (CanBeBurned(battlerAtk, battlerDef, abilityDef) && ( @@ -3492,7 +3589,7 @@ bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef, u32 abilityDef) return TRUE; } -bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef) +bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef) { if (!B_USE_FROSTBITE) { @@ -3524,7 +3621,7 @@ bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef) } } -bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, u32 abilityDef) +bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef) { // Battler can be paralyzed and has move/ability that synergizes with being paralyzed if (CanBeParalyzed(battlerAtk, battlerDef, abilityDef) && ( @@ -3541,7 +3638,7 @@ bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, u32 abilityDef) return TRUE; } -bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) +bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove) { if (!CanBePoisoned(battlerAtk, battlerDef, gAiLogicData->abilities[battlerAtk], defAbility) || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) @@ -3552,7 +3649,7 @@ bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u3 return TRUE; } -bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) +bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 move, u32 partnerMove) { if (!CanBeParalyzed(battlerAtk, battlerDef, defAbility) || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) @@ -3562,18 +3659,18 @@ bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, return TRUE; } -bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability) +bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability abilityDef) { if (gBattleMons[battlerDef].volatiles.confusionTurns > 0 - || (ability == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(battlerAtk, gAiLogicData->abilities[battlerAtk], move)) - || IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN) + || (abilityDef == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(battlerAtk, gAiLogicData->abilities[battlerAtk], move)) + || IsBattlerTerrainAffected(battlerDef, abilityDef, gAiLogicData->holdEffects[battlerDef], STATUS_FIELD_MISTY_TERRAIN) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) return FALSE; return TRUE; } -bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) +bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (GetBattlerMoveTargetType(battlerAtk, move) == MOVE_TARGET_FOES_AND_ALLY && AI_CanBeConfused(battlerAtk, battlerDef, move, defAbility) @@ -3587,7 +3684,7 @@ bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battler return TRUE; } -bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) +bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!CanBeBurned(battlerAtk, battlerDef, defAbility) || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) @@ -3599,7 +3696,7 @@ bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtk return TRUE; } -bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) +bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!CanBeFrozen(battlerAtk, battlerDef, defAbility) || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) @@ -3611,7 +3708,7 @@ bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 b return TRUE; } -bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) +bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, enum Ability defAbility) { if (gBattleMons[battlerDef].volatiles.infatuation || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) @@ -3622,7 +3719,7 @@ bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) return TRUE; } -u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) +u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, enum Ability defAbility, u32 move) { u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, gAiLogicData); if (((!IsMoldBreakerTypeAbility(battlerAtk, gAiLogicData->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) @@ -3699,14 +3796,14 @@ bool32 IsFlinchGuaranteed(u32 battlerAtk, u32 battlerDef, u32 move) bool32 HasChoiceEffect(u32 battler) { - u32 ability = gAiLogicData->abilities[battler]; + enum Ability ability = gAiLogicData->abilities[battler]; if (ability == ABILITY_GORILLA_TACTICS) return TRUE; if (ability == ABILITY_KLUTZ) return FALSE; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler]; switch (holdEffect) { case HOLD_EFFECT_CHOICE_BAND: @@ -3890,8 +3987,104 @@ bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects mo return FALSE; } +static bool32 ShouldCureStatusInternal(u32 battlerAtk, u32 battlerDef, bool32 usingItem, struct AiLogicData *aiData) +{ + bool32 targetingSelf = (battlerAtk == battlerDef); + bool32 targetingAlly = IsTargetingPartner(battlerAtk, battlerDef); + u32 status = gBattleMons[battlerDef].status1; + + if (status & STATUS1_SLEEP) + { + if (targetingAlly || targetingSelf) + { + if (HasMoveWithEffect(battlerDef, EFFECT_SLEEP_TALK) || HasMoveWithEffect(battlerDef, EFFECT_SNORE)) + return FALSE; + else + return usingItem || targetingAlly; + } + return FALSE; + } + + if (status & STATUS1_FREEZE) + { + if (targetingAlly || targetingSelf) + { + if (HasThawingMove(battlerDef)) + return FALSE; + return usingItem || targetingAlly; + } + return FALSE; + } + + bool32 isHarmless = FALSE; + + if (DoesBattlerBenefitFromAllVolatileStatus(battlerDef, aiData->abilities[battlerDef])) + isHarmless = TRUE; + + if (status & STATUS1_PSN_ANY) + { + if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_TOXIC_ORB) + return FALSE; + + if (aiData->abilities[battlerDef] == ABILITY_POISON_HEAL) + isHarmless = TRUE; + + if (aiData->abilities[battlerDef] == ABILITY_TOXIC_BOOST && !isHarmless) + { + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + isHarmless = TRUE; + else if (!(targetingSelf || targetingAlly) && !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + isHarmless = TRUE; + } + } + + if (status & STATUS1_BURN) + { + if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_FLAME_ORB) + return FALSE; + + if (aiData->abilities[battlerDef] == ABILITY_FLARE_BOOST && !isHarmless) + { + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + isHarmless = TRUE; + else if (!(targetingSelf || targetingAlly) && !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + isHarmless = TRUE; + } + } + +/* + if (status & STATUS1_PARALYSIS) + if (status & STATUS1_FROSTBITE) +*/ + + if (isHarmless) + { + if (targetingSelf || targetingAlly) + return FALSE; + else + return TRUE; + } + else + { + if (targetingSelf || targetingAlly) + return TRUE; + else + return FALSE; + } +} + +bool32 ShouldCureStatus(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData) +{ + return ShouldCureStatusInternal(battlerAtk, battlerDef, FALSE, aiData); +} + +bool32 ShouldCureStatusWithItem(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData) +{ + return ShouldCureStatusInternal(battlerAtk, battlerDef, TRUE, aiData); +} + // Partner Logic -bool32 IsBattle1v1() +bool32 IsBattle1v1(void) { if (IsDoubleBattle() && ((IsBattlerAlive(B_POSITION_PLAYER_LEFT) && IsBattlerAlive(B_POSITION_PLAYER_RIGHT)) @@ -3903,7 +4096,7 @@ bool32 IsBattle1v1() bool32 HasTwoOpponents(u32 battler) { if (IsDoubleBattle() - && IsBattlerAlive(FOE(battler)) && IsBattlerAlive(BATTLE_PARTNER(FOE(battler)))) + && IsBattlerAlive(LEFT_FOE(battler)) && IsBattlerAlive(RIGHT_FOE(battler))) return TRUE; return FALSE; } @@ -3943,9 +4136,9 @@ u32 GetAllyChosenMove(u32 battlerId) if (!IsBattlerAlive(partnerBattler) || !IsAiBattlerAware(partnerBattler)) return MOVE_NONE; else if (partnerBattler > battlerId) // Battler with the lower id chooses the move first. - return gLastMoves[partnerBattler]; + return gAiLogicData->lastUsedMove[partnerBattler]; else - return gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]]; + return GetChosenMoveFromPosition(partnerBattler); } bool32 AreMovesEquivalent(u32 battlerAtk, u32 battlerAtkPartner, u32 move, u32 partnerMove) @@ -4039,9 +4232,8 @@ static u32 GetAIEffectGroup(enum BattleMoveEffects effect) case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: + case EFFECT_OVERWRITE_ABILITY: aiEffect |= AI_EFFECT_CHANGE_ABILITY; break; default: @@ -4270,11 +4462,32 @@ void FreeRestoreBattleMons(struct BattlePokemon *savedBattleMons) Free(savedBattleMons); } +// Set potential field effect from ability for switch in +static void SetBattlerFieldStatusForSwitchin(u32 battler) +{ + switch (gAiLogicData->abilities[battler]) + { + case ABILITY_VESSEL_OF_RUIN: + gBattleMons[battler].volatiles.vesselOfRuin = TRUE; + break; + case ABILITY_SWORD_OF_RUIN: + gBattleMons[battler].volatiles.swordOfRuin = TRUE; + break; + case ABILITY_TABLETS_OF_RUIN: + gBattleMons[battler].volatiles.tabletsOfRuin = TRUE; + break; + case ABILITY_BEADS_OF_RUIN: + gBattleMons[battler].volatiles.beadsOfRuin = TRUE; + break; + default: + break; + } +} + // party logic -s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, enum DamageCalcContext calcContext) +s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, uq4_12_t *effectiveness, enum DamageCalcContext calcContext) { struct SimulatedDamage dmg; - uq4_12_t effectiveness; struct BattlePokemon *savedBattleMons = AllocSaveBattleMons(); if (calcContext == AI_ATTACKING) @@ -4282,6 +4495,7 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl gBattleMons[battlerAtk] = switchinCandidate; gAiThinkingStruct->saved[battlerDef].saved = TRUE; SetBattlerAiData(battlerAtk, gAiLogicData); // set known opposing battler data + SetBattlerFieldStatusForSwitchin(battlerAtk); gAiThinkingStruct->saved[battlerDef].saved = FALSE; } else if (calcContext == AI_DEFENDING) @@ -4289,10 +4503,11 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl gBattleMons[battlerDef] = switchinCandidate; gAiThinkingStruct->saved[battlerAtk].saved = TRUE; SetBattlerAiData(battlerDef, gAiLogicData); // set known opposing battler data + SetBattlerFieldStatusForSwitchin(battlerDef); gAiThinkingStruct->saved[battlerAtk].saved = FALSE; } - dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, NO_GIMMICK, NO_GIMMICK, AI_GetSwitchinWeather(switchinCandidate)); + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, effectiveness, NO_GIMMICK, NO_GIMMICK, AI_GetSwitchinWeather(switchinCandidate)); // restores original gBattleMon struct FreeRestoreBattleMons(savedBattleMons); @@ -4352,7 +4567,9 @@ s32 CountUsablePartyMons(u32 battlerId) } ret = 0; - for (i = 0; i < PARTY_SIZE; i++) + s32 firstId, lastId; + GetAIPartyIndexes(battlerId, &firstId, &lastId); + for (i = firstId; i < lastId; i++) { if (i != battlerOnField1 && i != battlerOnField2 && GetMonData(&party[i], MON_DATA_HP) != 0 @@ -4426,7 +4643,7 @@ bool32 SideHasMoveCategory(u32 battlerId, enum DamageCategory category) return FALSE; } -bool32 IsAbilityOfRating(u32 ability, s8 rating) +bool32 IsAbilityOfRating(enum Ability ability, s8 rating) { if (gAbilitiesInfo[ability].aiRating >= rating) return TRUE; @@ -4546,24 +4763,29 @@ static bool32 HasMoveThatChangesKOThreshold(u32 battlerId, u32 noOfHitsToFaint, return FALSE; } -static u32 GetStatBeingChanged(enum StatChange statChange) +static enum Stat GetStatBeingChanged(enum StatChange statChange) { switch(statChange) { case STAT_CHANGE_ATK: case STAT_CHANGE_ATK_2: + case STAT_CHANGE_ATK_3: return STAT_ATK; case STAT_CHANGE_DEF: case STAT_CHANGE_DEF_2: + case STAT_CHANGE_DEF_3: return STAT_DEF; case STAT_CHANGE_SPEED: case STAT_CHANGE_SPEED_2: + case STAT_CHANGE_SPEED_3: return STAT_SPEED; case STAT_CHANGE_SPATK: case STAT_CHANGE_SPATK_2: + case STAT_CHANGE_SPATK_3: return STAT_SPATK; case STAT_CHANGE_SPDEF: case STAT_CHANGE_SPDEF_2: + case STAT_CHANGE_SPDEF_3: return STAT_SPDEF; case STAT_CHANGE_ACC: return STAT_ACC; @@ -4573,6 +4795,34 @@ static u32 GetStatBeingChanged(enum StatChange statChange) return 0; // STAT_HP, should never be getting changed } +static u32 GetStagesOfStatChange(enum StatChange statChange) +{ + switch(statChange) + { + case STAT_CHANGE_ATK: + case STAT_CHANGE_DEF: + case STAT_CHANGE_SPEED: + case STAT_CHANGE_SPATK: + case STAT_CHANGE_SPDEF: + case STAT_CHANGE_ACC: + case STAT_CHANGE_EVASION: + return 1; + case STAT_CHANGE_ATK_2: + case STAT_CHANGE_DEF_2: + case STAT_CHANGE_SPEED_2: + case STAT_CHANGE_SPATK_2: + case STAT_CHANGE_SPDEF_2: + return 2; + case STAT_CHANGE_ATK_3: + case STAT_CHANGE_DEF_3: + case STAT_CHANGE_SPEED_3: + case STAT_CHANGE_SPATK_3: + case STAT_CHANGE_SPDEF_3: + return 3; + } + return 0; // STAT_HP, should never be getting changed +} + static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, enum StatChange statChange, bool32 considerContrary) { enum AIScore tempScore = NO_INCREASE; @@ -4581,13 +4831,13 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 aiIsFaster = AI_IsFaster(battlerAtk, battlerDef, MOVE_NONE, predictedMoveSpeedCheck, DONT_CONSIDER_PRIORITY); // Don't care about the priority of our setup move, care about outspeeding otherwise u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS); u32 i; - u32 statId = GetStatBeingChanged(statChange); + enum Stat statId = GetStatBeingChanged(statChange); + u32 stages = GetStagesOfStatChange(statChange); if (considerContrary && gAiLogicData->abilities[battlerAtk] == ABILITY_CONTRARY) return NO_INCREASE; - // Don't increase stats if opposing battler has Unaware - if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, gAiLogicData)) + if (!ShouldRaiseAnyStat(battlerAtk, battlerDef)) return NO_INCREASE; // Don't increase stat if AI is at +4 @@ -4598,36 +4848,14 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, if (gAiLogicData->hpPercents[battlerAtk] < 70 && noOfHitsToFaint == UNKNOWN_NO_OF_HITS) return NO_INCREASE; - // Don't set up if AI is dead to residual damage from weather - if (GetBattlerSecondaryDamage(battlerAtk) >= gBattleMons[battlerAtk].hp) - return NO_INCREASE; - - // Don't increase stats if opposing battler has Opportunist - if (gAiLogicData->abilities[battlerDef] == ABILITY_OPPORTUNIST) - return NO_INCREASE; - - // Don't increase stats if opposing battler has Encore - if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE)) - return NO_INCREASE; - - // Don't increase stats if opposing battler has used Haze effect or AI effect - if (!RandomPercentage(RNG_AI_BOOST_INTO_HAZE, BOOST_INTO_HAZE_CHANCE) - && HasBattlerSideUsedMoveWithEffect(battlerDef, EFFECT_HAZE)) - return NO_INCREASE; - - // Don't increase if AI is at +1 and opponent has Haze effect - if (gBattleMons[battlerAtk].statStages[statId] >= MAX_STAT_STAGE - 5 - && HasBattlerSideMoveWithAIEffect(battlerDef, AI_EFFECT_RESET_STATS)) - return NO_INCREASE; - - // Don't increase stats if AI could KO target through Sturdy effect, as otherwise it always 2HKOs - if (CanBattlerKOTargetIgnoringSturdy(battlerAtk, battlerDef)) - return NO_INCREASE; - // Don't increase stats if player has a move that can change the KO threshold if (HasMoveThatChangesKOThreshold(battlerDef, noOfHitsToFaint, aiIsFaster)) return NO_INCREASE; + // Stat stages are effectively doubled under Simple. + if (gAiLogicData->abilities[battlerAtk] == ABILITY_SIMPLE) + stages *= 2; + // Predicting switch if (IsBattlerPredictedToSwitch(battlerDef)) { @@ -4646,80 +4874,75 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, tempScore += WEAK_EFFECT; } - switch (statChange) + switch (statId) { - case STAT_CHANGE_ATK: + case STAT_ATK: if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) && shouldSetUp) - tempScore += DECENT_EFFECT; + { + if (stages == 1) + tempScore += DECENT_EFFECT; + else + tempScore += GOOD_EFFECT; + } break; - case STAT_CHANGE_DEF: + case STAT_DEF: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) { if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) - tempScore += DECENT_EFFECT; - else tempScore += WEAK_EFFECT; + if (stages == 1) + tempScore += WEAK_EFFECT; + else + tempScore += DECENT_EFFECT; } break; - case STAT_CHANGE_SPEED: + case STAT_SPEED: if ((noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS) - tempScore += DECENT_EFFECT; + { + if (stages == 1) + tempScore += DECENT_EFFECT; + else + tempScore += GOOD_EFFECT; + } break; - case STAT_CHANGE_SPATK: + case STAT_SPATK: if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL) && shouldSetUp) - tempScore += DECENT_EFFECT; + { + if (stages == 1) + tempScore += DECENT_EFFECT; + else + tempScore += GOOD_EFFECT; + } break; - case STAT_CHANGE_SPDEF: + case STAT_SPDEF: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) { if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) - tempScore += DECENT_EFFECT; - else tempScore += WEAK_EFFECT; - } - break; - case STAT_CHANGE_ATK_2: - if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) && shouldSetUp) - tempScore += GOOD_EFFECT; - break; - case STAT_CHANGE_DEF_2: - if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) - { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) - tempScore += GOOD_EFFECT; + if (stages == 1) + tempScore += WEAK_EFFECT; else tempScore += DECENT_EFFECT; } break; - case STAT_CHANGE_SPEED_2: - if ((noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS) - tempScore += GOOD_EFFECT; - break; - case STAT_CHANGE_SPATK_2: - if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL) && shouldSetUp) - tempScore += GOOD_EFFECT; - break; - case STAT_CHANGE_SPDEF_2: - if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) - { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) - tempScore += GOOD_EFFECT; - else - tempScore += DECENT_EFFECT; - } - break; - case STAT_CHANGE_ACC: + case STAT_ACC: if (gBattleMons[battlerAtk].statStages[statId] <= 3) // Increase only if necessary tempScore += DECENT_EFFECT; break; - case STAT_CHANGE_EVASION: + case STAT_EVASION: if (noOfHitsToFaint > 3 || noOfHitsToFaint == UNKNOWN_NO_OF_HITS) tempScore += GOOD_EFFECT; else tempScore += DECENT_EFFECT; break; + default: + break; } + // if already inclined to boost, be slightly more likely to if boost levels matter + if (tempScore > 0 && HasMoveWithEffect(battlerAtk, EFFECT_STORED_POWER)) + tempScore += WEAK_EFFECT; + return tempScore; } @@ -4864,7 +5087,7 @@ void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score } } -bool32 AI_MoveMakesContact(u32 ability, enum ItemHoldEffect holdEffect, u32 move) +bool32 AI_MoveMakesContact(enum Ability ability, enum HoldEffect holdEffect, u32 move) { if (MoveMakesContact(move) && ability != ABILITY_LONG_REACH @@ -4873,35 +5096,160 @@ bool32 AI_MoveMakesContact(u32 ability, enum ItemHoldEffect holdEffect, u32 move return FALSE; } + +bool32 IsConsideringZMove(u32 battlerAtk, u32 battlerDef, u32 move) +{ + if (GetMovePower(move) == 0 && GetMoveZEffect(move) == Z_EFFECT_NONE) + return FALSE; + + return gBattleStruct->gimmick.usableGimmick[battlerAtk] == GIMMICK_Z_MOVE && ShouldUseZMove(battlerAtk, battlerDef, move); +} + //TODO - this could use some more sophisticated logic bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove) { + // simple logic. just upgrades chosen move to z move if possible, unless regular move would kill opponent - if ((IsDoubleBattle()) && battlerDef == BATTLE_PARTNER(battlerAtk)) + if ((IsDoubleBattle()) && battlerDef == BATTLE_PARTNER(battlerAtk) && !(GetBattlerMoveTargetType(battlerAtk, chosenMove) & MOVE_TARGET_ALLY)) return FALSE; // don't use z move on partner if (HasTrainerUsedGimmick(battlerAtk, GIMMICK_Z_MOVE)) return FALSE; // can't use z move twice if (IsViableZMove(battlerAtk, chosenMove)) { - uq4_12_t effectiveness; + enum BattleMoveEffects baseEffect = GetMoveEffect(chosenMove); + bool32 isEager = FALSE; // more likely to use a z move than typical + + u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, gAiLogicData); + bool32 isSlower = AI_IsSlower(battlerAtk, battlerDef, chosenMove, predictedMoveSpeedCheck, CONSIDER_PRIORITY); + + switch (baseEffect) + { + case EFFECT_BELLY_DRUM: + case EFFECT_FILLET_AWAY: + if (isSlower) + return TRUE; + isEager = TRUE; + break; + case EFFECT_PROTECT: + if (HasDamagingMoveOfType(battlerAtk, GetMoveType(gMovesInfo[chosenMove].type))) + return FALSE; + else + isEager = TRUE; + break; + case EFFECT_TELEPORT: + isEager = TRUE; + break; + case EFFECT_TRANSFORM: + if (IsBattlerTrapped(battlerDef, battlerAtk) && !HasDamagingMoveOfType(battlerDef, GetMoveType(gMovesInfo[chosenMove].type))) + return TRUE; + if (isSlower) + isEager = TRUE; + break; + default: + break; + } + u32 zMove = GetUsableZMove(battlerAtk, chosenMove); + + if (IsBattleMoveStatus(chosenMove)) + { + u8 zEffect = GetMoveZEffect(chosenMove); + enum StatChange statChange = 0; + + if (zEffect == Z_EFFECT_CURSE) + { + if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) + zEffect = Z_EFFECT_RECOVER_HP; + else + zEffect = Z_EFFECT_ATK_UP_1; + } + + switch (zEffect) + { + case Z_EFFECT_NONE: + if (GetMovePower(chosenMove) == 0) + return FALSE; + break; + case Z_EFFECT_RESET_STATS: + if (CountNegativeStatStages(battlerAtk) > 1) + return TRUE; + break; + case Z_EFFECT_ALL_STATS_UP_1: + return ShouldRaiseAnyStat(battlerAtk, battlerDef); + case Z_EFFECT_BOOST_CRITS: + return TRUE; + case Z_EFFECT_FOLLOW_ME: + return HasPartnerIgnoreFlags(battlerAtk) && (GetHealthPercentage(battlerAtk) <= Z_EFFECT_FOLLOW_ME_THRESHOLD || GetBestNoOfHitsToKO(battlerDef, battlerAtk, AI_DEFENDING) == 1); + break; + case Z_EFFECT_RECOVER_HP: + if (GetBestNoOfHitsToKO(battlerDef, battlerAtk, AI_DEFENDING) == 1 && GetHealthPercentage(battlerAtk) > Z_EFFECT_RESTORE_HP_HIGHER_THRESHOLD) + return TRUE; + if (isEager) + return GetHealthPercentage(battlerAtk) <= Z_EFFECT_RESTORE_HP_HIGHER_THRESHOLD; + return GetHealthPercentage(battlerAtk) <= Z_EFFECT_RESTORE_HP_LOWER_THRESHOLD; + case Z_EFFECT_RESTORE_REPLACEMENT_HP: + break; + case Z_EFFECT_ACC_UP_1: + case Z_EFFECT_ACC_UP_2: + case Z_EFFECT_ACC_UP_3: + statChange = STAT_CHANGE_ACC; + break; + case Z_EFFECT_EVSN_UP_1: + case Z_EFFECT_EVSN_UP_2: + case Z_EFFECT_EVSN_UP_3: + statChange = STAT_CHANGE_EVASION; + break; + case Z_EFFECT_ATK_UP_1: + case Z_EFFECT_DEF_UP_1: + case Z_EFFECT_SPD_UP_1: + case Z_EFFECT_SPATK_UP_1: + case Z_EFFECT_SPDEF_UP_1: + statChange = STAT_CHANGE_ATK + zEffect - Z_EFFECT_ATK_UP_1; + break; + case Z_EFFECT_ATK_UP_2: + case Z_EFFECT_DEF_UP_2: + case Z_EFFECT_SPD_UP_2: + case Z_EFFECT_SPATK_UP_2: + case Z_EFFECT_SPDEF_UP_2: + statChange = STAT_CHANGE_ATK_2 + zEffect - Z_EFFECT_ATK_UP_2; + break; + case Z_EFFECT_ATK_UP_3: + case Z_EFFECT_DEF_UP_3: + case Z_EFFECT_SPD_UP_3: + case Z_EFFECT_SPATK_UP_3: + case Z_EFFECT_SPDEF_UP_3: + statChange = STAT_CHANGE_ATK_2 + zEffect - Z_EFFECT_ATK_UP_3; + break; + default: + return FALSE; + } + + if (statChange != 0 && (isEager || IncreaseStatUpScore(battlerAtk, battlerDef, statChange) > 0)) + return TRUE; + + } + else if (GetMoveEffect(zMove) == EFFECT_EXTREME_EVOBOOST) + { + return ShouldRaiseAnyStat(battlerAtk, battlerDef); + } + else if (!IsBattleMoveStatus(chosenMove) && IsBattleMoveStatus(zMove)) + { + return FALSE; + } + + uq4_12_t effectiveness; struct SimulatedDamage dmg; if (gBattleMons[battlerDef].ability == ABILITY_DISGUISE && !MoveIgnoresTargetAbility(zMove) - && (gBattleMons[battlerDef].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battlerDef].species == SPECIES_MIMIKYU_TOTEM_DISGUISED)) + && IsMimikyuDisguised(battlerDef)) return FALSE; // Don't waste a Z-Move busting disguise if (gBattleMons[battlerDef].ability == ABILITY_ICE_FACE && !MoveIgnoresTargetAbility(zMove) && gBattleMons[battlerDef].species == SPECIES_EISCUE_ICE && IsBattleMovePhysical(chosenMove)) return FALSE; // Don't waste a Z-Move busting Ice Face - if (IsBattleMoveStatus(chosenMove) && !IsBattleMoveStatus(zMove)) - return FALSE; - else if (!IsBattleMoveStatus(chosenMove) && IsBattleMoveStatus(zMove)) - return FALSE; - dmg = AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, NO_GIMMICK, NO_GIMMICK); if (!IsBattleMoveStatus(chosenMove) && dmg.minimum >= gBattleMons[battlerDef].hp) @@ -5013,7 +5361,8 @@ void DecideTerastal(u32 battler) #define takenWithTera altCalcs->takenWithTera #define takenWithoutTera gAiLogicData->simulatedDmg[opposingBattler][battler] -enum AIConsiderGimmick ShouldTeraFromCalcs(u32 battler, u32 opposingBattler, struct AltTeraCalcs *altCalcs) { +enum AIConsiderGimmick ShouldTeraFromCalcs(u32 battler, u32 opposingBattler, struct AltTeraCalcs *altCalcs) +{ struct Pokemon* party = GetBattlerParty(battler); // Check how many pokemon we have that could tera @@ -5190,7 +5539,7 @@ s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle) bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) { - u8 i; + enum Stat i; // Want to copy positive stat changes for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) { @@ -5203,13 +5552,15 @@ bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) case STAT_SPATK: return (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)); case STAT_ACC: - return (HasLowAccuracyMove(battlerAtk, battlerDef)); + return HasMoveWithLowAccuracy(battlerAtk, battlerDef, LOW_ACCURACY_THRESHOLD, FALSE); case STAT_EVASION: case STAT_SPEED: return TRUE; case STAT_DEF: case STAT_SPDEF: return (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL); + default: + break; } } } @@ -5264,14 +5615,14 @@ void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, struct AiLogicData *aiData) { u32 preventsStatLoss; - u32 partnerAbility = aiData->abilities[battlerAtkPartner]; + enum Ability partnerAbility = aiData->abilities[battlerAtkPartner]; u32 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battlerAtk)); u32 opposingBattler = GetBattlerAtPosition(opposingPosition); if (gBattleMons[battlerAtkPartner].statStages[STAT_ATK] == MAX_STAT_STAGE || partnerAbility == ABILITY_CONTRARY || partnerAbility == ABILITY_GOOD_AS_GOLD - || HasBattlerSideMoveWithEffect(FOE(battlerAtk), EFFECT_FOUL_PLAY)) + || HasBattlerSideMoveWithEffect(LEFT_FOE(battlerAtk), EFFECT_FOUL_PLAY)) return FALSE; preventsStatLoss = !CanLowerStat(battlerAtk, battlerAtkPartner, aiData, STAT_DEF); @@ -5334,17 +5685,6 @@ u32 IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) return scoreIncrease; } -bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef) -{ - int i; - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gAiLogicData->moveAccuracy[battlerAtk][battlerDef][i] <= LOW_ACCURACY_THRESHOLD) - return TRUE; - } - return FALSE; -} - bool32 IsBattlerItemEnabled(u32 battler) { if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_NEGATE_UNAWARE) @@ -5358,15 +5698,6 @@ bool32 IsBattlerItemEnabled(u32 battler) return TRUE; } -bool32 HasBattlerSideAbility(u32 battler, u32 ability, struct AiLogicData *aiData) -{ - if (aiData->abilities[battler] == ability) - return TRUE; - if (HasPartnerIgnoreFlags(battler) && gAiLogicData->abilities[BATTLE_PARTNER(battler)] == ability) - return TRUE; - return FALSE; -} - u32 GetFriendlyFireKOThreshold(u32 battler) { if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) @@ -5379,7 +5710,7 @@ u32 GetFriendlyFireKOThreshold(u32 battler) return FRIENDLY_FIRE_NORMAL_THRESHOLD; } -bool32 IsMoxieTypeAbility(u32 ability) +bool32 IsMoxieTypeAbility(enum Ability ability) { switch (ability) { @@ -5395,7 +5726,7 @@ bool32 IsMoxieTypeAbility(u32 ability) } } -bool32 DoesAbilityRaiseStatsWhenLowered(u32 ability) +bool32 DoesAbilityRaiseStatsWhenLowered(enum Ability ability) { switch (ability) { @@ -5408,7 +5739,7 @@ bool32 DoesAbilityRaiseStatsWhenLowered(u32 ability) } } -bool32 DoesIntimidateRaiseStats(u32 ability) +bool32 DoesIntimidateRaiseStats(enum Ability ability) { switch (ability) { @@ -5424,7 +5755,7 @@ bool32 DoesIntimidateRaiseStats(u32 ability) } // TODO: work out when to attack into the player's contextually 'beneficial' ability -bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, u32 ability) +bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability) { if (IsTargetingPartner(battlerAtk, battlerDef)) { @@ -5479,8 +5810,10 @@ bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, u32 ability) // Used by CheckBadMove; this is determining purely if the effect CAN change an ability, not if it SHOULD. // At the moment, the parts about Mummy and Wandering Spirit are not actually used. -bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct AiLogicData *aiData) +bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData) { + u32 effect = GetMoveEffect(move); + // Dynamaxed Pokemon are immune to some ability-changing effects. if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) { @@ -5497,8 +5830,8 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct if (gBattleMons[battlerDef].volatiles.gastroAcid) return FALSE; - u32 atkAbility = aiData->abilities[battlerAtk]; - u32 defAbility = aiData->abilities[battlerDef]; + enum Ability atkAbility = aiData->abilities[battlerAtk]; + enum Ability defAbility = aiData->abilities[battlerDef]; bool32 hasSameAbility = (atkAbility == defAbility); if (defAbility == ABILITY_NONE) @@ -5556,13 +5889,8 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct return FALSE; break; - case EFFECT_SIMPLE_BEAM: - if (defAbility == ABILITY_SIMPLE || gAbilitiesInfo[defAbility].cantBeOverwritten) - return FALSE; - break; - - case EFFECT_WORRY_SEED: - if (defAbility == ABILITY_INSOMNIA || gAbilitiesInfo[defAbility].cantBeOverwritten) + case EFFECT_OVERWRITE_ABILITY: + if (defAbility == GetMoveOverwriteAbility(move) || gAbilitiesInfo[defAbility].cantBeOverwritten) return FALSE; break; @@ -5577,9 +5905,8 @@ bool32 CanEffectChangeAbility(u32 battlerAtk, u32 battlerDef, u32 effect, struct case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: case EFFECT_ROLE_PLAY: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: + case EFFECT_OVERWRITE_ABILITY: return FALSE; default: break; @@ -5608,20 +5935,20 @@ bool32 DoesEffectReplaceTargetAbility(u32 effect) { case EFFECT_ENTRAINMENT: case EFFECT_GASTRO_ACID: - case EFFECT_SIMPLE_BEAM: case EFFECT_SKILL_SWAP: - case EFFECT_WORRY_SEED: + case EFFECT_OVERWRITE_ABILITY: return TRUE; default: return FALSE; } } -void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, struct AiLogicData *aiData) +void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score, struct AiLogicData *aiData) { + u32 effect = GetMoveEffect(move); bool32 isTargetingPartner = IsTargetingPartner(battlerAtk, battlerDef); - u32 abilityAtk = aiData->abilities[battlerAtk]; - u32 abilityDef = aiData->abilities[battlerDef]; + enum Ability abilityAtk = aiData->abilities[battlerAtk]; + enum Ability abilityDef = aiData->abilities[battlerDef]; bool32 partnerHasBadAbility = FALSE; u32 partnerAbility = ABILITY_NONE; bool32 attackerHasBadAbility = (gAbilitiesInfo[abilityAtk].aiRating < 0); @@ -5636,10 +5963,8 @@ void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, if (effect == EFFECT_GASTRO_ACID) abilityAtk = ABILITY_NONE; - else if (effect == EFFECT_SIMPLE_BEAM) - abilityAtk = ABILITY_SIMPLE; - else if (effect == EFFECT_WORRY_SEED) - abilityAtk = ABILITY_INSOMNIA; + else if (effect == EFFECT_OVERWRITE_ABILITY) + abilityAtk = GetMoveOverwriteAbility(move); if (effect == EFFECT_DOODLE || effect == EFFECT_ROLE_PLAY || effect == EFFECT_SKILL_SWAP) { @@ -5691,7 +6016,7 @@ void AbilityChangeScore(u32 battlerAtk, u32 battlerDef, u32 effect, s32 *score, } } -s32 BattlerBenefitsFromAbilityScore(u32 battler, u32 ability, struct AiLogicData *aiData) +s32 BattlerBenefitsFromAbilityScore(u32 battler, enum Ability ability, struct AiLogicData *aiData) { if (gAbilitiesInfo[ability].aiRating < 0) return WORST_EFFECT; @@ -5709,7 +6034,8 @@ s32 BattlerBenefitsFromAbilityScore(u32 battler, u32 ability, struct AiLogicData return GOOD_EFFECT; // Conditional ability logic goes here. case ABILITY_COMPOUND_EYES: - if (HasMoveWithLowAccuracy(battler, FOE(battler), 90, TRUE, aiData->abilities[battler], aiData->abilities[FOE(battler)], aiData->holdEffects[battler], aiData->holdEffects[FOE(battler)])) + if (HasMoveWithLowAccuracy(battler, LEFT_FOE(battler), 90, FALSE) + || HasMoveWithLowAccuracy(battler, RIGHT_FOE(battler), 90, FALSE)) return GOOD_EFFECT; break; case ABILITY_CONTRARY: @@ -5741,7 +6067,7 @@ s32 BattlerBenefitsFromAbilityScore(u32 battler, u32 ability, struct AiLogicData break; case ABILITY_INTIMIDATE: { - u32 abilityDef = aiData->abilities[FOE(battler)]; + enum Ability abilityDef = aiData->abilities[LEFT_FOE(battler)]; if (DoesIntimidateRaiseStats(abilityDef)) { return AWFUL_EFFECT; @@ -5750,26 +6076,27 @@ s32 BattlerBenefitsFromAbilityScore(u32 battler, u32 ability, struct AiLogicData { if (HasTwoOpponents(battler)) { - abilityDef = aiData->abilities[BATTLE_PARTNER(FOE(battler))]; + abilityDef = aiData->abilities[RIGHT_FOE(battler)]; if (DoesIntimidateRaiseStats(abilityDef)) { return AWFUL_EFFECT; } else { - s32 score1 = IncreaseStatDownScore(battler, FOE(battler), STAT_ATK); - s32 score2 = IncreaseStatDownScore(battler, BATTLE_PARTNER(FOE(battler)), STAT_ATK); + s32 score1 = IncreaseStatDownScore(battler, LEFT_FOE(battler), STAT_ATK); + s32 score2 = IncreaseStatDownScore(battler, RIGHT_FOE(battler), STAT_ATK); if (score1 > score2) return score1; else return score2; } } - return IncreaseStatDownScore(battler, FOE(battler), STAT_ATK); + return IncreaseStatDownScore(battler, LEFT_FOE(battler), STAT_ATK); } } case ABILITY_NO_GUARD: - if (HasLowAccuracyMove(battler, FOE(battler))) + if (HasMoveWithLowAccuracy(battler, LEFT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE) + || HasMoveWithLowAccuracy(battler, RIGHT_FOE(battler), LOW_ACCURACY_THRESHOLD, FALSE)) return GOOD_EFFECT; break; // Toxic counter ticks upward while Poison Healed; losing Poison Heal while Toxiced can KO. diff --git a/src/battle_anim.c b/src/battle_anim.c index 839f319031..f08c1eaa8d 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -196,6 +196,7 @@ static const u8* const sBattleAnims_StatusConditions[NUM_B_ANIMS_STATUS] = [B_ANIM_STATUS_FRZ] = gBattleAnimStatus_Freeze, [B_ANIM_STATUS_CURSED] = gBattleAnimStatus_Curse, [B_ANIM_STATUS_NIGHTMARE] = gBattleAnimStatus_Nightmare, + [B_ANIM_STATUS_FRB] = gBattleAnimStatus_Frostbite, }; static const u8* const sBattleAnims_General[NUM_B_ANIMS_GENERAL] = @@ -2221,7 +2222,7 @@ static void Cmd_stopsound(void) static void Cmd_jumpifmovetypeequal(void) { - const u8 *type = sBattleAnimScriptPtr + 1; + const enum Type *type = sBattleAnimScriptPtr + 1; sBattleAnimScriptPtr += 2; if (*type != GetBattleMoveType(gCurrentMove)) sBattleAnimScriptPtr += 4; diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index 49ec4e5e3a..4699f2008a 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -6831,10 +6831,10 @@ static void TrySwapStickyWebBattlerId(u32 battlerAtk, u32 battlerPartner) static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner) { u32 i, temp; - u32 oppSide = GetBattlerSide(BATTLE_OPPOSITE(battlerAtk)); // if used future sight on opposing side, properly track who used it - if (gSideStatuses[oppSide] & SIDE_STATUS_FUTUREATTACK) + if (gWishFutureKnock.futureSightCounter[LEFT_FOE(battlerAtk)] > 0 + || gWishFutureKnock.futureSightCounter[RIGHT_FOE(battlerAtk)] > 0) { for (i = 0; i < gBattlersCount; i++) { @@ -6858,8 +6858,8 @@ static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner) } // swap wish party indices - if (gWishFutureKnock.wishCounter[battlerAtk] > gBattleTurnCounter - || gWishFutureKnock.wishCounter[battlerPartner] > gBattleTurnCounter) + if (gWishFutureKnock.wishCounter[battlerAtk] > 0 + || gWishFutureKnock.wishCounter[battlerPartner] > 0) SWAP(gWishFutureKnock.wishPartyId[battlerAtk], gWishFutureKnock.wishPartyId[battlerPartner], temp); } @@ -6964,7 +6964,7 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) // For Snipe Shot and abilities Stalwart/Propeller Tail - keep the original target. for (i = 0; i < gBattlersCount; i++) { - u16 ability = GetBattlerAbility(i); + enum Ability ability = GetBattlerAbility(i); // if not targeting a slot that got switched, continue if (!IsBattlerAlly(gBattleStruct->moveTarget[i], battlerAtk)) continue; diff --git a/src/battle_anim_effects_3.c b/src/battle_anim_effects_3.c index e30a8afd15..cc6203ce5b 100644 --- a/src/battle_anim_effects_3.c +++ b/src/battle_anim_effects_3.c @@ -5775,7 +5775,7 @@ static void AnimRecycle_Step(struct Sprite *sprite) void AnimTask_GetWeather(u8 taskId) { - bool32 utilityUmbrellaAffected = GetBattlerHoldEffect(gBattleAnimAttacker, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA; + bool32 utilityUmbrellaAffected = GetBattlerHoldEffect(gBattleAnimAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA; gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_NONE; if (gWeatherMoveAnim & B_WEATHER_SUN && !utilityUmbrellaAffected) diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index 378fde42a4..fff35b4073 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -9058,7 +9058,7 @@ void AnimTask_ShellSideArm(u8 taskId) void AnimTask_TerrainPulse(u8 taskId) { - if (IsBattlerTerrainAffected(gBattleAnimAttacker, STATUS_FIELD_TERRAIN_ANY)) + if (IsBattlerTerrainAffected(gBattleAnimAttacker, GetBattlerAbility(gBattleAnimAttacker), GetBattlerHoldEffect(gBattleAnimAttacker), STATUS_FIELD_TERRAIN_ANY)) { if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) gBattleAnimArgs[0] = TYPE_ELECTRIC; diff --git a/src/battle_anim_status_effects.c b/src/battle_anim_status_effects.c index b70f481d6c..f27d7da0ea 100644 --- a/src/battle_anim_status_effects.c +++ b/src/battle_anim_status_effects.c @@ -530,7 +530,7 @@ static void AnimTask_FrozenIceCube_Step4(u8 taskId) void AnimTask_StatsChange(u8 taskId) { bool16 goesDown = FALSE; - s16 animStatId = 0; + enum StatAnimPal animStatId = 0; bool16 sharply = FALSE; switch (gBattleSpritesDataPtr->animationData->animArg) diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index 5860a57630..d276c80ddb 100644 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -2313,7 +2313,7 @@ void AnimTask_SwapMonSpriteToFromSubstitute(u8 taskId) { u8 spriteId; u32 x; - u32 done = FALSE; + bool32 done = FALSE; spriteId = gBattlerSpriteIds[gBattleAnimAttacker]; switch (gTasks[taskId].data[10]) diff --git a/src/battle_anim_utility_funcs.c b/src/battle_anim_utility_funcs.c index 54b9f949ba..54aa3e14aa 100644 --- a/src/battle_anim_utility_funcs.c +++ b/src/battle_anim_utility_funcs.c @@ -480,7 +480,7 @@ static void StatsChangeAnimation_Step2(u8 taskId) AnimLoadCompressedBgTilemapHandleContest(&animBgData, gStatAnim_Decrease_Tilemap, FALSE); AnimLoadCompressedBgGfx(animBgData.bgId, gStatAnim_Gfx, animBgData.tilesOffset); - switch (sAnimStatsChangeData->aAnimStatId) + switch ((enum StatAnimPal)sAnimStatsChangeData->aAnimStatId) { case STAT_ANIM_PAL_ATK: LoadPalette(gStatAnim_Attack_Pal, BG_PLTT_ID(animBgData.paletteId), PLTT_SIZE_4BPP); diff --git a/src/battle_arena.c b/src/battle_arena.c index 8474595b0d..3708fec024 100644 --- a/src/battle_arena.c +++ b/src/battle_arena.c @@ -427,14 +427,11 @@ void BattleArena_DeductSkillPoints(u8 battler, enum StringID stringId) case STRINGID_PKMNSXBLOCKSY2: case STRINGID_PKMNSXPREVENTSYLOSS: case STRINGID_PKMNSXMADEYINEFFECTIVE: - case STRINGID_PKMNSXPREVENTSBURNS: case STRINGID_PKMNSXBLOCKSY: case STRINGID_PKMNPROTECTEDBY: case STRINGID_PKMNPREVENTSUSAGE: case STRINGID_PKMNRESTOREDHPUSING: - case STRINGID_PKMNPREVENTSPARALYSISWITH: case STRINGID_PKMNPREVENTSROMANCEWITH: - case STRINGID_PKMNPREVENTSPOISONINGWITH: case STRINGID_PKMNPREVENTSCONFUSIONWITH: case STRINGID_PKMNRAISEDFIREPOWERWITH: case STRINGID_PKMNANCHORSITSELFWITH: diff --git a/src/battle_bg.c b/src/battle_bg.c index 3524dbee2d..14244c4e95 100644 --- a/src/battle_bg.c +++ b/src/battle_bg.c @@ -19,6 +19,7 @@ #include "sound.h" #include "sprite.h" #include "task.h" +#include "test_runner.h" #include "text_window.h" #include "trig.h" #include "window.h" @@ -650,7 +651,13 @@ static u8 GetBattleEnvironmentOverride(void) { u8 battleScene = GetCurrentMapBattleScene(); - if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_EREADER_TRAINER)) + if (TestRunner_Battle_GetForcedEnvironment() + && gBattleEnvironmentInfo[gBattleEnvironment].background.tilemap + && gBattleEnvironmentInfo[gBattleEnvironment].background.tileset) + { + return gBattleEnvironment; + } + else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_EREADER_TRAINER)) return BATTLE_ENVIRONMENT_FRONTIER; else if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY) { @@ -1022,7 +1029,13 @@ void DrawBattleEntryBackground(void) } else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_EREADER_TRAINER)) { - if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) + if (TestRunner_Battle_GetForcedEnvironment() + && gBattleEnvironmentInfo[gBattleEnvironment].background.tilemap + && gBattleEnvironmentInfo[gBattleEnvironment].background.tileset) + { + LoadBattleEnvironmentEntryGfx(gBattleEnvironment); + } + else if (!(gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) || gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) { LoadBattleEnvironmentEntryGfx(BATTLE_ENVIRONMENT_BUILDING); } diff --git a/src/battle_controller_link_opponent.c b/src/battle_controller_link_opponent.c index 658a2d3831..3418293530 100644 --- a/src/battle_controller_link_opponent.c +++ b/src/battle_controller_link_opponent.c @@ -150,8 +150,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } else { @@ -163,8 +162,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) { - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } } diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 1f1953ea61..a2d40bc5e1 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -39,6 +39,8 @@ #include "constants/trainers.h" #include "trainer_hill.h" #include "test_runner.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void OpponentHandleDrawTrainerPic(u32 battler); static void OpponentHandleTrainerSlideBack(u32 battler); @@ -49,8 +51,6 @@ static void OpponentHandleChoosePokemon(u32 battler); static void OpponentHandleIntroTrainerBallThrow(u32 battler); static void OpponentHandleDrawPartyStatusSummary(u32 battler); static void OpponentHandleEndLinkBattle(u32 battler); -static u8 CountAIAliveNonEggMonsExcept(u8 slotToIgnore); - static void OpponentBufferRunCommand(u32 battler); static void (*const sOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = @@ -159,8 +159,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } else { @@ -174,8 +173,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim) { - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } else { @@ -371,18 +369,40 @@ static u32 OpponentGetTrainerPicId(u32 battlerId) static void OpponentHandleDrawTrainerPic(u32 battler) { s16 xPos; - u32 trainerPicId = OpponentGetTrainerPicId(battler); - - if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) + u32 trainerPicId; + + // Sets Multibattle test opponent sprites to not be Hiker + if (IsMultibattleTest()) { - if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon + if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) + { + trainerPicId = TRAINER_PIC_LEAF; + if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + xPos = 176; + else + xPos = 200; + } + else + { + trainerPicId = TRAINER_PIC_RED; xPos = 152; - else // first mon - xPos = 200; + } } else { - xPos = 176; + trainerPicId = OpponentGetTrainerPicId(battler); + + if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) + { + if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon + xPos = 152; + else // first mon + xPos = 200; + } + else + { + xPos = 176; + } } BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, xPos, 40, -1); @@ -442,12 +462,15 @@ static void OpponentHandleChooseMove(u32 battler) gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); } // If opponent can and should use a gimmick (considering trainer data), do it - if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE && IsAIUsingGimmick(battler)) + enum Gimmick usableGimmick = gBattleStruct->gimmick.usableGimmick[battler]; + if (usableGimmick != GIMMICK_NONE && IsAIUsingGimmick(battler) && !HasTrainerUsedGimmick(battler, usableGimmick)) { + gBattleStruct->gimmick.toActivate |= 1u << battler; BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_EXEC_SCRIPT, (chosenMoveIndex) | (RET_GIMMICK) | (gBattlerTarget << 8)); } else { + SetAIUsingGimmick(battler, NO_GIMMICK); BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_EXEC_SCRIPT, (chosenMoveIndex) | (gBattlerTarget << 8)); } } @@ -505,70 +528,9 @@ static void OpponentHandleChooseItem(u32 battler) BtlController_Complete(battler); } -static inline bool32 IsAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler) -{ - return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_ACE_POKEMON - && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) - && CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle; -} - -static inline bool32 IsDoubleAceSlot(u32 battler, u32 partyId) -{ - u32 partyCountEnd; - - if (!(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON)) - return FALSE; - - partyCountEnd = CalculateEnemyPartyCountInSide(battler); - if (partyCountEnd == 0) - return FALSE; - - if (partyId == partyCountEnd - 1) - return TRUE; - if (partyCountEnd > 1 && partyId == partyCountEnd - 2) - return TRUE; - - return FALSE; -} - -static inline bool32 IsDoubleAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler) -{ - s32 battler1, battler2, firstId, lastId; - s32 i; - - if (!IsDoubleAceSlot(battler, chosenMonId)) - return FALSE; - - if (!IsDoubleBattle()) - { - battler2 = battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - } - else - { - battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - } - - GetAIPartyIndexes(battler, &firstId, &lastId); - for (i = firstId; i < lastId; i++) - { - if (!IsValidForBattle(&gEnemyParty[i]) - || i == gBattlerPartyIndexes[battler1] - || i == gBattlerPartyIndexes[battler2] - || i == chosenMonId) - continue; - - if (!IsAcePokemon(i, pokemonInBattle, battler) && !IsDoubleAceSlot(battler, i)) - return TRUE; - } - - return FALSE; -} - static void OpponentHandleChoosePokemon(u32 battler) { s32 chosenMonId; - s32 pokemonInBattle = 1; enum SwitchType switchType = SWITCH_AFTER_KO; // Choosing Revival Blessing target @@ -580,7 +542,7 @@ static void OpponentHandleChoosePokemon(u32 battler) else if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE) { if (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch) - switchType = SWITCH_MID_BATTLE; + switchType = SWITCH_MID_BATTLE_FORCED; // reset the AI data to consider the correct on-field state at time of switch SetBattlerAiData(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), gAiLogicData); @@ -588,7 +550,7 @@ static void OpponentHandleChoosePokemon(u32 battler) SetBattlerAiData(GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT), gAiLogicData); chosenMonId = GetMostSuitableMonToSwitchInto(battler, switchType); - if (chosenMonId == PARTY_SIZE) + if (chosenMonId == PARTY_SIZE) // Advanced logic failed so we pick the next available battler { s32 battler1, battler2, firstId, lastId; @@ -600,31 +562,24 @@ static void OpponentHandleChoosePokemon(u32 battler) { battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - pokemonInBattle = 2; } GetAIPartyIndexes(battler, &firstId, &lastId); - for (chosenMonId = (lastId-1); chosenMonId >= firstId; chosenMonId--) + for (chosenMonId = firstId; chosenMonId < lastId; chosenMonId++) { - if (!IsValidForBattle(&gEnemyParty[chosenMonId]) - || chosenMonId == gBattlerPartyIndexes[battler1] - || chosenMonId == gBattlerPartyIndexes[battler2]) - continue; - - if (!IsAcePokemon(chosenMonId, pokemonInBattle, battler) - && !IsDoubleAcePokemon(chosenMonId, pokemonInBattle, battler)) + if (IsValidForBattle(&gEnemyParty[chosenMonId]) + && chosenMonId != gBattlerPartyIndexes[battler1] + && chosenMonId != gBattlerPartyIndexes[battler2]) break; } } gBattleStruct->monToSwitchIntoId[battler] = chosenMonId; - GetBattlerPartyState(battler)->sentOut = TRUE; } else { chosenMonId = gBattleStruct->AI_monToSwitchIntoId[battler]; gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; gBattleStruct->monToSwitchIntoId[battler] = chosenMonId; - GetBattlerPartyState(battler)->sentOut = TRUE; } #if TESTING TestRunner_Battle_CheckSwitch(battler, chosenMonId); @@ -633,22 +588,6 @@ static void OpponentHandleChoosePokemon(u32 battler) BtlController_Complete(battler); } -static u8 CountAIAliveNonEggMonsExcept(u8 slotToIgnore) -{ - u16 i, count; - - for (i = 0, count = 0; i < PARTY_SIZE; i++) - { - if (i != slotToIgnore - && IsValidForBattle(&gEnemyParty[i])) - { - count++; - } - } - - return count; -} - static void OpponentHandleIntroTrainerBallThrow(u32 battler) { BtlController_HandleIntroTrainerBallThrow(battler, 0, NULL, 0, Intro_TryShinyAnimShowHealthbox); diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 93fd846a5b..aba9d7d837 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -35,7 +35,6 @@ #include "constants/battle_anim.h" #include "constants/battle_move_effects.h" #include "constants/battle_partner.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/party_menu.h" @@ -47,6 +46,8 @@ #include "pokemon_summary_screen.h" #include "type_icons.h" #include "pokedex.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void PlayerHandleLoadMonSprite(u32 battler); static void PlayerHandleDrawTrainerPic(u32 battler); @@ -1244,8 +1245,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); HandleLowHpMusicChange(GetBattlerMon(battler), battler); @@ -1670,7 +1670,7 @@ static void MoveSelectionDisplayMoveType(u32 battler) struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType); u32 move = moveInfo->moves[gMoveSelectionCursor[battler]]; - u32 type = GetMoveType(move); + enum Type type = GetMoveType(move); enum BattleMoveEffects effect = GetMoveEffect(move); if (effect == EFFECT_TERA_BLAST) @@ -1872,30 +1872,40 @@ static void PlayerHandleDrawTrainerPic(u32 battler) bool32 isFrontPic; s16 xPos, yPos; u32 trainerPicId; - - trainerPicId = PlayerGetTrainerBackPicId(); - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (IsMultibattleTest()) { - if ((GetBattlerPosition(battler) & BIT_FLANK) != B_FLANK_LEFT) // Second mon, on the right. - xPos = 90; - else // First mon, on the left. + trainerPicId = TRAINER_BACK_PIC_BRENDAN; + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) xPos = 32; - - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE)) - { - xPos = 90; - yPos = 80; - } else - { - yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; - } - + xPos = 80; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; } else { - xPos = 80; - yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + trainerPicId = PlayerGetTrainerBackPicId(); + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if ((GetBattlerPosition(battler) & BIT_FLANK) != B_FLANK_LEFT) // Second mon, on the right. + xPos = 90; + else // First mon, on the left. + xPos = 32; + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE)) + { + xPos = 90; + yPos = 80; + } + else + { + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + } + else + { + xPos = 80; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } } // Use front pic table for any tag battles unless your partner is Steven or a custom partner. @@ -1995,7 +2005,7 @@ static void PlayerHandleChooseAction(u32 battler) if (B_SHOW_PARTNER_TARGET && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && IsBattlerAlive(B_POSITION_PLAYER_RIGHT)) { StringCopy(gStringVar1, COMPOUND_STRING("Partner will use:\n")); - u32 move = gBattleMons[B_POSITION_PLAYER_RIGHT].moves[gBattleStruct->chosenMovePositions[B_POSITION_PLAYER_RIGHT]]; + u32 move = GetChosenMoveFromPosition(B_POSITION_PLAYER_RIGHT); StringAppend(gStringVar1, GetMoveName(move)); u32 moveTarget = GetBattlerMoveTargetType(B_POSITION_PLAYER_RIGHT, move); if (moveTarget == MOVE_TARGET_SELECTED) @@ -2363,8 +2373,8 @@ static u32 CheckTypeEffectiveness(u32 battlerAtk, u32 battlerDef) ctx.updateFlags = FALSE; ctx.abilityAtk = GetBattlerAbility(battlerAtk); ctx.abilityDef = GetBattlerAbility(battlerDef); - ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); - ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); + ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk); + ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef); uq4_12_t modifier = CalcTypeEffectivenessMultiplier(&ctx); diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index 58911f1518..37af6497df 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -31,6 +31,8 @@ #include "constants/songs.h" #include "constants/party_menu.h" #include "constants/trainers.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void PlayerPartnerHandleDrawTrainerPic(u32 battler); static void PlayerPartnerHandleTrainerSlideBack(u32 battler); @@ -204,7 +206,13 @@ static void PlayerPartnerHandleDrawTrainerPic(u32 battler) enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId); - if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) + if (IsMultibattleTest()) + { + trainerPicId = TRAINER_BACK_PIC_STEVEN; + xPos = 90; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + else if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) { trainerPicId = gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerBackPic; xPos = 90; @@ -261,12 +269,15 @@ static void PlayerPartnerHandleChooseMove(u32 battler) gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); } // If partner can and should use a gimmick (considering trainer data), do it - if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE && IsAIUsingGimmick(battler)) + enum Gimmick usableGimmick = gBattleStruct->gimmick.usableGimmick[battler]; + if (usableGimmick != GIMMICK_NONE && IsAIUsingGimmick(battler) && !HasTrainerUsedGimmick(battler, usableGimmick)) { + gBattleStruct->gimmick.toActivate |= 1u << battler; BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_EXEC_SCRIPT, (chosenMoveIndex) | (RET_GIMMICK) | (gBattlerTarget << 8)); } else { + SetAIUsingGimmick(battler, NO_GIMMICK); BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_EXEC_SCRIPT, (chosenMoveIndex) | (gBattlerTarget << 8)); } @@ -302,15 +313,15 @@ static void PlayerPartnerHandleChoosePokemon(u32 battler) } } gBattleStruct->monToSwitchIntoId[battler] = chosenMonId; - GetBattlerPartyState(battler)->sentOut = TRUE; } else // Mon to switch out has been already chosen. { chosenMonId = gBattleStruct->monToSwitchIntoId[battler]; gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE; gBattleStruct->monToSwitchIntoId[battler] = chosenMonId; - GetBattlerPartyState(battler)->sentOut = TRUE; } + if (TESTING) + TestRunner_Battle_CheckSwitch(battler, chosenMonId); BtlController_EmitChosenMonReturnValue(battler, B_COMM_TO_ENGINE, chosenMonId, NULL); BtlController_Complete(battler); } diff --git a/src/battle_controller_recorded_opponent.c b/src/battle_controller_recorded_opponent.c index a27318aee8..954fdc4bc3 100644 --- a/src/battle_controller_recorded_opponent.c +++ b/src/battle_controller_recorded_opponent.c @@ -31,6 +31,8 @@ #include "constants/battle_anim.h" #include "constants/songs.h" #include "constants/trainers.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void RecordedOpponentHandleDrawTrainerPic(u32 battler); static void RecordedOpponentHandleTrainerSlideBack(u32 battler); @@ -170,8 +172,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); } gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3; @@ -274,7 +275,24 @@ static void RecordedOpponentHandleDrawTrainerPic(u32 battler) s16 xPos; u32 trainerPicId; - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + // Sets Multibattle test opponent sprites to not be Hiker + if (IsMultibattleTest()) + { + if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) + { + trainerPicId = TRAINER_PIC_LEAF; + if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + xPos = 176; + else + xPos = 200; + } + else + { + trainerPicId = TRAINER_PIC_RED; + xPos = 152; + } + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon xPos = 152; diff --git a/src/battle_controller_recorded_partner.c b/src/battle_controller_recorded_partner.c new file mode 100644 index 0000000000..d135329635 --- /dev/null +++ b/src/battle_controller_recorded_partner.c @@ -0,0 +1,269 @@ +#include "global.h" +#include "battle.h" +#include "battle_ai_main.h" +#include "battle_ai_util.h" +#include "battle_anim.h" +#include "battle_controllers.h" +#include "battle_message.h" +#include "battle_interface.h" +#include "battle_setup.h" +#include "battle_tower.h" +#include "battle_z_move.h" +#include "bg.h" +#include "data.h" +#include "item_use.h" +#include "link.h" +#include "main.h" +#include "m4a.h" +#include "palette.h" +#include "party_menu.h" +#include "pokeball.h" +#include "pokemon.h" +#include "recorded_battle.h" +#include "reshow_battle_screen.h" +#include "sound.h" +#include "string_util.h" +#include "task.h" +#include "test_runner.h" +#include "text.h" +#include "util.h" +#include "window.h" +#include "constants/battle_anim.h" +#include "constants/battle_partner.h" +#include "constants/songs.h" +#include "constants/party_menu.h" +#include "constants/trainers.h" + +static void RecordedPartnerHandleDrawTrainerPic(u32 battler); +static void RecordedPartnerHandleTrainerSlideBack(u32 battler); +static void RecordedPartnerHandleChooseAction(u32 battler); +static void RecordedPartnerHandleChooseMove(u32 battler); +static void RecordedPartnerHandleChoosePokemon(u32 battler); +static void RecordedPartnerHandleIntroTrainerBallThrow(u32 battler); +static void RecordedPartnerHandleDrawPartyStatusSummary(u32 battler); +static void RecordedPartnerHandleEndLinkBattle(u32 battler); +static void RecordedPartnerBufferRunCommand(u32 battler); + +static void (*const sRecordedPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = +{ + [CONTROLLER_GETMONDATA] = BtlController_HandleGetMonData, + [CONTROLLER_GETRAWMONDATA] = BtlController_Empty, + [CONTROLLER_SETMONDATA] = BtlController_HandleSetMonData, + [CONTROLLER_SETRAWMONDATA] = BtlController_HandleSetRawMonData, + [CONTROLLER_LOADMONSPRITE] = BtlController_HandleLoadMonSprite, + [CONTROLLER_SWITCHINANIM] = BtlController_HandleSwitchInAnim, + [CONTROLLER_RETURNMONTOBALL] = BtlController_HandleReturnMonToBall, + [CONTROLLER_DRAWTRAINERPIC] = RecordedPartnerHandleDrawTrainerPic, + [CONTROLLER_TRAINERSLIDE] = BtlController_Empty, + [CONTROLLER_TRAINERSLIDEBACK] = RecordedPartnerHandleTrainerSlideBack, + [CONTROLLER_FAINTANIMATION] = BtlController_HandleFaintAnimation, + [CONTROLLER_PALETTEFADE] = BtlController_Empty, + [CONTROLLER_SUCCESSBALLTHROWANIM] = BtlController_Empty, + [CONTROLLER_BALLTHROWANIM] = BtlController_Empty, + [CONTROLLER_PAUSE] = BtlController_Empty, + [CONTROLLER_MOVEANIMATION] = BtlController_HandleMoveAnimation, + [CONTROLLER_PRINTSTRING] = BtlController_HandlePrintString, + [CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, + [CONTROLLER_CHOOSEACTION] = RecordedPartnerHandleChooseAction, + [CONTROLLER_YESNOBOX] = BtlController_Empty, + [CONTROLLER_CHOOSEMOVE] = RecordedPartnerHandleChooseMove, + [CONTROLLER_OPENBAG] = BtlController_Empty, + [CONTROLLER_CHOOSEPOKEMON] = RecordedPartnerHandleChoosePokemon, + [CONTROLLER_23] = BtlController_Empty, + [CONTROLLER_HEALTHBARUPDATE] = BtlController_HandleHealthBarUpdate, + [CONTROLLER_EXPUPDATE] = PlayerHandleExpUpdate, // Partner's player gets experience the same way as the player. + [CONTROLLER_STATUSICONUPDATE] = BtlController_HandleStatusIconUpdate, + [CONTROLLER_STATUSANIMATION] = BtlController_HandleStatusAnimation, + [CONTROLLER_STATUSXOR] = BtlController_Empty, + [CONTROLLER_DATATRANSFER] = BtlController_Empty, + [CONTROLLER_DMA3TRANSFER] = BtlController_Empty, + [CONTROLLER_PLAYBGM] = BtlController_Empty, + [CONTROLLER_32] = BtlController_Empty, + [CONTROLLER_TWORETURNVALUES] = BtlController_Empty, + [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, + [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, + [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, + [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, + [CONTROLLER_CANTSWITCH] = BtlController_Empty, + [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, + [CONTROLLER_PLAYFANFAREORBGM] = BtlController_HandlePlayFanfareOrBGM, + [CONTROLLER_FAINTINGCRY] = BtlController_HandleFaintingCry, + [CONTROLLER_INTROSLIDE] = BtlController_HandleIntroSlide, + [CONTROLLER_INTROTRAINERBALLTHROW] = RecordedPartnerHandleIntroTrainerBallThrow, + [CONTROLLER_DRAWPARTYSTATUSSUMMARY] = RecordedPartnerHandleDrawPartyStatusSummary, + [CONTROLLER_HIDEPARTYSTATUSSUMMARY] = BtlController_HandleHidePartyStatusSummary, + [CONTROLLER_ENDBOUNCE] = BtlController_Empty, + [CONTROLLER_SPRITEINVISIBILITY] = BtlController_HandleSpriteInvisibility, + [CONTROLLER_BATTLEANIMATION] = BtlController_HandleBattleAnimation, + [CONTROLLER_LINKSTANDBYMSG] = BtlController_Empty, + [CONTROLLER_RESETACTIONMOVESELECTION] = BtlController_Empty, + [CONTROLLER_ENDLINKBATTLE] = RecordedPartnerHandleEndLinkBattle, + [CONTROLLER_DEBUGMENU] = BtlController_Empty, + [CONTROLLER_TERMINATOR_NOP] = BtlController_TerminatorNop +}; + +void SetControllerToRecordedPartner(u32 battler) +{ + gBattlerControllerEndFuncs[battler] = RecordedPartnerBufferExecCompleted; + gBattlerControllerFuncs[battler] = RecordedPartnerBufferRunCommand; +} + +static void RecordedPartnerBufferRunCommand(u32 battler) +{ + if (IsBattleControllerActiveOnLocal(battler)) + { + if (gBattleResources->bufferA[battler][0] < ARRAY_COUNT(sRecordedPartnerBufferCommands)) + sRecordedPartnerBufferCommands[gBattleResources->bufferA[battler][0]](battler); + else + BtlController_Complete(battler); + } +} + +static void Intro_WaitForHealthbox(u32 battler) +{ + bool32 finished = FALSE; + + if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI))) + { + if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy) + finished = TRUE; + } + else + { + if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy + && gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy) + { + finished = TRUE; + } + } + + if (IsCryPlayingOrClearCrySongs()) + finished = FALSE; + + if (finished) + { + gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3; + gBattlerControllerFuncs[battler] = BtlController_Intro_DelayAndEnd; + } +} + +void Controller_RecordedPartnerShowIntroHealthbox(u32 battler) +{ + if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive + && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive + && gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy + && gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy + && ++gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay != 1) + { + gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 0; + TryShinyAnimation(battler, GetBattlerMon(battler)); + + if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI)) + { + DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]); + UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], GetBattlerMon(BATTLE_PARTNER(battler)), HEALTHBOX_ALL); + StartHealthboxSlideIn(BATTLE_PARTNER(battler)); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]); + } + + DestroySprite(&gSprites[gBattleControllerData[battler]]); + UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], GetBattlerMon(battler), HEALTHBOX_ALL); + StartHealthboxSlideIn(battler); + SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); + + gBattleSpritesDataPtr->animationData->introAnimActive = FALSE; + + gBattlerControllerFuncs[battler] = Intro_WaitForHealthbox; + } +} + +void RecordedPartnerBufferExecCompleted(u32 battler) +{ + gBattlerControllerFuncs[battler] = RecordedPartnerBufferRunCommand; + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + u8 playerId = GetMultiplayerId(); + + PrepareBufferDataTransferLink(battler, B_COMM_CONTROLLER_IS_DONE, 4, &playerId); + gBattleResources->bufferA[battler][0] = CONTROLLER_TERMINATOR_NOP; + } + else + { + MarkBattleControllerIdleOnLocal(battler); + } +} + +// some explanation here +// in emerald it's possible to have a tag battle in the battle frontier facilities with AI +// which use the front sprite for both the player and the partner as opposed to any other battles (including the one with Steven) that use the back pic as well as animate it +static void RecordedPartnerHandleDrawTrainerPic(u32 battler) +{ + bool32 isFrontPic; + s16 xPos, yPos; + u32 trainerPicId; + + trainerPicId = TRAINER_BACK_PIC_STEVEN; + xPos = 90; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + + isFrontPic = FALSE; + + BtlController_HandleDrawTrainerPic(battler, trainerPicId, isFrontPic, xPos, yPos, -1); +} + +static void RecordedPartnerHandleTrainerSlideBack(u32 battler) +{ + BtlController_HandleTrainerSlideBack(battler, 35, FALSE); +} + +static void RecordedPartnerHandleChooseAction(u32 battler) +{ + BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, RecordedBattle_GetBattlerAction(RECORDED_ACTION_TYPE, battler), 0); + BtlController_Complete(battler); +} + +static void RecordedPartnerHandleChooseMove(u32 battler) +{ + u8 moveIndex = RecordedBattle_GetBattlerAction(RECORDED_MOVE_SLOT, battler); + u8 target = RecordedBattle_GetBattlerAction(RECORDED_MOVE_TARGET, battler); + BtlController_EmitTwoReturnValues(battler, B_COMM_TO_ENGINE, B_ACTION_EXEC_SCRIPT, moveIndex | (target << 8)); + + BtlController_Complete(battler); +} + +static void RecordedPartnerHandleChoosePokemon(u32 battler) +{ + gBattleStruct->monToSwitchIntoId[battler] = RecordedBattle_GetBattlerAction(RECORDED_PARTY_INDEX, battler); + gSelectedMonPartyId = gBattleStruct->monToSwitchIntoId[battler]; // Revival Blessing + BtlController_EmitChosenMonReturnValue(battler, B_COMM_TO_ENGINE, gBattleStruct->monToSwitchIntoId[battler], NULL); + BtlController_Complete(battler); +} + +static void RecordedPartnerHandleIntroTrainerBallThrow(u32 battler) +{ + const u16 *trainerPal; + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId); + + if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) + trainerPal = gTrainerBacksprites[gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].palette.data; + else if (IsAiVsAiBattle()) + trainerPal = gTrainerSprites[GetTrainerPicFromId(gPartnerTrainerId)].palette.data; + else + trainerPal = gTrainerSprites[GetFrontierTrainerFrontSpriteId(gPartnerTrainerId)].palette.data; // 2 vs 2 multi battle in Battle Frontier, load front sprite and pal. + + BtlController_HandleIntroTrainerBallThrow(battler, 0xD6F9, trainerPal, 24, Controller_RecordedPartnerShowIntroHealthbox); +} + +static void RecordedPartnerHandleDrawPartyStatusSummary(u32 battler) +{ + BtlController_HandleDrawPartyStatusSummary(battler, B_SIDE_PLAYER, TRUE); +} + +static void RecordedPartnerHandleEndLinkBattle(u32 battler) +{ + gBattleOutcome = gBattleResources->bufferA[battler][1]; + FadeOutMapMusic(5); + BeginFastPaletteFade(3); + BtlController_Complete(battler); + gBattlerControllerFuncs[battler] = SetBattleEndCallbacks; +} diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c index 0230451827..51bfa5327b 100644 --- a/src/battle_controller_recorded_player.c +++ b/src/battle_controller_recorded_player.c @@ -28,6 +28,8 @@ #include "constants/battle_anim.h" #include "constants/songs.h" #include "constants/trainers.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" static void RecordedPlayerHandleDrawTrainerPic(u32 battler); static void RecordedPlayerHandleTrainerSlideBack(u32 battler); @@ -40,7 +42,6 @@ static void RecordedPlayerHandleStatusAnimation(u32 battler); static void RecordedPlayerHandleIntroTrainerBallThrow(u32 battler); static void RecordedPlayerHandleDrawPartyStatusSummary(u32 battler); static void RecordedPlayerHandleEndLinkBattle(u32 battler); - static void RecordedPlayerBufferRunCommand(u32 battler); static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = @@ -147,8 +148,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); HandleLowHpMusicChange(GetBattlerMon(battler), battler); if (IsDoubleBattle()) @@ -276,43 +276,54 @@ static void RecordedPlayerHandleDrawTrainerPic(u32 battler) s16 xPos, yPos; u32 trainerPicId; - if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK) + // Sets Multibattle test player sprites to not be Hiker + if (IsMultibattleTest()) { - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - trainerPicId = GetBattlerLinkPlayerGender(battler); - else - trainerPicId = gLinkPlayers[gRecordedBattleMultiplayerId].gender; - } - else - { - trainerPicId = gLinkPlayers[0].gender; - } - - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - { - if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon - xPos = 90; - else // first mon - xPos = 32; - + trainerPicId = TRAINER_BACK_PIC_BRENDAN; if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - { - xPos = 90; - yPos = 80; - } + xPos = 32; else - { - yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; - } - - } - else - { - xPos = 80; + xPos = 80; yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK) + { + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + trainerPicId = GetBattlerLinkPlayerGender(battler); + else + trainerPicId = gLinkPlayers[gRecordedBattleMultiplayerId].gender; + } + else + trainerPicId = gLinkPlayers[0].gender; - if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon + xPos = 90; + else // first mon + xPos = 32; + + // !TESTING added as otherwise first test battle sprite is positioned incorrectly + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && !TESTING) + { + xPos = 90; + yPos = 80; + } + else + { + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + } + else + { + xPos = 80; + yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; + } + } + + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && !TESTING) isFrontPic = TRUE; else isFrontPic = FALSE; diff --git a/src/battle_controller_wally.c b/src/battle_controller_wally.c index 932b4a26b4..11955787d9 100644 --- a/src/battle_controller_wally.c +++ b/src/battle_controller_wally.c @@ -255,8 +255,7 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); CreateTask(Task_PlayerController_RestoreBgmAfterCry, 10); HandleLowHpMusicChange(GetBattlerMon(battler), battler); diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 3b416afe5b..889b2bec6b 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -29,6 +29,9 @@ #include "constants/abilities.h" #include "constants/item_effects.h" #include "constants/songs.h" +#include "test/battle.h" +#include "test/test.h" +#include "test/test_runner_battle.h" #include "pokemon_animation.h" static EWRAM_DATA u8 sLinkSendTaskId = 0; @@ -144,6 +147,7 @@ static void InitBtlControllersInternal(void) if ((gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) || !isMulti + || (IsMultibattleTest()) || (!isLink && !isRecorded) || (isLink && !isDouble)) { @@ -168,64 +172,82 @@ static void InitBtlControllersInternal(void) if (isLink) { if (isDouble && isMulti && !isMaster) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToLinkPartner; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToLinkPartner; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToPlayer; if (!isDouble || !isMulti || !isMaster) { - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToLinkOpponent; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayer; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToLinkOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToLinkOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToLinkOpponent; } else { - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToOpponent; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToLinkPartner; - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToLinkPartner; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToOpponent; } } else { // Player 1 if (isRecorded) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToRecordedPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToRecordedPlayer; else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToSafari; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToSafari; else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToWally; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToWally; else if (isAIvsAI) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToPlayerPartner; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToPlayerPartner; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_0]] = SetControllerToPlayer; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_0)] = SetControllerToPlayer; // Opponent 1 bool32 isOpponent1Recorded; if (isDouble) - isOpponent1Recorded = (!isInGamePartner && isRecorded && !isMulti && isRecordedLink); + isOpponent1Recorded = ((!isInGamePartner && isRecorded && !isMulti && isRecordedLink) || (IsMultibattleTest() && isRecordedLink)); else isOpponent1Recorded = isRecorded && isRecordedLink; if (isOpponent1Recorded) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToRecordedOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToRecordedOpponent; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_1]] = SetControllerToOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_1)] = SetControllerToOpponent; // Player 2 - if (isInGamePartner) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayerPartner; + if (IsMultibattleTest() && isRecordedLink) + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToRecordedPartner; + } + else if (IsMultibattleTest() && isRecorded && !isRecordedLink) + { // Sets to PlayerPartner if EXPECT_XXXX used in test for partner trainer, else sets to RecordedPartner. + if (gBattleTestRunnerState->data.expectedAiActions[B_BATTLER_2][0].actionSet == TRUE) + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayerPartner; + else + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToRecordedPartner; + } + else if ((isInGamePartner && !isRecorded) + || isAIvsAI) + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayerPartner; + } else if (isRecorded) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToRecordedPlayer; - else if (isAIvsAI) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayerPartner; + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToRecordedPlayer; + } else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_2]] = SetControllerToPlayer; + { + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_2)] = SetControllerToPlayer; + } // Opponent 2 - if (isInGamePartner || !isRecorded || isMulti || !isRecordedLink) - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToOpponent; + if (IsMultibattleTest() && isRecordedLink) + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToRecordedOpponent; + else if (isInGamePartner || !isRecorded || isMulti || !isRecordedLink) + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToOpponent; else - gBattlerControllerFuncs[gBattlerPositions[B_BATTLER_3]] = SetControllerToRecordedOpponent; + gBattlerControllerFuncs[GetBattlerPosition(B_BATTLER_3)] = SetControllerToRecordedOpponent; } bool32 bufferPartyOrders; @@ -318,6 +340,11 @@ static inline bool32 IsControllerRecordedPlayer(u32 battler) return (gBattlerControllerEndFuncs[battler] == RecordedPlayerBufferExecCompleted); } +static inline bool32 IsControllerRecordedPartner(u32 battler) +{ + return (gBattlerControllerEndFuncs[battler] == RecordedPartnerBufferExecCompleted); +} + static inline bool32 IsControllerOpponent(u32 battler) { return (gBattlerControllerEndFuncs[battler] == OpponentBufferExecCompleted); @@ -2249,6 +2276,7 @@ void BtlController_HandleSwitchInAnim(u32 battler) bool32 isPlayerSide = (IsControllerPlayer(battler) || IsControllerPlayerPartner(battler) || IsControllerRecordedPlayer(battler) + || IsControllerRecordedPartner(battler) || IsControllerLinkPartner(battler)); if (IsControllerPlayer(battler)) @@ -2339,7 +2367,8 @@ void BtlController_HandleDrawTrainerPic(u32 battler, u32 trainerPicId, bool32 is if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) gBattlerSpriteIds[battler] = gBattleStruct->trainerSlideSpriteIds[battler]; - gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = battler; + // Aiming for palette slots 8 and 9 for Player and PlayerPartner to prevent Trainer Slides causing mons to change colour + gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = (8 + battler/2); } gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].x2 = DISPLAY_WIDTH; gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].sSpeedX = -2; @@ -2364,7 +2393,8 @@ void BtlController_HandleTrainerSlide(u32 battler, u32 trainerPicId) 30); if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) gBattlerSpriteIds[battler] = gBattleStruct->trainerSlideSpriteIds[battler]; - gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = battler; + // Aiming for palette slots 8 and 9 for Player and PlayerPartner to prevent Trainer Slides causing mons to change colour + gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = (8 + battler/2); gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].x2 = -96; gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].sSpeedX = 2; } @@ -2541,6 +2571,7 @@ void BtlController_HandleHealthBarUpdate(u32 battler) SetBattleBarStruct(battler, gHealthboxSpriteIds[battler], maxHP, 0, hpVal); if (IsControllerPlayer(battler) || IsControllerRecordedPlayer(battler) + || IsControllerRecordedPartner(battler) || IsControllerWally(battler)) UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, 0, maxHP); TestRunner_Battle_RecordHP(battler, curHP, 0); @@ -2686,7 +2717,7 @@ bool32 TwoOpponentIntroMons(u32 battler) // Double battle with both opponent pok void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, const u16 *trainerPal, s16 framesToWait, void (*controllerCallback)(u32 battler)) { u8 paletteNum, taskId; - u32 side = GetBattlerSide(battler); + enum BattleSide side = GetBattlerSide(battler); SetSpritePrimaryCoordsFromSecondaryCoords(&gSprites[gBattleStruct->trainerSlideSpriteIds[battler]]); if (side == B_SIDE_PLAYER) @@ -2711,7 +2742,7 @@ void BtlController_HandleIntroTrainerBallThrow(u32 battler, u16 tagTrainerPal, c paletteNum = AllocSpritePalette(tagTrainerPal); LoadPalette(trainerPal, OBJ_PLTT_ID(paletteNum), PLTT_SIZE_4BPP); - gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = paletteNum; + gSprites[gBattleStruct->trainerSlideSpriteIds[battler]].oam.paletteNum = (8 + battler/2); } else { @@ -2812,7 +2843,7 @@ static void SpriteCB_FreeOpponentSprite(struct Sprite *sprite) #undef sBattlerId -void BtlController_HandleDrawPartyStatusSummary(u32 battler, u32 side, bool32 considerDelay) +void BtlController_HandleDrawPartyStatusSummary(u32 battler, enum BattleSide side, bool32 considerDelay) { if (gBattleResources->bufferA[battler][1] != 0 && IsOnPlayerSide(battler)) { @@ -2950,8 +2981,7 @@ void TryShinyAnimAfterMonAnim(u32 battler) { gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); BtlController_Complete(battler); } } @@ -3016,14 +3046,13 @@ void BtlController_HandleSwitchInSoundAndEnd(u32 battler) void BtlController_HandleSwitchInShowHealthbox(u32 battler) { - u32 side = GetBattlerSide(battler); + enum BattleSide side = GetBattlerSide(battler); if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim && (side == B_SIDE_PLAYER || gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)) { gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); if (side == B_SIDE_PLAYER) { @@ -3053,8 +3082,7 @@ static void SwitchIn_CleanShinyAnimShowSubstitute(u32 battler) // Reset shiny anim (even if it didn't occur) gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; - FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); - FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); + FreeShinyStars(); // Check if Substitute should be shown if (gBattleSpritesDataPtr->battlerData[battler].behindSubstitute) @@ -3117,3 +3145,19 @@ void UpdateFriendshipFromXItem(u32 battler) SetBattlerMonData(battler, GetBattlerParty(battler), gBattlerPartyIndexes[battler]); } } + +bool32 ShouldBattleRestrictionsApply(u32 battler) +{ + return IsControllerPlayer(battler); +} + +void FreeShinyStars(void) +{ + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim) + return; + } + FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); + FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); +} diff --git a/src/battle_debug.c b/src/battle_debug.c index b160dd9d78..836329d660 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -35,7 +35,6 @@ #include "constants/moves.h" #include "constants/items.h" #include "constants/rgb.h" -#include "constants/hold_effects.h" #define MAX_MODIFY_DIGITS 4 @@ -230,7 +229,7 @@ enum }; // Static Declarations -static const u8 *GetHoldEffectName(enum ItemHoldEffect holdEffect); +static const u8 *GetHoldEffectName(enum HoldEffect holdEffect); // const rom data static const u8 sText_Ability[] = _("Ability"); @@ -379,7 +378,7 @@ static const struct ListMenuItem sVolatileStatusListItems[] = {COMPOUND_STRING("Lock On"), VOLATILE_LOCK_ON}, {COMPOUND_STRING("Perish Song"), VOLATILE_PERISH_SONG}, {COMPOUND_STRING("Minimize"), VOLATILE_MINIMIZE}, - {COMPOUND_STRING("Charge"), VOLATILE_CHARGE}, + {COMPOUND_STRING("Charge"), VOLATILE_CHARGE_TIMER}, {COMPOUND_STRING("Root"), VOLATILE_ROOT}, {COMPOUND_STRING("Yawn"), VOLATILE_YAWN}, {COMPOUND_STRING("Imprison"), VOLATILE_IMPRISON}, @@ -719,17 +718,27 @@ void CB2_BattleDebugMenu(void) } } +enum { + COLORID_RED, +}; + +static const u8 sTextColorTable[][3] = +{ + [COLORID_RED] = {TEXT_COLOR_WHITE, TEXT_COLOR_RED, TEXT_COLOR_LIGHT_RED}, +}; + static void PutMovesPointsText(struct BattleDebugMenu *data) { - u32 i, j, count, battlerDef; + u32 i, j, count, battlerDef, chosenMoveIndex = gAiBattleData->chosenMoveIndex[data->aiBattlerId]; u8 *text = Alloc(0x50); FillWindowPixelBuffer(data->aiMovesWindowId, 0x11); + AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, COMPOUND_STRING("Score/Dmg"), 3, 0, 0, NULL); for (i = 0; i < MAX_MON_MOVES; i++) { text[0] = CHAR_SPACE; StringCopy(text + 1, GetMoveName(gBattleMons[data->aiBattlerId].moves[i])); - AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 0, i * 15, 0, NULL); + AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 0, (i * 15) + 15, 0, NULL); for (count = 0, j = 0; j < MAX_BATTLERS_COUNT; j++) { if (data->spriteIds.aiIconSpriteIds[j] == 0xFF) @@ -738,12 +747,24 @@ static void PutMovesPointsText(struct BattleDebugMenu *data) ConvertIntToDecimalStringN(text, gAiBattleData->finalScore[data->aiBattlerId][battlerDef][i], STR_CONV_MODE_RIGHT_ALIGN, 3); - AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 83 + count * 54, i * 15, 0, NULL); + // If chosen move and chosen target + if ((chosenMoveIndex == i) && (gAiBattleData->chosenTarget[data->aiBattlerId] == j) && !(gAiLogicData->shouldSwitch & (1u << data->aiBattlerId))) + AddTextPrinterParameterized3(data->aiMovesWindowId, FONT_NORMAL, 84 + count * 54, (i * 15) + 15, sTextColorTable[COLORID_RED], 0, text); + else + AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 84 + count * 54, (i * 15) + 15, 0, NULL); + + if ((chosenMoveIndex == i) && (gAiBattleData->chosenTarget[data->aiBattlerId] == j) && !(gAiLogicData->shouldSwitch & (1u << data->aiBattlerId))) + AddTextPrinterParameterized3(data->aiMovesWindowId, FONT_NORMAL, 103 + count * 54, (i * 15) + 15, sTextColorTable[COLORID_RED], 0, COMPOUND_STRING("/")); + else + AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, COMPOUND_STRING("/"), 103 + count * 54, (i * 15) + 15, 0, NULL); ConvertIntToDecimalStringN(text, AI_GetDamage(data->aiBattlerId, battlerDef, i, AI_ATTACKING, gAiLogicData), - STR_CONV_MODE_RIGHT_ALIGN, 3); - AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 110 + count * 54, i * 15, 0, NULL); + STR_CONV_MODE_LEADING_ZEROS, 3); + if ((chosenMoveIndex == i) && (gAiBattleData->chosenTarget[data->aiBattlerId] == j) && !(gAiLogicData->shouldSwitch & (1u << data->aiBattlerId))) + AddTextPrinterParameterized3(data->aiMovesWindowId, FONT_NORMAL, 110 + count * 54, (i * 15) + 15, sTextColorTable[COLORID_RED], 0, text); + else + AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 110 + count * 54, (i * 15) + 15, 0, NULL); count++; } @@ -751,15 +772,10 @@ static void PutMovesPointsText(struct BattleDebugMenu *data) if (gAiLogicData->shouldSwitch & (1u << data->aiBattlerId)) { - u32 switchMon = GetMonData(&gEnemyParty[gAiLogicData->mostSuitableMonId[data->aiBattlerId]], MON_DATA_SPECIES); - AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, COMPOUND_STRING("Switching to "), 74, 64, 0, NULL); - AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, gSpeciesInfo[switchMon].speciesName, 74 + 68, 64, 0, NULL); - } - else - { - u32 chosenMoveIndex = gAiBattleData->chosenMoveIndex[data->aiBattlerId]; - AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, COMPOUND_STRING("Chosen move: "), 74, 64, 0, NULL); - AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, GetMoveName(gBattleMons[data->aiBattlerId].moves[chosenMoveIndex]), 74 + 68, 64, 0, NULL); + struct Pokemon *party = GetBattlerParty(data->aiBattlerId); + u32 switchMon = GetMonData(&party[gAiLogicData->mostSuitableMonId[data->aiBattlerId]], MON_DATA_SPECIES); + AddTextPrinterParameterized3(data->aiMovesWindowId, FONT_NORMAL, 74, 79, sTextColorTable[COLORID_RED], 0, COMPOUND_STRING("Switching to ")); + AddTextPrinterParameterized3(data->aiMovesWindowId, FONT_NORMAL, 74 + 68, 79, sTextColorTable[COLORID_RED], 0, gSpeciesInfo[switchMon].speciesName); } CopyWindowToVram(data->aiMovesWindowId, COPYWIN_FULL); @@ -811,7 +827,7 @@ static void Task_ShowAiPoints(u8 taskId) { data->spriteIds.aiIconSpriteIds[i] = CreateMonIcon(gBattleMons[i].species, SpriteCallbackDummy, - 95 + (count * 60), 17, 0, 0); + 106 + (count * 54), 17, 0, 0); gSprites[data->spriteIds.aiIconSpriteIds[i]].data[0] = i; // battler id count++; } @@ -826,7 +842,7 @@ static void Task_ShowAiPoints(u8 taskId) GetMonData(mon, MON_DATA_IS_SHINY), gBattleMons[data->aiBattlerId].personality, TRUE, - 39, 130, 15, TAG_NONE); + 39, 135, 15, TAG_NONE); data->aiViewState++; break; // Put text @@ -902,8 +918,8 @@ static void PutAiInfoText(struct BattleDebugMenu *data) { if (IsOnPlayerSide(i) && IsBattlerAlive(i)) { - u16 ability = gAiLogicData->abilities[i]; - enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[i]; + enum Ability ability = gAiLogicData->abilities[i]; + enum HoldEffect holdEffect = gAiLogicData->holdEffects[i]; u16 item = gAiLogicData->items[i]; u8 x = (i == B_POSITION_PLAYER_LEFT) ? 83 + (i) * 75 : 83 + (i-1) * 75; AddTextPrinterParameterized(data->aiMovesWindowId, FONT_SMALL, gAbilitiesInfo[ability].name, x, 0, 0, NULL); @@ -1478,7 +1494,7 @@ static void PrintSecondaryEntries(struct BattleDebugMenu *data) case LIST_ITEM_TYPES: for (i = 0; i < 3; i++) { - u8 *types = &gBattleMons[data->battlerId].types[0]; + enum Type *types = &gBattleMons[data->battlerId].types[0]; PadString(gTypesInfo[types[i]].name, text); printer.currentY = printer.y = (i * yMultiplier) + sSecondaryListTemplate.upText_Y; @@ -2254,7 +2270,7 @@ static const u8 *const sHoldEffectNames[HOLD_EFFECT_COUNT] = [HOLD_EFFECT_PRIMAL_ORB] = COMPOUND_STRING("Primal Orb"), [HOLD_EFFECT_PROTECTIVE_PADS] = COMPOUND_STRING("Protective Pads"), [HOLD_EFFECT_TERRAIN_EXTENDER] = COMPOUND_STRING("Terrain Extender"), - [HOLD_EFFECT_SEEDS] = COMPOUND_STRING("Seeds"), + [HOLD_EFFECT_TERRAIN_SEED] = COMPOUND_STRING("Seeds"), [HOLD_EFFECT_ADRENALINE_ORB] = COMPOUND_STRING("Adrenaline Orb"), [HOLD_EFFECT_MEMORY] = COMPOUND_STRING("Memory"), [HOLD_EFFECT_Z_CRYSTAL] = COMPOUND_STRING("Z-Crystal"), @@ -2274,7 +2290,8 @@ static const u8 *const sHoldEffectNames[HOLD_EFFECT_COUNT] = [HOLD_EFFECT_OGERPON_MASK] = COMPOUND_STRING("Ogerpon Mask"), [HOLD_EFFECT_BERSERK_GENE] = COMPOUND_STRING("Berserk Gene"), }; -static const u8 *GetHoldEffectName(enum ItemHoldEffect holdEffect) + +static const u8 *GetHoldEffectName(enum HoldEffect holdEffect) { if (sHoldEffectNames[holdEffect] == NULL) return sHoldEffectNames[0]; diff --git a/src/battle_dome.c b/src/battle_dome.c index 68bd6af252..df96737f8d 100644 --- a/src/battle_dome.c +++ b/src/battle_dome.c @@ -2136,9 +2136,8 @@ static void InitDomeTrainers(void) static void CalcDomeMonStats(const struct TrainerMon *fmon, int level, u8 ivs, int *stats) { int evs[NUM_STATS]; - int i; - for (i = 0; i < NUM_STATS; i++) + for (enum Stat i = 0; i < NUM_STATS; i++) { if (fmon->ev != NULL) evs[i] = fmon->ev[i]; @@ -2393,8 +2392,9 @@ static int SelectOpponentMonsFromParty(int *partyMovePoints, bool8 allowRandom) static int GetTypeEffectivenessPoints(int move, int targetSpecies, int mode) { - int defType1, defType2, defAbility, moveType; + enum Type defType1, defType2, moveType; int typePower = TYPE_x1; + enum Ability defAbility; if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || IsBattleMoveStatus(move)) return 0; @@ -5141,7 +5141,7 @@ static u16 GetWinningMove(int winnerTournamentId, int loserTournamentId, u8 roun { u32 personality = 0; u32 targetSpecies = 0; - u32 targetAbility = 0; + enum Ability targetAbility = 0; uq4_12_t typeMultiplier = 0; do { diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index c6e91742e8..d5edbc0e61 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -19,7 +19,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_string_ids.h" #include "constants/flags.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/moves.h" @@ -28,7 +27,7 @@ static u32 GetMaxPowerTier(u32 move); struct GMaxMove { u16 species; - u8 moveType; + enum Type moveType; u16 gmaxMove; }; @@ -66,15 +65,15 @@ static const struct GMaxMove sGMaxMoveTable[] = {SPECIES_ALCREMIE_GMAX, TYPE_FAIRY, MOVE_G_MAX_FINALE}, {SPECIES_COPPERAJAH_GMAX, TYPE_STEEL, MOVE_G_MAX_STEELSURGE}, {SPECIES_DURALUDON_GMAX, TYPE_DRAGON, MOVE_G_MAX_DEPLETION}, - {SPECIES_URSHIFU_SINGLE_STRIKE_GMAX,TYPE_DARK, MOVE_G_MAX_ONE_BLOW}, - {SPECIES_URSHIFU_RAPID_STRIKE_GMAX, TYPE_WATER, MOVE_G_MAX_RAPID_FLOW}, + {SPECIES_URSHIFU_SINGLE_STRIKE_GMAX, TYPE_DARK, MOVE_G_MAX_ONE_BLOW}, + {SPECIES_URSHIFU_RAPID_STRIKE_GMAX, TYPE_WATER, MOVE_G_MAX_RAPID_FLOW}, }; // Returns whether a battler can Dynamax. bool32 CanDynamax(u32 battler) { u16 species = GetBattlerVisualSpecies(battler); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Prevents Zigzagoon from dynamaxing in vanilla. if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && !IsOnPlayerSide(battler)) @@ -178,7 +177,7 @@ void ActivateDynamax(u32 battler) // Set appropriate use flags. SetActiveGimmick(battler, GIMMICK_DYNAMAX); SetGimmickAsActivated(battler, GIMMICK_DYNAMAX); - gBattleStruct->dynamax.dynamaxTurns[battler] = gBattleTurnCounter + DYNAMAX_TURNS_COUNT; + gBattleStruct->dynamax.dynamaxTurns[battler] = DYNAMAX_TURNS_COUNT; // Substitute is removed upon Dynamaxing. gBattleMons[battler].volatiles.substitute = FALSE; @@ -234,22 +233,7 @@ bool32 IsMoveBlockedByMaxGuard(u32 move) return FALSE; } -// Weight-based moves (and some other moves in Raids) are blocked by Dynamax. -bool32 IsMoveBlockedByDynamax(u32 move) -{ - // TODO: Certain moves are banned in raids. - switch (GetMoveEffect(move)) - { - case EFFECT_HEAT_CRASH: - case EFFECT_LOW_KICK: - return TRUE; - default: - break; - } - return FALSE; -} - -static u16 GetTypeBasedMaxMove(u32 battler, u32 type) +static u16 GetTypeBasedMaxMove(u32 battler, enum Type type) { // Gigantamax check u32 i; @@ -280,7 +264,7 @@ static u16 GetTypeBasedMaxMove(u32 battler, u32 type) // Returns the appropriate Max Move or G-Max Move for a battler to use. u16 GetMaxMove(u32 battler, u32 baseMove) { - u32 moveType; + enum Type moveType; SetTypeBeforeUsingMove(baseMove, battler); moveType = GetBattleMoveType(baseMove); @@ -333,7 +317,7 @@ u32 GetMaxMovePower(u32 move) } tier = GetMaxPowerTier(move); - u32 moveType = GetMoveType(move); + enum Type moveType = GetMoveType(move); if (moveType == TYPE_FIGHTING || moveType == TYPE_POISON || move == MOVE_MULTI_ATTACK) @@ -453,7 +437,7 @@ bool32 IsMaxMove(u32 move) } // Assigns the multistring to use for the "Damage Non- Types" G-Max effect. -void ChooseDamageNonTypesString(u8 type) +void ChooseDamageNonTypesString(enum Type type) { switch (type) { @@ -469,6 +453,8 @@ void ChooseDamageNonTypesString(u8 type) case TYPE_ROCK: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SURROUNDED_BY_ROCKS; break; + default: + break; } } diff --git a/src/battle_end_turn.c b/src/battle_end_turn.c index 62a8f67006..b4d71c2cf4 100644 --- a/src/battle_end_turn.c +++ b/src/battle_end_turn.c @@ -1,5 +1,6 @@ #include "global.h" #include "battle.h" +#include "battle_hold_effects.h" #include "battle_util.h" #include "battle_controllers.h" #include "battle_ai_util.h" @@ -7,100 +8,10 @@ #include "battle_scripts.h" #include "constants/battle.h" #include "constants/battle_string_ids.h" -#include "constants/hold_effects.h" #include "constants/abilities.h" #include "constants/items.h" #include "constants/moves.h" -// General End Turn Effects based on research from smogon from vanilla games: -// https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179 -enum EndTurnResolutionOrder -{ - ENDTURN_ORDER, - ENDTURN_VARIOUS, - ENDTURN_WEATHER, - ENDTURN_WEATHER_DAMAGE, - ENDTURN_GEN_3_BERRY_ACTIVATION, - ENDTURN_EMERGENCY_EXIT_1, - ENDTURN_AFFECTION, - ENDTURN_FUTURE_SIGHT, - ENDTURN_WISH, - ENDTURN_FIRST_EVENT_BLOCK, - ENDTURN_EMERGENCY_EXIT_2, - ENDTURN_AQUA_RING, - ENDTURN_INGRAIN, - ENDTURN_LEECH_SEED, - ENDTURN_POISON, - ENDTURN_BURN, - ENDTURN_FROSTBITE, - ENDTURN_NIGHTMARE, - ENDTURN_CURSE, - ENDTURN_WRAP, - ENDTURN_SALT_CURE, - ENDTURN_OCTOLOCK, - ENDTURN_SYRUP_BOMB, - ENDTURN_TAUNT, - ENDTURN_TORMENT, - ENDTURN_ENCORE, - ENDTURN_DISABLE, - ENDTURN_MAGNET_RISE, - ENDTURN_TELEKINESIS, - ENDTURN_HEAL_BLOCK, - ENDTURN_EMBARGO, - ENDTURN_YAWN, - ENDTURN_PERISH_SONG, - ENDTURN_ROOST, - ENDTURN_EMERGENCY_EXIT_3, - ENDTURN_SECOND_EVENT_BLOCK, - ENDTURN_TRICK_ROOM, - ENDTURN_GRAVITY, - ENDTURN_WATER_SPORT, - ENDTURN_MUD_SPORT, - ENDTURN_WONDER_ROOM, - ENDTURN_MAGIC_ROOM, - ENDTURN_TERRAIN, - ENDTURN_THIRD_EVENT_BLOCK, - ENDTURN_EMERGENCY_EXIT_4, - ENDTURN_FORM_CHANGE_ABILITIES, - ENDTURN_EJECT_PACK, - ENDTURN_DYNAMAX, - ENDTURN_COUNT, -}; - -// Block that handles effects for each individual battler on the field (eg residual damage) -enum FirstEventBlock -{ - FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL, // Needs to be split - FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE, - FIRST_EVENT_BLOCK_THRASH, // Thrash isn't handled here in vanilla but for now it is that best place for it. - FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL, - FIRST_EVENT_BLOCK_ABILITIES, - FIRST_EVENT_BLOCK_HEAL_ITEMS, -}; - -// Block that tries to remove side statuses -enum SecondEventBlock -{ - SECOND_EVENT_BLOCK_REFLECT, - SECOND_EVENT_BLOCK_LIGHT_SCREEN, - SECOND_EVENT_BLOCK_SAFEGUARD, - SECOND_EVENT_BLOCK_MIST, - SECOND_EVENT_BLOCK_TAILWIND, - SECOND_EVENT_BLOCK_LUCKY_CHANT, - SECOND_EVENT_BLOCK_RAINBOW, - SECOND_EVENT_BLOCK_SEA_OF_FIRE, - SECOND_EVENT_BLOCK_SWAMP, - SECOND_EVENT_BLOCK_AURORA_VEIL, -}; - -// Block that handles Uproar, items and non-form changing abilities -enum ThirdEventBlock -{ - THIRD_EVENT_BLOCK_UPROAR, - THIRD_EVENT_BLOCK_ABILITIES, - THIRD_EVENT_BLOCK_ITEMS, -}; - static u32 GetBattlerSideForMessage(u32 side) { u32 battler = 0; @@ -119,7 +30,7 @@ static bool32 HandleEndTurnOrder(u32 battler) bool32 effect = FALSE; gBattleTurnCounter++; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; for (u32 i = 0; i < gBattlersCount; i++) gBattlerByTurnOrder[i] = i; @@ -133,29 +44,32 @@ static bool32 HandleEndTurnVarious(u32 battler) u32 i; bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK && gFieldTimers.fairyLockTimer == gBattleTurnCounter) + if (gFieldTimers.fairyLockTimer > 0 && --gFieldTimers.fairyLockTimer == 0) gFieldStatuses &= ~STATUS_FIELD_FAIRY_LOCK; for (i = 0; i < NUM_BATTLE_SIDES; i++) { - if (gSideStatuses[i] & SIDE_STATUS_DAMAGE_NON_TYPES && gSideTimers[i].damageNonTypesTimer == gBattleTurnCounter) + if (gSideTimers[i].damageNonTypesTimer > 0 && --gSideTimers[i].damageNonTypesTimer == 0) gSideStatuses[i] &= ~SIDE_STATUS_DAMAGE_NON_TYPES; } for (i = 0; i < gBattlersCount; i++) { + if (gDisableStructs[i].throatChopTimer > 0) + gDisableStructs[i].throatChopTimer--; + if (gBattleMons[i].volatiles.lockOn > 0) gBattleMons[i].volatiles.lockOn--; - if (gDisableStructs[i].chargeTimer && --gDisableStructs[i].chargeTimer == 0) - gBattleMons[i].volatiles.charge = FALSE; + if (B_CHARGE < GEN_9 && gBattleMons[i].volatiles.chargeTimer > 0) + gBattleMons[i].volatiles.chargeTimer--; - if (gBattleMons[i].volatiles.laserFocus && gDisableStructs[i].laserFocusTimer == gBattleTurnCounter) + if (gDisableStructs[i].laserFocusTimer > 0 && --gDisableStructs[i].laserFocusTimer == 0) gBattleMons[i].volatiles.laserFocus = FALSE; - gBattleStruct->hpBefore[i] = gBattleMons[i].hp; + gBattleStruct->battlerState[i].wasAboveHalfHp = gBattleMons[i].hp > gBattleMons[i].maxHP / 2; } if (gBattleStruct->incrementEchoedVoice) @@ -174,7 +88,7 @@ static bool32 HandleEndTurnVarious(u32 battler) static bool32 HandleEndTurnWeather(u32 battler) { - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; return EndOrContinueWeather(); } @@ -182,18 +96,18 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) { bool32 effect = FALSE; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); u32 currBattleWeather = GetCurrentBattleWeather(); if (currBattleWeather == 0xFF) { // If there is no weather on the field, no need to check other battlers so go to next state - gBattleStruct->turnEffectsBattlerId = 0; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurnBattler = 0; + gBattleStruct->eventState.endTurn++; return effect; } - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (!IsBattlerAlive(battler) || !HasWeatherEffect()) return effect; @@ -229,12 +143,10 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) && !IS_BATTLER_ANY_TYPE(battler, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL) && gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERGROUND && gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER - && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES + && GetBattlerHoldEffect(battler) != HOLD_EFFECT_SAFETY_GOGGLES && !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 16); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SANDSTORM; BattleScriptExecute(BattleScript_DamagingWeather); effect = TRUE; @@ -254,12 +166,10 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) && !IS_BATTLER_OF_TYPE(battler, TYPE_ICE) && gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERGROUND && gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER - && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES + && GetBattlerHoldEffect(battler) != HOLD_EFFECT_SAFETY_GOGGLES && !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 16); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_HAIL; BattleScriptExecute(BattleScript_DamagingWeather); effect = TRUE; @@ -271,48 +181,24 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler) return effect; } -static bool32 HandleEndTurnGenThreeBerryActivation(u32 battler) -{ - bool32 effect = FALSE; - - if (B_HP_BERRIES >= GEN_4) // Skip handler for > Gen3 - { - gBattleStruct->endTurnEventsCounter++; - return effect; - } - gBattleStruct->turnEffectsBattlerId++; - effect = TryRestoreHPBerries(battler, ITEMEFFECT_NORMAL); - return effect; -} - static bool32 HandleEndTurnEmergencyExit(u32 battler) { bool32 effect = FALSE; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (ability == ABILITY_EMERGENCY_EXIT || ability == ABILITY_WIMP_OUT) + if (EmergencyExitCanBeTriggered(battler)) { - u32 cutoff = gBattleMons[battler].maxHP / 2; - bool32 HadMoreThanHalfHpNowDoesnt = gBattleStruct->hpBefore[battler] > cutoff && gBattleMons[battler].hp <= cutoff; + gBattlerAbility = battler; + gLastUsedAbility = ability; - if (HadMoreThanHalfHpNowDoesnt - && IsBattlerAlive(battler) - && (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) - && !(gBattleTypeFlags & BATTLE_TYPE_ARENA) - && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP) // Not currently held by Sky Drop - { - gBattlerAbility = battler; - gLastUsedAbility = ability; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + BattleScriptExecute(BattleScript_EmergencyExitEnd2); + else + BattleScriptExecute(BattleScript_EmergencyExitWildEnd2); - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - BattleScriptExecute(BattleScript_EmergencyExitEnd2); - else - BattleScriptExecute(BattleScript_EmergencyExitWildEnd2); - - effect = TRUE; - } + effect = TRUE; } return effect; @@ -322,7 +208,7 @@ static bool32 HandleEndTurnAffection(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (!B_AFFECTION_MECHANICS || !IsBattlerAlive(battler) @@ -345,16 +231,10 @@ static bool32 HandleEndTurnFutureSight(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gWishFutureKnock.futureSightCounter[battler] == gBattleTurnCounter) + if (gWishFutureKnock.futureSightCounter[battler] > 0 && --gWishFutureKnock.futureSightCounter[battler] == 0) { - if (gWishFutureKnock.futureSightCounter[battler] == gBattleTurnCounter - && gWishFutureKnock.futureSightCounter[BATTLE_PARTNER(battler)] <= gBattleTurnCounter) - { - gSideStatuses[GetBattlerSide(battler)] &= ~SIDE_STATUS_FUTUREATTACK; - } - if (!IsBattlerAlive(battler)) return effect; @@ -383,25 +263,26 @@ static bool32 HandleEndTurnWish(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gWishFutureKnock.wishCounter[battler] == gBattleTurnCounter && IsBattlerAlive(battler)) + if (gWishFutureKnock.wishCounter[battler] > 0 && --gWishFutureKnock.wishCounter[battler] == 0 && IsBattlerAlive(battler)) { + s32 wishHeal = 0; gBattlerTarget = battler; PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, battler, gWishFutureKnock.wishPartyId[battler]) if (B_WISH_HP_SOURCE >= GEN_5) { if (IsOnPlayerSide(battler)) - gBattleStruct->moveDamage[battler] = max(1, GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2); + wishHeal = GetMonData(&gPlayerParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2; else - gBattleStruct->moveDamage[battler] = max(1, GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2); + wishHeal = GetMonData(&gEnemyParty[gWishFutureKnock.wishPartyId[battler]], MON_DATA_MAX_HP) / 2; } else { - gBattleStruct->moveDamage[battler] = max(1, GetNonDynamaxMaxHP(battler) / 2); + wishHeal = GetNonDynamaxMaxHP(battler) / 2; } - gBattleStruct->moveDamage[battler] *= -1; + SetHealAmount(battler, wishHeal); if (gBattleMons[battler].volatiles.healBlock) BattleScriptExecute(BattleScript_WishButHealBlocked); else if (gBattleMons[battler].hp == gBattleMons[battler].maxHP) @@ -418,39 +299,43 @@ static bool32 HandleEndTurnWish(u32 battler) static bool32 HandleEndTurnFirstEventBlock(u32 battler) { bool32 effect = FALSE; - u32 side; - switch (gBattleStruct->eventBlockCounter) + if (!IsBattlerAlive(battler)) + { + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler++; + return effect; + } + + switch (gBattleStruct->eventState.endTurnBlock) { case FIRST_EVENT_BLOCK_GMAX_MOVE_RESIDUAL: // TODO: Has to be split into 3 statuses and needs a queue side = GetBattlerSide(battler); if (gSideStatuses[side] & SIDE_STATUS_DAMAGE_NON_TYPES) { - if (IsBattlerAlive(battler) - && !IS_BATTLER_OF_TYPE(battler, gSideTimers[side].damageNonTypesType) + if (!IS_BATTLER_OF_TYPE(battler, gSideTimers[side].damageNonTypesType) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { - gBattlerAttacker = battler; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 6; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 6); ChooseDamageNonTypesString(gSideTimers[side].damageNonTypesType); BattleScriptExecute(BattleScript_DamageNonTypesContinues); effect = TRUE; } } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_SEA_OF_FIRE_DAMAGE: - if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE && IsBattlerAlive(battler)) + if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE) { gBattlerAttacker = battler; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); BtlController_EmitStatusAnimation(battler, B_COMM_TO_CONTROLLER, FALSE, STATUS1_BURN); MarkBattlerForControllerExec(battler); BattleScriptExecute(BattleScript_HurtByTheSeaOfFire); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_THRASH: if (gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP) @@ -465,36 +350,31 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) gBattleMons[battler].volatiles.multipleTurns = FALSE; if (!gBattleMons[battler].volatiles.confusionTurns) { - gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; - SetMoveEffect(battler, battler, TRUE, FALSE); + SetMoveEffect(battler, battler, MOVE_EFFECT_CONFUSION, gBattlescriptCurrInstr, EFFECT_PRIMARY); if (gBattleMons[battler].volatiles.confusionTurns) BattleScriptExecute(BattleScript_ThrashConfuses); effect = TRUE; } } } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_GRASSY_TERRAIN_HEAL: if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN - && IsBattlerAlive(battler) && !IsBattlerAtMaxHp(battler) && !gBattleMons[battler].volatiles.healBlock && !IsSemiInvulnerable(battler, CHECK_ALL) - && IsBattlerGrounded(battler)) + && IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler))) { - gBattlerAttacker = battler; - gBattleStruct->moveDamage[battler] = -(GetNonDynamaxMaxHP(battler) / 16); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = -1; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 16); BattleScriptExecute(BattleScript_GrassyTerrainHeals); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case FIRST_EVENT_BLOCK_ABILITIES: { - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); switch (ability) { case ABILITY_HEALER: @@ -503,27 +383,18 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE)) effect = TRUE; break; - } - gBattleStruct->eventBlockCounter++; - break; - } - case FIRST_EVENT_BLOCK_HEAL_ITEMS: - { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); - switch (holdEffect) - { - case HOLD_EFFECT_LEFTOVERS: - case HOLD_EFFECT_BLACK_SLUDGE: - if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler)) - effect = TRUE; - break; default: break; } - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBlock++; break; } + case FIRST_EVENT_BLOCK_HEAL_ITEMS: + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsLeftoversActivation)) + effect = TRUE; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler++; + break; } return effect; @@ -533,14 +404,14 @@ static bool32 HandleEndTurnAquaRing(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.aquaRing && !gBattleMons[battler].volatiles.healBlock && !IsBattlerAtMaxHp(battler) && IsBattlerAlive(battler)) { - gBattleStruct->moveDamage[battler] = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); + SetHealAmount(battler, GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16)); BattleScriptExecute(BattleScript_AquaRingHeal); effect = TRUE; } @@ -552,14 +423,14 @@ static bool32 HandleEndTurnIngrain(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.root && !gBattleMons[battler].volatiles.healBlock && !IsBattlerAtMaxHp(battler) && IsBattlerAlive(battler)) { - gBattleStruct->moveDamage[battler] = GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16); + SetHealAmount(battler, GetDrainedBigRootHp(battler, GetNonDynamaxMaxHP(battler) / 16)); BattleScriptExecute(BattleScript_IngrainTurnHeal); effect = TRUE; } @@ -571,7 +442,7 @@ static bool32 HandleEndTurnLeechSeed(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.leechSeed && IsBattlerAlive(gBattleMons[battler].volatiles.leechSeed - 1) @@ -581,12 +452,12 @@ static bool32 HandleEndTurnLeechSeed(u32 battler) gBattlerTarget = gBattleMons[battler].volatiles.leechSeed - 1; // leech seed receiver gBattleScripting.animArg1 = gBattlerTarget; gBattleScripting.animArg2 = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, GetNonDynamaxMaxHP(battler) / 8); - gBattleStruct->moveDamage[gBattlerTarget] = GetDrainedBigRootHp(gBattlerTarget, gBattleStruct->moveDamage[gBattlerAttacker]); - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE; + s32 drainAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; + s32 healAmount = GetDrainedBigRootHp(gBattlerTarget, drainAmount); if (GetBattlerAbility(battler) == ABILITY_LIQUID_OOZE) { - gBattleStruct->moveDamage[gBattlerTarget] = gBattleStruct->moveDamage[gBattlerTarget] * -1; + SetPassiveDamageAmount(gBattlerAttacker, drainAmount); + SetPassiveDamageAmount(gBattlerTarget, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LEECH_SEED_OOZE; BattleScriptExecute(BattleScript_LeechSeedTurnDrainLiquidOoze); } @@ -596,6 +467,8 @@ static bool32 HandleEndTurnLeechSeed(u32 battler) } else { + SetPassiveDamageAmount(gBattlerAttacker, drainAmount); + SetHealAmount(gBattlerTarget, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LEECH_SEED_DRAIN; BattleScriptExecute(BattleScript_LeechSeedTurnDrainRecovery); } @@ -609,9 +482,9 @@ static bool32 HandleEndTurnPoison(u32 battler) { bool32 effect = FALSE; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if ((gBattleMons[battler].status1 & STATUS1_POISON || gBattleMons[battler].status1 & STATUS1_TOXIC_POISON) && IsBattlerAlive(battler) @@ -621,30 +494,23 @@ static bool32 HandleEndTurnPoison(u32 battler) { if (!IsBattlerAtMaxHp(battler) && !gBattleMons[battler].volatiles.healBlock) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 8); BattleScriptExecute(BattleScript_PoisonHealActivates); effect = TRUE; } } else if (gBattleMons[battler].status1 & STATUS1_TOXIC_POISON) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 16); if ((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns gBattleMons[battler].status1 += STATUS1_TOXIC_TURN(1); - gBattleStruct->moveDamage[battler] *= (gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >> 8; + gBattleStruct->passiveHpUpdate[battler] *= (gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >> 8; BattleScriptExecute(BattleScript_PoisonTurnDmg); effect = TRUE; } else { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); BattleScriptExecute(BattleScript_PoisonTurnDmg); effect = TRUE; } @@ -657,23 +523,22 @@ static bool32 HandleEndTurnBurn(u32 battler) { bool32 effect = FALSE; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].status1 & STATUS1_BURN && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); + s32 burnDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); if (ability == ABILITY_HEATPROOF) { - if (gBattleStruct->moveDamage[battler] > (gBattleStruct->moveDamage[battler] / 2) + 1) // Record ability if the burn takes less damage than it normally would. + if (burnDamage > (burnDamage / 2) + 1) // Record ability if the burn takes less damage than it normally would. RecordAbilityBattle(battler, ABILITY_HEATPROOF); - gBattleStruct->moveDamage[battler] /= 2; + burnDamage /= 2; } - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, burnDamage); BattleScriptExecute(BattleScript_BurnTurnDmg); effect = TRUE; } @@ -685,15 +550,13 @@ static bool32 HandleEndTurnFrostbite(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].status1 & STATUS1_FROSTBITE && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8)); BattleScriptExecute(BattleScript_FrostbiteTurnDmg); effect = TRUE; } @@ -705,7 +568,7 @@ static bool32 HandleEndTurnNightmare(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.nightmare && IsBattlerAlive(battler) @@ -713,9 +576,7 @@ static bool32 HandleEndTurnNightmare(u32 battler) { if (gBattleMons[battler].status1 & STATUS1_SLEEP) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 4); BattleScriptExecute(BattleScript_NightmareTurnDmg); effect = TRUE; } @@ -732,15 +593,13 @@ static bool32 HandleEndTurnCurse(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.cursed && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 4); BattleScriptExecute(BattleScript_CurseTurnDmg); effect = TRUE; } @@ -752,7 +611,7 @@ static bool32 HandleEndTurnWrap(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.wrapped && IsBattlerAlive(battler)) { @@ -762,22 +621,21 @@ static bool32 HandleEndTurnWrap(u32 battler) if (IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) return effect; - gBattleScripting.animArg1 = gBattleStruct->wrappedMove[battler]; - gBattleScripting.animArg2 = gBattleStruct->wrappedMove[battler] >> 8; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]); + gBattleScripting.animArg1 = gBattleMons[battler].volatiles.wrappedMove; + gBattleScripting.animArg2 = gBattleMons[battler].volatiles.wrappedMove >> 8; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[battler].volatiles.wrappedMove); BattleScriptExecute(BattleScript_WrapTurnDmg); - if (GetBattlerHoldEffect(gBattleStruct->wrappedBy[battler], TRUE) == HOLD_EFFECT_BINDING_BAND) - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); + s32 bindDamage = 0; + if (GetBattlerHoldEffect(gBattleMons[battler].volatiles.wrappedBy) == HOLD_EFFECT_BINDING_BAND) + bindDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); else - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); - - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + bindDamage = GetNonDynamaxMaxHP(battler) / (B_BINDING_DAMAGE >= GEN_6 ? 8 : 16); + SetPassiveDamageAmount(battler, bindDamage); } else // broke free { gBattleMons[battler].volatiles.wrapped = FALSE; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]); + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[battler].volatiles.wrappedMove); BattleScriptExecute(BattleScript_WrapEnds); } effect = TRUE; @@ -790,18 +648,18 @@ static bool32 HandleEndTurnSaltCure(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.saltCure && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { + s32 saltCureDamage = 0; if (IS_BATTLER_ANY_TYPE(battler, TYPE_STEEL, TYPE_WATER)) - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4; + saltCureDamage = GetNonDynamaxMaxHP(battler) / 4; else - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + saltCureDamage = GetNonDynamaxMaxHP(battler) / 8; + SetPassiveDamageAmount(battler, saltCureDamage); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SALT_CURE); BattleScriptExecute(BattleScript_SaltCureExtraDamage); effect = TRUE; @@ -814,7 +672,7 @@ static bool32 HandleEndTurnOctolock(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].octolock) { @@ -831,7 +689,7 @@ static bool32 HandleEndTurnSyrupBomb(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.syrupBomb && (IsBattlerAlive(battler))) { @@ -850,10 +708,11 @@ static bool32 HandleEndTurnTaunt(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].tauntTimer && --gDisableStructs[battler].tauntTimer == 0) { + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_BufferEndTurn); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); effect = TRUE; @@ -866,11 +725,12 @@ static bool32 HandleEndTurnTorment(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gDisableStructs[battler].tormentTimer == gBattleTurnCounter) + if (gDisableStructs[battler].tormentTimer > 0 && --gDisableStructs[battler].tormentTimer == 0) { gBattleMons[battler].volatiles.torment = FALSE; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_TormentEnds); effect = TRUE; } @@ -882,7 +742,7 @@ static bool32 HandleEndTurnEncore(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].encoreTimer != 0) { @@ -896,6 +756,7 @@ static bool32 HandleEndTurnEncore(u32 battler) { gDisableStructs[battler].encoredMove = 0; gDisableStructs[battler].encoreTimer = 0; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_EncoredNoMore); effect = TRUE; } @@ -909,7 +770,7 @@ static bool32 HandleEndTurnDisable(u32 battler) bool32 effect = FALSE; u32 moveIndex = 0; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].disableTimer != 0) { @@ -926,6 +787,7 @@ static bool32 HandleEndTurnDisable(u32 battler) else if (--gDisableStructs[battler].disableTimer == 0) // disable ends { gDisableStructs[battler].disabledMove = 0; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_DisabledNoMore); effect = TRUE; } @@ -938,9 +800,9 @@ static bool32 HandleEndTurnMagnetRise(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.magnetRise && gDisableStructs[battler].magnetRiseTimer == gBattleTurnCounter) + if (gDisableStructs[battler].magnetRiseTimer > 0 && --gDisableStructs[battler].magnetRiseTimer == 0) { gBattleMons[battler].volatiles.magnetRise = FALSE; BattleScriptExecute(BattleScript_BufferEndTurn); @@ -955,9 +817,9 @@ static bool32 HandleEndTurnTelekinesis(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.telekinesis && gDisableStructs[battler].telekinesisTimer == gBattleTurnCounter) + if (gDisableStructs[battler].telekinesisTimer > 0 && --gDisableStructs[battler].telekinesisTimer == 0) { gBattleMons[battler].volatiles.telekinesis = FALSE; BattleScriptExecute(BattleScript_TelekinesisEndTurn); @@ -971,11 +833,12 @@ static bool32 HandleEndTurnHealBlock(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.healBlock && gDisableStructs[battler].healBlockTimer == gBattleTurnCounter) + if (gDisableStructs[battler].healBlockTimer > 0 && --gDisableStructs[battler].healBlockTimer == 0) { gBattleMons[battler].volatiles.healBlock = FALSE; + gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_BufferEndTurn); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_HEAL_BLOCK); effect = TRUE; @@ -988,9 +851,9 @@ static bool32 HandleEndTurnEmbargo(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (gBattleMons[battler].volatiles.embargo && gDisableStructs[battler].embargoTimer == gBattleTurnCounter) + if (gDisableStructs[battler].embargoTimer > 0 && --gDisableStructs[battler].embargoTimer == 0) { gBattleMons[battler].volatiles.embargo = FALSE; BattleScriptExecute(BattleScript_EmbargoEndTurn); @@ -1004,9 +867,9 @@ static bool32 HandleEndTurnYawn(u32 battler) { bool32 effect = FALSE; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gBattleMons[battler].volatiles.yawn > 0) { @@ -1019,12 +882,13 @@ static bool32 HandleEndTurnYawn(u32 battler) && !IsLeafGuardProtected(battler, ability)) { gEffectBattler = gBattlerTarget = battler; - if (IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN)) + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (IsBattlerTerrainAffected(battler, ability, holdEffect, STATUS_FIELD_ELECTRIC_TERRAIN)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_ELECTRIC; BattleScriptExecute(BattleScript_TerrainPreventsEnd2); } - else if (IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN)) + else if (IsBattlerTerrainAffected(battler, ability, holdEffect, STATUS_FIELD_MISTY_TERRAIN)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAINPREVENTS_MISTY; BattleScriptExecute(BattleScript_TerrainPreventsEnd2); @@ -1065,7 +929,7 @@ static bool32 HandleEndTurnPerishSong(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (IsBattlerAlive(battler) && gBattleMons[battler].volatiles.perishSong) { @@ -1073,7 +937,7 @@ static bool32 HandleEndTurnPerishSong(u32 battler) if (gDisableStructs[battler].perishSongTimer == 0) { gBattleMons[battler].volatiles.perishSong = FALSE; - gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp; + SetPassiveDamageAmount(battler, gBattleMons[battler].hp); BattleScriptExecute(BattleScript_PerishSongTakesLife); } else @@ -1091,7 +955,7 @@ static bool32 HandleEndTurnRoost(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; if (gDisableStructs[battler].roostActive) gDisableStructs[battler].roostActive = FALSE; @@ -1103,12 +967,12 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) { bool32 effect = FALSE; - u32 side = gBattleStruct->turnSideTracker; + u32 side = gBattleStruct->eventState.battlerSide; - switch (gBattleStruct->eventBlockCounter) + switch (gBattleStruct->eventState.endTurnBlock) { case SECOND_EVENT_BLOCK_REFLECT: - if (gSideStatuses[side] & SIDE_STATUS_REFLECT && gSideTimers[side].reflectTimer == gBattleTurnCounter) + if (gSideTimers[side].reflectTimer > 0 && --gSideTimers[side].reflectTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_REFLECT; @@ -1117,10 +981,10 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_REFLECT); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_LIGHT_SCREEN: - if (gSideStatuses[side] & SIDE_STATUS_LIGHTSCREEN && gSideTimers[side].lightscreenTimer == gBattleTurnCounter) + if (gSideTimers[side].lightscreenTimer > 0 && --gSideTimers[side].lightscreenTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_LIGHTSCREEN; @@ -1129,20 +993,20 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_LIGHT_SCREEN); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_SAFEGUARD: - if (gSideStatuses[side] & SIDE_STATUS_SAFEGUARD && gSideTimers[side].safeguardTimer == gBattleTurnCounter) + if (gSideTimers[side].safeguardTimer > 0 && --gSideTimers[side].safeguardTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_SAFEGUARD; BattleScriptExecute(BattleScript_SafeguardEnds); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_MIST: - if (gSideTimers[side].mistTimer != 0 && gSideTimers[side].mistTimer == gBattleTurnCounter) + if (gSideTimers[side].mistTimer > 0 && --gSideTimers[side].mistTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_MIST; @@ -1151,59 +1015,59 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_MIST); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_TAILWIND: - if (gSideStatuses[side] & SIDE_STATUS_TAILWIND && gSideTimers[side].tailwindTimer == gBattleTurnCounter) + if (gSideTimers[side].tailwindTimer > 0 && --gSideTimers[side].tailwindTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_TAILWIND; BattleScriptExecute(BattleScript_TailwindEnds); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_LUCKY_CHANT: - if (gSideStatuses[side] & SIDE_STATUS_LUCKY_CHANT && gSideTimers[side].luckyChantTimer == gBattleTurnCounter) + if (gSideTimers[side].luckyChantTimer > 0 && --gSideTimers[side].luckyChantTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_LUCKY_CHANT; BattleScriptExecute(BattleScript_LuckyChantEnds); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_RAINBOW: gBattlerAttacker = GetBattlerSideForMessage(side); - if (gSideStatuses[side] & SIDE_STATUS_RAINBOW && gSideTimers[side].rainbowTimer == gBattleTurnCounter) + if (gSideTimers[side].rainbowTimer > 0 && --gSideTimers[side].rainbowTimer == 0) { gSideStatuses[side] &= ~SIDE_STATUS_RAINBOW; BattleScriptExecute(BattleScript_TheRainbowDisappeared); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_SEA_OF_FIRE: - if (gSideStatuses[side] & SIDE_STATUS_SEA_OF_FIRE && gSideTimers[side].seaOfFireTimer == gBattleTurnCounter) + if (gSideTimers[side].seaOfFireTimer > 0 && --gSideTimers[side].seaOfFireTimer == 0) { gSideStatuses[side] &= ~SIDE_STATUS_SEA_OF_FIRE; BattleScriptExecute(BattleScript_TheSeaOfFireDisappeared); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_SWAMP: gBattlerAttacker = GetBattlerSideForMessage(side); - if (gSideStatuses[side] & SIDE_STATUS_SWAMP && gSideTimers[side].swampTimer == gBattleTurnCounter) + if (gSideTimers[side].swampTimer > 0 && --gSideTimers[side].swampTimer == 0) { gSideStatuses[side] &= ~SIDE_STATUS_SWAMP; BattleScriptExecute(BattleScript_TheSwampDisappeared); effect = TRUE; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case SECOND_EVENT_BLOCK_AURORA_VEIL: - if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL && gSideTimers[side].auroraVeilTimer == gBattleTurnCounter) + if (gSideTimers[side].auroraVeilTimer > 0 && --gSideTimers[side].auroraVeilTimer == 0) { gBattlerAttacker = GetBattlerSideForMessage(side); gSideStatuses[side] &= ~SIDE_STATUS_AURORA_VEIL; @@ -1212,8 +1076,8 @@ static bool32 HandleEndTurnSecondEventBlock(u32 battler) PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_AURORA_VEIL); effect = TRUE; } - gBattleStruct->turnSideTracker++; - gBattleStruct->eventBlockCounter = 0; + gBattleStruct->eventState.battlerSide++; + gBattleStruct->eventState.endTurnBlock = 0; break; } @@ -1224,9 +1088,9 @@ static bool32 HandleEndTurnTrickRoom(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer == gBattleTurnCounter) + if (gFieldTimers.trickRoomTimer > 0 && --gFieldTimers.trickRoomTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_TRICK_ROOM; BattleScriptExecute(BattleScript_TrickRoomEnds); @@ -1240,9 +1104,9 @@ static bool32 HandleEndTurnGravity(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_GRAVITY && gFieldTimers.gravityTimer == gBattleTurnCounter) + if (gFieldTimers.gravityTimer > 0 && --gFieldTimers.gravityTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_GRAVITY; BattleScriptExecute(BattleScript_GravityEnds); @@ -1256,9 +1120,9 @@ static bool32 HandleEndTurnWaterSport(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_WATERSPORT && gFieldTimers.waterSportTimer == gBattleTurnCounter) + if (gFieldTimers.waterSportTimer > 0 && --gFieldTimers.waterSportTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_WATERSPORT; BattleScriptExecute(BattleScript_WaterSportEnds); @@ -1272,9 +1136,9 @@ static bool32 HandleEndTurnMudSport(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_MUDSPORT && gFieldTimers.mudSportTimer == gBattleTurnCounter) + if (gFieldTimers.mudSportTimer > 0 && --gFieldTimers.mudSportTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_MUDSPORT; BattleScriptExecute(BattleScript_MudSportEnds); @@ -1288,9 +1152,9 @@ static bool32 HandleEndTurnWonderRoom(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM && gFieldTimers.wonderRoomTimer == gBattleTurnCounter) + if (gFieldTimers.wonderRoomTimer > 0 && --gFieldTimers.wonderRoomTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_WONDER_ROOM; BattleScriptExecute(BattleScript_WonderRoomEnds); @@ -1304,9 +1168,9 @@ static bool32 HandleEndTurnMagicRoom(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; - if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM && gFieldTimers.magicRoomTimer == gBattleTurnCounter) + if (gFieldTimers.magicRoomTimer > 0 && --gFieldTimers.magicRoomTimer == 0) { gFieldStatuses &= ~STATUS_FIELD_MAGIC_ROOM; BattleScriptExecute(BattleScript_MagicRoomEnds); @@ -1318,7 +1182,7 @@ static bool32 HandleEndTurnMagicRoom(u32 battler) static bool32 EndTurnTerrain(u32 terrainFlag, u32 stringTableId) { - if (gFieldStatuses & terrainFlag && gFieldTimers.terrainTimer == gBattleTurnCounter) + if (gFieldTimers.terrainTimer > 0 && --gFieldTimers.terrainTimer == 0) { gFieldStatuses &= ~terrainFlag; TryToRevertMimicryAndFlags(); @@ -1334,7 +1198,7 @@ static bool32 HandleEndTurnTerrain(u32 battler) { bool32 effect = FALSE; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurn++; if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) effect = EndTurnTerrain(STATUS_FIELD_ELECTRIC_TERRAIN, B_MSG_TERRAIN_END_ELECTRIC); @@ -1354,11 +1218,11 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) if (!IsBattlerAlive(battler)) { - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; return effect; } - switch (gBattleStruct->eventBlockCounter) + switch (gBattleStruct->eventState.endTurnBlock) { case THIRD_EVENT_BLOCK_UPROAR: if (gBattleMons[battler].volatiles.uproarTurns) @@ -1401,11 +1265,11 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) effect = TRUE; } } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; case THIRD_EVENT_BLOCK_ABILITIES: { - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); switch (ability) { case ABILITY_TRUANT: // Not fully accurate but it has to be handled somehow. TODO: Find a better way. @@ -1420,30 +1284,33 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE)) effect = TRUE; break; + default: + break; } - gBattleStruct->eventBlockCounter++; + gBattleStruct->eventState.endTurnBlock++; break; } case THIRD_EVENT_BLOCK_ITEMS: { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); + // TODO: simplify + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); switch (holdEffect) { case HOLD_EFFECT_FLAME_ORB: case HOLD_EFFECT_STICKY_BARB: case HOLD_EFFECT_TOXIC_ORB: - if (ItemBattleEffects(ITEMEFFECT_ORBS, battler)) + if (ItemBattleEffects(battler, 0, holdEffect, IsOrbsActivation)) effect = TRUE; break; case HOLD_EFFECT_WHITE_HERB: - if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler)) + if (ItemBattleEffects(battler, 0, holdEffect, IsWhiteHerbEndTurnActivation)) effect = TRUE; break; default: break; } - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler++; break; } } @@ -1455,9 +1322,9 @@ static bool32 HandleEndTurnFormChangeAbilities(u32 battler) { bool32 effect = FALSE; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; switch (ability) { @@ -1468,6 +1335,8 @@ static bool32 HandleEndTurnFormChangeAbilities(u32 battler) case ABILITY_HUNGER_SWITCH: if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE)) effect = TRUE; + default: + break; } return effect; @@ -1475,17 +1344,17 @@ static bool32 HandleEndTurnFormChangeAbilities(u32 battler) static bool32 HandleEndTurnEjectPack(u32 battler) { - gBattleStruct->turnEffectsBattlerId++; - return TrySwitchInEjectPack(ITEMEFFECT_NORMAL); + gBattleStruct->eventState.endTurn++; + return TrySwitchInEjectPack(END_TURN); } static bool32 HandleEndTurnDynamax(u32 battler) { bool32 effect = FALSE; - gBattleStruct->turnEffectsBattlerId++; + gBattleStruct->eventState.endTurnBattler++; - if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gBattleStruct->dynamax.dynamaxTurns[battler] == gBattleTurnCounter) + if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gBattleStruct->dynamax.dynamaxTurns[battler] > 0 && --gBattleStruct->dynamax.dynamaxTurns[battler] == 0) { gBattleScripting.battler = battler; UndoDynamax(battler); @@ -1496,13 +1365,25 @@ static bool32 HandleEndTurnDynamax(u32 battler) return effect; } +/* + * Various end turn effects that happen after all battlers moved. + * Each Case will apply the effects for each battler. Moving to the next case when all battlers are done. + * If an effect is going to be applied on a better, the bool effect will be set to TRUE and a script set. + * The script is set with `BattleScriptExecute` and should have the ending `end2` + Example: + BattleScriptExecute(BattleScript_X); + + (in battle_scripts_1.s) + BattleScript_X: + some commands + end2 + */ static bool32 (*const sEndTurnEffectHandlers[])(u32 battler) = { [ENDTURN_ORDER] = HandleEndTurnOrder, [ENDTURN_VARIOUS] = HandleEndTurnVarious, [ENDTURN_WEATHER] = HandleEndTurnWeather, [ENDTURN_WEATHER_DAMAGE] = HandleEndTurnWeatherDamage, - [ENDTURN_GEN_3_BERRY_ACTIVATION] = HandleEndTurnGenThreeBerryActivation, [ENDTURN_EMERGENCY_EXIT_1] = HandleEndTurnEmergencyExit, [ENDTURN_AFFECTION] = HandleEndTurnAffection, [ENDTURN_FUTURE_SIGHT] = HandleEndTurnFutureSight, @@ -1551,29 +1432,25 @@ static bool32 (*const sEndTurnEffectHandlers[])(u32 battler) = u32 DoEndTurnEffects(void) { u32 battler = MAX_BATTLERS_COUNT; - gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); for (;;) { // If either turnEffectsBattlerId or turnSideTracker are at max count, reest values and go to the next state - if (gBattleStruct->turnEffectsBattlerId == gBattlersCount || gBattleStruct->turnSideTracker == NUM_BATTLE_SIDES) + if (gBattleStruct->eventState.endTurnBattler == gBattlersCount || gBattleStruct->eventState.battlerSide == NUM_BATTLE_SIDES) { - gBattleStruct->turnEffectsBattlerId = 0; - gBattleStruct->turnSideTracker = 0; - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->endTurnEventsCounter++; + gBattleStruct->eventState.endTurnBattler = 0; + gBattleStruct->eventState.battlerSide = 0; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurn++; } // Jump out if possible after endTurnEventsCounter was increased in the above code block - if (gBattleStruct->endTurnEventsCounter == ENDTURN_COUNT) - { - gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); + if (gBattleStruct->eventState.endTurn == ENDTURN_COUNT) return FALSE; - } - battler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->turnEffectsBattlerId]; + battler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->eventState.endTurnBattler]; - if (sEndTurnEffectHandlers[gBattleStruct->endTurnEventsCounter](battler)) + if (sEndTurnEffectHandlers[gBattleStruct->eventState.endTurn](battler)) return TRUE; } } diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index a6362bb24f..0c2b0d5c20 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -466,8 +466,10 @@ void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isVolatile, u32 stat gBattleSpritesDataPtr->healthBoxesData[battler].statusAnimActive = 1; if (!isVolatile) { - if (status == STATUS1_FREEZE || status == STATUS1_FROSTBITE) + if (status == STATUS1_FREEZE) LaunchStatusAnimation(battler, B_ANIM_STATUS_FRZ); + else if (status == STATUS1_FROSTBITE) + LaunchStatusAnimation(battler, B_ANIM_STATUS_FRB); else if (status == STATUS1_POISON || status & STATUS1_TOXIC_POISON) LaunchStatusAnimation(battler, B_ANIM_STATUS_PSN); else if (status == STATUS1_BURN) @@ -694,8 +696,9 @@ void DecompressTrainerBackPic(u16 backPicId, u8 battler) { u8 position = GetBattlerPosition(battler); CopyTrainerBackspriteFramesToDest(backPicId, gMonSpritesGfxPtr->spritesGfx[position]); + // Aiming for palette slots 8 and 9 for Player and PlayerPartner to prevent Trainer Slides causing mons to change colour LoadPalette(gTrainerBacksprites[backPicId].palette.data, - OBJ_PLTT_ID(battler), PLTT_SIZE_4BPP); + OBJ_PLTT_ID(8 + battler/2), PLTT_SIZE_4BPP); } void FreeTrainerFrontPicPalette(u16 frontPicId) @@ -1237,6 +1240,12 @@ void LoadAndCreateEnemyShadowSprites(void) void SpriteCB_EnemyShadow(struct Sprite *shadowSprite) { + if (gBattleSpritesDataPtr == NULL) + { + shadowSprite->callback = SpriteCB_SetInvisible; + return; + } + bool8 invisible = FALSE; u8 battler = shadowSprite->tBattlerId; struct Sprite *battlerSprite = &gSprites[gBattlerSpriteIds[battler]]; diff --git a/src/battle_gimmick.c b/src/battle_gimmick.c index 38d60d4365..3969932faf 100644 --- a/src/battle_gimmick.c +++ b/src/battle_gimmick.c @@ -91,20 +91,15 @@ bool32 ShouldTrainerBattlerUseGimmick(u32 battler, enum Gimmick gimmick) // Returns whether a trainer has used a gimmick during a battle. bool32 HasTrainerUsedGimmick(u32 battler, enum Gimmick gimmick) { - // Check whether partner battler has used gimmick or plans to during turn. - if (IsDoubleBattle() - && IsPartnerMonFromSameTrainer(battler) - && (gBattleStruct->gimmick.activated[BATTLE_PARTNER(battler)][gimmick] - || ((gBattleStruct->gimmick.toActivate & (1u << BATTLE_PARTNER(battler)) - && gBattleStruct->gimmick.usableGimmick[BATTLE_PARTNER(battler)] == gimmick)))) + if (IsDoubleBattle() && IsPartnerMonFromSameTrainer(battler)) { - return TRUE; - } - // Otherwise, return whether current battler has used gimmick. - else - { - return gBattleStruct->gimmick.activated[battler][gimmick]; + u32 partner = BATTLE_PARTNER(battler); + if (gBattleStruct->gimmick.activated[partner][gimmick] + || ((gBattleStruct->gimmick.toActivate & (1u << partner)) && gBattleStruct->gimmick.usableGimmick[partner] == gimmick)) + return TRUE; } + + return gBattleStruct->gimmick.activated[battler][gimmick]; } // Sets a gimmick as used by a trainer with checks for Multi Battles. diff --git a/src/battle_hold_effects.c b/src/battle_hold_effects.c new file mode 100644 index 0000000000..9f363ea120 --- /dev/null +++ b/src/battle_hold_effects.c @@ -0,0 +1,1275 @@ +#include "global.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_ai_util.h" // maybe move some stuff over to battle.h +#include "battle_controllers.h" +#include "battle_util.h" +#include "battle_hold_effects.h" +#include "battle_scripts.h" +#include "item.h" +#include "string_util.h" +#include "data/hold_effects.h" +#include "constants/berry.h" + +bool32 IsOnSwitchInActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onSwitchIn; } +bool32 IsOnSwitchInFirstTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onSwitchInFirstTurn; } +bool32 IsMirrorHerbActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].mirrorHerb; } +bool32 IsMirrorHerbFirstTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].mirrorHerbFirstTurn; } +bool32 IsWhiteHerbActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].whiteHerb; } +bool32 IsWhiteHerbFirstTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].whiteHerbFirstTurn; } +bool32 IsWhiteHerbEndTurnActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].whiteHerbEndTurn; } +bool32 IsOnStatusChangeActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onStatusChange; } +bool32 IsOnHpThresholdActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onHpThreshold; } +bool32 IsKeeMarangaBerryActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].keeMarangaBerry; } +bool32 IsOnTargetHitActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onTargetAfterHit; } +bool32 IsOnAttackerAfterHitActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onAttackerAfterHit; } +bool32 IsLifeOrbShellBellActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].lifeOrbShellBell; } +bool32 IsLeftoversActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].leftovers; } +bool32 IsOrbsActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].orbs; } +bool32 IsOnEffectActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onEffect; } +bool32 IsOnBerryActivation(enum HoldEffect holdEffect) { return GetItemPocket(gLastUsedItem) == POCKET_BERRIES; } +bool32 IsOnFlingActivation(enum HoldEffect holdEffect) { return gHoldEffectsInfo[holdEffect].onFling; } + +bool32 IsForceTriggerItemActivation(enum HoldEffect holdEffect) +{ + return gHoldEffectsInfo[holdEffect].onSwitchIn + || gHoldEffectsInfo[holdEffect].whiteHerb + || gHoldEffectsInfo[holdEffect].onStatusChange + || gHoldEffectsInfo[holdEffect].onHpThreshold; +} + +static enum ItemEffect TryDoublePrize(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsOnPlayerSide(battler) && !gBattleStruct->moneyMultiplierItem) + { + gBattleStruct->moneyMultiplier *= 2; + gBattleStruct->moneyMultiplierItem = TRUE; + } + + return effect; +} + +enum ItemEffect TryBoosterEnergy(u32 battler, enum Ability ability, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gDisableStructs[battler].boosterEnergyActivated || gBattleMons[battler].volatiles.transformed) + return ITEM_NO_EFFECT; + + if (((ability == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect())) + || ((ability == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))) + { + gDisableStructs[battler].paradoxBoostedStat = GetParadoxHighestStatId(battler); + PREPARE_STAT_BUFFER(gBattleTextBuff1, gDisableStructs[battler].paradoxBoostedStat); + gBattlerAbility = gBattleScripting.battler = battler; + gDisableStructs[battler].boosterEnergyActivated = TRUE; + RecordAbilityBattle(battler, ability); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BoosterEnergyEnd2); + else + BattleScriptCall(BattleScript_BoosterEnergyRet); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryRoomService(u32 battler, ActivationTiming timing) +{ + if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN, GetBattlerAbility(battler))) + { + gEffectBattler = gBattleScripting.battler = battler; + SET_STATCHANGER(STAT_SPEED, 1, TRUE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_SPEED; + gBattleScripting.animArg2 = 0; + + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + + return ITEM_STATS_CHANGE; + } + + return ITEM_NO_EFFECT; +} + +enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, enum Stat statId, ActivationTiming timing) +{ + if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battler))) + { + gEffectBattler = gBattleScripting.battler = battler; + SET_STATCHANGER(statId, 1, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; + gBattleScripting.animArg2 = 0; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + return ITEM_STATS_CHANGE; + } + return ITEM_NO_EFFECT; +} + +static enum ItemEffect TryTerrainSeeds(u32 battler, u32 item, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + switch (GetItemHoldEffectParam(item)) + { + case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, timing); + break; + case HOLD_EFFECT_PARAM_GRASSY_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, timing); + break; + case HOLD_EFFECT_PARAM_MISTY_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, timing); + break; + case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN: + effect = TryHandleSeed(battler, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, timing); + break; + } + + return effect; +} + +static bool32 CanBeInfinitelyConfused(u32 battler) +{ + enum Ability ability = GetBattlerAbility(battler); + if (ability == ABILITY_OWN_TEMPO + || IsBattlerTerrainAffected(battler, ability, GetBattlerHoldEffect(battler), STATUS_FIELD_MISTY_TERRAIN) + || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) + return FALSE; + return TRUE; +} + +static enum ItemEffect TryBerserkGene(u32 battler, ActivationTiming timing) +{ + if (CanBeInfinitelyConfused(battler)) + gBattleMons[battler].volatiles.infiniteConfusion = TRUE; + + SET_STATCHANGER(STAT_ATK, 2, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; + gBattleScripting.animArg2 = 0; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerserkGeneRetEnd2); + else + BattleScriptCall(BattleScript_BerserkGeneRet); + + return ITEM_STATS_CHANGE; +} + +static enum ItemEffect RestoreWhiteHerbStats(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + for (u32 i = 0; i < NUM_BATTLE_STATS; i++) + { + if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE) + { + gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; + effect = ITEM_STATS_CHANGE; + } + } + if (effect != ITEM_NO_EFFECT) + { + if (timing == IsWhiteHerbActivation || timing == IsOnFlingActivation) + BattleScriptCall(BattleScript_WhiteHerbRet); + else + BattleScriptExecute(BattleScript_WhiteHerbEnd2); + } + + return effect; +} + +static enum ItemEffect TryConsumeMirrorHerb(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gProtectStructs[battler].eatMirrorHerb) + { + gProtectStructs[battler].eatMirrorHerb = 0; + ChooseStatBoostAnimation(battler); + if (timing == IsMirrorHerbFirstTurnActivation) + BattleScriptExecute(BattleScript_MirrorHerbCopyStatChangeEnd2); + else + BattleScriptCall(BattleScript_MirrorHerbCopyStatChange); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryKingsRock(u32 battlerAtk, u32 battlerDef, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!IsBattlerAlive(battlerDef) + || !IsBattlerTurnDamaged(battlerDef) + || MoveIgnoresKingsRock(gCurrentMove) + || MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_FLINCH)) + return effect; + + enum Ability ability = GetBattlerAbility(battlerAtk); + u32 holdEffectParam = GetItemHoldEffectParam(item); + + if (B_SERENE_GRACE_BOOST >= GEN_5 && ability == ABILITY_SERENE_GRACE) + holdEffectParam *= 2; + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_RAINBOW && gCurrentMove != MOVE_SECRET_POWER) + holdEffectParam *= 2; + if (ability != ABILITY_STENCH && RandomPercentage(RNG_HOLD_EFFECT_FLINCH, holdEffectParam)) + { + SetMoveEffect(battlerAtk, battlerDef, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, NO_FLAGS); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryAirBalloon(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (timing == IsOnTargetHitActivation) + { + if (IsBattlerTurnDamaged(battler)) + { + BattleScriptCall(BattleScript_AirBalloonMsgPop); + effect = ITEM_EFFECT_OTHER; + } + } + else if (!gSpecialStatuses[battler].switchInItemDone) + { + gSpecialStatuses[battler].switchInItemDone = TRUE; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptPushCursorAndCallback(BattleScript_AirBalloonMsgIn); + else + BattleScriptCall(BattleScript_AirBalloonMsgInRet); + RecordItemEffectBattle(battler, HOLD_EFFECT_AIR_BALLOON); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryRockyHelmet(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battlerAtk); + + if (IsBattlerTurnDamaged(battlerDef) + && IsBattlerAlive(battlerAtk) + && !CanBattlerAvoidContactEffects(battlerAtk, battlerDef, ability, GetBattlerHoldEffect(battlerAtk), gCurrentMove) + && !IsAbilityAndRecord(battlerAtk, ability, ABILITY_MAGIC_GUARD)) + { + SetPassiveDamageAmount(battlerAtk, GetNonDynamaxMaxHP(battlerAtk) / 6); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + BattleScriptCall(BattleScript_RockyHelmetActivates); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryWeaknessPolicy(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_SUPER_EFFECTIVE) + { + BattleScriptCall(BattleScript_WeaknessPolicy); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TrySnowball(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_ICE) + { + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_ATK, 1, FALSE); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryLuminousMoss(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_WATER) + { + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_SPDEF, 1, FALSE); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCellBattery(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_ELECTRIC) + { + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_ATK, 1, FALSE); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryAbsorbBulb(u32 battlerDef) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && IsBattlerTurnDamaged(battlerDef) + && GetBattleMoveType(gCurrentMove) == TYPE_WATER) + { + effect = ITEM_STATS_CHANGE; + BattleScriptCall(BattleScript_TargetItemStatRaise); + SET_STATCHANGER(STAT_SPATK, 1, FALSE); + } + + return effect; +} + +static enum ItemEffect TryJabocaBerry(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerAtk) + && IsBattlerTurnDamaged(battlerDef) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && IsBattleMovePhysical(gCurrentMove) + && !IsAbilityAndRecord(battlerAtk, GetBattlerAbility(battlerAtk), ABILITY_MAGIC_GUARD)) + { + s32 jabocaDamage = GetNonDynamaxMaxHP(battlerAtk) / 8; + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + jabocaDamage *= 2; + SetPassiveDamageAmount(battlerAtk, jabocaDamage); + BattleScriptCall(BattleScript_JabocaRowapBerryActivates); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryRowapBerry(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerAtk) + && IsBattlerTurnDamaged(battlerDef) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && IsBattleMoveSpecial(gCurrentMove) + && !IsAbilityAndRecord(battlerAtk, GetBattlerAbility(battlerAtk), ABILITY_MAGIC_GUARD)) + { + s32 rowapDamage = GetNonDynamaxMaxHP(battlerAtk) / 8; + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + rowapDamage *= 2; + SetPassiveDamageAmount(battlerAtk, rowapDamage); + BattleScriptCall(BattleScript_JabocaRowapBerryActivates); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TrySetEnigmaBerry(u32 battlerDef, u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerDef) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && ((IsBattlerTurnDamaged(battlerDef) && gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements) + && !(gBattleScripting.overrideBerryRequirements && gBattleMons[battlerDef].hp == gBattleMons[battlerDef].maxHP) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battlerDef].volatiles.healBlock)) + { + s32 healAmount = gBattleMons[battlerDef].maxHP * 25 / 100; + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + healAmount *= 2; + SetHealAmount(battlerDef, healAmount); + BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryBlunderPolicy(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleStruct->blunderPolicy + && IsBattlerAlive(battlerAtk) + && CompareStat(battlerAtk, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerAtk))) + { + gBattleStruct->blunderPolicy = FALSE; + SET_STATCHANGER(STAT_SPEED, 2, FALSE); + BattleScriptCall(BattleScript_AttackerItemStatRaise); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryMentalHerb(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + // Check infatuation + if (gBattleMons[battler].volatiles.infatuation) + { + gBattleMons[battler].volatiles.infatuation = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; + StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); + effect = ITEM_EFFECT_OTHER; + } + if (B_MENTAL_HERB >= GEN_5) + { + // Check taunt + if (gDisableStructs[battler].tauntTimer != 0) + { + gDisableStructs[battler].tauntTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); + effect = ITEM_EFFECT_OTHER; + } + // Check encore + if (gDisableStructs[battler].encoreTimer != 0) + { + gDisableStructs[battler].encoredMove = 0; + gDisableStructs[battler].encoreTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; + effect = ITEM_EFFECT_OTHER; + } + // Check torment + if (gBattleMons[battler].volatiles.torment == TRUE) + { + gBattleMons[battler].volatiles.torment = FALSE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; + effect = ITEM_EFFECT_OTHER; + } + // Check heal block + if (gBattleMons[battler].volatiles.healBlock) + { + gBattleMons[battler].volatiles.healBlock = FALSE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK; + effect = ITEM_EFFECT_OTHER; + } + // Check disable + if (gDisableStructs[battler].disableTimer != 0) + { + gDisableStructs[battler].disableTimer = 0; + gDisableStructs[battler].disabledMove = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE; + effect = ITEM_EFFECT_OTHER; + } + } + + if (effect) + BattleScriptCall(BattleScript_MentalHerbCureRet); + + return effect; +} + +static enum ItemEffect TryThroatSpray(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsSoundMove(gCurrentMove) + && gMultiHitCounter == 0 + && IsBattlerAlive(battlerAtk) + && IsAnyTargetTurnDamaged(battlerAtk) + && CompareStat(battlerAtk, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerAtk)) + && !NoAliveMonsForEitherParty()) // Don't activate if battle will end + { + SET_STATCHANGER(STAT_SPATK, 1, FALSE); + BattleScriptCall(BattleScript_AttackerItemStatRaise); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect DamagedStatBoostBerryEffect(u32 battlerDef, u32 battlerAtk, enum Stat statId, enum DamageCategory category) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!IsBattlerAlive(battlerDef) || !CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battlerDef))) + return effect; + + if (gBattleScripting.overrideBerryRequirements + || (!DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && GetBattleMoveCategory(gCurrentMove) == category + && IsBattlerTurnDamaged(battlerDef))) + { + if (GetBattlerAbility(battlerDef) == ABILITY_RIPEN) + SET_STATCHANGER(statId, 2, FALSE); + else + SET_STATCHANGER(statId, 1, FALSE); + + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; + gBattleScripting.animArg2 = 0; + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryShellBell(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleScripting.savedDmg > 0 + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && (IsAnyTargetTurnDamaged(battlerAtk) || gBattleScripting.savedDmg > 0) + && !IsBattlerAtMaxHp(battlerAtk) + && IsBattlerAlive(battlerAtk) + && GetMoveEffect(gCurrentMove) != EFFECT_PAIN_SPLIT + && !IsFutureSightAttackerInParty(battlerAtk, gBattlerTarget, gCurrentMove) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battlerAtk].volatiles.healBlock)) + { + SetHealAmount(battlerAtk, gBattleScripting.savedDmg / GetBattlerHoldEffectParam(battlerAtk)); + BattleScriptCall(BattleScript_ItemHealHP_Ret); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryLifeOrb(u32 battlerAtk) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerAlive(battlerAtk) + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && (IsAnyTargetTurnDamaged(battlerAtk) || gBattleScripting.savedDmg > 0) + && !IsAbilityAndRecord(battlerAtk, GetBattlerAbility(battlerAtk), ABILITY_MAGIC_GUARD) + && GetMoveEffect(gCurrentMove) != EFFECT_PAIN_SPLIT + && !IsFutureSightAttackerInParty(battlerAtk, gBattlerTarget, gCurrentMove)) + { + SetPassiveDamageAmount(battlerAtk, GetNonDynamaxMaxHP(battlerAtk) / 10); + BattleScriptCall(BattleScript_ItemHurtRet); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryStickyBarbOnTargetHit(u32 battlerDef, u32 battlerAtk, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (IsBattlerTurnDamaged(battlerDef) + && !CanBattlerAvoidContactEffects(battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), GetBattlerHoldEffect(battlerAtk), gCurrentMove) + && !DoesSubstituteBlockMove(battlerAtk, battlerDef, gCurrentMove) + && IsBattlerAlive(battlerAtk) + && CanStealItem(battlerAtk, battlerDef, item) + && gBattleMons[battlerAtk].item == ITEM_NONE) + { + // No sticky hold checks. + gEffectBattler = battlerDef; + StealTargetItem(battlerAtk, battlerDef); // Attacker takes target's barb + BattleScriptCall(BattleScript_StickyBarbTransfer); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryStickyBarbOnEndTurn(u32 battler, u32 item) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) + { + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, item); + BattleScriptExecute(BattleScript_ItemHurtEnd2); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryToxicOrb(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (CanBePoisoned(battler, battler, ability, ability)) // Can corrosion trigger toxic orb on itself? + { + gBattleMons[battler].status1 = STATUS1_TOXIC_POISON; + BattleScriptExecute(BattleScript_ToxicOrb); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryFlameOrb(u32 battler) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (CanBeBurned(battler, battler, ability)) + { + gBattleMons[battler].status1 = STATUS1_BURN; + BattleScriptExecute(BattleScript_FlameOrb); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryLeftovers(u32 battler, enum HoldEffect holdEffect) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].hp < gBattleMons[battler].maxHP + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battler].volatiles.healBlock)) + { + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 16); + RecordItemEffectBattle(battler, holdEffect); + BattleScriptExecute(BattleScript_ItemHealHP_End2); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryBlackSludgeDamage(u32 battler, enum HoldEffect holdEffect) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) + { + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); + RecordItemEffectBattle(battler, holdEffect); + BattleScriptExecute(BattleScript_ItemHurtEnd2); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureParalysis(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + { + gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PARALYSIS; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCurePoison(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) + { + gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_POISON; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureBurn(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_BURN) + { + gBattleMons[battler].status1 &= ~STATUS1_BURN; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_BURN; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureFreezeOrFrostbite(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_FREEZE) + { + gBattleMons[battler].status1 &= ~STATUS1_FREEZE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_FREEEZE; + effect = ITEM_STATUS_CHANGE; + } + else if (gBattleMons[battler].status1 & STATUS1_FROSTBITE) + { + gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_FROSTBITE; + effect = ITEM_STATUS_CHANGE; + } + + if (effect == ITEM_STATUS_CHANGE) + { + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + } + + return effect; +} + +static enum ItemEffect TryCureSleep(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + { + gBattleMons[battler].status1 &= ~STATUS1_SLEEP; + gBattleMons[battler].volatiles.nightmare = FALSE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_SLEEP; + TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TryCureConfusion(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (gBattleMons[battler].volatiles.confusionTurns > 0) + { + RemoveConfusionStatus(battler); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); + else + BattleScriptCall(BattleScript_BerryCureConfusionRet); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect TryCureAnyStatus(u32 battler, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + u32 string = 0; + + if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0)) + { + if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_SLEEP) + { + gBattleMons[battler].volatiles.nightmare = FALSE; + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_BURN) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + string++; + } + if (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + string++; + } + if (gBattleMons[battler].volatiles.confusionTurns > 0) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); + string++; + } + if (string <= 1) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PROBLEM; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_NORMALIZED_STATUS; + gBattleMons[battler].status1 = 0; + RemoveConfusionStatus(battler); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryCureStatusEnd2); + else + BattleScriptCall(BattleScript_BerryCureStatusRet); + effect = ITEM_STATUS_CHANGE; + } + + return effect; +} + +enum HealAmount +{ + FIXED_HEAL_AMOUNT, + PERCENT_HEAL_AMOUNT, +}; + +static u32 ItemHealHp(u32 battler, u32 itemId, enum HealAmount percentHeal, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (!(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battler].volatiles.healBlock) + && HasEnoughHpToEatBerry(battler, ability, 2, itemId)) + { + s32 healAmount = 0; + if (percentHeal == PERCENT_HEAL_AMOUNT) + healAmount = (GetNonDynamaxMaxHP(battler) * GetItemHoldEffectParam(itemId) / 100); + else + healAmount = GetItemHoldEffectParam(itemId); + + if (ability == ABILITY_RIPEN && GetItemPocket(itemId) == POCKET_BERRIES) + healAmount *= 2; + + SetHealAmount(battler, healAmount); + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); + else + BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); + + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static u32 ItemRestorePp(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + struct Pokemon *mon = GetBattlerMon(battler); + u32 i, changedPP = 0; + enum Ability ability = GetBattlerAbility(battler); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = GetMonData(mon, MON_DATA_MOVE1 + i); + u32 currentPP = GetMonData(mon, MON_DATA_PP1 + i); + u32 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES); + u32 maxPP = CalculatePPWithBonus(move, ppBonuses, i); + if (move && (currentPP == 0 || (gBattleScripting.overrideBerryRequirements && currentPP != maxPP))) + { + u32 ppRestored = GetItemHoldEffectParam(itemId); + + if (ability == ABILITY_RIPEN) + { + ppRestored *= 2; + gBattlerAbility = battler; + } + if (currentPP + ppRestored > maxPP) + changedPP = maxPP; + else + changedPP = currentPP + ppRestored; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, move); + + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryPPHealEnd2); + else + BattleScriptCall(BattleScript_BerryPPHealRet); + + gBattleScripting.battler = battler; + BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); + MarkBattlerForControllerExec(battler); + if (MOVE_IS_PERMANENT(battler, i)) + gBattleMons[battler].pp[i] = changedPP; + effect = ITEM_PP_CHANGE; + } + } + return effect; +} + +static enum ItemEffect HealConfuseBerry(u32 battler, u32 itemId, u32 flavorId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + u32 hpFraction = B_CONFUSE_BERRIES_HEAL >= GEN_7 ? 4 : 2; + u32 ability = GetBattlerAbility(battler); + + if (HasEnoughHpToEatBerry(battler, ability, hpFraction, itemId) + && !(B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battler].volatiles.healBlock)) + { + s32 healAmount = GetNonDynamaxMaxHP(battler) / GetItemHoldEffectParam(itemId); + if (ability == ABILITY_RIPEN) + healAmount *= 2; + SetHealAmount(battler, healAmount); + if (timing == IsOnSwitchInFirstTurnActivation) + { + if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); + else + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); + } + else + { + if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) + BattleScriptCall(BattleScript_BerryConfuseHealRet); + else + BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); + } + PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId); + effect = ITEM_HP_CHANGE; + } + + return effect; +} + +static enum ItemEffect StatRaiseBerry(u32 battler, u32 itemId, enum Stat statId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Ability ability = GetBattlerAbility(battler); + + if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ability) + && HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId)) + { + gEffectBattler = gBattleScripting.battler = battler; + SET_STATCHANGER(statId, ability == ABILITY_RIPEN ? 2 : 1, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; + gBattleScripting.animArg2 = 0; + + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect CriticalHitRatioUp(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (!gBattleMons[battler].volatiles.focusEnergy + && !gBattleMons[battler].volatiles.dragonCheer + && HasEnoughHpToEatBerry(battler, GetBattlerAbility(battler), GetItemHoldEffectParam(itemId), itemId)) + { + gBattleMons[battler].volatiles.focusEnergy = TRUE; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); + else + BattleScriptCall(BattleScript_BerryFocusEnergyRet); + effect = ITEM_EFFECT_OTHER; + } + + return effect; +} + +static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + enum Stat stat; + enum Ability ability = GetBattlerAbility(battler); + + for (stat = STAT_ATK; stat < NUM_STATS; stat++) + { + if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_LESS_THAN, ability)) + break; + } + + if (stat == NUM_STATS) + return effect; + + if (HasEnoughHpToEatBerry(battler, ability, GetItemHoldEffectParam(itemId), itemId)) + { + u32 savedAttacker = gBattlerAttacker; + // MoodyCantRaiseStat requires that the battler is set to gBattlerAttacker + gBattlerAttacker = gBattleScripting.battler = battler; + gBattleScripting.statChanger = 0; + if (ability != ABILITY_CONTRARY) + stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantRaiseStat); + else + stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantLowerStat); + gBattlerAttacker = savedAttacker; + + PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); + SET_STATCHANGER(stat, ability == ABILITY_RIPEN ? 4 : 2, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS2 + stat; + gBattleScripting.animArg2 = 0; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); + else + BattleScriptCall(BattleScript_ConsumableStatRaiseRet); + effect = ITEM_STATS_CHANGE; + } + + return effect; +} + +static enum ItemEffect TrySetMicleBerry(u32 battler, u32 itemId, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + + if (HasEnoughHpToEatBerry(battler, GetBattlerAbility(battler), 4, itemId)) + { + gBattleStruct->battlerState[battler].usedMicleBerry = TRUE; + if (timing == IsOnSwitchInFirstTurnActivation) + BattleScriptExecute(BattleScript_MicleBerryActivateEnd2); + else + BattleScriptCall(BattleScript_MicleBerryActivateRet); + effect = ITEM_EFFECT_OTHER; + } + return effect; +} + +enum ItemEffect ItemBattleEffects(u32 itemBattler, u32 battler, enum HoldEffect holdEffect, ActivationTiming timing) +{ + enum ItemEffect effect = ITEM_NO_EFFECT; + u32 item; + + if (timing == IsOnBerryActivation || timing == IsOnFlingActivation) + item = gLastUsedItem; + else + item = gBattleMons[itemBattler].item; + + if (holdEffect == HOLD_EFFECT_NONE + || !timing(holdEffect) + || IsUnnerveBlocked(itemBattler, item)) + return effect; + + if (!IsBattlerAlive(itemBattler) + && holdEffect != HOLD_EFFECT_ROWAP_BERRY // Hacky workaround for them right now + && holdEffect != HOLD_EFFECT_JABOCA_BERRY + && holdEffect != HOLD_EFFECT_ROCKY_HELMET) + return effect; + + switch (holdEffect) + { + case HOLD_EFFECT_DOUBLE_PRIZE: + effect = TryDoublePrize(itemBattler); + break; + case HOLD_EFFECT_ROOM_SERVICE: + effect = TryRoomService(itemBattler, timing); + break; + case HOLD_EFFECT_TERRAIN_SEED: + effect = TryTerrainSeeds(itemBattler, item, timing); + break; + case HOLD_EFFECT_BERSERK_GENE: + effect = TryBerserkGene(itemBattler, timing); + break; + case HOLD_EFFECT_BOOSTER_ENERGY: + effect = TryBoosterEnergy(itemBattler, GetBattlerAbility(itemBattler), timing); + break; + case HOLD_EFFECT_WHITE_HERB: + effect = RestoreWhiteHerbStats(itemBattler, timing); + break; + case HOLD_EFFECT_MIRROR_HERB: + effect = TryConsumeMirrorHerb(itemBattler, timing); + break; + case HOLD_EFFECT_FLINCH: // Kings Rock + effect = TryKingsRock(itemBattler, battler, item); + break; + case HOLD_EFFECT_AIR_BALLOON: + effect = TryAirBalloon(itemBattler, timing); + break; + case HOLD_EFFECT_ROCKY_HELMET: + effect = TryRockyHelmet(itemBattler, battler, item); + break; + case HOLD_EFFECT_WEAKNESS_POLICY: + effect = TryWeaknessPolicy(itemBattler); + break; + case HOLD_EFFECT_SNOWBALL: + effect = TrySnowball(itemBattler); + break; + case HOLD_EFFECT_LUMINOUS_MOSS: + effect = TryLuminousMoss(itemBattler); + break; + case HOLD_EFFECT_CELL_BATTERY: + effect = TryCellBattery(itemBattler); + break; + case HOLD_EFFECT_ABSORB_BULB: + effect = TryAbsorbBulb(itemBattler); + break; + case HOLD_EFFECT_JABOCA_BERRY: + effect = TryJabocaBerry(itemBattler, battler, item); + break; + case HOLD_EFFECT_ROWAP_BERRY: + effect = TryRowapBerry(itemBattler, battler, item); + break; + case HOLD_EFFECT_ENIGMA_BERRY: // consume and heal if hit by super effective move + effect = TrySetEnigmaBerry(itemBattler, battler); + break; + case HOLD_EFFECT_BLUNDER_POLICY: + effect = TryBlunderPolicy(itemBattler); + break; + case HOLD_EFFECT_MENTAL_HERB: + effect = TryMentalHerb(itemBattler); + break; + case HOLD_EFFECT_THROAT_SPRAY: + effect = TryThroatSpray(itemBattler); + break; + case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move + effect = DamagedStatBoostBerryEffect(itemBattler, battler, STAT_DEF, DAMAGE_CATEGORY_PHYSICAL); + break; + case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move + effect = DamagedStatBoostBerryEffect(itemBattler, battler, STAT_SPDEF, DAMAGE_CATEGORY_SPECIAL); + break; + case HOLD_EFFECT_SHELL_BELL: + effect = TryShellBell(itemBattler); + break; + case HOLD_EFFECT_LIFE_ORB: + effect = TryLifeOrb(itemBattler); + break; + case HOLD_EFFECT_STICKY_BARB: + if (timing == IsOnTargetHitActivation) + effect = TryStickyBarbOnTargetHit(itemBattler, battler, item); + else + effect = TryStickyBarbOnEndTurn(itemBattler, item); + break; + case HOLD_EFFECT_TOXIC_ORB: + effect = TryToxicOrb(itemBattler); + break; + case HOLD_EFFECT_FLAME_ORB: + effect = TryFlameOrb(itemBattler); + break; + case HOLD_EFFECT_LEFTOVERS: + effect = TryLeftovers(itemBattler, holdEffect); + break; + case HOLD_EFFECT_BLACK_SLUDGE: + if (IS_BATTLER_OF_TYPE(itemBattler, TYPE_POISON)) + effect = TryLeftovers(itemBattler, holdEffect); + else + effect = TryBlackSludgeDamage(itemBattler, holdEffect); + break; + case HOLD_EFFECT_CURE_PAR: // Cheri Berry + effect = TryCureParalysis(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_PSN: // Pecha Berry + effect = TryCurePoison(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_BRN: // Rawst Berry + effect = TryCureBurn(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_FRZ: // Aspear Berry + effect = TryCureFreezeOrFrostbite(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_SLP: // Chesto Berry + effect = TryCureSleep(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_CONFUSION: // Persim Berry + effect = TryCureConfusion(itemBattler, timing); + break; + case HOLD_EFFECT_CURE_STATUS: // Lum Berry + effect = TryCureAnyStatus(itemBattler, timing); + break; + case HOLD_EFFECT_RESTORE_HP: // Oran / Sitrus Berry / Berry Juice + effect = ItemHealHp(itemBattler, item, FIXED_HEAL_AMOUNT, timing); + break; + case HOLD_EFFECT_RESTORE_PCT_HP: // Sitrus Berry + effect = ItemHealHp(itemBattler, item, PERCENT_HEAL_AMOUNT, timing); + break; + case HOLD_EFFECT_RESTORE_PP: // Leppa Berry + effect = ItemRestorePp(itemBattler, item, timing); + break; + case HOLD_EFFECT_CONFUSE_SPICY: // Figy Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_SPICY, timing); + break; + case HOLD_EFFECT_CONFUSE_DRY: // Wiki Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_DRY, timing); + break; + case HOLD_EFFECT_CONFUSE_SWEET: // Mago Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_SWEET, timing); + break; + case HOLD_EFFECT_CONFUSE_BITTER: // Aguav Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_BITTER, timing); + break; + case HOLD_EFFECT_CONFUSE_SOUR: // Iapapa Berry + effect = HealConfuseBerry(itemBattler, item, FLAVOR_SOUR, timing); + break; + case HOLD_EFFECT_ATTACK_UP: // Liechi Berry + effect = StatRaiseBerry(itemBattler, item, STAT_ATK, timing); + break; + case HOLD_EFFECT_DEFENSE_UP: // Ganlon Berry + effect = StatRaiseBerry(itemBattler, item, STAT_DEF, timing); + break; + case HOLD_EFFECT_SPEED_UP: // Salac Berry + effect = StatRaiseBerry(itemBattler, item, STAT_SPEED, timing); + break; + case HOLD_EFFECT_SP_ATTACK_UP: // Petaya Berry + effect = StatRaiseBerry(itemBattler, item, STAT_SPATK, timing); + break; + case HOLD_EFFECT_SP_DEFENSE_UP: // Apicot Berry + effect = StatRaiseBerry(itemBattler, item, STAT_SPDEF, timing); + break; + case HOLD_EFFECT_CRITICAL_UP: // Lansat Berry + effect = CriticalHitRatioUp(itemBattler, item, timing); + break; + case HOLD_EFFECT_RANDOM_STAT_UP: // Starf Berry + effect = RandomStatRaiseBerry(itemBattler, item, timing); + break; + case HOLD_EFFECT_MICLE_BERRY: + effect = TrySetMicleBerry(itemBattler, item, timing); + break; + default: + break; + } + + if (effect == ITEM_STATUS_CHANGE) + { + BtlController_EmitSetMonData(itemBattler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[itemBattler].status1); + MarkBattlerForControllerExec(itemBattler); + } + + if (effect) + { + gLastUsedItem = item; + gBattleScripting.battler = gPotentialItemEffectBattler = itemBattler; + if ((item >= FIRST_BERRY_INDEX && item <= LAST_BERRY_INDEX)) + GetBattlerPartyState(itemBattler)->ateBerry = TRUE; + } + + return effect; +} diff --git a/src/battle_interface.c b/src/battle_interface.c index 29a2cf0436..f87a889641 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -2604,7 +2604,7 @@ static void PrintBattlerOnAbilityPopUp(u8 battler, u8 spriteId1, u8 spriteId2) TRUE, gSprites[spriteId1].sBattlerId); } -static void PrintAbilityOnAbilityPopUp(u32 ability, u8 spriteId1, u8 spriteId2) +static void PrintAbilityOnAbilityPopUp(enum Ability ability, u8 spriteId1, u8 spriteId2) { PrintOnAbilityPopUp(COMPOUND_STRING(" "), (void *)(OBJ_VRAM0) + TILE_OFFSET_4BPP(gSprites[spriteId1].oam.tileNum) + TILE_OFFSET_4BPP(8), @@ -2632,16 +2632,13 @@ static inline bool32 IsAnyAbilityPopUpActive(void) return activeAbilityPopUps; } -void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle) +void CreateAbilityPopUp(u8 battler, enum Ability ability, bool32 isDoubleBattle) { u8 *spriteIds; u32 xSlide, tileTag, battlerPosition = GetBattlerPosition(battler); struct SpriteTemplate template; const s16 (*coords)[2]; - if (!B_ABILITY_POP_UP) - return; - if (gBattleScripting.abilityPopupOverwrite) ability = gBattleScripting.abilityPopupOverwrite; @@ -2700,7 +2697,7 @@ void CreateAbilityPopUp(u8 battler, u32 ability, bool32 isDoubleBattle) void UpdateAbilityPopup(u8 battler) { u8 *spriteIds = gBattleStruct->abilityPopUpSpriteIds[battler]; - u16 ability = (gBattleScripting.abilityPopupOverwrite) ? gBattleScripting.abilityPopupOverwrite + enum Ability ability = (gBattleScripting.abilityPopupOverwrite) ? gBattleScripting.abilityPopupOverwrite : gBattleMons[battler].ability; PrintAbilityOnAbilityPopUp(ability, spriteIds[0], spriteIds[1]); } diff --git a/src/battle_intro.c b/src/battle_intro.c index 5239a81575..ebc737dac1 100644 --- a/src/battle_intro.c +++ b/src/battle_intro.c @@ -125,6 +125,9 @@ void HandleIntroSlide(u8 environment) } else { + if (environment >= NELEMS(sBattleIntroSlideFuncs) + || sBattleIntroSlideFuncs[environment] == NULL) + environment = BATTLE_ENVIRONMENT_PLAIN; taskId = CreateTask(sBattleIntroSlideFuncs[environment], 0); } diff --git a/src/battle_main.c b/src/battle_main.c index 83c003150c..a0d578bf33 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -6,6 +6,7 @@ #include "battle_arena.h" #include "battle_controllers.h" #include "battle_end_turn.h" +#include "battle_hold_effects.h" #include "battle_interface.h" #include "battle_main.h" #include "battle_message.h" @@ -13,7 +14,6 @@ #include "battle_scripts.h" #include "battle_setup.h" #include "battle_tower.h" -#include "battle_util.h" #include "battle_z_move.h" #include "battle_gimmick.h" #include "berry.h" @@ -53,6 +53,7 @@ #include "string_util.h" #include "strings.h" #include "task.h" +#include "test/battle.h" #include "test_runner.h" #include "text.h" #include "trainer_pools.h" @@ -66,7 +67,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_string_ids.h" #include "constants/battle_partner.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/party_menu.h" @@ -76,6 +76,7 @@ #include "constants/trainers.h" #include "constants/weather.h" #include "cable_club.h" +#include "test/test_runner_battle.h" extern const struct BgTemplate gBattleBgTemplates[]; extern const struct WindowTemplate *const gBattleWindowTemplates[]; @@ -112,7 +113,7 @@ static void SetActionsAndBattlersTurnOrder(void); static void UpdateBattlerPartyOrdersOnSwitch(u32 battler); static bool8 AllAtActionConfirmed(void); static void TryChangeTurnOrder(void); -static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickClawRandom, u32 *quickDrawRandom); +static void TryChangingTurnOrderEffects(struct BattleContext *ctx, u32 *quickClawRandom, u32 *quickDrawRandom); static void CheckChangingTurnOrderEffects(void); static void FreeResetData_ReturnToOvOrDoEvolutions(void); static void ReturnFromBattleToOverworld(void); @@ -167,7 +168,7 @@ EWRAM_DATA u16 gChosenMove = 0; EWRAM_DATA u16 gCalledMove = 0; EWRAM_DATA s32 gBideDmg[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA u16 gLastUsedItem = 0; -EWRAM_DATA u16 gLastUsedAbility = 0; +EWRAM_DATA enum Ability gLastUsedAbility = 0; EWRAM_DATA u8 gBattlerAttacker = 0; EWRAM_DATA u8 gBattlerTarget = 0; EWRAM_DATA u8 gBattlerFainted = 0; @@ -520,6 +521,8 @@ static void CB2_InitBattleInternal(void) } if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) gBattleEnvironment = BATTLE_ENVIRONMENT_BUILDING; + if (TestRunner_Battle_GetForcedEnvironment()) + gBattleEnvironment = TestRunner_Battle_GetForcedEnvironment() - 1; if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER @@ -547,9 +550,9 @@ static void CB2_InitBattleInternal(void) SetVBlankCallback(VBlankCB_Battle); SetUpBattleVarsAndBirchZigzagoon(); - if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) - SetMainCallback2(CB2_HandleStartMultiPartnerBattle); - else if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + if ((IsMultibattleTest() && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER) + || (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)) SetMainCallback2(CB2_HandleStartMultiPartnerBattle); else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) SetMainCallback2(CB2_HandleStartMultiBattle); @@ -1984,7 +1987,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer } if (partyData[monIndex].isShiny) { - u32 data = TRUE; + bool32 data = TRUE; SetMonData(&party[i], MON_DATA_IS_SHINY, &data); } if (partyData[monIndex].dynamaxLevel > 0) @@ -2002,7 +2005,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer if (partyData[monIndex].teraType > 0) { gBattleStruct->opponentMonCanTera |= 1 << i; - u32 data = partyData[monIndex].teraType; + enum Type data = partyData[monIndex].teraType; SetMonData(&party[i], MON_DATA_TERA_TYPE, &data); } CalculateMonStats(&party[i]); @@ -2981,7 +2984,7 @@ void BeginBattleIntro(void) { BattleStartClearSetData(); gBattleCommunication[1] = 0; - gBattleStruct->introState = 0; + gBattleStruct->eventState.battleIntro = 0; gBattleMainFunc = DoBattleIntro; } @@ -3015,7 +3018,7 @@ static void BattleStartClearSetData(void) s32 i; TurnValuesCleanUp(FALSE); - SpecialStatusesClear(); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); memset(&gDisableStructs, 0, sizeof(gDisableStructs)); memset(&gFieldTimers, 0, sizeof(gFieldTimers)); @@ -3105,13 +3108,12 @@ static void BattleStartClearSetData(void) { gSideTimers[i].stickyWebBattlerId = 0xFF; } - gBattleStruct->appearedInBattle = 0; gBattleStruct->beatUpSlot = 0; for (i = 0; i < PARTY_SIZE; i++) { - gBattleStruct->usedHeldItems[i][B_SIDE_PLAYER] = 0; - gBattleStruct->usedHeldItems[i][B_SIDE_OPPONENT] = 0; + gBattleStruct->partyState[B_SIDE_PLAYER][i].usedHeldItem = ITEM_NONE; + gBattleStruct->partyState[B_SIDE_OPPONENT][i].usedHeldItem = ITEM_NONE; gBattleStruct->itemLost[B_SIDE_PLAYER][i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); gBattleStruct->itemLost[B_SIDE_OPPONENT][i].originalItem = GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM); gPartyCriticalHits[i] = 0; @@ -3187,9 +3189,9 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) { if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler)) gBattleMons[i].volatiles.infatuation = 0; - if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler) + if (gBattleMons[i].volatiles.wrapped && gBattleMons[i].volatiles.wrappedBy == battler) gBattleMons[i].volatiles.wrapped = FALSE; - if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler) + if (gBattleMons[i].volatiles.syrupBomb && gBattleMons[i].volatiles.stickySyrupedBy == battler) gBattleMons[i].volatiles.syrupBomb = FALSE; if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler) gDisableStructs[i].octolock = FALSE; @@ -3238,6 +3240,7 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) gBattleStruct->battlerState[battler].stompingTantrumTimer = 0; gBattleStruct->palaceFlags &= ~(1u << battler); gBattleStruct->battlerState[battler].canPickupItem = FALSE; + gBattleStruct->battlerState[battler].wasAboveHalfHp = gBattleMons[battler].hp > gBattleMons[battler].maxHP / 2; gBattleStruct->hazardsCounter = 0; gDisableStructs[battler].hazardsDone = FALSE; gSpecialStatuses[battler].switchInItemDone = FALSE; @@ -3260,7 +3263,7 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) } gBattleStruct->choicedMove[battler] = MOVE_NONE; - gBattleStruct->arenaTurnCounter = 0xFF; + gBattleStruct->eventState.arenaTurn = 0xFF; // Restore struct member so replacement does not miss timing gSpecialStatuses[battler].switchInAbilityDone = FALSE; @@ -3312,9 +3315,9 @@ const u8* FaintClearSetData(u32 battler) gBattleMons[i].volatiles.escapePrevention = FALSE; if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler)) gBattleMons[i].volatiles.infatuation = 0; - if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler) + if (gBattleMons[i].volatiles.wrapped && gBattleMons[i].volatiles.wrappedBy == battler) gBattleMons[i].volatiles.wrapped = FALSE; - if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler) + if (gBattleMons[i].volatiles.syrupBomb && gBattleMons[i].volatiles.stickySyrupedBy == battler) gBattleMons[i].volatiles.syrupBomb = FALSE; if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler) gDisableStructs[i].octolock = FALSE; @@ -3338,7 +3341,6 @@ const u8* FaintClearSetData(u32 battler) gProtectStructs[battler].confusionSelfDmg = FALSE; gProtectStructs[battler].chargingTurn = FALSE; gProtectStructs[battler].fleeType = 0; - gProtectStructs[battler].notFirstStrike = FALSE; gProtectStructs[battler].statRaised = FALSE; gProtectStructs[battler].pranksterElevated = FALSE; @@ -3422,9 +3424,10 @@ const u8* FaintClearSetData(u32 battler) // If the released mon can be confused, do so. // Don't use CanBeConfused here, since it can cause issues in edge cases. - if (!(GetBattlerAbility(otherSkyDropper) == ABILITY_OWN_TEMPO + enum Ability ability = GetBattlerAbility(otherSkyDropper); + if (!(ability == ABILITY_OWN_TEMPO || gBattleMons[otherSkyDropper].volatiles.confusionTurns - || IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN))) + || IsBattlerTerrainAffected(otherSkyDropper, ability, GetBattlerHoldEffect(otherSkyDropper), STATUS_FIELD_MISTY_TERRAIN))) { gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2; gBattlerAttacker = otherSkyDropper; @@ -3442,21 +3445,21 @@ static void DoBattleIntro(void) s32 i; u32 battler; - switch ((enum BattleIntroStates)gBattleStruct->introState) + switch ((enum BattleIntroStates)gBattleStruct->eventState.battleIntro) { case BATTLE_INTRO_STATE_GET_MON_DATA: battler = gBattleCommunication[1]; BtlController_EmitGetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_ALL_BATTLE, 0); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_LOOP_BATTLER_DATA: if (!gBattleControllerExecFlags) { if (++gBattleCommunication[1] == gBattlersCount) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; else - gBattleStruct->introState = BATTLE_INTRO_STATE_GET_MON_DATA; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_GET_MON_DATA; } break; case BATTLE_INTRO_STATE_PREPARE_BG_SLIDE: @@ -3467,12 +3470,12 @@ static void DoBattleIntro(void) MarkBattlerForControllerExec(battler); gBattleCommunication[0] = 0; gBattleCommunication[1] = 0; - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_WAIT_FOR_BG_SLIDE: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_DRAW_SPRITES: for (battler = 0; battler < gBattlersCount; battler++) @@ -3553,9 +3556,9 @@ static void DoBattleIntro(void) } if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; else // Skip party summary since it is a wild battle. - gBattleStruct->introState = BATTLE_INTRO_STATE_INTRO_TEXT; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_INTRO_TEXT; break; case BATTLE_INTRO_STATE_DRAW_PARTY_SUMMARY: if (!gBattleControllerExecFlags) @@ -3600,18 +3603,18 @@ static void DoBattleIntro(void) BtlController_EmitDrawPartyStatusSummary(battler, B_COMM_TO_CONTROLLER, hpStatus, PARTY_SUMM_SKIP_DRAW_DELAY); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_WAIT_FOR_PARTY_SUMMARY: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_INTRO_TEXT: if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) { PrepareStringBattle(STRINGID_INTROMSG, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_WAIT_FOR_INTRO_TEXT: @@ -3619,14 +3622,14 @@ static void DoBattleIntro(void) { if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } else { if (B_FAST_INTRO_PKMN_TEXT == TRUE) - gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; else - gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM; + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM; } } break; @@ -3635,11 +3638,11 @@ static void DoBattleIntro(void) PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)); else PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_SEND_OUT_TEXT: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_TRAINER_1_SEND_OUT_ANIM: if (gBattleTypeFlags & BATTLE_TYPE_RECORDED_LINK && !(gBattleTypeFlags & BATTLE_TYPE_RECORDED_IS_MASTER)) @@ -3649,7 +3652,7 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_TRAINER_2_SEND_OUT_ANIM: if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT) @@ -3664,17 +3667,17 @@ static void DoBattleIntro(void) } if (B_FAST_INTRO_PKMN_TEXT == TRUE && !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_LINK))) - gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; // Print at the same time as trainer sends out second mon. + gBattleStruct->eventState.battleIntro = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; // Print at the same time as trainer sends out second mon. else - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM: if (!gBattleControllerExecFlags) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT: if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_PRINT_PLAYER_SEND_OUT_TEXT: if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI)) @@ -3695,7 +3698,7 @@ static void DoBattleIntro(void) PrepareStringBattle(STRINGID_INTROSENDOUT, battler); } - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_WAIT_FOR_PLAYER_SEND_OUT_TEXT: if (!(gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleControllerExecFlags)) @@ -3706,7 +3709,7 @@ static void DoBattleIntro(void) battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); if (!IsBattlerMarkedForControllerExec(battler)) - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; } break; case BATTLE_INTRO_STATE_PRINT_PLAYER_1_SEND_OUT_TEXT: @@ -3717,7 +3720,7 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_PRINT_PLAYER_2_SEND_OUT_TEXT: if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) @@ -3730,14 +3733,13 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); } - gBattleStruct->introState++; + gBattleStruct->eventState.battleIntro++; break; case BATTLE_INTRO_STATE_SET_DEX_AND_BATTLE_VARS: if (!gBattleControllerExecFlags) { - gBattleStruct->eventsBeforeFirstTurnState = 0; + gBattleStruct->eventState.beforeFristTurn = 0; gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->overworldWeatherDone = FALSE; Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield. // mark all battlers as sent out @@ -3774,7 +3776,7 @@ static void TryDoEventsBeforeFirstTurn(void) if (gBattleControllerExecFlags) return; - switch ((enum FirstTurnEventsStates)gBattleStruct->eventsBeforeFirstTurnState) + switch (gBattleStruct->eventState.beforeFristTurn) { case FIRST_TURN_EVENTS_START: // Set invalid mons as absent(for example when starting a double battle with only one pokemon). @@ -3806,45 +3808,40 @@ static void TryDoEventsBeforeFirstTurn(void) gBattleStruct->speedTieBreaks = RandomUniform(RNG_SPEED_TIE, 0, Factorial(MAX_BATTLERS_COUNT) - 1); gBattleTurnCounter = 0; + struct BattleContext ctx = {0}; for (i = 0; i < gBattlersCount; i++) + { gBattlerByTurnOrder[i] = i; + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = 0; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - if (GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) == -1) + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; + + if (GetWhichBattlerFaster(&ctx, TRUE) == -1) SwapTurnOrder(i, j); } } - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_OVERWORLD_WEATHER: - if (!gBattleStruct->overworldWeatherDone - && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_WEATHER, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0) - { - gBattleStruct->overworldWeatherDone = TRUE; + gBattleStruct->eventState.beforeFristTurn++; + if (TryFieldEffects(FIELD_EFFECT_OVERWORLD_WEATHER)) return; - } - gBattleStruct->eventsBeforeFirstTurnState++; break; case FIRST_TURN_EVENTS_TERRAIN: - if (!gBattleStruct->terrainDone - && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_TERRAIN, 0, 0, ABILITYEFFECT_SWITCH_IN_TERRAIN, 0) != 0) - { - gBattleStruct->terrainDone = TRUE; + gBattleStruct->eventState.beforeFristTurn++; + if (TryFieldEffects(FIELD_EFFECT_OVERWORLD_TERRAIN)) return; - } - gBattleStruct->eventsBeforeFirstTurnState++; break; case FIRST_TURN_EVENTS_STARTING_STATUS: - if (!gBattleStruct->startingStatusDone - && gBattleStruct->startingStatus - && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_STATUSES, 0, 0, ABILITYEFFECT_SWITCH_IN_STATUSES, 0) != 0) - { - gBattleStruct->startingStatusDone = TRUE; + gBattleStruct->eventState.beforeFristTurn++; + if (TryFieldEffects(FIELD_EFFECT_TRAINER_STATUSES)) return; - } - gBattleStruct->eventsBeforeFirstTurnState++; break; case FIRST_TURN_EVENTS_TOTEM_BOOST: for (i = 0; i < gBattlersCount; i++) @@ -3857,57 +3854,78 @@ static void TryDoEventsBeforeFirstTurn(void) } } memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); // erase all totem boosts for Mirror Herb and Opportunist - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_NEUTRALIZING_GAS: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest { i = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; - if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, i, 0, 0, 0) != 0) + if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN, i, 0, 0, 0) != 0) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest { - i = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; - if (TryPrimalReversion(i)) + if (TryPrimalReversion(battler)) return; - if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0) != 0) + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battler, 0, 0, 0)) return; - if (TryClearIllusion(i, ABILITYEFFECT_ON_SWITCHIN)) + if (TryClearIllusion(battler, ABILITYEFFECT_ON_SWITCHIN)) return; - if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES, i, 0, 0, 0) != 0) + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES, battler, 0, 0, 0) != 0) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; - break; - case FIRST_TURN_EVENTS_OPPORTUNIST_1: - if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0)) - return; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_ITEM_EFFECTS: while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest { - if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++])) + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnSwitchInFirstTurnActivation)) return; } gBattleStruct->switchInBattlerCounter = 0; - gBattleStruct->eventsBeforeFirstTurnState++; + gBattleStruct->eventState.beforeFristTurn++; break; - case FIRST_TURN_EVENTS_OPPORTUNIST_2: - if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0)) - return; - gBattleStruct->eventsBeforeFirstTurnState++; + case FIRST_TURN_EVENTS_WHITE_HERB: + while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest + { + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsWhiteHerbFirstTurnActivation)) + return; + } + gBattleStruct->switchInBattlerCounter = 0; + gBattleStruct->eventState.beforeFristTurn++; + break; + case FIRST_TURN_EVENTS_OPPORTUNIST: + while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest + { + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST_FIRST_TURN, battler, GetBattlerAbility(battler), 0, 0)) + return; + } + gBattleStruct->switchInBattlerCounter = 0; + gBattleStruct->eventState.beforeFristTurn++; + break; + case FIRST_TURN_EVENTS_MIRROR_HERB: + while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest + { + u32 battler = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++]; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsMirrorHerbFirstTurnActivation)) + return; + } + gBattleStruct->switchInBattlerCounter = 0; + gBattleStruct->eventState.beforeFristTurn++; break; case FIRST_TURN_EVENTS_EJECT_PACK: - gBattleStruct->eventsBeforeFirstTurnState++; - if (TrySwitchInEjectPack(ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN)) + gBattleStruct->eventState.beforeFristTurn++; + if (TrySwitchInEjectPack(FIRST_TURN)) return; break; case FIRST_TURN_EVENTS_END: @@ -3918,7 +3936,7 @@ static void TryDoEventsBeforeFirstTurn(void) gChosenMoveByBattler[i] = MOVE_NONE; } TurnValuesCleanUp(FALSE); - SpecialStatusesClear(); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); AssignUsableGimmicks(); gBattleMainFunc = HandleTurnActionSelectionState; @@ -3927,19 +3945,11 @@ static void TryDoEventsBeforeFirstTurn(void) for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++) gBattleCommunication[i] = 0; - for (i = 0; i < gBattlersCount; i++) - { - gBattleMons[i].volatiles.flinched = FALSE; - // Record party slots of player's mons that appeared in battle - if (!BattlerHasAi(i)) - gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[i]; - } - - *(&gBattleStruct->eventBlockCounter) = 0; - *(&gBattleStruct->turnEffectsBattlerId) = 0; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler = 0; gBattleScripting.moveendState = 0; - gBattleStruct->faintedActionsState = 0; - gBattleStruct->endTurnEventsCounter = 0; + gBattleStruct->eventState.faintedAction = 0; + gBattleStruct->eventState.endTurn = 0; memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); SetShellSideArmCategory(); @@ -3953,7 +3963,7 @@ static void TryDoEventsBeforeFirstTurn(void) if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_BEFORE_FIRST_TURN))) BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2); - gBattleStruct->eventsBeforeFirstTurnState = 0; + gBattleStruct->eventState.beforeFristTurn = 0; break; } } @@ -3973,9 +3983,9 @@ static void HandleEndTurn_ContinueBattle(void) if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].volatiles.multipleTurns)) CancelMultiTurnMoves(i, SKY_DROP_IGNORE); } - gBattleStruct->eventBlockCounter = 0; - gBattleStruct->turnEffectsBattlerId = 0; - gBattleStruct->endTurnEventsCounter = 0; + gBattleStruct->eventState.endTurnBlock = 0; + gBattleStruct->eventState.endTurnBattler = 0; + gBattleStruct->eventState.endTurn = 0; } } @@ -3994,13 +4004,11 @@ void BattleTurnPassed(void) if (HandleFaintedMonActions()) return; - gBattleStruct->faintedActionsState = 0; + gBattleStruct->eventState.faintedAction = 0; TurnValuesCleanUp(FALSE); - gHitMarker &= ~HITMARKER_NO_ATTACKSTRING; gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE; gHitMarker &= ~HITMARKER_PLAYER_FAINTED; - gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE; gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; gBattleScripting.moveendState = 0; @@ -4018,7 +4026,7 @@ void BattleTurnPassed(void) if (gBattleResults.battleTurnCounter < 0xFF) { gBattleResults.battleTurnCounter++; - gBattleStruct->arenaTurnCounter++; + gBattleStruct->eventState.arenaTurn++; } for (i = 0; i < gBattlersCount; i++) @@ -4050,7 +4058,7 @@ void BattleTurnPassed(void) if (gBattleTypeFlags & BATTLE_TYPE_PALACE) BattleScriptExecute(BattleScript_PalacePrintFlavorText); - else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->arenaTurnCounter == 0) + else if (gBattleTypeFlags & BATTLE_TYPE_ARENA && gBattleStruct->eventState.arenaTurn == 0) BattleScriptExecute(BattleScript_ArenaTurnBeginning); else if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_LAST_LOW_HP))) BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2); @@ -4070,7 +4078,7 @@ void BattleTurnPassed(void) u8 IsRunningFromBattleImpossible(u32 battler) { - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; u32 i; if (FlagGet(B_FLAG_NO_RUNNING)) @@ -4262,7 +4270,7 @@ static void HandleTurnActionSelectionState(void) if (AreAllMovesUnusable(battler)) { gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3]; return; @@ -4273,7 +4281,12 @@ static void HandleTurnActionSelectionState(void) gBattleStruct->chosenMovePositions[battler] = gDisableStructs[battler].encoredMovePos; gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; if (gTestRunnerEnabled) - TestRunner_Battle_CheckChosenMove(battler, gDisableStructs[battler].encoredMove, gDisableStructs[battler].encoredMovePos); + { + UNUSED enum Gimmick gimmick = GIMMICK_NONE; + if (gBattleResources->bufferB[battler][2] & RET_GIMMICK) + gimmick = gBattleStruct->gimmick.usableGimmick[battler]; + TestRunner_Battle_CheckChosenMove(battler, gDisableStructs[battler].encoredMove, gDisableStructs[battler].encoredMovePos, gimmick); + } return; } else @@ -4301,12 +4314,12 @@ static void HandleTurnActionSelectionState(void) } break; case B_ACTION_USE_ITEM: - if (FlagGet(B_FLAG_NO_BAG_USE)) + if (ShouldBattleRestrictionsApply(battler) && !IsAllowedToUseBag()) { RecordedBattle_ClearBattlerAction(battler, 1); gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4322,7 +4335,7 @@ static void HandleTurnActionSelectionState(void) RecordedBattle_ClearBattlerAction(battler, 1); gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4335,7 +4348,7 @@ static void HandleTurnActionSelectionState(void) case B_ACTION_SWITCH: gBattleStruct->battlerPartyIndexes[battler] = gBattlerPartyIndexes[battler]; if (gBattleTypeFlags & BATTLE_TYPE_ARENA - || (!CanBattlerEscape(battler) && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SHED_SHELL)) + || (!CanBattlerEscape(battler) && GetBattlerHoldEffect(battler) != HOLD_EFFECT_SHED_SHELL)) { BtlController_EmitChoosePokemon(battler, B_COMM_TO_CONTROLLER, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, 0, gBattleStruct->battlerPartyOrders[battler]); } @@ -4360,7 +4373,7 @@ static void HandleTurnActionSelectionState(void) { gSelectionBattleScripts[battler] = BattleScript_PrintFullBox; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4421,7 +4434,7 @@ static void HandleTurnActionSelectionState(void) { gSelectionBattleScripts[battler] = BattleScript_AskIfWantsToForfeitMatch; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT_MAY_RUN; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4429,7 +4442,7 @@ static void HandleTurnActionSelectionState(void) { gSelectionBattleScripts[battler] = BattleScript_QuestionForfeitBattle; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT_MAY_RUN; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4446,7 +4459,7 @@ static void HandleTurnActionSelectionState(void) { gSelectionBattleScripts[battler] = BattleScript_PrintCantEscapeFromBattle; gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_BEFORE_ACTION_CHOSEN; return; } @@ -4488,7 +4501,7 @@ static void HandleTurnActionSelectionState(void) { RecordedBattle_ClearBattlerAction(battler, 1); gBattleCommunication[battler] = STATE_SELECTION_SCRIPT; - gBattleStruct->selectionScriptFinished[battler] = FALSE; + gBattleStruct->battlerState[battler].selectionScriptFinished = FALSE; gBattleResources->bufferB[battler][1] = B_ACTION_USE_MOVE; gBattleStruct->stateIdAfterSelScript[battler] = STATE_WAIT_ACTION_CHOSEN; return; @@ -4503,11 +4516,11 @@ static void HandleTurnActionSelectionState(void) // Get the chosen move position (and thus the chosen move) and target from the returned buffer. gBattleStruct->chosenMovePositions[battler] = gBattleResources->bufferB[battler][2] & ~RET_GIMMICK; - gChosenMoveByBattler[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; + gChosenMoveByBattler[battler] = GetChosenMoveFromPosition(battler); gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3]; if (IsBattleMoveStatus(gChosenMoveByBattler[battler]) && GetBattlerAbility(battler) == ABILITY_MYCELIUM_MIGHT) gProtectStructs[battler].myceliumMight = TRUE; - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_LAGGING_TAIL) + if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_LAGGING_TAIL) gProtectStructs[battler].laggingTail = TRUE; // Check to see if any gimmicks need to be prepared. @@ -4517,13 +4530,16 @@ static void HandleTurnActionSelectionState(void) // Max Move check if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX)) { - gBattleStruct->dynamax.baseMoves[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; + gBattleStruct->dynamax.baseMoves[battler] = GetChosenMoveFromPosition(battler); } gBattleCommunication[battler]++; if (gTestRunnerEnabled) { - TestRunner_Battle_CheckChosenMove(battler, gChosenMoveByBattler[battler], gBattleStruct->moveTarget[battler]); + UNUSED enum Gimmick gimmick = GIMMICK_NONE; + if (gBattleResources->bufferB[battler][2] & RET_GIMMICK) + gimmick = gBattleStruct->gimmick.usableGimmick[battler]; + TestRunner_Battle_CheckChosenMove(battler, gChosenMoveByBattler[battler], gBattleStruct->moveTarget[battler], gimmick); } } break; @@ -4619,7 +4635,7 @@ static void HandleTurnActionSelectionState(void) } break; case STATE_SELECTION_SCRIPT: - if (gBattleStruct->selectionScriptFinished[battler]) + if (gBattleStruct->battlerState[battler].selectionScriptFinished) { gBattleCommunication[battler] = gBattleStruct->stateIdAfterSelScript[battler]; } @@ -4641,7 +4657,7 @@ static void HandleTurnActionSelectionState(void) } break; case STATE_SELECTION_SCRIPT_MAY_RUN: - if (gBattleStruct->selectionScriptFinished[battler]) + if (gBattleStruct->battlerState[battler].selectionScriptFinished) { if (gBattleResources->bufferB[battler][1] == B_ACTION_NOTHING_FAINTED) { @@ -4742,7 +4758,7 @@ void SwapTurnOrder(u8 id1, u8 id2) } // For AI, so it doesn't 'cheat' by knowing player's ability -u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect holdEffect) +u32 GetBattlerTotalSpeedStat(u32 battler, enum Ability ability, enum HoldEffect holdEffect) { u32 speed = gBattleMons[battler].speed; @@ -4809,14 +4825,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect h return speed; } -u32 GetBattlerTotalSpeedStat(u32 battler) -{ - u32 ability = GetBattlerAbility(battler); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); - return GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); -} - -s32 GetChosenMovePriority(u32 battler, u32 ability) +s32 GetChosenMovePriority(u32 battler, enum Ability ability) { u16 move; @@ -4824,12 +4833,12 @@ s32 GetChosenMovePriority(u32 battler, u32 ability) if (gProtectStructs[battler].noValidMoves) move = MOVE_STRUGGLE; else - move = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; + move = GetChosenMoveFromPosition(battler); return GetBattleMovePriority(battler, ability, move); } -s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move) +s32 GetBattleMovePriority(u32 battler, enum Ability ability, u32 move) { s32 priority = 0; @@ -4857,7 +4866,7 @@ s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move) gProtectStructs[battler].pranksterElevated = 1; priority++; } - else if (GetMoveEffect(move) == EFFECT_GRASSY_GLIDE && IsBattlerTerrainAffected(battler, STATUS_FIELD_GRASSY_TERRAIN) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_DYNAMAX && !IsGimmickSelected(battler, GIMMICK_DYNAMAX)) + else if (GetMoveEffect(move) == EFFECT_GRASSY_GLIDE && IsBattlerTerrainAffected(battler, ability, GetBattlerHoldEffect(battler), STATUS_FIELD_GRASSY_TERRAIN) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_DYNAMAX && !IsGimmickSelected(battler, GIMMICK_DYNAMAX)) { priority++; } @@ -4869,8 +4878,7 @@ s32 GetBattleMovePriority(u32 battler, u32 ability, u32 move) return priority; } -s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2, - enum ItemHoldEffect holdEffectBattler1, enum ItemHoldEffect holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2) +s32 GetWhichBattlerFasterArgs(struct BattleContext *ctx, bool32 ignoreChosenMoves, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2) { u32 strikesFirst = 0; @@ -4879,18 +4887,18 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov // Quick Claw / Quick Draw / Custap Berry - always first // Stall / Mycelium Might - last but before Lagging Tail // Lagging Tail - always last - bool32 battler1HasQuickEffect = gProtectStructs[battler1].quickDraw || gProtectStructs[battler1].usedCustapBerry; - bool32 battler2HasQuickEffect = gProtectStructs[battler2].quickDraw || gProtectStructs[battler2].usedCustapBerry; - bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || gProtectStructs[battler1].myceliumMight; - bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || gProtectStructs[battler2].myceliumMight; + bool32 battler1HasQuickEffect = gProtectStructs[ctx->battlerAtk].quickDraw || gProtectStructs[ctx->battlerAtk].usedCustapBerry; + bool32 battler2HasQuickEffect = gProtectStructs[ctx->battlerDef].quickDraw || gProtectStructs[ctx->battlerDef].usedCustapBerry; + bool32 battler1HasStallingAbility = ctx->abilities[ctx->battlerAtk] == ABILITY_STALL || gProtectStructs[ctx->battlerAtk].myceliumMight; + bool32 battler2HasStallingAbility = ctx->abilities[ctx->battlerDef] == ABILITY_STALL || gProtectStructs[ctx->battlerDef].myceliumMight; if (battler1HasQuickEffect && !battler2HasQuickEffect) strikesFirst = 1; else if (battler2HasQuickEffect && !battler1HasQuickEffect) strikesFirst = -1; - else if (gProtectStructs[battler1].laggingTail && !gProtectStructs[battler2].laggingTail) + else if (gProtectStructs[ctx->battlerAtk].laggingTail && !gProtectStructs[ctx->battlerDef].laggingTail) strikesFirst = -1; - else if (gProtectStructs[battler2].laggingTail && !gProtectStructs[battler1].laggingTail) + else if (gProtectStructs[ctx->battlerDef].laggingTail && !gProtectStructs[ctx->battlerAtk].laggingTail) strikesFirst = 1; else if (battler1HasStallingAbility && !battler2HasStallingAbility) strikesFirst = -1; @@ -4932,32 +4940,27 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov return strikesFirst; } -s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves) +s32 GetWhichBattlerFasterOrTies(struct BattleContext *ctx, bool32 ignoreChosenMoves) { s32 priority1 = 0, priority2 = 0; - u32 ability1 = GetBattlerAbility(battler1); - u32 speedBattler1 = GetBattlerTotalSpeedStat(battler1); - enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE); - u32 speedBattler2 = GetBattlerTotalSpeedStat(battler2); - enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE); - u32 ability2 = GetBattlerAbility(battler2); + u32 speedBattler1 = GetBattlerTotalSpeedStat(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ctx->holdEffects[ctx->battlerAtk]); + u32 speedBattler2 = GetBattlerTotalSpeedStat(ctx->battlerDef, ctx->abilities[ctx->battlerDef], ctx->holdEffects[ctx->battlerDef]); if (!ignoreChosenMoves) { - if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE) - priority1 = GetChosenMovePriority(battler1, ability1); - if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE) - priority2 = GetChosenMovePriority(battler2, ability2); + if (gChosenActionByBattler[ctx->battlerAtk] == B_ACTION_USE_MOVE) + priority1 = GetChosenMovePriority(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk]); + if (gChosenActionByBattler[ctx->battlerDef] == B_ACTION_USE_MOVE) + priority2 = GetChosenMovePriority(ctx->battlerDef, ctx->abilities[ctx->battlerDef]); } return GetWhichBattlerFasterArgs( - battler1, battler2, + ctx, ignoreChosenMoves, - ability1, ability2, - holdEffectBattler1, holdEffectBattler2, - speedBattler1, speedBattler2, - priority1, priority2 - ); + speedBattler1, + speedBattler2, + priority1, + priority2); } // 24 == MAX_BATTLERS_COUNT!. @@ -4991,13 +4994,13 @@ static const u8 sBattlerOrders[24][4] = { 3, 2, 1, 0 }, }; -s32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves) +s32 GetWhichBattlerFaster(struct BattleContext *ctx, bool32 ignoreChosenMoves) { - s32 strikesFirst = GetWhichBattlerFasterOrTies(battler1, battler2, ignoreChosenMoves); + s32 strikesFirst = GetWhichBattlerFasterOrTies(ctx, ignoreChosenMoves); if (strikesFirst == 0) { - s32 order1 = sBattlerOrders[gBattleStruct->speedTieBreaks][battler1]; - s32 order2 = sBattlerOrders[gBattleStruct->speedTieBreaks][battler2]; + s32 order1 = sBattlerOrders[gBattleStruct->speedTieBreaks][ctx->battlerAtk]; + s32 order2 = sBattlerOrders[gBattleStruct->speedTieBreaks][ctx->battlerDef]; if (order1 < order2) strikesFirst = 1; else @@ -5091,13 +5094,19 @@ static void SetActionsAndBattlersTurnOrder(void) turnOrderId++; } } + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = 0; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - u8 battler1 = gBattlerByTurnOrder[i]; - u8 battler2 = gBattlerByTurnOrder[j]; - TryChangingTurnOrderEffects(battler1, battler2, quickClawRandom, quickDrawRandom); + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; + TryChangingTurnOrderEffects(&ctx, quickClawRandom, quickDrawRandom); if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM && gActionsByTurnOrder[j] != B_ACTION_USE_ITEM && gActionsByTurnOrder[i] != B_ACTION_SWITCH @@ -5105,7 +5114,7 @@ static void SetActionsAndBattlersTurnOrder(void) && gActionsByTurnOrder[i] != B_ACTION_THROW_BALL && gActionsByTurnOrder[j] != B_ACTION_THROW_BALL) { - if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) + if (GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); } } @@ -5141,6 +5150,7 @@ static void TurnValuesCleanUp(bool8 var0) gDisableStructs[i].rechargeTimer--; gBattleStruct->battlerState[i].canPickupItem = FALSE; + gBattleStruct->battlerState[i].wasAboveHalfHp = FALSE; } if (gDisableStructs[i].substituteHP == 0) @@ -5159,15 +5169,12 @@ static void TurnValuesCleanUp(bool8 var0) gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceler + gBattleStruct->tryDestinyBond = FALSE; + gBattleStruct->tryGrudge = FALSE; ClearPursuitValues(); ClearDamageCalcResults(); } -void SpecialStatusesClear(void) -{ - memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); -} - static void PopulateArrayWithBattlers(u8 *battlers) { u32 i; @@ -5255,29 +5262,38 @@ static bool32 TryDoMoveEffectsBeforeMoves(void) static void TryChangeTurnOrder(void) { u32 i, j; + + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = gCurrentTurnActionNumber; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - u32 battler1 = gBattlerByTurnOrder[i]; - u32 battler2 = gBattlerByTurnOrder[j]; + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; if (gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE) { - if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) + if (GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); } } } } -static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickClawRandom, u32 *quickDrawRandom) +static void TryChangingTurnOrderEffects(struct BattleContext *ctx, u32 *quickClawRandom, u32 *quickDrawRandom) { - u32 ability1 = GetBattlerAbility(battler1); - enum ItemHoldEffect holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE); - enum ItemHoldEffect holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE); - u32 ability2 = GetBattlerAbility(battler2); + u32 battler1 = ctx->battlerAtk; + u32 battler2 = ctx->battlerDef; + enum Ability ability1 = ctx->abilities[ctx->battlerAtk]; + enum Ability ability2 = ctx->abilities[ctx->battlerDef]; + enum HoldEffect holdEffectBattler1 = ctx->holdEffects[ctx->battlerAtk]; + enum HoldEffect holdEffectBattler2 = ctx->holdEffects[ctx->battlerDef]; // Battler 1 // Quick Draw @@ -5286,7 +5302,7 @@ static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickCl // Quick Claw and Custap Berry if (!gProtectStructs[battler1].quickDraw && ((holdEffectBattler1 == HOLD_EFFECT_QUICK_CLAW && quickClawRandom[battler1]) - || (holdEffectBattler1 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler1, 4, gBattleMons[battler1].item)))) + || (holdEffectBattler1 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler1, ability1, 4, gBattleMons[battler1].item)))) gProtectStructs[battler1].usedCustapBerry = TRUE; // Battler 2 @@ -5296,7 +5312,7 @@ static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2, u32 *quickCl // Quick Claw and Custap Berry if (!gProtectStructs[battler2].quickDraw && ((holdEffectBattler2 == HOLD_EFFECT_QUICK_CLAW && quickClawRandom[battler2]) - || (holdEffectBattler2 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler2, 4, gBattleMons[battler2].item)))) + || (holdEffectBattler2 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler2, ability2, 4, gBattleMons[battler2].item)))) gProtectStructs[battler2].usedCustapBerry = TRUE; } @@ -5321,14 +5337,14 @@ static void CheckChangingTurnOrderEffects(void) { gLastUsedItem = gBattleMons[battler].item; PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - if (GetBattlerHoldEffect(battler, FALSE) == HOLD_EFFECT_CUSTAP_BERRY) + if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_CUSTAP_BERRY) { // don't record berry since its gone now BattleScriptExecute(BattleScript_CustapBerryActivation); } else { - RecordItemEffectBattle(battler, GetBattlerHoldEffect(battler, FALSE)); + RecordItemEffectBattle(battler, GetBattlerHoldEffect(battler)); BattleScriptExecute(BattleScript_QuickClawActivation); } } @@ -5361,7 +5377,6 @@ static void CheckChangingTurnOrderEffects(void) gBattleMainFunc = RunTurnActionsFunctions; gBattleCommunication[3] = 0; gBattleCommunication[4] = 0; - gBattleScripting.multihitMoveEffect = 0; gBattleResources->battleScriptsStack->size = 0; } @@ -5393,16 +5408,12 @@ static void RunTurnActionsFunctions(void) if (gCurrentTurnActionNumber >= gBattlersCount) // everyone did their actions, turn finished { - gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE; gBattleMainFunc = sEndTurnFuncsTable[gBattleOutcome & 0x7F]; } else { if (gBattleStruct->savedTurnActionNumber != gCurrentTurnActionNumber) // action turn has been done, clear hitmarker bits for another battler - { - gHitMarker &= ~HITMARKER_NO_ATTACKSTRING; gHitMarker &= ~HITMARKER_UNABLE_TO_USE_MOVE; - } } } @@ -5588,7 +5599,7 @@ static void HandleEndTurn_FinishBattle(void) | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_FRONTIER))) { - for (u32 side = 0; side < NUM_BATTLE_SIDES; side++) + for (enum BattleSide side = 0; side < NUM_BATTLE_SIDES; side++) { struct Pokemon *party = GetSideParty(side); @@ -5633,8 +5644,7 @@ static void HandleEndTurn_FinishBattle(void) for (i = 0; i < PARTY_SIZE; i++) { - bool8 changedForm = TryRevertPartyMonFormChange(i); - gBattleStruct->partyState[B_SIDE_OPPONENT][i].changedSpecies = SPECIES_NONE; + bool32 changedForm = TryRevertPartyMonFormChange(i); // Recalculate the stats of every party member before the end if (!changedForm && B_RECALCULATE_STATS >= GEN_5) @@ -5806,9 +5816,9 @@ void RunBattleScriptCommands(void) gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } -u32 TrySetAteType(u32 move, u32 battlerAtk, u32 attackerAbility) +enum Type TrySetAteType(u32 move, u32 battlerAtk, enum Ability attackerAbility) { - u32 ateType = TYPE_NONE; + enum Type ateType = TYPE_NONE; switch (GetMoveEffect(move)) { @@ -5854,12 +5864,14 @@ u32 TrySetAteType(u32 move, u32 battlerAtk, u32 attackerAbility) } // Returns TYPE_NONE if type doesn't change. -u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) +enum Type GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) { - u32 moveType = GetMoveType(move); + enum Type moveType = GetMoveType(move); enum BattleMoveEffects moveEffect = GetMoveEffect(move); - u32 species, heldItem, ability, type1, type2, type3; - enum ItemHoldEffect holdEffect; + u32 species, heldItem; + enum Type type1, type2, type3; + enum Ability ability; + enum HoldEffect holdEffect; enum Gimmick gimmick = GetActiveGimmick(battler); if (state == MON_IN_BATTLE) @@ -5869,7 +5881,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState species = gBattleMons[battler].species; heldItem = gBattleMons[battler].item; - holdEffect = GetBattlerHoldEffect(battler, TRUE); + holdEffect = GetBattlerHoldEffect(battler); ability = GetBattlerAbility(battler); type1 = gBattleMons[battler].types[0]; type2 = gBattleMons[battler].types[1]; @@ -5967,7 +5979,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState case EFFECT_REVELATION_DANCE: if (gimmick != GIMMICK_Z_MOVE) { - u32 teraType; + enum Type teraType; if (gimmick == GIMMICK_TERA && ((teraType = GetMonData(mon, MON_DATA_TERA_TYPE)) != TYPE_STELLAR)) return teraType; else if (type1 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type1 == TYPE_FLYING)) @@ -6011,7 +6023,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState case EFFECT_TERRAIN_PULSE: if (state == MON_IN_BATTLE) { - if (IsBattlerTerrainAffected(battler, STATUS_FIELD_TERRAIN_ANY)) + if (IsBattlerTerrainAffected(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler), STATUS_FIELD_TERRAIN_ANY)) { if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) return TYPE_ELECTRIC; @@ -6092,9 +6104,9 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState void SetTypeBeforeUsingMove(u32 move, u32 battler) { - u32 moveType; + enum Type moveType; u32 heldItem = gBattleMons[battler].item; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); gBattleStruct->dynamicMoveType = 0; gBattleStruct->battlerState[battler].ateBoost = FALSE; diff --git a/src/battle_message.c b/src/battle_message.c index aeb32f259f..0ca29c0a46 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -67,7 +67,7 @@ const u8 gText_PkmnsXPreventsSwitching[] = _("{B_BUFF1} is preventing switching const u8 gText_StatSharply[] = _("sharply "); const u8 gText_StatRose[] = _("rose!"); const u8 gText_StatFell[] = _("fell!"); -const u8 gText_DefendersStatRose[] = _("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}"); +const u8 gText_DefendersStatRose[] = _("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}rose!"); static const u8 sText_GotAwaySafely[] = _("{PLAY_SE SE_FLEE}You got away safely!\p"); static const u8 sText_PlayerDefeatedLinkTrainer[] = _("You defeated {B_LINK_OPPONENT1_NAME}!"); static const u8 sText_TwoLinkTrainersDefeated[] = _("You defeated {B_LINK_OPPONENT1_NAME} and {B_LINK_OPPONENT2_NAME}!"); @@ -108,6 +108,7 @@ static const u8 sText_PkmnComeBack[] = _("{B_BUFF1}, come back!"); static const u8 sText_PkmnOkComeBack[] = _("OK, {B_BUFF1}! Come back!"); static const u8 sText_PkmnGoodComeBack[] = _("Good job, {B_BUFF1}! Come back!"); static const u8 sText_Trainer1WithdrewPkmn[] = _("{B_TRAINER1_NAME_WITH_CLASS} withdrew {B_BUFF1}!"); +static const u8 sText_Trainer2WithdrewPkmn[] = _("{B_TRAINER2_NAME_WITH_CLASS} withdrew {B_BUFF1}!"); static const u8 sText_LinkTrainer1WithdrewPkmn[] = _("{B_LINK_OPPONENT1_NAME} withdrew {B_BUFF1}!"); static const u8 sText_LinkTrainer2WithdrewPkmn[] = _("{B_LINK_SCR_TRAINER_NAME} withdrew {B_BUFF1}!"); static const u8 sText_WildPkmnPrefix[] = _("The wild "); @@ -187,8 +188,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_STATSWONTINCREASE2] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s stats won't go any higher!"), [STRINGID_AVOIDEDDAMAGE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} avoided damage with {B_DEF_ABILITY}!"), //not in gen 5+, ability popup [STRINGID_ITDOESNTAFFECT] = COMPOUND_STRING("It doesn't affect {B_DEF_NAME_WITH_PREFIX2}…"), - [STRINGID_ATTACKERFAINTED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} fainted!\p"), - [STRINGID_TARGETFAINTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} fainted!\p"), + [STRINGID_BATTLERFAINTED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} fainted!\p"), [STRINGID_PLAYERGOTMONEY] = COMPOUND_STRING("You got ¥{B_BUFF1} for winning!\p"), [STRINGID_PLAYERWHITEOUT] = COMPOUND_STRING("You have no more Pokémon that can fight!\p"), [STRINGID_PLAYERWHITEOUT2_WILD] = COMPOUND_STRING("You panicked and dropped ¥{B_BUFF1}…"), @@ -220,11 +220,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNISPARALYZED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} couldn't move because it's paralyzed!"), [STRINGID_PKMNISALREADYPARALYZED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is already paralyzed!"), [STRINGID_PKMNHEALEDPARALYSIS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was cured of paralysis!"), - [STRINGID_PKMNDREAMEATEN] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s dream was eaten!"), //not in gen 5+, expansion doesn't use anymore [STRINGID_STATSWONTINCREASE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} won't go any higher!"), [STRINGID_STATSWONTDECREASE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} won't go any lower!"), - [STRINGID_TEAMSTOPPEDWORKING] = COMPOUND_STRING("Your team's {B_BUFF1} stopped working!"), //unused - [STRINGID_FOESTOPPEDWORKING] = COMPOUND_STRING("The foe's {B_BUFF1} stopped working!"), //unused [STRINGID_PKMNISCONFUSED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is confused!"), [STRINGID_PKMNHEALEDCONFUSION] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} snapped out of its confusion!"), [STRINGID_PKMNWASCONFUSED] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX} became confused!"), @@ -232,7 +229,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNFELLINLOVE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} fell in love!"), [STRINGID_PKMNINLOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is in love with {B_SCR_NAME_WITH_PREFIX2}!"), [STRINGID_PKMNIMMOBILIZEDBYLOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is immobilized by love!"), - [STRINGID_PKMNBLOWNAWAY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was blown away!"), //unused [STRINGID_PKMNCHANGEDTYPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} transformed into the {B_BUFF1} type!"), [STRINGID_PKMNFLINCHED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} flinched and couldn't move!"), [STRINGID_PKMNREGAINEDHEALTH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s HP was restored."), @@ -276,7 +272,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNCALMEDDOWN] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} calmed down."), [STRINGID_PKMNCANTSLEEPINUPROAR] = COMPOUND_STRING("But {B_DEF_NAME_WITH_PREFIX2} can't sleep in an uproar!"), [STRINGID_PKMNSTOCKPILED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stockpiled {B_BUFF1}!"), - [STRINGID_PKMNCANTSTOCKPILE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} can't stockpile any more!"), //I think this was replaced with just "But it failed!" [STRINGID_PKMNCANTSLEEPINUPROAR2] = COMPOUND_STRING("But {B_DEF_NAME_WITH_PREFIX2} can't sleep in an uproar!"), [STRINGID_UPROARKEPTPKMNAWAKE] = COMPOUND_STRING("But the uproar kept {B_DEF_NAME_WITH_PREFIX2} awake!"), [STRINGID_PKMNSTAYEDAWAKEUSING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} stayed awake using its {B_DEF_ABILITY}!"), //not in gen 5+, ability popup @@ -294,10 +289,10 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNRAGEBUILDING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s rage is building!"), [STRINGID_PKMNMOVEWASDISABLED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} was disabled!"), [STRINGID_PKMNMOVEISDISABLED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE} is disabled!\p"), - [STRINGID_PKMNMOVEDISABLEDNOMORE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s move is no longer disabled!"), + [STRINGID_PKMNMOVEDISABLEDNOMORE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s move is no longer disabled!"), [STRINGID_PKMNGOTENCORE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} must do an encore!"), [STRINGID_PKMNGOTENCOREDMOVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} can only use {B_CURRENT_MOVE}!\p"), - [STRINGID_PKMNENCOREENDED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} ended its encore!"), + [STRINGID_PKMNENCOREENDED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} ended its encore!"), [STRINGID_PKMNTOOKAIM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} took aim at {B_DEF_NAME_WITH_PREFIX2}!"), [STRINGID_PKMNSKETCHEDMOVE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} sketched {B_BUFF1}!"), [STRINGID_PKMNTRYINGTOTAKEFOE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is hoping to take its attacker down with it!"), @@ -324,7 +319,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNFLEDFROMBATTLE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} fled from battle!"), [STRINGID_PKMNFORESAWATTACK] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} foresaw an attack!"), [STRINGID_PKMNTOOKATTACK] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} took the {B_BUFF1} attack!"), - [STRINGID_PKMNATTACK] = COMPOUND_STRING("{B_BUFF1}'s attack!"), //not in gen 5+, expansion doesn't use anymore + [STRINGID_PKMNATTACK] = COMPOUND_STRING("{B_BUFF1}'s attack!"), //not in gen 5+ [STRINGID_PKMNCENTERATTENTION] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} became the center of attention!"), [STRINGID_PKMNCHARGINGPOWER] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} began charging power!"), [STRINGID_NATUREPOWERTURNEDINTO] = COMPOUND_STRING("Nature Power turned into {B_CURRENT_MOVE}!"), @@ -338,7 +333,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNREADYTOHELP] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is ready to help {B_DEF_NAME_WITH_PREFIX2}!"), [STRINGID_PKMNSWITCHEDITEMS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} switched items with its target!"), [STRINGID_PKMNCOPIEDFOE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} copied {B_DEF_NAME_WITH_PREFIX2}'s Ability!"), - [STRINGID_PKMNMADEWISH] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} made a wish!"), //unused [STRINGID_PKMNWISHCAMETRUE] = COMPOUND_STRING("{B_BUFF1}'s wish came true!"), [STRINGID_PKMNPLANTEDROOTS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} planted its roots!"), [STRINGID_PKMNABSORBEDNUTRIENTS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} absorbed nutrients with its roots!"), @@ -355,15 +349,12 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNWAITSFORTARGET] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} waits for a target to make a move!"), [STRINGID_PKMNSNATCHEDMOVE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} snatched {B_SCR_NAME_WITH_PREFIX2}'s move!"), [STRINGID_PKMNMADEITRAIN] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} made it rain!"), //not in gen 5+, ability popup - [STRINGID_PKMNRAISEDSPEED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} raised its Speed!"), //not in gen 5+, ability popup [STRINGID_PKMNPROTECTEDBY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was protected by {B_DEF_ABILITY}!"), //not in gen 5+, ability popup [STRINGID_PKMNPREVENTSUSAGE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents {B_ATK_NAME_WITH_PREFIX2} from using {B_CURRENT_MOVE}!"), //I don't see this in SV text [STRINGID_PKMNRESTOREDHPUSING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} restored HP using its {B_DEF_ABILITY}!"), //not in gen 5+, ability popup - [STRINGID_PKMNCHANGEDTYPEWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} made it the {B_BUFF1} type!"), //not in gen 5+, ability popup - [STRINGID_PKMNPREVENTSPARALYSISWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} prevents paralysis!"), //not in gen 5+, ability popup + [STRINGID_PKMNCHANGEDTYPEWITH] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_EFF_ABILITY} made it the {B_BUFF1} type!"), //not in gen 5+, ability popup [STRINGID_PKMNPREVENTSROMANCEWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents romance!"), //not in gen 5+, ability popup - [STRINGID_PKMNPREVENTSPOISONINGWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} prevents poisoning!"), //not in gen 5+, ability popup - [STRINGID_PKMNPREVENTSCONFUSIONWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevents confusion!"), //not in gen 5+, ability popup + [STRINGID_PKMNPREVENTSCONFUSIONWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} prevents confusion!"), //not in gen 5+, ability popup [STRINGID_PKMNRAISEDFIREPOWERWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} raised the power of Fire-type moves!"), //not in gen 5+, ability popup [STRINGID_PKMNANCHORSITSELFWITH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} anchors itself with {B_DEF_ABILITY}!"), //not in gen 5+, ability popup [STRINGID_PKMNCUTSATTACKWITH] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} cuts {B_DEF_NAME_WITH_PREFIX2}'s Attack!"), //not in gen 5+, ability popup @@ -374,10 +365,10 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_STATROSE] = gText_StatRose, [STRINGID_STATHARSHLY] = COMPOUND_STRING("harshly "), [STRINGID_STATFELL] = gText_StatFell, - [STRINGID_ATTACKERSSTATROSE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}"), + [STRINGID_ATTACKERSSTATROSE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}rose!"), [STRINGID_DEFENDERSSTATROSE] = gText_DefendersStatRose, - [STRINGID_ATTACKERSSTATFELL] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}"), - [STRINGID_DEFENDERSSTATFELL] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}"), + [STRINGID_ATTACKERSSTATFELL] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}fell!"), + [STRINGID_DEFENDERSSTATFELL] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} {B_BUFF2}fell!"), [STRINGID_CRITICALHIT] = COMPOUND_STRING("A critical hit!"), [STRINGID_ONEHITKO] = COMPOUND_STRING("It's a one-hit KO!"), [STRINGID_123POOF] = COMPOUND_STRING("One…{PAUSE 10}two…{PAUSE 10}and…{PAUSE 10}{PAUSE 20}{PLAY_SE SE_BALL_BOUNCE_1}ta-da!\p"), @@ -392,7 +383,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_BUTNOTHINGHAPPENED] = COMPOUND_STRING("But nothing happened!"), [STRINGID_BUTITFAILED] = COMPOUND_STRING("But it failed!"), [STRINGID_ITHURTCONFUSION] = COMPOUND_STRING("It hurt itself in its confusion!"), - [STRINGID_MIRRORMOVEFAILED] = COMPOUND_STRING("The Mirror Move failed!"), //not in gen 5+, uses "but it failed" [STRINGID_STARTEDTORAIN] = COMPOUND_STRING("It started to rain!"), [STRINGID_DOWNPOURSTARTED] = COMPOUND_STRING("A downpour started!"), // corresponds to DownpourText in pokegold and pokecrystal and is used by Rain Dance in GSC [STRINGID_RAINCONTINUES] = COMPOUND_STRING("Rain continues to fall."), //not in gen 5+ @@ -407,9 +397,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_STARTEDHAIL] = COMPOUND_STRING("It started to hail!"), [STRINGID_HAILCONTINUES] = COMPOUND_STRING("The hail is crashing down."), [STRINGID_HAILSTOPPED] = COMPOUND_STRING("The hail stopped."), - [STRINGID_FAILEDTOSPITUP] = COMPOUND_STRING("But it failed to spit up a thing!"), //not in gen 5+, uses "but it failed" - [STRINGID_FAILEDTOSWALLOW] = COMPOUND_STRING("But it failed to swallow a thing!"), //not in gen 5+, uses "but it failed" - [STRINGID_WINDBECAMEHEATWAVE] = COMPOUND_STRING("The wind turned into a Heat Wave!"), //unused [STRINGID_STATCHANGESGONE] = COMPOUND_STRING("All stat changes were eliminated!"), [STRINGID_COINSSCATTERED] = COMPOUND_STRING("Coins were scattered everywhere!"), [STRINGID_TOOWEAKFORSUBSTITUTE] = COMPOUND_STRING("But it does not have enough HP left to make a substitute!"), @@ -466,7 +453,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_ITEMALLOWSONLYYMOVE] = COMPOUND_STRING("{B_LAST_ITEM} only allows the use of {B_CURRENT_MOVE}!\p"), [STRINGID_PKMNHUNGONWITHX] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} hung on using its {B_LAST_ITEM}!"), [STRINGID_EMPTYSTRING3] = gText_EmptyString3, - [STRINGID_PKMNSXPREVENTSBURNS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} prevents burns!"), //not in gen 5+, ability popup [STRINGID_PKMNSXBLOCKSY] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} blocks {B_CURRENT_MOVE}!"), //not in gen 5+, ability popup [STRINGID_PKMNSXRESTOREDHPALITTLE2] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} restored its HP a little!"), //not in gen 5+, ability popup [STRINGID_PKMNSXWHIPPEDUPSANDSTORM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} whipped up a sandstorm!"), //not in gen 5+, ability popup @@ -485,8 +471,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PLAYERDEFEATEDTRAINER1] = sText_PlayerDefeatedLinkTrainerTrainer1, [STRINGID_SOOTHINGAROMA] = COMPOUND_STRING("A soothing aroma wafted through the area!"), [STRINGID_ITEMSCANTBEUSEDNOW] = COMPOUND_STRING("Items can't be used now.{PAUSE 64}"), //not in gen 5+, i think - [STRINGID_FORXCOMMAYZ] = COMPOUND_STRING("For {B_SCR_NAME_WITH_PREFIX2}, {B_LAST_ITEM} {B_BUFF1}"), //not in gen 5+, expansion doesn't use anymore - [STRINGID_USINGITEMSTATOFPKMNROSE] = COMPOUND_STRING("Using {B_LAST_ITEM}, the {B_BUFF1} of {B_SCR_NAME_WITH_PREFIX2} {B_BUFF2}"), //todo: update this, will require code changes + [STRINGID_USINGITEMSTATOFPKMNROSE] = COMPOUND_STRING("Using {B_LAST_ITEM}, the {B_BUFF1} of {B_SCR_NAME_WITH_PREFIX2} {B_BUFF2}rose!"), //todo: update this, will require code changes + [STRINGID_USINGITEMSTATOFPKMNFELL] = COMPOUND_STRING("Using {B_LAST_ITEM}, the {B_BUFF1} of {B_SCR_NAME_WITH_PREFIX2} {B_BUFF2}fell!"), [STRINGID_PKMNUSEDXTOGETPUMPED] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} used the {B_LAST_ITEM} to get pumped!"), [STRINGID_PKMNSXMADEYUSELESS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} made {B_CURRENT_MOVE} useless!"), //not in gen 5+, ability popup [STRINGID_PKMNTRAPPEDBYSANDTOMB] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} became trapped by the quicksand!"), @@ -502,7 +488,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNFLEDUSINGITS] = COMPOUND_STRING("{PLAY_SE SE_FLEE}{B_ATK_NAME_WITH_PREFIX} fled using its {B_LAST_ITEM}!\p"), [STRINGID_PKMNFLEDUSING] = COMPOUND_STRING("{PLAY_SE SE_FLEE}{B_ATK_NAME_WITH_PREFIX} fled using {B_ATK_ABILITY}!\p"), //not in gen 5+ [STRINGID_PKMNWASDRAGGEDOUT] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was dragged out!\p"), - [STRINGID_PREVENTEDFROMWORKING] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} prevented {B_SCR_NAME_WITH_PREFIX2}'s {B_BUFF1} from working!"), //unused [STRINGID_PKMNSITEMNORMALIZEDSTATUS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_LAST_ITEM} normalized its status!"), [STRINGID_TRAINER1USEDITEM] = COMPOUND_STRING("{B_ATK_TRAINER_NAME_WITH_CLASS} used {B_LAST_ITEM}!"), [STRINGID_BOXISFULL] = COMPOUND_STRING("The Box is full! You can't catch any more!\p"), @@ -513,17 +498,13 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_STATSWONTDECREASE2] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s stats won't go any lower!"), [STRINGID_PKMNSXBLOCKSY2] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} blocks {B_CURRENT_MOVE}!"), //not in gen 5+, ability popup [STRINGID_PKMNSXWOREOFF] = COMPOUND_STRING("{B_ATK_TEAM1} team's {B_BUFF1} wore off!"), - [STRINGID_PKMNRAISEDDEFALITTLE] = COMPOUND_STRING("{B_ATK_PREFIX1}'s {B_CURRENT_MOVE} raised DEFENSE a little!"), //expansion doesn't use anymore - [STRINGID_PKMNRAISEDSPDEFALITTLE] = COMPOUND_STRING("{B_ATK_PREFIX1}'s {B_CURRENT_MOVE} raised SP. DEF a little!"), //expansion doesn't use anymore [STRINGID_THEWALLSHATTERED] = COMPOUND_STRING("The wall shattered!"), //not in gen5+, uses "your teams light screen wore off!" etc instead - [STRINGID_PKMNSXPREVENTSYSZ] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} prevents {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY} from working!"), [STRINGID_PKMNSXCUREDITSYPROBLEM] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} cured its {B_BUFF1} problem!"), //not in gen 5+, ability popup [STRINGID_ATTACKERCANTESCAPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} can't escape!"), [STRINGID_PKMNOBTAINEDX] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} obtained {B_BUFF1}."), [STRINGID_PKMNOBTAINEDX2] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} obtained {B_BUFF2}."), [STRINGID_PKMNOBTAINEDXYOBTAINEDZ] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} obtained {B_BUFF1}.\p{B_DEF_NAME_WITH_PREFIX} obtained {B_BUFF2}."), [STRINGID_BUTNOEFFECT] = COMPOUND_STRING("But it had no effect!"), - [STRINGID_PKMNSXHADNOEFFECTONY] = COMPOUND_STRING("Target protected by {B_LAST_ABILITY}!"), //not in gen 5+, ability popup [STRINGID_TWOENEMIESDEFEATED] = sText_TwoInGameTrainersDefeated, [STRINGID_TRAINER2LOSETEXT] = COMPOUND_STRING("{B_TRAINER2_LOSE_TEXT}"), [STRINGID_PKMNINCAPABLEOFPOWER] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} appears incapable of using its power!"), @@ -582,10 +563,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_FELLSTRAIGHTDOWN] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} fell straight down!"), [STRINGID_TARGETCHANGEDTYPE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} transformed into the {B_BUFF1} type!"), [STRINGID_PKMNACQUIREDSIMPLE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} acquired Simple!"), //shouldn't directly use the name - [STRINGID_EMPTYSTRING5] = sText_EmptyString4, [STRINGID_KINDOFFER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} took the kind offer!"), [STRINGID_RESETSTARGETSSTATLEVELS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s stat changes were removed!"), - [STRINGID_EMPTYSTRING6] = sText_EmptyString4, [STRINGID_ALLYSWITCHPOSITION] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} and {B_SCR_NAME_WITH_PREFIX2} switched places!"), [STRINGID_RESTORETARGETSHEALTH] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s HP was restored!"), [STRINGID_TOOKPJMNINTOTHESKY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} took {B_DEF_NAME_WITH_PREFIX2} into the sky!"), @@ -595,7 +574,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_TRANSFERHELDITEM] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} received {B_LAST_ITEM} from {B_ATK_NAME_WITH_PREFIX2}"), [STRINGID_EMBARGOENDS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} can use items again!"), [STRINGID_ELECTROMAGNETISM] = COMPOUND_STRING("electromagnetism"), - [STRINGID_BUFFERENDS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} wore off!"), + [STRINGID_BUFFERENDS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_BUFF1} wore off!"), [STRINGID_TELEKINESISENDS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} was freed from the telekinesis!"), [STRINGID_TAILWINDENDS] = COMPOUND_STRING("{B_ATK_TEAM1} team's Tailwind petered out!"), [STRINGID_LUCKYCHANTENDS] = COMPOUND_STRING("{B_ATK_TEAM1} team's Lucky Chant wore off!"), @@ -610,9 +589,9 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_MISTYTERRAINENDS] = COMPOUND_STRING("The mist disappeared from the battlefield."), [STRINGID_PSYCHICTERRAINENDS] = COMPOUND_STRING("The weirdness disappeared from the battlefield!"), [STRINGID_GRASSYTERRAINENDS] = COMPOUND_STRING("The grass disappeared from the battlefield."), - [STRINGID_TARGETABILITYSTATRAISE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} raised its {B_BUFF1}!"), + [STRINGID_TARGETABILITYSTATRAISE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} {B_BUFF2}raised its {B_BUFF1}!"), [STRINGID_TARGETSSTATWASMAXEDOUT] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} maxed its {B_BUFF1}!"), - [STRINGID_ATTACKERABILITYSTATRAISE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} raised its {B_BUFF1}!"), + [STRINGID_ATTACKERABILITYSTATRAISE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} {B_BUFF2}raised its {B_BUFF1}!"), [STRINGID_POISONHEALHPUP] = COMPOUND_STRING("The poisoning healed {B_ATK_NAME_WITH_PREFIX2} a little bit!"), //don't think this message is displayed anymore [STRINGID_BADDREAMSDMG] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is tormented!"), [STRINGID_MOLDBREAKERENTERS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} breaks the mold!"), @@ -642,7 +621,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_LUNARDANCECAMETRUE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became cloaked in mystical moonlight!"), [STRINGID_CURSEDBODYDISABLED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_BUFF1} was disabled by {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY}!"), [STRINGID_ATTACKERACQUIREDABILITY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} acquired {B_ATK_ABILITY}!"), - [STRINGID_TARGETABILITYSTATLOWER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} lowered its {B_BUFF1}!"), + [STRINGID_TARGETABILITYSTATLOWER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_DEF_ABILITY} {B_BUFF2}lowered its {B_BUFF1}!"), [STRINGID_TARGETSTATWONTGOHIGHER] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s {B_BUFF1} won't go any higher!"), [STRINGID_PKMNMOVEBOUNCEDABILITY] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_CURRENT_MOVE} was bounced back by {B_DEF_NAME_WITH_PREFIX2}'s {B_DEF_ABILITY}!"), [STRINGID_IMPOSTERTRANSFORM] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} transformed into {B_DEF_NAME_WITH_PREFIX2} using {B_LAST_ABILITY}!"), @@ -681,7 +660,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_MISTYTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with a protective mist!"), [STRINGID_GRASSYTERRAINHEALS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is healed by the grassy terrain!"), [STRINGID_ELECTRICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with electrified terrain!"), - [STRINGID_PSYCHICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounds itself with psychic terrain!"), + [STRINGID_PSYCHICTERRAINPREVENTS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is protected by the Psychic Terrain!"), [STRINGID_SAFETYGOGGLESPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is not affected thanks to its {B_LAST_ITEM}!"), [STRINGID_FLOWERVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} surrounded itself with a veil of petals!"), [STRINGID_SWEETVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} can't fall asleep due to a veil of sweetness!"), @@ -701,7 +680,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_ATTACKERCUREDTARGETSTATUS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} cured {B_DEF_NAME_WITH_PREFIX2}'s problem!"), [STRINGID_ATTACKERLOSTFIRETYPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} burned itself out!"), [STRINGID_HEALERCURE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} cured {B_SCR_NAME_WITH_PREFIX2}'s problem!"), - [STRINGID_SCRIPTINGABILITYSTATRAISE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} raised its {B_BUFF1}!"), + [STRINGID_SCRIPTINGABILITYSTATRAISE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} {B_BUFF2}raised its {B_BUFF1}!"), [STRINGID_RECEIVERABILITYTAKEOVER] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} was taken over!"), [STRINGID_PKNMABSORBINGPOWER] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is absorbing power!"), [STRINGID_NOONEWILLBEABLETORUNAWAY] = COMPOUND_STRING("No one will be able to run away during the next turn!"), @@ -717,10 +696,8 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_COMATOSEENTERS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is drowsing!"), [STRINGID_SCREENCLEANERENTERS] = COMPOUND_STRING("All screens on the field were cleansed!"), [STRINGID_FETCHEDPOKEBALL] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} found a {B_LAST_ITEM}!"), - [STRINGID_BATTLERABILITYRAISEDSTAT] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} raised its {B_BUFF1}!"), [STRINGID_ASANDSTORMKICKEDUP] = COMPOUND_STRING("A sandstorm kicked up!"), [STRINGID_PKMNSWILLPERISHIN3TURNS] = COMPOUND_STRING("Both Pokémon will perish in three turns!"), //don't think this message is displayed anymore - [STRINGID_ABILITYRAISEDSTATDRASTICALLY] = COMPOUND_STRING("{B_DEF_ABILITY} raised {B_DEF_NAME_WITH_PREFIX2}'s {B_BUFF1} drastically!"), [STRINGID_AURAFLAREDTOLIFE] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s aura flared to life!"), [STRINGID_ASONEENTERS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} has two Abilities!"), [STRINGID_CURIOUSMEDICINEENTERS] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s stat changes were removed!"), @@ -733,9 +710,9 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNBURNHEALED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s burn was cured!"), [STRINGID_REDCARDACTIVATE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} held up its Red Card against {B_ATK_NAME_WITH_PREFIX2}!"), [STRINGID_EJECTBUTTONACTIVATE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is switched out with the {B_LAST_ITEM}!"), - [STRINGID_ATKGOTOVERINFATUATION] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} got over its infatuation!"), - [STRINGID_TORMENTEDNOMORE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is no longer tormented!"), - [STRINGID_HEALBLOCKEDNOMORE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} is cured of its heal block!"), + [STRINGID_ATKGOTOVERINFATUATION] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} got over its infatuation!"), + [STRINGID_TORMENTEDNOMORE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is no longer tormented!"), + [STRINGID_HEALBLOCKEDNOMORE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is cured of its heal block!"), [STRINGID_ATTACKERBECAMEFULLYCHARGED] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became fully charged due to its bond with its trainer!\p"), [STRINGID_ATTACKERBECAMEASHSPECIES] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became Ash-Greninja!\p"), [STRINGID_EXTREMELYHARSHSUNLIGHT] = COMPOUND_STRING("The sunlight turned extremely harsh!"), @@ -757,7 +734,6 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_BROKETHROUGHPROTECTION] = COMPOUND_STRING("It broke through {B_DEF_NAME_WITH_PREFIX2}'s protection!"), [STRINGID_ABILITYALLOWSONLYMOVE] = COMPOUND_STRING("{B_ATK_ABILITY} only allows the use of {B_CURRENT_MOVE}!\p"), [STRINGID_SWAPPEDABILITIES] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} swapped Abilities with its target!"), - [STRINGID_PASTELVEILPROTECTED] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is protected by a pastel veil!"), [STRINGID_PASTELVEILENTERS] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} was cured of its poisoning!"), [STRINGID_BATTLERTYPECHANGEDTO] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s type changed to {B_BUFF1}!"), [STRINGID_BOTHCANNOLONGERESCAPE] = COMPOUND_STRING("Neither Pokémon can run away!"), @@ -1094,24 +1070,12 @@ const u16 gUproarOverTurnStringIds[] = [B_MSG_UPROAR_ENDS] = STRINGID_PKMNCALMEDDOWN }; -const u16 gStockpileUsedStringIds[] = -{ - [B_MSG_STOCKPILED] = STRINGID_PKMNSTOCKPILED, - [B_MSG_CANT_STOCKPILE] = STRINGID_PKMNCANTSTOCKPILE, -}; - const u16 gWokeUpStringIds[] = { [B_MSG_WOKE_UP] = STRINGID_PKMNWOKEUP, [B_MSG_WOKE_UP_UPROAR] = STRINGID_PKMNWOKEUPINUPROAR }; -const u16 gSwallowFailStringIds[] = -{ - [B_MSG_SWALLOW_FAILED] = STRINGID_FAILEDTOSWALLOW, - [B_MSG_SWALLOW_FULL_HP] = STRINGID_PKMNHPFULL -}; - const u16 gUproarAwakeStringIds[] = { [B_MSG_CANT_SLEEP_UPROAR] = STRINGID_PKMNCANTSLEEPINUPROAR2, @@ -1120,20 +1084,21 @@ const u16 gUproarAwakeStringIds[] = const u16 gStatUpStringIds[] = { - [B_MSG_ATTACKER_STAT_ROSE] = STRINGID_ATTACKERSSTATROSE, - [B_MSG_DEFENDER_STAT_ROSE] = STRINGID_DEFENDERSSTATROSE, - [B_MSG_STAT_WONT_INCREASE] = STRINGID_STATSWONTINCREASE, - [B_MSG_STAT_ROSE_EMPTY] = STRINGID_EMPTYSTRING3, - [B_MSG_STAT_ROSE_ITEM] = STRINGID_USINGITEMSTATOFPKMNROSE, - [B_MSG_USED_DIRE_HIT] = STRINGID_PKMNUSEDXTOGETPUMPED, + [B_MSG_ATTACKER_STAT_CHANGED] = STRINGID_ATTACKERSSTATROSE, + [B_MSG_DEFENDER_STAT_CHANGED] = STRINGID_DEFENDERSSTATROSE, + [B_MSG_STAT_WONT_CHANGE] = STRINGID_STATSWONTINCREASE, + [B_MSG_STAT_CHANGE_EMPTY] = STRINGID_EMPTYSTRING3, + [B_MSG_STAT_CHANGED_ITEM] = STRINGID_USINGITEMSTATOFPKMNROSE, + [B_MSG_USED_DIRE_HIT] = STRINGID_PKMNUSEDXTOGETPUMPED, }; const u16 gStatDownStringIds[] = { - [B_MSG_ATTACKER_STAT_FELL] = STRINGID_ATTACKERSSTATFELL, - [B_MSG_DEFENDER_STAT_FELL] = STRINGID_DEFENDERSSTATFELL, - [B_MSG_STAT_WONT_DECREASE] = STRINGID_STATSWONTDECREASE, - [B_MSG_STAT_FELL_EMPTY] = STRINGID_EMPTYSTRING3, + [B_MSG_ATTACKER_STAT_CHANGED] = STRINGID_ATTACKERSSTATFELL, + [B_MSG_DEFENDER_STAT_CHANGED] = STRINGID_DEFENDERSSTATFELL, + [B_MSG_STAT_WONT_CHANGE] = STRINGID_STATSWONTDECREASE, + [B_MSG_STAT_CHANGE_EMPTY] = STRINGID_EMPTYSTRING3, + [B_MSG_STAT_CHANGED_ITEM] = STRINGID_USINGITEMSTATOFPKMNFELL, }; // Index copied from move's index in sTrappingMoves @@ -1327,22 +1292,18 @@ const u16 gSafariPokeblockResultStringIds[] = [B_MSG_MON_IGNORED] = STRINGID_PKMNIGNOREDX }; -const u16 gBerryEffectStringIds[] = +const u16 CureStatusBerryEffectStringID[] = { + [B_MSG_CURED_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS, + [B_MSG_CURED_POISON] = STRINGID_PKMNSITEMCUREDPOISON, + [B_MSG_CURED_BURN] = STRINGID_PKMNSITEMHEALEDBURN, + [B_MSG_CURED_FREEEZE] = STRINGID_PKMNSITEMDEFROSTEDIT, + [B_MSG_CURED_FROSTBITE] = STRINGID_PKMNSITEMHEALEDFROSTBITE, + [B_MSG_CURED_SLEEP] = STRINGID_PKMNSITEMWOKEIT, [B_MSG_CURED_PROBLEM] = STRINGID_PKMNSITEMCUREDPROBLEM, [B_MSG_NORMALIZED_STATUS] = STRINGID_PKMNSITEMNORMALIZEDSTATUS }; -const u16 gStatusPreventionStringIds[] = -{ - [B_MSG_ABILITY_PREVENTS_MOVE_BURN] = STRINGID_PKMNSXPREVENTSBURNS, - [B_MSG_ABILITY_PREVENTS_MOVE_PARALYSIS] = STRINGID_PKMNPREVENTSPARALYSISWITH, - [B_MSG_ABILITY_PREVENTS_MOVE_POISON] = STRINGID_PKMNPREVENTSPOISONINGWITH, - [B_MSG_ABILITY_PREVENTS_ABILITY_STATUS] = STRINGID_PKMNSXPREVENTSYSZ, - [B_MSG_STATUS_HAD_NO_EFFECT] = STRINGID_PKMNSXHADNOEFFECTONY, - [B_MSG_ABILITY_PASTEL_VEIL] = STRINGID_PASTELVEILPROTECTED -}; - const u16 gItemSwapStringIds[] = { [B_MSG_ITEM_SWAP_TAKEN] = STRINGID_PKMNOBTAINEDX, @@ -1482,6 +1443,8 @@ static const u8 sText_TwoTrainersSentPkmn[] = _("{B_TRAINER1_NAME_WITH_CLASS} se static const u8 sText_Trainer2SentOutPkmn[] = _("{B_TRAINER2_NAME_WITH_CLASS} sent out {B_BUFF1}!"); static const u8 sText_TwoTrainersWantToBattle[] = _("You are challenged by {B_TRAINER1_NAME_WITH_CLASS} and {B_TRAINER2_NAME_WITH_CLASS}!\p"); static const u8 sText_InGamePartnerSentOutZGoN[] = _("{B_PARTNER_NAME_WITH_CLASS} sent out {B_PLAYER_MON2_NAME}! Go, {B_PLAYER_MON1_NAME}!"); +static const u8 sText_InGamePartnerSentOutPkmn2[] = _("{B_PARTNER_NAME_WITH_CLASS} sent out {B_PLAYER_MON2_NAME}!"); +static const u8 sText_InGamePartnerWithdrewPkmn2[] = _("{B_PARTNER_NAME_WITH_CLASS} withdrew {B_PLAYER_MON2_NAME}!"); const u16 gBattlePalaceFlavorTextTable[] = { @@ -2104,9 +2067,31 @@ void BufferStringBattle(enum StringID stringID, u32 battler) else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { if (gBattleTypeFlags & BATTLE_TYPE_RECORDED) - stringPtr = sText_TwoLinkTrainersWantToBattlePause; + { + if (TESTING && gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + stringPtr = sText_Trainer1WantsToBattle; + else + stringPtr = sText_TwoTrainersWantToBattle; + } + else if (TESTING && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + stringPtr = sText_TwoTrainersWantToBattle; + } + else if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + { + stringPtr = sText_LinkTrainerWantsToBattlePause; + } + else + { + stringPtr = sText_TwoLinkTrainersWantToBattlePause; + } + } else + { stringPtr = sText_TwoLinkTrainersWantToBattle; + } } else { @@ -2192,7 +2177,9 @@ void BufferStringBattle(enum StringID stringID, u32 battler) case STRINGID_RETURNMON: // sending poke to ball msg if (IsOnPlayerSide(battler)) { - if (*(&gBattleStruct->hpScale) == 0) + if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT) + stringPtr = sText_InGamePartnerWithdrewPkmn2; + else if (*(&gBattleStruct->hpScale) == 0) stringPtr = sText_PkmnThatsEnough; else if (*(&gBattleStruct->hpScale) == 1 || IsDoubleBattle()) stringPtr = sText_PkmnComeBack; @@ -2212,14 +2199,27 @@ void BufferStringBattle(enum StringID stringID, u32 battler) } else { - stringPtr = sText_Trainer1WithdrewPkmn; + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT) + stringPtr = sText_Trainer1WithdrewPkmn; + else + stringPtr = sText_Trainer2WithdrewPkmn; + + } + else + { + stringPtr = sText_Trainer1WithdrewPkmn; + } } } break; case STRINGID_SWITCHINMON: // switch-in msg if (IsOnPlayerSide(gBattleScripting.battler)) { - if (*(&gBattleStruct->hpScale) == 0 || IsDoubleBattle()) + if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) && (GetBattlerAtPosition(gBattleScripting.battler) == 2)) + stringPtr = sText_InGamePartnerSentOutPkmn2; + else if (*(&gBattleStruct->hpScale) == 0 || IsDoubleBattle()) stringPtr = sText_GoPkmn2; else if (*(&gBattleStruct->hpScale) == 1) stringPtr = sText_DoItPkmn; @@ -2241,12 +2241,39 @@ void BufferStringBattle(enum StringID stringID, u32 battler) } else { - if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (TESTING && gBattleTypeFlags & BATTLE_TYPE_MULTI) + { + if (gBattleScripting.battler == 1) + { + stringPtr = sText_Trainer1SentOutPkmn; + } + else + { + if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + stringPtr = sText_Trainer2SentOutPkmn; + else + stringPtr = sText_Trainer1SentOutPkmn2; + } + } + else if (TESTING && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + { + if (gBattleScripting.battler == 1) + stringPtr = sText_Trainer1SentOutPkmn; + else + stringPtr = sText_Trainer2SentOutPkmn; + } + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + { stringPtr = sText_LinkTrainerMultiSentOutPkmn; + } else if (TRAINER_BATTLE_PARAM.opponentA == TRAINER_UNION_ROOM) + { stringPtr = sText_Trainer1SentOutPkmn2; + } else + { stringPtr = sText_LinkTrainerSentOutPkmn2; + } } } else diff --git a/src/battle_pike.c b/src/battle_pike.c index 8f669ca06f..fa6bcc50cc 100644 --- a/src/battle_pike.c +++ b/src/battle_pike.c @@ -811,7 +811,7 @@ static void HealMon(struct Pokemon *mon) static bool8 DoesAbilityPreventStatus(struct Pokemon *mon, u32 status) { - u16 ability = GetMonAbility(mon); + enum Ability ability = GetMonAbility(mon); bool8 ret = FALSE; if (ability == ABILITY_COMATOSE) @@ -1623,7 +1623,7 @@ static bool8 CanEncounterWildMon(u8 enemyMonLevel) { if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) { - u16 monAbility = GetMonAbility(&gPlayerParty[0]); + enum Ability monAbility = GetMonAbility(&gPlayerParty[0]); if (monAbility == ABILITY_KEEN_EYE || monAbility == ABILITY_INTIMIDATE) { u8 playerMonLevel = GetMonData(&gPlayerParty[0], MON_DATA_LEVEL); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c old mode 100755 new mode 100644 index c9c5f6dec6..99847ba3f3 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1,5 +1,6 @@ #include "global.h" #include "battle.h" +#include "battle_hold_effects.h" #include "battle_message.h" #include "battle_anim.h" #include "battle_ai_main.h" @@ -53,7 +54,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_string_ids.h" #include "constants/battle_partner.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/item_effects.h" #include "constants/moves.h" @@ -67,8 +67,10 @@ #include "constants/pokemon.h" #include "config/battle.h" #include "data/battle_move_effects.h" +#include "test/battle.h" #include "follower_npc.h" #include "load_save.h" +#include "test/test_runner_battle.h" // table to avoid ugly powing on gba (courtesy of doesnt) // this returns (i^2.5)/4 @@ -308,8 +310,7 @@ enum GiveCaughtMonStates #define TAG_LVLUP_BANNER_MON_ICON 55130 -static void TrySetDestinyBondToHappen(void); -static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr); +static u32 ChangeStatBuffs(u32 battler, s8 statValue, enum Stat statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr); static bool32 IsMonGettingExpSentOut(void); static void InitLevelUpBanner(void); static bool8 SlideInLevelUpBanner(void); @@ -321,26 +322,27 @@ static void DrawLevelUpBannerText(void); static void SpriteCB_MonIconOnLvlUpBanner(struct Sprite *sprite); static bool32 CriticalCapture(u32 odds); static void BestowItem(u32 battlerAtk, u32 battlerDef); -static bool8 IsFinalStrikeEffect(enum BattleMoveEffects moveEffect); +static bool32 IsFinalStrikeEffect(enum MoveEffect moveEffect); static void TryUpdateRoundTurnOrder(void); static bool32 ChangeOrderTargetAfterAttacker(void); static bool32 SetTargetToNextPursuiter(u32 battlerDef); void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler); static void RemoveAllWeather(void); static void RemoveAllTerrains(void); -static bool32 CanAbilityPreventStatLoss(u32 abilityDef); +static bool32 CanAbilityPreventStatLoss(enum Ability abilityDef); static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent); static void TryUpdateEvolutionTracker(u32 evolutionCondition, u32 upAmount, u16 usedMove); static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move); static void ResetValuesForCalledMove(void); -static void TryRestoreDamageAfterCheekPouch(u32 battler); static bool32 TrySymbiosis(u32 battler, u32 itemId, bool32 moveEnd); static bool32 CanAbilityShieldActivateForBattler(u32 battler); +static void TryClearChargeVolatile(u32 moveType); +static bool32 IsAnyTargetAffected(void); static void Cmd_attackcanceler(void); static void Cmd_accuracycheck(void); -static void Cmd_attackstring(void); -static void Cmd_ppreduce(void); +static void Cmd_printattackstring(void); +static void Cmd_unused_0x3(void); static void Cmd_critcalc(void); static void Cmd_damagecalc(void); static void Cmd_typecalc(void); @@ -396,7 +398,7 @@ static void Cmd_bichalfword(void); static void Cmd_bicword(void); static void Cmd_pause(void); static void Cmd_waitstate(void); -static void Cmd_absorb(void); +static void Cmd_isdmgblockedbydisguise(void); static void Cmd_return(void); static void Cmd_end(void); static void Cmd_end2(void); @@ -455,25 +457,25 @@ static void Cmd_jumpifplayerran(void); static void Cmd_hpthresholds(void); static void Cmd_hpthresholds2(void); static void Cmd_useitemonopponent(void); -static void Cmd_various(void); +static void Cmd_unused_0x78(void); static void Cmd_setprotectlike(void); static void Cmd_tryexplosion(void); static void Cmd_setatkhptozero(void); static void Cmd_jumpifnexttargetvalid(void); static void Cmd_tryhealhalfhealth(void); -static void Cmd_trymirrormove(void); +static void Cmd_unused_0x7e(void); static void Cmd_setfieldweather(void); static void Cmd_setreflect(void); static void Cmd_setseeded(void); static void Cmd_manipulatedamage(void); static void Cmd_trysetrest(void); -static void Cmd_jumpifnotfirstturn(void); +static void Cmd_unused_0x82(void); static void Cmd_unused_0x83(void); static void Cmd_jumpifuproarwakes(void); static void Cmd_stockpile(void); static void Cmd_stockpiletobasedamage(void); static void Cmd_stockpiletohpheal(void); -static void Cmd_setdrainedhp(void); +static void Cmd_unused_0x88(void); static void Cmd_statbuffchange(void); static void Cmd_normalisebuffs(void); static void Cmd_setbide(void); @@ -495,7 +497,7 @@ static void Cmd_setfocusenergy(void); static void Cmd_transformdataexecution(void); static void Cmd_setsubstitute(void); static void Cmd_mimicattackcopy(void); -static void Cmd_metronome(void); +static void Cmd_setcalledmove(void); static void Cmd_unused_0x9f(void); static void Cmd_unused_0xA0(void); static void Cmd_counterdamagecalculator(void); @@ -506,9 +508,9 @@ static void Cmd_painsplitdmgcalc(void); static void Cmd_settypetorandomresistance(void); static void Cmd_setalwayshitflag(void); static void Cmd_copymovepermanently(void); -static void Cmd_trychoosesleeptalkmove(void); -static void Cmd_trysetdestinybond(void); -static void Cmd_trysetdestinybondtohappen(void); +static void Cmd_unused_0xA9(void); +static void Cmd_unused_AA(void); +static void Cmd_unused_0xab(void); static void Cmd_settailwind(void); static void Cmd_tryspiteppreduce(void); static void Cmd_healpartystatus(void); @@ -524,7 +526,7 @@ static void Cmd_presentdamagecalculation(void); static void Cmd_setsafeguard(void); static void Cmd_magnitudedamagecalculation(void); static void Cmd_jumpifnopursuitswitchdmg(void); -static void Cmd_tryrestorehpberry(void); +static void Cmd_tryactivateitem(void); static void Cmd_halvehp(void); static void Cmd_copyfoestats(void); static void Cmd_rapidspinfree(void); @@ -532,7 +534,7 @@ static void Cmd_unused_0xBF(void); static void Cmd_recoverbasedonsunlight(void); static void Cmd_setstickyweb(void); static void Cmd_selectfirstvalidtarget(void); -static void Cmd_trysetfutureattack(void); +static void Cmd_setfutureattack(void); static void Cmd_trydobeatup(void); static void Cmd_setsemiinvulnerablebit(void); static void Cmd_tryfiretwoturnmovenowbyeffect(void); @@ -540,8 +542,8 @@ static void Cmd_unused_0xC7(void); static void Cmd_unused_c8(void); static void Cmd_trymemento(void); static void Cmd_setforcedtarget(void); -static void Cmd_setcharge(void); -static void Cmd_callenvironmentattack(void); +static void Cmd_unused_0xcb(void); +static void Cmd_unused_0xCC(void); static void Cmd_curestatuswithmove(void); static void Cmd_settorment(void); static void Cmd_jumpifnodamage(void); @@ -559,13 +561,13 @@ static void Cmd_tryswapabilities(void); static void Cmd_tryimprison(void); static void Cmd_setstealthrock(void); static void Cmd_trysetvolatile(void); -static void Cmd_assistattackselect(void); +static void Cmd_unused_0xde(void); static void Cmd_trysetmagiccoat(void); static void Cmd_trysetsnatch(void); static void Cmd_unused2(void); static void Cmd_switchoutabilities(void); static void Cmd_jumpifhasnohp(void); -static void Cmd_jumpifnotcurrentmoveargtype(void); +static void Cmd_unused_0xE4(void); static void Cmd_pickup(void); static void Cmd_unused_0xE6(void); static void Cmd_unused_0xE7(void); @@ -581,7 +583,7 @@ static void Cmd_givecaughtmon(void); static void Cmd_trysetcaughtmondexflags(void); static void Cmd_displaydexinfo(void); static void Cmd_trygivecaughtmonnick(void); -static void Cmd_subattackerhpbydmg(void); +static void Cmd_unused_0xf4(void); static void Cmd_removeattackerstatus1(void); static void Cmd_finishaction(void); static void Cmd_finishturn(void); @@ -591,15 +593,15 @@ static void Cmd_swapstatstages(void); static void Cmd_averagestats(void); static void Cmd_jumpifcaptivateaffected(void); static void Cmd_setnonvolatilestatus(void); -static void Cmd_tryworryseed(void); +static void Cmd_tryoverwriteability(void); static void Cmd_callnative(void); void (*const gBattleScriptingCommandsTable[])(void) = { Cmd_attackcanceler, //0x0 Cmd_accuracycheck, //0x1 - Cmd_attackstring, //0x2 - Cmd_ppreduce, //0x3 + Cmd_printattackstring, //0x2 + Cmd_unused_0x3, //0x3 Cmd_critcalc, //0x4 Cmd_damagecalc, //0x5 Cmd_typecalc, //0x6 @@ -655,7 +657,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_bicword, //0x38 Cmd_pause, //0x39 Cmd_waitstate, //0x3A - Cmd_absorb, //0x3B + Cmd_isdmgblockedbydisguise, //0x3B Cmd_return, //0x3C Cmd_end, //0x3D Cmd_end2, //0x3E @@ -714,25 +716,25 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_hpthresholds, //0x73 Cmd_hpthresholds2, //0x74 Cmd_useitemonopponent, //0x75 - Cmd_various, //0x76 + Cmd_unused_0x78, //0x76 Cmd_setprotectlike, //0x77 Cmd_tryexplosion, //0x78 Cmd_setatkhptozero, //0x79 Cmd_jumpifnexttargetvalid, //0x7A Cmd_tryhealhalfhealth, //0x7B - Cmd_trymirrormove, //0x7C + Cmd_unused_0x7e, //0x7C Cmd_setfieldweather, //0x7D Cmd_setreflect, //0x7E Cmd_setseeded, //0x7F Cmd_manipulatedamage, //0x80 Cmd_trysetrest, //0x81 - Cmd_jumpifnotfirstturn, //0x82 + Cmd_unused_0x82, //0x82 Cmd_unused_0x83, //0x83 Cmd_jumpifuproarwakes, //0x84 Cmd_stockpile, //0x85 Cmd_stockpiletobasedamage, //0x86 Cmd_stockpiletohpheal, //0x87 - Cmd_setdrainedhp, //0x88 + Cmd_unused_0x88, //0x88 Cmd_statbuffchange, //0x89 Cmd_normalisebuffs, //0x8A Cmd_setbide, //0x8B @@ -754,7 +756,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_transformdataexecution, //0x9B Cmd_setsubstitute, //0x9C Cmd_mimicattackcopy, //0x9D - Cmd_metronome, //0x9E + Cmd_setcalledmove, //0x9E Cmd_unused_0x9f, //0x9F Cmd_unused_0xA0, //0xA0 Cmd_counterdamagecalculator, //0xA1 @@ -765,9 +767,9 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_settypetorandomresistance, //0xA6 Cmd_setalwayshitflag, //0xA7 Cmd_copymovepermanently, //0xA8 - Cmd_trychoosesleeptalkmove, //0xA9 - Cmd_trysetdestinybond, //0xAA - Cmd_trysetdestinybondtohappen, //0xAB + Cmd_unused_0xA9, //0xA9 + Cmd_unused_AA, //0xAA + Cmd_unused_0xab, //0xAB Cmd_settailwind, //0xAC Cmd_tryspiteppreduce, //0xAD Cmd_healpartystatus, //0xAE @@ -783,7 +785,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_setsafeguard, //0xB8 Cmd_magnitudedamagecalculation, //0xB9 Cmd_jumpifnopursuitswitchdmg, //0xBA - Cmd_tryrestorehpberry, //0xBB + Cmd_tryactivateitem, //0xBB Cmd_halvehp, //0xBC Cmd_copyfoestats, //0xBD Cmd_rapidspinfree, //0xBE @@ -791,7 +793,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_recoverbasedonsunlight, //0xC0 Cmd_setstickyweb, //0xC1 Cmd_selectfirstvalidtarget, //0xC2 - Cmd_trysetfutureattack, //0xC3 + Cmd_setfutureattack, //0xC3 Cmd_trydobeatup, //0xC4 Cmd_setsemiinvulnerablebit, //0xC5 Cmd_tryfiretwoturnmovenowbyeffect, //0xC6 @@ -799,8 +801,8 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_unused_c8, //0xC8 Cmd_trymemento, //0xC9 Cmd_setforcedtarget, //0xCA - Cmd_setcharge, //0xCB - Cmd_callenvironmentattack, //0xCC + Cmd_unused_0xcb, //0xCB + Cmd_unused_0xCC, //0xCC Cmd_curestatuswithmove, //0xCD Cmd_settorment, //0xCE Cmd_jumpifnodamage, //0xCF @@ -818,13 +820,13 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_tryimprison, //0xDB Cmd_setstealthrock, //0xDC Cmd_trysetvolatile, //0xDD - Cmd_assistattackselect, //0xDE + Cmd_unused_0xde, //0xDE Cmd_trysetmagiccoat, //0xDF Cmd_trysetsnatch, //0xE0 Cmd_unused2, //0xE1 Cmd_switchoutabilities, //0xE2 Cmd_jumpifhasnohp, //0xE3 - Cmd_jumpifnotcurrentmoveargtype, //0xE4 + Cmd_unused_0xE4, //0xE4 Cmd_pickup, //0xE5 Cmd_unused_0xE6, //0xE6 Cmd_unused_0xE7, //0xE7 @@ -840,7 +842,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_trysetcaughtmondexflags, //0xF1 Cmd_displaydexinfo, //0xF2 Cmd_trygivecaughtmonnick, //0xF3 - Cmd_subattackerhpbydmg, //0xF4 + Cmd_unused_0xf4, //0xF4 Cmd_removeattackerstatus1, //0xF5 Cmd_finishaction, //0xF6 Cmd_finishturn, //0xF7 @@ -850,7 +852,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_averagestats, //0xFB Cmd_jumpifcaptivateaffected, //0xFC Cmd_setnonvolatilestatus, //0xFD - Cmd_tryworryseed, //0xFE + Cmd_tryoverwriteability, //0xFE Cmd_callnative, //0xFF }; @@ -915,15 +917,6 @@ static const struct SpriteTemplate sSpriteTemplate_MonIconOnLvlUpBanner = static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / 4, USHRT_MAX / 8}; -static const u16 sFinalStrikeOnlyEffects[] = -{ - MOVE_EFFECT_REMOVE_ARG_TYPE, - MOVE_EFFECT_REMOVE_STATUS, - MOVE_EFFECT_RECOIL_HP_25, - MOVE_EFFECT_PREVENT_ESCAPE, - MOVE_EFFECT_WRAP, -}; - #define _ 0 static const struct PickupItem sPickupTable[] = @@ -962,6 +955,24 @@ static const struct PickupItem sPickupTable[] = #undef _ +static void ValidateSavedBattlerCounts(void) +{ + if (gBattleStruct->savedAttackerCount > 0) + { + if (TESTING) + Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!", __FILE__, __LINE__); + else + DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!"); + } + if (gBattleStruct->savedTargetCount > 0) + { + if (TESTING) + Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!", __FILE__, __LINE__); + else + DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!"); + } +} + static bool32 NoTargetPresent(u8 battler, u32 move) { if (!IsBattlerAlive(gBattlerTarget)) @@ -988,7 +999,7 @@ static bool32 NoTargetPresent(u8 battler, u32 move) return FALSE; } -bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType) +bool32 ProteanTryChangeType(u32 battler, enum Ability ability, u32 move, enum Type moveType) { if ((ability == ABILITY_PROTEAN || ability == ABILITY_LIBERO) && !gDisableStructs[gBattlerAttacker].usedProteanLibero @@ -1008,6 +1019,33 @@ bool32 IsMoveNotAllowedInSkyBattles(u32 move) return (gBattleStruct->isSkyBattle && IsMoveSkyBattleBanned(gCurrentMove)); } +static void TryClearChargeVolatile(u32 moveType) +{ + if (B_CHARGE < GEN_9) // Prior to gen9, charge is cleared during the end turn + return; + + if (gBattleMons[gBattlerAttacker].volatiles.chargeTimer == 2) // Has been set this turn by move + gBattleMons[gBattlerAttacker].volatiles.chargeTimer--; + else if (moveType == TYPE_ELECTRIC && gBattleMons[gBattlerAttacker].volatiles.chargeTimer == 1) + gBattleMons[gBattlerAttacker].volatiles.chargeTimer = 0; +} + +static bool32 IsAnyTargetAffected(void) +{ + if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + return FALSE; + + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (battler == gBattlerAttacker) + continue; + + if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT)) + return TRUE; + } + return FALSE; +} + u32 NumAffectedSpreadMoveTargets(void) { u32 targetCount = 0; @@ -1040,11 +1078,11 @@ u32 NumFaintedBattlersByAttacker(u32 battlerAtk) return numMonsFainted; } -bool32 IsPowderMoveBlocked(u32 battlerAtk, u32 battlerDef, u32 move) +bool32 IsPowderMoveBlocked(struct BattleContext *ctx) { - if (!IsPowderMove(move) - || battlerAtk == battlerDef - || IsAffectedByPowderMove(battlerDef, GetBattlerAbility(battlerDef), GetBattlerHoldEffect(battlerDef, TRUE))) + if (!IsPowderMove(ctx->currentMove) + || ctx->battlerAtk == ctx->battlerDef + || IsAffectedByPowderMove(ctx->battlerDef, ctx->abilities[ctx->battlerDef], GetBattlerHoldEffect(ctx->battlerDef))) return FALSE; gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; @@ -1053,13 +1091,12 @@ bool32 IsPowderMoveBlocked(u32 battlerAtk, u32 battlerDef, u32 move) bool32 EmergencyExitCanBeTriggered(u32 battler) { - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); if (ability != ABILITY_EMERGENCY_EXIT && ability != ABILITY_WIMP_OUT) return FALSE; - if (IsBattlerTurnDamaged(battler) - && IsBattlerAlive(battler) + if (IsBattlerAlive(battler) && HadMoreThanHalfHpNowDoesnt(battler) && (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) && !(gBattleTypeFlags & BATTLE_TYPE_ARENA) @@ -1095,22 +1132,31 @@ static void Cmd_attackcanceler(void) return; } - enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove); + struct BattleContext ctx = {0}; + ctx.battlerAtk = gBattlerAttacker; + ctx.battlerDef = gBattlerTarget; + ctx.currentMove = gCurrentMove; + + enum BattleMoveEffects moveEffect = GetMoveEffect(ctx.currentMove); if (!IsBattlerAlive(gBattlerAttacker) - && effect != EFFECT_EXPLOSION - && effect != EFFECT_MISTY_EXPLOSION - && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + && moveEffect != EFFECT_EXPLOSION + && moveEffect != EFFECT_MISTY_EXPLOSION) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveEnd; return; } - if (AtkCanceler_MoveSuccessOrder() != MOVE_STEP_SUCCESS) + + // With how attackcanceler works right now we only need attacker and target abilities. Might change in the future + ctx.abilities[ctx.battlerAtk] = GetBattlerAbility(ctx.battlerAtk); + ctx.abilities[ctx.battlerDef] = GetBattlerAbility(ctx.battlerDef); + + if (AtkCanceler_MoveSuccessOrder(&ctx) != MOVE_STEP_SUCCESS) return; if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF - && GetBattlerAbility(gBattlerAttacker) == ABILITY_PARENTAL_BOND + && ctx.abilities[ctx.battlerAtk] == ABILITY_PARENTAL_BOND && IsMoveAffectedByParentalBond(gCurrentMove, gBattlerAttacker) && !(gAbsentBattlerFlags & (1u << gBattlerTarget)) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE) @@ -1121,56 +1167,43 @@ static void Cmd_attackcanceler(void) return; } - - u32 abilityDef = GetBattlerAbility(gBattlerTarget); if (CanAbilityBlockMove( - gBattlerAttacker, - gBattlerTarget, - GetBattlerAbility(gBattlerAttacker), - abilityDef, - gCurrentMove, + ctx.battlerAtk, + ctx.battlerDef, + ctx.abilities[ctx.battlerAtk], + ctx.abilities[ctx.battlerDef], + ctx.currentMove, RUN_SCRIPT)) return; - if (GetMoveNonVolatileStatus(gCurrentMove) == MOVE_EFFECT_PARALYSIS) + if (GetMoveNonVolatileStatus(ctx.currentMove) == MOVE_EFFECT_PARALYSIS) { if (CanAbilityAbsorbMove( - gBattlerAttacker, - gBattlerTarget, - abilityDef, - gCurrentMove, - GetBattleMoveType(gCurrentMove), + ctx.battlerAtk, + ctx.battlerDef, + ctx.abilities[ctx.battlerDef], + ctx.currentMove, + GetBattleMoveType(ctx.currentMove), RUN_SCRIPT)) return; } - if (IsPowderMoveBlocked(gBattlerAttacker, gBattlerTarget, gCurrentMove)) + if (IsPowderMoveBlocked(&ctx)) return; - if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE - && !(gHitMarker & (HITMARKER_ALLOW_NO_PP | HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT)) - && !(gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) - { - gBattlescriptCurrInstr = BattleScript_NoPPForMove; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - return; - } - - gHitMarker &= ~HITMARKER_ALLOW_NO_PP; - // Check if no available target present on the field or if Sky Battles ban the move if ((NoTargetPresent(gBattlerAttacker, gCurrentMove) - && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) + && (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) || (IsMoveNotAllowedInSkyBattles(gCurrentMove))) { gBattleStruct->noTargetPresent = TRUE; - if (effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. + if (moveEffect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem; else - gBattlescriptCurrInstr = BattleScript_FailedFromAtkString; + gBattlescriptCurrInstr = BattleScript_ButItFailed; - if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) + if (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); return; } @@ -1203,7 +1236,6 @@ static void Cmd_attackcanceler(void) // Edge case for bouncing a powder move against a grass type pokemon. ClearDamageCalcResults(); - SetAtkCancelerForCalledMove(); gEffectBattler = gBattlerTarget; if (BlocksPrankster(gCurrentMove, gBattlerTarget, gBattlerAttacker, TRUE)) { @@ -1221,7 +1253,7 @@ static void Cmd_attackcanceler(void) { u32 battler = gBattlerTarget; - if (abilityDef == ABILITY_MAGIC_BOUNCE) + if (ctx.abilities[ctx.battlerDef] == ABILITY_MAGIC_BOUNCE) { battler = gBattlerTarget; gBattleStruct->bouncedMoveIsUsed = TRUE; @@ -1237,7 +1269,6 @@ static void Cmd_attackcanceler(void) if (gBattleStruct->bouncedMoveIsUsed) { ClearDamageCalcResults(); - SetAtkCancelerForCalledMove(); // Edge case for bouncing a powder move against a grass type pokemon. BattleScriptCall(BattleScript_MagicBounce); gBattlerAbility = battler; return; @@ -1267,28 +1298,17 @@ static void Cmd_attackcanceler(void) } } - if (gSpecialStatuses[gBattlerTarget].lightningRodRedirected) + if (gSpecialStatuses[gBattlerTarget].abilityRedirected) { - gSpecialStatuses[gBattlerTarget].lightningRodRedirected = FALSE; - gLastUsedAbility = ABILITY_LIGHTNING_ROD; + gSpecialStatuses[gBattlerTarget].abilityRedirected = FALSE; BattleScriptCall(BattleScript_TookAttack); - RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); - } - else if (gSpecialStatuses[gBattlerTarget].stormDrainRedirected) - { - gSpecialStatuses[gBattlerTarget].stormDrainRedirected = FALSE; - gLastUsedAbility = ABILITY_STORM_DRAIN; - BattleScriptCall(BattleScript_TookAttack); - RecordAbilityBattle(gBattlerTarget, gLastUsedAbility); } else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) - && (effect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) - && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) - && effect != EFFECT_SUCKER_PUNCH - && effect != EFFECT_COUNTER - && effect != EFFECT_UPPER_HAND) + && (moveEffect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) + && (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) + && moveEffect != EFFECT_COUNTER) { - if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove)) + if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove)) gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; @@ -1305,7 +1325,7 @@ static void Cmd_attackcanceler(void) gBattlescriptCurrInstr = cmd->nextInstr; } else if (IsBattlerUsingBeakBlast(gBattlerTarget) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove)) { gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; @@ -1327,8 +1347,6 @@ static void JumpIfMoveFailed(u32 adder, u32 move, u32 moveType, const u8 *failIn } else { - TrySetDestinyBondToHappen(); - if (CanAbilityAbsorbMove(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), @@ -1371,14 +1389,12 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u if (move == ACC_CURR_MOVE) move = gCurrentMove; - enum BattleMoveEffects effect = GetMoveEffect(move); - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); - enum ItemHoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - if (move == NO_ACC_CALC_CHECK_LOCK_ON) { if (gBattleMons[gBattlerTarget].volatiles.lockOn && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker) + { gBattlescriptCurrInstr = nextInstr; + } else if (IsSemiInvulnerable(gBattlerTarget, CHECK_ALL)) { if (gBattlerTarget != BATTLE_PARTNER(gBattlerAttacker)) @@ -1397,7 +1413,10 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u gBattlescriptCurrInstr = failInstr; } else + { gBattlescriptCurrInstr = nextInstr; + } + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX) { if (gProtectStructs[gBattlerTarget].protected == PROTECT_MAX_GUARD) @@ -1410,8 +1429,14 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u GetBattleMoveType(gCurrentMove), RUN_SCRIPT); } + return; } - else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT + + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); + enum HoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); + enum BattleMoveEffects effect = GetMoveEffect(move); + + if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT || (gSpecialStatuses[gBattlerAttacker].multiHitOn && (abilityAtk == ABILITY_SKILL_LINK || holdEffectAtk == HOLD_EFFECT_LOADED_DICE || !(effect == EFFECT_TRIPLE_KICK || effect == EFFECT_POPULATION_BOMB)))) @@ -1439,12 +1464,12 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u continue; numTargets++; - u32 abilityDef = GetBattlerAbility(battlerDef); + enum Ability abilityDef = GetBattlerAbility(battlerDef); if (JumpIfMoveAffectedByProtect(move, battlerDef, FALSE, failInstr) || CanMoveSkipAccuracyCalc(gBattlerAttacker, battlerDef, abilityAtk, abilityDef, move, RUN_SCRIPT)) continue; - u32 holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); + u32 holdEffectDef = GetBattlerHoldEffect(battlerDef); u32 accuracy = GetTotalAccuracy(gBattlerAttacker, battlerDef, move, @@ -1481,6 +1506,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u ctx.battlerAtk = gBattlerAttacker; ctx.battlerDef = battlerDef; ctx.move = move; + ctx.chosenMove = gChosenMove; ctx.moveType = moveType; ctx.updateFlags = TRUE; ctx.abilityAtk = abilityAtk; @@ -1516,76 +1542,20 @@ static void Cmd_accuracycheck(void) AccuracyCheck(FALSE, cmd->nextInstr, cmd->failInstr, cmd->move); } -static void Cmd_attackstring(void) +static void Cmd_printattackstring(void) { CMD_ARGS(); if (gBattleControllerExecFlags) return; - if (!(gHitMarker & (HITMARKER_NO_ATTACKSTRING | HITMARKER_ATTACKSTRING_PRINTED))) - { - PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker); - gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; - } - gBattlescriptCurrInstr = cmd->nextInstr; + PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker); gBattleCommunication[MSG_DISPLAY] = 0; + gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_ppreduce(void) +static void Cmd_unused_0x3(void) { - CMD_ARGS(); - - s32 i, ppToDeduct = 1; - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - - if (gBattleControllerExecFlags) - return; - - if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns) - gHitMarker |= HITMARKER_NO_PPDEDUCT; - - if (moveTarget == MOVE_TARGET_BOTH - || moveTarget == MOVE_TARGET_FOES_AND_ALLY - || moveTarget == MOVE_TARGET_ALL_BATTLERS - || MoveForcesPressure(gCurrentMove)) - { - for (i = 0; i < gBattlersCount; i++) - { - if (!IsBattlerAlly(i, gBattlerAttacker) && IsBattlerAlive(i)) - ppToDeduct += (GetBattlerAbility(i) == ABILITY_PRESSURE); - } - } - else if (moveTarget != MOVE_TARGET_OPPONENTS_FIELD) - { - if (gBattlerAttacker != gBattlerTarget && GetBattlerAbility(gBattlerTarget) == ABILITY_PRESSURE) - ppToDeduct++; - } - - if (!(gHitMarker & (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING)) && gBattleMons[gBattlerAttacker].pp[gCurrMovePos]) - { - gProtectStructs[gBattlerAttacker].notFirstStrike = TRUE; - - // For item Metronome, echoed voice - if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] || WasUnableToUseMove(gBattlerAttacker)) - gBattleStruct->metronomeItemCounter[gBattlerAttacker] = 0; - - if (gBattleMons[gBattlerAttacker].pp[gCurrMovePos] > ppToDeduct) - gBattleMons[gBattlerAttacker].pp[gCurrMovePos] -= ppToDeduct; - else - gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = 0; - - if (MOVE_IS_PERMANENT(gBattlerAttacker, gCurrMovePos)) - { - BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, REQUEST_PPMOVE1_BATTLE + gCurrMovePos, 0, - sizeof(gBattleMons[gBattlerAttacker].pp[gCurrMovePos]), - &gBattleMons[gBattlerAttacker].pp[gCurrMovePos]); - MarkBattlerForControllerExec(gBattlerAttacker); - } - } - - gHitMarker &= ~HITMARKER_NO_PPDEDUCT; - gBattlescriptCurrInstr = cmd->nextInstr; } // The chance is 1/N for each stage. @@ -1606,7 +1576,7 @@ static inline u32 GetCriticalHitOdds(u32 critChance) return sCriticalHitOdds[critChance]; } -static inline u32 IsBattlerLeekAffected(u32 battler, enum ItemHoldEffect holdEffect) +static inline u32 IsBattlerLeekAffected(u32 battler, enum HoldEffect holdEffect) { if (holdEffect == HOLD_EFFECT_LEEK) { @@ -1616,7 +1586,7 @@ static inline u32 IsBattlerLeekAffected(u32 battler, enum ItemHoldEffect holdEff return FALSE; } -static inline u32 GetHoldEffectCritChanceIncrease(u32 battler, enum ItemHoldEffect holdEffect) +static inline u32 GetHoldEffectCritChanceIncrease(u32 battler, enum HoldEffect holdEffect) { u32 critStageIncrease = 0; @@ -1641,7 +1611,7 @@ static inline u32 GetHoldEffectCritChanceIncrease(u32 battler, enum ItemHoldEffe return critStageIncrease; } -s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk) +s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk) { s32 critChance = 0; @@ -1690,7 +1660,7 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA // Threshold = Base Speed / 2 // High crit move = 8 * (Base Speed / 2) // Focus Energy = 4 * (Base Speed / 2) -s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, enum ItemHoldEffect holdEffectAtk) +s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, enum Ability abilityAtk, enum Ability abilityDef, enum HoldEffect holdEffectAtk) { s32 critChance = 0; s32 moveCritStage = GetMoveCriticalHitStage(gCurrentMove); @@ -1756,10 +1726,9 @@ static void Cmd_critcalc(void) u32 partySlot = gBattlerPartyIndexes[gBattlerAttacker], moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove), - abilityAtk = GetBattlerAbility(gBattlerAttacker), battlerDef; bool32 calcSpreadMoveDamage = IsSpreadMove(moveTarget) && !IsBattleMoveStatus(gCurrentMove); - enum ItemHoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); + enum HoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); gPotentialItemEffectBattler = gBattlerAttacker; for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) @@ -1775,7 +1744,8 @@ static void Cmd_critcalc(void) || gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT) continue; - u32 abilityDef = GetBattlerAbility(battlerDef); + enum Ability abilityDef = GetBattlerAbility(battlerDef); + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); if (GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_1) gBattleStruct->critChance[battlerDef] = CalcCritChanceStageGen1(gBattlerAttacker, battlerDef, gCurrentMove, TRUE, abilityAtk, abilityDef, holdEffectAtk); @@ -1837,6 +1807,7 @@ static void Cmd_damagecalc(void) struct DamageContext ctx = {0}; ctx.battlerAtk = gBattlerAttacker; ctx.move = gCurrentMove; + ctx.chosenMove = gChosenMove; ctx.moveType = GetBattleMoveType(gCurrentMove); ctx.randomFactor = TRUE; ctx.updateFlags = TRUE; @@ -1874,12 +1845,13 @@ static void Cmd_typecalc(void) ctx.battlerAtk = gBattlerAttacker; ctx.battlerDef = gBattlerTarget; ctx.move = gCurrentMove; + ctx.chosenMove = gChosenMove; ctx.moveType = GetBattleMoveType(gCurrentMove); ctx.updateFlags = TRUE; ctx.abilityAtk = GetBattlerAbility(gBattlerAttacker); ctx.abilityDef = GetBattlerAbility(gBattlerTarget); - ctx.holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - ctx.holdEffectDef = GetBattlerHoldEffect(gBattlerTarget, TRUE); + ctx.holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); + ctx.holdEffectDef = GetBattlerHoldEffect(gBattlerTarget); CalcTypeEffectivenessMultiplier(&ctx); } @@ -1891,7 +1863,7 @@ static void Cmd_adjustdamage(void) { CMD_ARGS(); - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; u8 param; u32 battlerDef; u32 rand = Random() % 100; @@ -1937,7 +1909,7 @@ static void Cmd_adjustdamage(void) if (gBattleMons[battlerDef].hp > gBattleStruct->moveDamage[battlerDef]) continue; - holdEffect = GetBattlerHoldEffect(battlerDef, TRUE); + holdEffect = GetBattlerHoldEffect(battlerDef); param = GetBattlerHoldEffectParam(battlerDef); affectionScore = GetBattlerAffectionHearts(battlerDef); @@ -2039,7 +2011,7 @@ static void Cmd_multihitresultmessage(void) static inline bool32 DoesBattlerNegateDamage(u32 battler) { u32 species = gBattleMons[battler].species; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); if (gBattleMons[battler].volatiles.transformed) return FALSE; @@ -2285,8 +2257,7 @@ static void Cmd_waitanimation(void) static void DoublesHPBarReduction(void) { - if (gBattleStruct->doneDoublesSpreadHit - || gHitMarker & (HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_HP_UPDATE)) + if (gBattleStruct->doneDoublesSpreadHit) return; for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) @@ -2298,12 +2269,10 @@ static void DoublesHPBarReduction(void) || DoesDisguiseBlockMove(battlerDef, gCurrentMove)) continue; - s32 currDmg = gBattleStruct->moveDamage[battlerDef]; - s32 healthValue = min(currDmg, 10000); // Max damage (10000) not present in R/S, ensures that huge damage values don't change sign - BtlController_EmitHealthBarUpdate(battlerDef, B_COMM_TO_CONTROLLER, healthValue); + s32 dmgUpdate = min(gBattleStruct->moveDamage[battlerDef], 10000); + BtlController_EmitHealthBarUpdate(battlerDef, B_COMM_TO_CONTROLLER, dmgUpdate); MarkBattlerForControllerExec(battlerDef); - - if (IsOnPlayerSide(battlerDef) && currDmg > 0) + if (IsOnPlayerSide(battlerDef) && dmgUpdate > 0) gBattleResults.playerMonWasDamaged = TRUE; } @@ -2312,185 +2281,201 @@ static void DoublesHPBarReduction(void) static void Cmd_healthbarupdate(void) { - CMD_ARGS(u8 battler); + CMD_ARGS(u8 battler, u8 updateState); u32 battler = GetBattlerForBattleScript(cmd->battler); if (gBattleControllerExecFlags) return; - if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) || (gHitMarker & HITMARKER_PASSIVE_HP_UPDATE)) + switch (cmd->updateState) { - if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && gDisableStructs[battler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) + case PASSIVE_HP_UPDATE: + BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, min(gBattleStruct->passiveHpUpdate[battler], 10000)); + MarkBattlerForControllerExec(battler); + break; + case MOVE_DAMAGE_HP_UPDATE: + if (IsDoubleSpreadMove()) + { + DoublesHPBarReduction(); + if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)) + PrepareStringBattle(STRINGID_SUBSTITUTEDAMAGED, battler); + } + else if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)) { PrepareStringBattle(STRINGID_SUBSTITUTEDAMAGED, battler); - if (IsDoubleSpreadMove()) - DoublesHPBarReduction(); } - else if (!DoesDisguiseBlockMove(battler, gCurrentMove)) + else if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) + && !DoesDisguiseBlockMove(battler, gCurrentMove)) { - if (IsDoubleSpreadMove()) - { - DoublesHPBarReduction(); - } - else - { - s16 healthValue = min(gBattleStruct->moveDamage[battler], 10000); // Max damage (10000) not present in R/S, ensures that huge damage values don't change sign - - BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, healthValue); - MarkBattlerForControllerExec(battler); - - if (IsOnPlayerSide(battler) && gBattleStruct->moveDamage[battler] > 0) - gBattleResults.playerMonWasDamaged = TRUE; - } + s32 damage = min(gBattleStruct->moveDamage[battler], 10000); + BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, damage); + MarkBattlerForControllerExec(battler); + if (IsOnPlayerSide(battler) && damage > 0) + gBattleResults.playerMonWasDamaged = TRUE; } - } - else if (IsDoubleSpreadMove()) - { - DoublesHPBarReduction(); + break; } gBattlescriptCurrInstr = cmd->nextInstr; } -// Update the active battler's HP and various HP trackers (Substitute, Bide, etc.) +static void PassiveDataHpUpdate(u32 battler, const u8 *nextInstr) +{ + if (gBattleStruct->passiveHpUpdate[battler] < 0) + { + // Negative damage is HP gain + gBattleMons[battler].hp += -gBattleStruct->passiveHpUpdate[battler]; + if (gBattleMons[battler].hp > gBattleMons[battler].maxHP) + gBattleMons[battler].hp = gBattleMons[battler].maxHP; + } + else + { + if (gBattleMons[battler].hp > gBattleStruct->passiveHpUpdate[battler]) + gBattleMons[battler].hp -= gBattleStruct->passiveHpUpdate[battler]; + else + gBattleMons[battler].hp = 0; + } + + // Send updated HP + BtlController_EmitSetMonData( + battler, + B_COMM_TO_CONTROLLER, + REQUEST_HP_BATTLE, + 0, + sizeof(gBattleMons[battler].hp), &gBattleMons[battler].hp); + MarkBattlerForControllerExec(battler); + + gBattleStruct->passiveHpUpdate[battler] = 0; + gBattlescriptCurrInstr = nextInstr; +} + +static void MoveDamageDataHpUpdate(u32 battler, u32 scriptBattler, const u8 *nextInstr) +{ + if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) + { + gBattlescriptCurrInstr = nextInstr; + } + else if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && gDisableStructs[battler].substituteHP) + { + if (gDisableStructs[battler].substituteHP >= gBattleStruct->moveDamage[battler]) + { + gDisableStructs[battler].substituteHP -= gBattleStruct->moveDamage[battler]; + } + else + { + gBattleStruct->moveDamage[battler] = gDisableStructs[battler].substituteHP; + gDisableStructs[battler].substituteHP = 0; + } + // check substitute fading + if (gDisableStructs[battler].substituteHP == 0) + { + gBattlescriptCurrInstr = nextInstr; + BattleScriptCall(BattleScript_SubstituteFade); + return; + } + else + { + gBattlescriptCurrInstr = nextInstr; + return; + } + } + else if (DoesDisguiseBlockMove(battler, gCurrentMove)) + { + // TODO: Convert this to a proper FORM_CHANGE type. + gBattleScripting.battler = battler; + if (GetBattlerPartyState(battler)->changedSpecies == SPECIES_NONE) + GetBattlerPartyState(battler)->changedSpecies = gBattleMons[battler].species; + if (gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) + gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED_TOTEM; + else + gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED; + if (GetGenConfig(GEN_CONFIG_DISGUISE_HP_LOSS) >= GEN_8) + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); + BattleScriptPush(nextInstr); + gBattlescriptCurrInstr = BattleScript_TargetFormChange; + } + else + { + if (gBattleStruct->moveDamage[battler] < 0) + { + // Negative damage is HP gain + gBattleMons[battler].hp += -gBattleStruct->moveDamage[battler]; + if (gBattleMons[battler].hp > gBattleMons[battler].maxHP) + gBattleMons[battler].hp = gBattleMons[battler].maxHP; + } + else + { + gBideDmg[battler] += gBattleStruct->moveDamage[battler]; + if (scriptBattler == BS_TARGET) + gBideTarget[battler] = gBattlerAttacker; + else + gBideTarget[battler] = gBattlerTarget; + + // Deal damage to the battler + if (gBattleMons[battler].hp > gBattleStruct->moveDamage[battler]) + { + gBattleMons[battler].hp -= gBattleStruct->moveDamage[battler]; + } + else + { + gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp; + gBattleMons[battler].hp = 0; + } + + // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are + // used in combination as general damage trackers for other purposes. specialDmg is additionally used + // to help determine if a fire move should defrost the target. + if (IsBattleMovePhysical(gCurrentMove)) + { + gProtectStructs[battler].physicalDmg = gBattleStruct->moveDamage[battler]; + gSpecialStatuses[battler].physicalDmg = gBattleStruct->moveDamage[battler]; + if (scriptBattler == BS_TARGET) // What's the point of this??? It will be always target + gProtectStructs[battler].physicalBattlerId = gBattlerAttacker; + else + gProtectStructs[battler].physicalBattlerId = gBattlerTarget; + gProtectStructs[battler].assuranceDoubled = TRUE; + } + else // Physical move + { + gProtectStructs[battler].specialDmg = gBattleStruct->moveDamage[battler]; + gSpecialStatuses[battler].specialDmg = gBattleStruct->moveDamage[battler]; + if (scriptBattler == BS_TARGET) // What's the point of this??? It will be always target + gProtectStructs[battler].specialBattlerId = gBattlerAttacker; + else + gProtectStructs[battler].specialBattlerId = gBattlerTarget; + gProtectStructs[battler].assuranceDoubled = TRUE; + } + } + // Send updated HP + BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HP_BATTLE, 0, sizeof(gBattleMons[battler].hp), &gBattleMons[battler].hp); + MarkBattlerForControllerExec(battler); + gBattlescriptCurrInstr = nextInstr; + } + + if (IsBattlerTurnDamaged(gBattlerTarget) && GetMoveCategory(gCurrentMove) != DAMAGE_CATEGORY_STATUS) + GetBattlerPartyState(battler)->timesGotHit++; +} + static void Cmd_datahpupdate(void) { - CMD_ARGS(u8 battler); - bool32 isPassiveHpUpdate = gHitMarker & HITMARKER_PASSIVE_HP_UPDATE; - bool32 disguiseActivates = FALSE; + CMD_ARGS(u8 battler, u8 updateState); + u32 battler = GetBattlerForBattleScript(cmd->battler); if (gBattleControllerExecFlags) return; - u32 battler = GetBattlerForBattleScript(cmd->battler); - - if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) || (gHitMarker & HITMARKER_PASSIVE_HP_UPDATE)) + switch (cmd->updateState) { - if (DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && gDisableStructs[battler].substituteHP && !(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE)) - { - if (gDisableStructs[battler].substituteHP >= gBattleStruct->moveDamage[battler]) - { - gDisableStructs[battler].substituteHP -= gBattleStruct->moveDamage[battler]; - } - else - { - gBattleStruct->moveDamage[battler] = gDisableStructs[battler].substituteHP; - gDisableStructs[battler].substituteHP = 0; - } - // check substitute fading - if (gDisableStructs[battler].substituteHP == 0) - { - gBattlescriptCurrInstr = cmd->nextInstr; - BattleScriptCall(BattleScript_SubstituteFade); - return; - } - } - else if (DoesDisguiseBlockMove(battler, gCurrentMove)) - { - // TODO: Convert this to a proper FORM_CHANGE type. - gBattleScripting.battler = battler; - if (GetBattlerPartyState(battler)->changedSpecies == SPECIES_NONE) - GetBattlerPartyState(battler)->changedSpecies = gBattleMons[battler].species; - if (gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) - gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED_TOTEM; - else - gBattleMons[battler].species = SPECIES_MIMIKYU_BUSTED; - if (GetGenConfig(GEN_CONFIG_DISGUISE_HP_LOSS) >= GEN_8) - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - BattleScriptPush(cmd->nextInstr); - gBattlescriptCurrInstr = BattleScript_TargetFormChange; - disguiseActivates = TRUE; - } - else - { - gHitMarker &= ~HITMARKER_IGNORE_SUBSTITUTE; - if (gBattleStruct->moveDamage[battler] < 0) - { - // Negative damage is HP gain - gBattleMons[battler].hp += -gBattleStruct->moveDamage[battler]; - if (gBattleMons[battler].hp > gBattleMons[battler].maxHP) - gBattleMons[battler].hp = gBattleMons[battler].maxHP; - } - else - { - if (gHitMarker & HITMARKER_IGNORE_BIDE) - { - gHitMarker &= ~HITMARKER_IGNORE_BIDE; - } - else - { - gBideDmg[battler] += gBattleStruct->moveDamage[battler]; - if (cmd->battler == BS_TARGET) - gBideTarget[battler] = gBattlerAttacker; - else - gBideTarget[battler] = gBattlerTarget; - } - - // Deal damage to the battler - if (gBattleMons[battler].hp > gBattleStruct->moveDamage[battler]) - { - gBattleMons[battler].hp -= gBattleStruct->moveDamage[battler]; - } - else - { - gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp; - gBattleMons[battler].hp = 0; - } - - enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove); - - // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are - // used in combination as general damage trackers for other purposes. specialDmg is additionally used - // to help determine if a fire move should defrost the target. - if (IsBattleMovePhysical(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_HP_UPDATE) && effect != EFFECT_PAIN_SPLIT) - { - gProtectStructs[battler].physicalDmg = gBattleStruct->moveDamage[battler]; - gSpecialStatuses[battler].physicalDmg = gBattleStruct->moveDamage[battler]; - if (cmd->battler == BS_TARGET) - gProtectStructs[battler].physicalBattlerId = gBattlerAttacker; - else - gProtectStructs[battler].physicalBattlerId = gBattlerTarget; - gProtectStructs[battler].assuranceDoubled = TRUE; - } - else if (!IsBattleMovePhysical(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_HP_UPDATE) && effect != EFFECT_PAIN_SPLIT) - { - // Record special damage/attacker for Mirror Coat - gProtectStructs[battler].specialDmg = gBattleStruct->moveDamage[battler]; - gSpecialStatuses[battler].specialDmg = gBattleStruct->moveDamage[battler]; - if (cmd->battler == BS_TARGET) - gProtectStructs[battler].specialBattlerId = gBattlerAttacker; - else - gProtectStructs[battler].specialBattlerId = gBattlerTarget; - gProtectStructs[battler].assuranceDoubled = TRUE; - } - } - gHitMarker &= ~HITMARKER_PASSIVE_HP_UPDATE; - // Send updated HP - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HP_BATTLE, 0, sizeof(gBattleMons[battler].hp), &gBattleMons[battler].hp); - MarkBattlerForControllerExec(battler); - } - - if (gBattlerAttacker != gBattlerTarget - && !isPassiveHpUpdate - && GetMoveCategory(gCurrentMove) != DAMAGE_CATEGORY_STATUS - && IsBattlerTurnDamaged(gBattlerTarget)) - GetBattlerPartyState(gBattlerTarget)->timesGotHit++; - - if (GetMoveEffect(gCurrentMove) == EFFECT_KNOCK_OFF - && !isPassiveHpUpdate - && IsBattlerTurnDamaged(gBattlerTarget) - && gBattleMons[gBattlerTarget].item != ITEM_NONE - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerTarget].item) - && !NoAliveMonsForEitherParty()) - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = TRUE; - - if (disguiseActivates) - return; + case PASSIVE_HP_UPDATE: + PassiveDataHpUpdate(battler, cmd->nextInstr); + break; + case MOVE_DAMAGE_HP_UPDATE: + MoveDamageDataHpUpdate(battler, cmd->battler, cmd->nextInstr); + break; } + if (gBattleMons[battler].hp > gBattleMons[battler].maxHP / 2) + gBattleStruct->battlerState[battler].wasAboveHalfHp = TRUE; - TryRestoreDamageAfterCheekPouch(battler); - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_critmessage(void) @@ -2909,10 +2894,10 @@ static inline bool32 TrySetReflect(u32 battler) if (!(gSideStatuses[side] & SIDE_STATUS_REFLECT)) { gSideStatuses[side] |= SIDE_STATUS_REFLECT; - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[side].reflectTimer = gBattleTurnCounter + 8; + if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[side].reflectTimer = 8; else - gSideTimers[side].reflectTimer = gBattleTurnCounter + 5; + gSideTimers[side].reflectTimer = 5; if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, battler) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_DOUBLE; @@ -2930,10 +2915,10 @@ static inline bool32 TrySetLightScreen(u32 battler) if (!(gSideStatuses[side] & SIDE_STATUS_LIGHTSCREEN)) { gSideStatuses[side] |= SIDE_STATUS_LIGHTSCREEN; - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[side].lightscreenTimer = gBattleTurnCounter + 8; + if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[side].lightscreenTimer = 8; else - gSideTimers[side].lightscreenTimer = gBattleTurnCounter + 5; + gSideTimers[side].lightscreenTimer = 5; if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, battler) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_DOUBLE; @@ -2945,7 +2930,7 @@ static inline bool32 TrySetLightScreen(u32 battler) return FALSE; } -static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, enum StatusTrigger trigger) +static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, const u8 *battleScript, enum StatusTrigger trigger) { gEffectBattler = effectBattler; @@ -2958,7 +2943,7 @@ static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, enum gBattlescriptCurrInstr = cancelMultiTurnMovesResult; } - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); switch (effect) { @@ -3020,9 +3005,11 @@ static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, enum } // To avoid confusion the arguments are naned battler/effectBattler since they can be different from gBattlerAttacker/gBattlerTarget -void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certain) +void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags) { s32 i; + bool32 primary = effectFlags & EFFECT_PRIMARY; + bool32 certain = effectFlags & EFFECT_CERTAIN; bool32 affectsUser = (battler == effectBattler); bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); union StatChangeFlags flags = {0}; @@ -3030,48 +3017,49 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai bool32 activateAfterFaint = FALSE; // NULL move effect - if (gBattleScripting.moveEffect == MOVE_EFFECT_NONE) + if (moveEffect == MOVE_EFFECT_NONE) return; if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_1ST_HIT && IsBattlerAlive(gBattlerTarget) - && IsFinalStrikeEffect(gBattleScripting.moveEffect)) + && IsFinalStrikeEffect(moveEffect)) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; return; } - switch (gBattleScripting.moveEffect) // Set move effects which happen later on + switch (moveEffect) // Set move effects which happen later on { case MOVE_EFFECT_STEALTH_ROCK: case MOVE_EFFECT_PAYDAY: case MOVE_EFFECT_BUG_BITE: activateAfterFaint = TRUE; break; + default: + break; } gBattleScripting.battler = battler; gEffectBattler = effectBattler; battlerAbility = GetBattlerAbility(gEffectBattler); - if (!primary && !affectsUser - && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) - && IsMoveEffectBlockedByTarget(battlerAbility)) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; - else if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) + if (!primary && !affectsUser && IsMoveEffectBlockedByTarget(battlerAbility)) + moveEffect = MOVE_EFFECT_NONE; + else if (!primary && TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) - && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE) - && !primary) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; + && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE)) + moveEffect = MOVE_EFFECT_NONE; else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; + moveEffect = MOVE_EFFECT_NONE; else if (DoesSubstituteBlockMove(gBattlerAttacker, gEffectBattler, gCurrentMove) && !affectsUser) - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; + moveEffect = MOVE_EFFECT_NONE; - switch (gBattleScripting.moveEffect) + gBattleScripting.moveEffect = moveEffect; // ChangeStatBuffs still needs the global moveEffect + + switch (moveEffect) { case MOVE_EFFECT_NONE: - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_SLEEP: case MOVE_EFFECT_POISON: @@ -3080,23 +3068,23 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_PARALYSIS: case MOVE_EFFECT_TOXIC: case MOVE_EFFECT_FROSTBITE: - if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary) - gBattlescriptCurrInstr++; + if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary) + gBattlescriptCurrInstr = battleScript; else if (CanSetNonVolatileStatus( gBattlerAttacker, gEffectBattler, GetBattlerAbility(gBattlerAttacker), battlerAbility, - gBattleScripting.moveEffect, + moveEffect, CHECK_TRIGGER)) - SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_MOVE); + SetNonVolatileStatus(gEffectBattler, moveEffect, battleScript, TRIGGER_ON_MOVE); break; case MOVE_EFFECT_CONFUSION: if (!CanBeConfused(gEffectBattler) || gBattleMons[gEffectBattler].volatiles.confusionTurns - || (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary)) + || (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !primary)) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { @@ -3112,7 +3100,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } else { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectConfusion; } } @@ -3127,27 +3115,27 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gLastUsedAbility = ABILITY_INNER_FOCUS; gBattlerAbility = gEffectBattler; RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_FlinchPrevention; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } } else if (gBattleMons[gEffectBattler].volatiles.flinched) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else if (!HasBattlerActedThisTurn(gEffectBattler) && GetActiveGimmick(gEffectBattler) != GIMMICK_DYNAMAX) { gBattleMons[gEffectBattler].volatiles.flinched = TRUE; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } break; case MOVE_EFFECT_UPROAR: @@ -3157,12 +3145,12 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gLockedMoves[gEffectBattler] = gCurrentMove; gBattleMons[gEffectBattler].volatiles.uproarTurns = B_UPROAR_TURNS >= GEN_5 ? 3 : (Random() & 3) + 2; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectUproar; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } break; case MOVE_EFFECT_PAYDAY: @@ -3179,15 +3167,15 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai // we only want to print the message on the final hit if (!(NumAffectedSpreadMoveTargets() > 1 && GetNextTarget(moveTarget, TRUE) != MAX_BATTLERS_COUNT)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectPayDay; } else - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } break; case MOVE_EFFECT_HAPPY_HOUR: @@ -3196,12 +3184,12 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gBattleStruct->moneyMultiplier *= 2; gBattleStruct->moneyMultiplierMove = 1; } - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_TRI_ATTACK: if (gBattleMons[gEffectBattler].status1) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { @@ -3211,27 +3199,24 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai MOVE_EFFECT_FREEZE_OR_FROSTBITE, MOVE_EFFECT_PARALYSIS }; - gBattleScripting.moveEffect = RandomElement(RNG_TRI_ATTACK, sTriAttackEffects); - SetMoveEffect(battler, effectBattler, primary, certain); + SetMoveEffect(battler, effectBattler, RandomElement(RNG_TRI_ATTACK, sTriAttackEffects), battleScript, effectFlags); } break; case MOVE_EFFECT_WRAP: if (gBattleMons[gEffectBattler].volatiles.wrapped) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleMons[gEffectBattler].volatiles.wrapped = TRUE; - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_GRIP_CLAW) + if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_GRIP_CLAW) gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? 7 : 5; else gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? RandomUniform(RNG_WRAP, 4, 5) : RandomUniform(RNG_WRAP, 2, 5); - - gBattleStruct->wrappedMove[gEffectBattler] = gCurrentMove; - gBattleStruct->wrappedBy[gEffectBattler] = gBattlerAttacker; - - BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattleMons[gEffectBattler].volatiles.wrapped = TRUE; + gBattleMons[gEffectBattler].volatiles.wrappedMove = gCurrentMove; + gBattleMons[gEffectBattler].volatiles.wrappedBy = gBattlerAttacker; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectWrap; } break; @@ -3246,17 +3231,17 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai || ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(1), - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_1 + 1, + moveEffect - MOVE_EFFECT_ATK_PLUS_1 + 1, STAT_CHANGE_UPDATE_MOVE_EFFECT, 0, 0) == STAT_CHANGE_DIDNT_WORK) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatUp; } break; @@ -3276,18 +3261,18 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, + moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, flags, - 0, gBattlescriptCurrInstr + 1) == STAT_CHANGE_DIDNT_WORK) + 0, battleScript) == STAT_CHANGE_DIDNT_WORK) { if (!mirrorArmorReflected) - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatDown; } break; @@ -3302,17 +3287,17 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai || ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(2), - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_PLUS_2 + 1, + moveEffect - MOVE_EFFECT_ATK_PLUS_2 + 1, STAT_CHANGE_UPDATE_MOVE_EFFECT, 0, 0) == STAT_CHANGE_DIDNT_WORK) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatUp; } break; @@ -3332,18 +3317,18 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (ChangeStatBuffs( effectBattler, SET_STAT_BUFF_VALUE(2) | STAT_BUFF_NEGATIVE, - gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1, + moveEffect - MOVE_EFFECT_ATK_MINUS_2 + 1, flags, - 0, gBattlescriptCurrInstr + 1) == STAT_CHANGE_DIDNT_WORK) + 0, battleScript) == STAT_CHANGE_DIDNT_WORK) { if (!mirrorArmorReflected) - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatDown; } break; @@ -3353,60 +3338,63 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gDisableStructs[gEffectBattler].rechargeTimer = 2; gLockedMoves[gEffectBattler] = gCurrentMove; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_RAGE: gBattleMons[gBattlerAttacker].volatiles.rage = TRUE; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_PREVENT_ESCAPE: - if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) + if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) // Do we need to check if the status is already set? { gBattleMons[gBattlerTarget].volatiles.escapePrevention = TRUE; gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; } - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_NIGHTMARE: gBattleMons[gBattlerTarget].volatiles.nightmare = TRUE; - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_ALL_STATS_UP: if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_AllStatsUp; } break; case MOVE_EFFECT_ATK_DEF_DOWN: // SuperPower if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_AtkDefDown; } break; case MOVE_EFFECT_DEF_SPDEF_DOWN: // Close Combat if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_DefSpDefDown; } break; case MOVE_EFFECT_RECOIL_HP_25: // Struggle - gBattleStruct->moveDamage[gEffectBattler] = (gBattleMons[gEffectBattler].maxHP) / 4; - if (gBattleStruct->moveDamage[gEffectBattler] == 0) - gBattleStruct->moveDamage[gEffectBattler] = 1; + { + s32 recoil = (gBattleMons[gEffectBattler].maxHP) / 4; + if (recoil == 0) + recoil = 1; if (GetBattlerAbility(gEffectBattler) == ABILITY_PARENTAL_BOND) - gBattleStruct->moveDamage[gEffectBattler] *= 2; - - BattleScriptPush(gBattlescriptCurrInstr + 1); + recoil *= 2; + SetPassiveDamageAmount(gEffectBattler, recoil); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; break; + } case MOVE_EFFECT_THRASH: // Petal Dance doesn't lock mons that copy the move with Dancer if (gSpecialStatuses[gEffectBattler].dancerUsedMove || gBattleMons[gEffectBattler].volatiles.lockConfusionTurns) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { @@ -3425,7 +3413,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { for (i = 0; i < NUM_BATTLE_STATS; i++) gBattleMons[gEffectBattler].statStages[i] = DEFAULT_STAT_STAGE; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectClearSmog; } break; @@ -3434,11 +3422,10 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai && !IsSemiInvulnerable(BATTLE_PARTNER(gBattlerTarget), CHECK_ALL) && GetBattlerAbility(BATTLE_PARTNER(gBattlerTarget)) != ABILITY_MAGIC_GUARD) { - gBattleScripting.battler = i = BATTLE_PARTNER(gBattlerTarget); - gBattleStruct->moveDamage[i] = gBattleMons[i].maxHP / 16; - if (gBattleStruct->moveDamage[i] == 0) - gBattleStruct->moveDamage[i] = 1; - BattleScriptPush(gBattlescriptCurrInstr + 1); + u32 partnerTarget = BATTLE_PARTNER(gBattlerTarget); + gBattleScripting.battler = partnerTarget; + SetPassiveDamageAmount(partnerTarget, gBattleMons[partnerTarget].maxHP / 16); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectFlameBurst; } break; @@ -3457,7 +3444,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } if (i) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); if (gCurrentMove == MOVE_HYPERSPACE_FURY) gBattlescriptCurrInstr = BattleScript_HyperspaceFuryRemoveProtect; else @@ -3467,7 +3454,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_V_CREATE: if (!NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_VCreateStatLoss; } break; @@ -3475,17 +3462,17 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (HasBattlerActedThisTurn(gBattlerTarget) && !NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectCoreEnforcer; } break; case MOVE_EFFECT_THROAT_CHOP: - gDisableStructs[gEffectBattler].throatChopTimer = gBattleTurnCounter + 2; - gBattlescriptCurrInstr++; + gDisableStructs[gEffectBattler].throatChopTimer = 2; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_INCINERATE: if ((gBattleMons[gEffectBattler].item >= FIRST_BERRY_INDEX && gBattleMons[gEffectBattler].item <= LAST_BERRY_INDEX) - || (B_INCINERATE_GEMS >= GEN_6 && GetBattlerHoldEffect(gEffectBattler, FALSE) == HOLD_EFFECT_GEMS)) + || (B_INCINERATE_GEMS >= GEN_6 && GetBattlerHoldEffect(gEffectBattler) == HOLD_EFFECT_GEMS)) { gLastUsedItem = gBattleMons[gEffectBattler].item; gBattleMons[gEffectBattler].item = 0; @@ -3493,15 +3480,15 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai BtlController_EmitSetMonData(gEffectBattler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gEffectBattler].item), &gBattleMons[gEffectBattler].item); MarkBattlerForControllerExec(gEffectBattler); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectIncinerate; } break; case MOVE_EFFECT_BUG_BITE: - if (GetBattlerHoldEffect(gEffectBattler, TRUE) == HOLD_EFFECT_JABOCA_BERRY) + if (GetBattlerHoldEffect(gEffectBattler) == HOLD_EFFECT_JABOCA_BERRY) { // jaboca berry triggers instead of being stolen - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else if (GetItemPocket(gBattleMons[gEffectBattler].item) == POCKET_BERRIES && battlerAbility != ABILITY_STICKY_HOLD) @@ -3513,14 +3500,14 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai BtlController_EmitSetMonData(gEffectBattler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gEffectBattler].item), &gBattleMons[gEffectBattler].item); MarkBattlerForControllerExec(gEffectBattler); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectBugBite; } break; case MOVE_EFFECT_TRAP_BOTH: if (!(gBattleMons[gBattlerTarget].volatiles.escapePrevention || gBattleMons[gBattlerAttacker].volatiles.escapePrevention)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_BothCanNoLongerEscape; } if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) @@ -3536,7 +3523,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { u32 type = GetMoveArgType(gCurrentMove); // This seems unnecessary but is done to make it work properly with Parental Bond - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); switch (type) { case TYPE_FIRE: // Burn Up @@ -3554,21 +3541,20 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } case MOVE_EFFECT_ROUND: TryUpdateRoundTurnOrder(); // If another Pokémon uses Round before the user this turn, the user will use Round directly after it - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; break; case MOVE_EFFECT_DIRE_CLAW: if (!gBattleMons[gEffectBattler].status1) { static const u8 sDireClawEffects[] = { MOVE_EFFECT_POISON, MOVE_EFFECT_PARALYSIS, MOVE_EFFECT_SLEEP }; - gBattleScripting.moveEffect = RandomElement(RNG_DIRE_CLAW, sDireClawEffects); - SetMoveEffect(battler, effectBattler, primary, certain); + SetMoveEffect(battler, effectBattler, RandomElement(RNG_DIRE_CLAW, sDireClawEffects), battleScript, effectFlags); } break; case MOVE_EFFECT_STEALTH_ROCK: if (!IsHazardOnSide(GetBattlerSide(gEffectBattler), HAZARDS_STEALTH_ROCK)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_POINTEDSTONESFLOAT; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StealthRockActivates; } break; @@ -3578,10 +3564,10 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai struct Pokemon *mon = GetBattlerMon(gBattlerAttacker); gBattleMons[gEffectBattler].volatiles.syrupBomb = TRUE; + gBattleMons[gEffectBattler].volatiles.stickySyrupedBy = gBattlerAttacker; gDisableStructs[gEffectBattler].syrupBombTimer = 3; gDisableStructs[gEffectBattler].syrupBombIsShiny = IsMonShiny(mon); - gBattleStruct->stickySyrupdBy[gEffectBattler] = gBattlerAttacker; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_SyrupBombActivates; } break; @@ -3591,25 +3577,24 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai switch (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) { case STATUS_FIELD_MISTY_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1; + moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1; break; case STATUS_FIELD_GRASSY_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_SLEEP; + moveEffect = MOVE_EFFECT_SLEEP; break; case STATUS_FIELD_ELECTRIC_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; + moveEffect = MOVE_EFFECT_PARALYSIS; break; case STATUS_FIELD_PSYCHIC_TERRAIN: - gBattleScripting.moveEffect = MOVE_EFFECT_SPD_MINUS_1; + moveEffect = MOVE_EFFECT_SPD_MINUS_1; break; default: - gBattleScripting.moveEffect = MOVE_EFFECT_PARALYSIS; + moveEffect = MOVE_EFFECT_PARALYSIS; break; } } else - gBattleScripting.moveEffect = gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect; - SetMoveEffect(battler, effectBattler, primary, certain); + SetMoveEffect(battler, effectBattler, gBattleEnvironmentInfo[gBattleEnvironment].secretPowerEffect, battleScript, effectFlags); break; case MOVE_EFFECT_PSYCHIC_NOISE: battlerAbility = IsAbilityOnSide(gEffectBattler, ABILITY_AROMA_VEIL); @@ -3617,14 +3602,14 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (battlerAbility) { gBattlerAbility = battlerAbility - 1; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_AromaVeilProtectsRet; } else if (!gBattleMons[gEffectBattler].volatiles.healBlock) { gBattleMons[gEffectBattler].volatiles.healBlock = TRUE; - gDisableStructs[gEffectBattler].healBlockTimer = gBattleTurnCounter + 2; - BattleScriptPush(gBattlescriptCurrInstr + 1); + gDisableStructs[gEffectBattler].healBlockTimer = 2; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectPsychicNoise; } break; @@ -3633,13 +3618,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai && GetBattlerTeraType(gEffectBattler) == TYPE_STELLAR && !NoAliveMonsForEitherParty()) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_LowerAtkSpAtk; } break; case MOVE_EFFECT_ORDER_UP: { - u32 stat = 0; + enum Stat stat = 0; bool32 commanderAffected = TRUE; switch (gBattleStruct->battlerState[gEffectBattler].commanderSpecies) { @@ -3666,13 +3651,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai 0, 0) == STAT_CHANGE_DIDNT_WORK) { - gBattlescriptCurrInstr++; + gBattlescriptCurrInstr = battleScript; } else { - gBattleScripting.animArg1 = gBattleScripting.moveEffect; + gBattleScripting.animArg1 = moveEffect; gBattleScripting.animArg2 = 0; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_StatUp; } } @@ -3681,35 +3666,35 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!(gFieldStatuses & STATUS_FIELD_ION_DELUGE)) { gFieldStatuses |= STATUS_FIELD_ION_DELUGE; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectIonDeluge; } break; case MOVE_EFFECT_HAZE: for (i = 0; i < gBattlersCount; i++) TryResetBattlerStatChanges(i); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectHaze; break; case MOVE_EFFECT_LEECH_SEED: if (!IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) && !gBattleMons[gBattlerTarget].volatiles.leechSeed) { gBattleMons[gBattlerTarget].volatiles.leechSeed = LEECHSEEDED_BY(gBattlerAttacker); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectLeechSeed; } break; case MOVE_EFFECT_REFLECT: if (TrySetReflect(gBattlerAttacker)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectReflect; } break; case MOVE_EFFECT_LIGHT_SCREEN: if (TrySetLightScreen(gBattlerAttacker)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectLightScreen; } break; @@ -3717,7 +3702,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!gBattleMons[gBattlerTarget].volatiles.saltCure) { gBattleMons[gBattlerTarget].volatiles.saltCure = TRUE; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectSaltCure; } break; @@ -3753,7 +3738,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == SKY_DROP_NO_TARGET) CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_IGNORE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectEerieSpell; } } @@ -3763,7 +3748,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_ATK, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3772,7 +3757,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_DEF, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3781,7 +3766,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_SPEED, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3790,7 +3775,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_SPATK, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3799,7 +3784,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { // Max Effects are ordered by stat ID. SET_STATCHANGER(STAT_SPDEF, 1, FALSE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; } break; @@ -3812,9 +3797,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_LOWER_EVASIVENESS_SIDE: if (!NoAliveMonsForEitherParty()) { - u32 statId = 0; + enum Stat statId = 0; u32 stage = 1; - switch (gBattleScripting.moveEffect) + switch (moveEffect) { case MOVE_EFFECT_LOWER_SPEED_2_SIDE: statId = STAT_SPEED; @@ -3825,11 +3810,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai break; default: // Max Effects are ordered by stat ID. - statId = gBattleScripting.moveEffect - MOVE_EFFECT_LOWER_ATTACK_SIDE + 1; + statId = moveEffect - MOVE_EFFECT_LOWER_ATTACK_SIDE + 1; break; } SET_STATCHANGER(statId, stage, TRUE); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectLowerStatFoes; } break; @@ -3839,7 +3824,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_HAIL: { u8 weather = 0, msg = 0; - switch (gBattleScripting.moveEffect) + switch (moveEffect) { case MOVE_EFFECT_SUN: weather = BATTLE_WEATHER_SUN; @@ -3865,11 +3850,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai msg = B_MSG_STARTED_HAIL; } break; + default: + break; } if (TryChangeBattleWeather(gBattlerAttacker, weather, ABILITY_NONE)) { gBattleCommunication[MULTISTRING_CHOOSER] = msg; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectSetWeather; } break; @@ -3880,7 +3867,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai case MOVE_EFFECT_PSYCHIC_TERRAIN: { u32 statusFlag = 0; - switch (gBattleScripting.moveEffect) + switch (moveEffect) { case MOVE_EFFECT_MISTY_TERRAIN: statusFlag = STATUS_FIELD_MISTY_TERRAIN; @@ -3898,16 +3885,18 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; break; + default: + break; } if (!(gFieldStatuses & statusFlag) && statusFlag != 0) { gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; gFieldStatuses |= statusFlag; - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_TERRAIN_EXTENDER) - gFieldTimers.terrainTimer = gBattleTurnCounter + 8; + if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_TERRAIN_EXTENDER) + gFieldTimers.terrainTimer = 8; else - gFieldTimers.terrainTimer = gBattleTurnCounter + 5; - BattleScriptPush(gBattlescriptCurrInstr + 1); + gFieldTimers.terrainTimer = 5; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectSetTerrain; } break; @@ -3922,9 +3911,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { u32 moveType = GetMoveType(gCurrentMove); gSideStatuses[side] |= SIDE_STATUS_DAMAGE_NON_TYPES; - gSideTimers[side].damageNonTypesTimer = gBattleTurnCounter + 5; // damage is dealt for 4 turns, ends on 5th + gSideTimers[side].damageNonTypesTimer = 5; gSideTimers[side].damageNonTypesType = moveType; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); ChooseDamageNonTypesString(moveType); gBattlescriptCurrInstr = BattleScript_DamageNonTypesStarts; } @@ -3934,7 +3923,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!IsHazardOnSide(GetBattlerSide(gBattlerTarget), HAZARDS_STEELSURGE)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SHARPSTEELFLOATS; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectSteelsurge; } break; @@ -3944,7 +3933,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai || AreAnyHazardsOnSide(GetBattlerSide(gBattlerAttacker)) || gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectDefog; } break; @@ -3952,12 +3941,12 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!(gSideStatuses[GetBattlerSide(gBattlerAttacker)] & SIDE_STATUS_AURORA_VEIL)) { gSideStatuses[GetBattlerSide(gBattlerAttacker)] |= SIDE_STATUS_AURORA_VEIL; - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 8; + if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 8; else - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SAFEGUARD; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectAuroraVeil; } break; @@ -3965,8 +3954,8 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!(gFieldStatuses & STATUS_FIELD_GRAVITY)) { gFieldStatuses |= STATUS_FIELD_GRAVITY; - gFieldTimers.gravityTimer = gBattleTurnCounter + 5; - BattleScriptPush(gBattlescriptCurrInstr + 1); + gFieldTimers.gravityTimer = 5; + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectGravitySuccess; } break; @@ -3982,16 +3971,16 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (!gBattleMons[battler].volatiles.wrapped) { gBattleMons[battler].volatiles.wrapped = TRUE; - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_GRIP_CLAW) + if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_GRIP_CLAW) gDisableStructs[battler].wrapTurns = (B_BINDING_TURNS >= GEN_5) ? 7 : 5; else gDisableStructs[battler].wrapTurns = (Random() % 2) + 4; // The Wrap effect does not expire when the user switches, so here's some cheese. - gBattleStruct->wrappedBy[battler] = gBattlerTarget; - if (gBattleScripting.moveEffect == MOVE_EFFECT_SANDBLAST_SIDE) - gBattleStruct->wrappedMove[battler] = MOVE_SAND_TOMB; + gBattleMons[battler].volatiles.wrappedBy = gBattlerTarget; + if (moveEffect == MOVE_EFFECT_SANDBLAST_SIDE) + gBattleMons[battler].volatiles.wrappedMove = MOVE_SAND_TOMB; else - gBattleStruct->wrappedMove[battler] = MOVE_FIRE_SPIN; + gBattleMons[battler].volatiles.wrappedMove = MOVE_FIRE_SPIN; } } break; @@ -4003,7 +3992,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai && RandomPercentage(RNG_G_MAX_SNOOZE, 50)) { gBattleMons[gBattlerTarget].volatiles.yawn = 2; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectYawnSide; } break; @@ -4012,24 +4001,24 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (gLastMoves[gBattlerTarget] != MOVE_NONE && gLastMoves[gBattlerTarget] != MOVE_UNAVAILABLE) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectTryReducePP; } break; case MOVE_EFFECT_PARALYZE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectParalyzeSide; break; case MOVE_EFFECT_POISON_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectPoisonSide; break; case MOVE_EFFECT_POISON_PARALYZE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectPoisonParalyzeSide; break; case MOVE_EFFECT_EFFECT_SPORE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectEffectSporeSide; break; case MOVE_EFFECT_CONFUSE_PAY_DAY_SIDE: @@ -4043,39 +4032,39 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } // fall through case MOVE_EFFECT_CONFUSE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectConfuseSide; break; case MOVE_EFFECT_INFATUATE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectInfatuateSide; break; case MOVE_EFFECT_TORMENT_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectTormentSide; break; case MOVE_EFFECT_PREVENT_ESCAPE_SIDE: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectMeanLookSide; break; case MOVE_EFFECT_CRIT_PLUS_SIDE: gBattleStruct->bonusCritStages[gBattlerAttacker]++; gBattleStruct->bonusCritStages[BATTLE_PARTNER(gBattlerAttacker)]++; - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRaiseCritAlliesAnim; break; case MOVE_EFFECT_HEAL_TEAM: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectHealOneSixthAllies; break; case MOVE_EFFECT_AROMATHERAPY: - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_MoveEffectAromatherapy; break; case MOVE_EFFECT_RECYCLE_BERRIES: if (RandomPercentage(RNG_G_MAX_REPLENISH, 50)) { - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); gBattlescriptCurrInstr = BattleScript_EffectRecycleBerriesAllies; } break; @@ -4088,7 +4077,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gBattleMons[gEffectBattler].status1 &= ~(argStatus); BtlController_EmitSetMonData(gEffectBattler, 0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gEffectBattler].status1); MarkBattlerForControllerExec(gEffectBattler); - BattleScriptPush(gBattlescriptCurrInstr + 1); + BattleScriptPush(battleScript); switch (argStatus) { @@ -4117,13 +4106,19 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } break; } + default: + break; } - gBattleScripting.moveEffect = 0; + gBattleScripting.moveEffect = MOVE_EFFECT_NONE; } static bool32 CanApplyAdditionalEffect(const struct AdditionalEffect *additionalEffect) { + // If Toxic Chain will activate it blocks all other non volatile effects + if (gBattleStruct->toxicChainPriority && additionalEffect->moveEffect <= MOVE_EFFECT_FROSTBITE) + return FALSE; + if (additionalEffect->self && NumAffectedSpreadMoveTargets() > 1 && GetNextTarget(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove), TRUE) != MAX_BATTLERS_COUNT) @@ -4140,6 +4135,20 @@ static bool32 CanApplyAdditionalEffect(const struct AdditionalEffect *additional return TRUE; } +static void SetToxicChainPriority(void) +{ + if (gBattleStruct->toxicChainPriority) + return; + + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); + if (abilityAtk == ABILITY_TOXIC_CHAIN + && IsBattlerAlive(gBattlerTarget) + && CanBePoisoned(gBattlerAttacker, gBattlerTarget, abilityAtk, GetBattlerAbility(gBattlerTarget)) + && IsBattlerTurnDamaged(gBattlerTarget) + && RandomWeighted(RNG_TOXIC_CHAIN, 7, 3)) + gBattleStruct->toxicChainPriority = TRUE; +} + static void Cmd_setadditionaleffects(void) { CMD_ARGS(); @@ -4147,6 +4156,7 @@ static void Cmd_setadditionaleffects(void) if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) { u32 numAdditionalEffects = GetMoveAdditionalEffectCount(gCurrentMove); + SetToxicChainPriority(); if (numAdditionalEffects > gBattleStruct->additionalEffectsCounter) { u32 percentChance; @@ -4161,14 +4171,18 @@ static void Cmd_setadditionaleffects(void) // Activate effect if it's primary (chance == 0) or if RNGesus says so if ((percentChance == 0) || RandomPercentage(RNG_SECONDARY_EFFECT + gBattleStruct->additionalEffectsCounter, percentChance)) { - gBattleScripting.moveEffect = additionalEffect->moveEffect; gBattleCommunication[MULTISTRING_CHOOSER] = *((u8 *) &additionalEffect->multistring); + enum SetMoveEffectFlags flags = NO_FLAGS; + if (percentChance == 0) flags |= EFFECT_PRIMARY; + if (percentChance >= 100) flags |= EFFECT_CERTAIN; + SetMoveEffect( gBattlerAttacker, additionalEffect->self ? gBattlerAttacker : gBattlerTarget, - percentChance == 0, // a primary effect - percentChance >= 100 // certain to happen + additionalEffect->moveEffect, + cmd->nextInstr, + flags ); } } @@ -4195,8 +4209,6 @@ static void Cmd_setadditionaleffects(void) gBattleScripting.moveEffect = 0; gBattlescriptCurrInstr = cmd->nextInstr; } - - gBattleScripting.multihitMoveEffect = 0; } static void Cmd_seteffectprimary(void) @@ -4205,8 +4217,7 @@ static void Cmd_seteffectprimary(void) u32 battler = GetBattlerForBattleScript(cmd->battler); u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler); - gBattlescriptCurrInstr = cmd->nextInstr - 1; - SetMoveEffect(battler, effectBattler, TRUE, FALSE); + SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY); } static void Cmd_seteffectsecondary(void) @@ -4215,8 +4226,7 @@ static void Cmd_seteffectsecondary(void) u32 battler = GetBattlerForBattleScript(cmd->battler); u32 effectBattler = GetBattlerForBattleScript(cmd->effectBattler); - gBattlescriptCurrInstr = cmd->nextInstr - 1; - SetMoveEffect(battler, effectBattler, FALSE, FALSE); + SetMoveEffect(battler, effectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY); } static void Cmd_clearvolatile(void) @@ -4230,13 +4240,12 @@ static void Cmd_clearvolatile(void) gProtectStructs[battler].chargingTurn = FALSE; gBattlescriptCurrInstr = cmd->nextInstr; - gBattleScripting.multihitMoveEffect = 0; } static void Cmd_tryfaintmon(void) { CMD_ARGS(u8 battler, bool8 isSpikes, const u8 *instr); - u32 battler, destinyBondBattler; + u32 battler; const u8 *faintScript; battler = GetBattlerForBattleScript(cmd->battler); @@ -4266,16 +4275,12 @@ static void Cmd_tryfaintmon(void) return; } } + if (cmd->battler == BS_ATTACKER) - { - destinyBondBattler = gBattlerTarget; - faintScript = BattleScript_FaintAttacker; - } - else - { - destinyBondBattler = gBattlerAttacker; - faintScript = BattleScript_FaintTarget; - } + TryUpdateEvolutionTracker(IF_DEFEAT_X_WITH_ITEMS, 1, MOVE_NONE); + + gBattlerFainted = battler; + faintScript = BattleScript_FaintBattler; if (!(gAbsentBattlerFlags & (1u << battler)) && !IsBattlerAlive(battler)) { @@ -4297,30 +4302,11 @@ static void Cmd_tryfaintmon(void) gBattleResults.lastOpponentSpecies = GetMonData(GetBattlerMon(battler), MON_DATA_SPECIES, NULL); gSideTimers[B_SIDE_OPPONENT].retaliateTimer = 2; } - if ((gHitMarker & HITMARKER_DESTINYBOND) && IsBattlerAlive(gBattlerAttacker) - && !(GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX)) - { - gHitMarker &= ~HITMARKER_DESTINYBOND; - BattleScriptPush(gBattlescriptCurrInstr); - gBattleStruct->moveDamage[destinyBondBattler] = gBattleMons[destinyBondBattler].hp; - gBattlescriptCurrInstr = BattleScript_DestinyBondTakesLife; - } - if (gBattleMons[gBattlerTarget].volatiles.grudge - && !(gHitMarker & HITMARKER_GRUDGE) - && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) - && IsBattlerAlive(gBattlerAttacker) - && gCurrentMove != MOVE_STRUGGLE) - { - u8 moveIndex = gBattleStruct->chosenMovePositions[gBattlerAttacker]; - gBattleMons[gBattlerAttacker].pp[moveIndex] = 0; - BattleScriptPush(gBattlescriptCurrInstr); - gBattlescriptCurrInstr = BattleScript_GrudgeTakesPp; - BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, sizeof(gBattleMons[gBattlerAttacker].pp[moveIndex]), &gBattleMons[gBattlerAttacker].pp[moveIndex]); - MarkBattlerForControllerExec(gBattlerAttacker); - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].moves[moveIndex]) - } + if (gBattleMons[gBattlerTarget].volatiles.destinyBond) + gBattleStruct->tryDestinyBond = TRUE; + if (gBattleMons[gBattlerTarget].volatiles.grudge) + gBattleStruct->tryGrudge = TRUE; TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); } @@ -4405,11 +4391,11 @@ static void Cmd_jumpifvolatile(void) static void Cmd_jumpifability(void) { - CMD_ARGS(u8 battler, u16 ability, const u8 *jumpInstr); + CMD_ARGS(u8 battler, enum Ability ability, const u8 *jumpInstr); u32 battler; bool32 hasAbility = FALSE; - u32 ability = cmd->ability; + enum Ability ability = cmd->ability; switch (cmd->battler) { @@ -4544,7 +4530,7 @@ static bool32 BattleTypeAllowsExp(void) static u32 GetMonHoldEffect(struct Pokemon *mon) { - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; u32 item = GetMonData(mon, MON_DATA_HELD_ITEM); if (item == ITEM_ENIGMA_BERRY_E_READER) @@ -4563,7 +4549,7 @@ static void Cmd_getexp(void) { CMD_ARGS(u8 battler); - enum ItemHoldEffect holdEffect; + enum HoldEffect holdEffect; s32 i; // also used as stringId u8 *expMonId = &gBattleStruct->expGetterMonId; u32 currLvl; @@ -4692,7 +4678,7 @@ static void Cmd_getexp(void) if (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER) && (gBattleMons[0].hp || (IsDoubleBattle() && gBattleMons[2].hp)) && !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)) - && !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)) + && (!IsDoubleBattle() || !IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT))) && !gBattleStruct->wildVictorySong) { BattleStopLowHpSound(); @@ -4917,16 +4903,14 @@ bool32 NoAliveMonsForPlayer(void) { HP_count += GetMonData(&gPlayerParty[i], MON_DATA_HP); } - // Get the number of fainted mons or eggs (not empty slots) in the first three party slots. if (i < 3 && ((GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) && !GetMonData(&gPlayerParty[i], MON_DATA_HP)) || GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG))) ineligibleMonsCount++; } - // Get the number of inelligible slots in the saved player party. if (B_MULTI_BATTLE_WHITEOUT > GEN_3 && gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER) - && !(gBattleTypeFlags & BATTLE_TYPE_ARENA)) + && !(gBattleTypeFlags & BATTLE_TYPE_ARENA) && !(IsMultibattleTest())) // Multibattle tests appear to not save the player party data for the check below. { for (i = 0; i < PARTY_SIZE; i++) { @@ -4979,7 +4963,6 @@ static void Cmd_checkteamslost(void) if (NoAliveMonsForPlayer()) gBattleOutcome |= B_OUTCOME_LOST; - if (NoAliveMonsForOpponent()) gBattleOutcome |= B_OUTCOME_WON; @@ -4994,14 +4977,14 @@ static void Cmd_checkteamslost(void) for (emptyPlayerSpots = 0, i = 0; i < gBattlersCount; i += 2) { - if ((gHitMarker & HITMARKER_FAINTED2(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) + if ((gHitMarker & HITMARKER_FAINTED(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) emptyPlayerSpots++; } emptyOpponentSpots = 0; for (i = 1; i < gBattlersCount; i += 2) { - if ((gHitMarker & HITMARKER_FAINTED2(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) + if ((gHitMarker & HITMARKER_FAINTED(i)) && (!gSpecialStatuses[i].faintedHasReplacement)) emptyOpponentSpots++; } @@ -5036,8 +5019,8 @@ static void MoveValuesCleanUp(void) gBattleScripting.moveEffect = MOVE_EFFECT_NONE; gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE; gBattleCommunication[MISS_TYPE] = 0; - if (!gMultiHitCounter) - gHitMarker &= ~HITMARKER_DESTINYBOND; + gBattleStruct->tryDestinyBond = FALSE; + gBattleStruct->tryGrudge = FALSE; } static void Cmd_movevaluescleanup(void) @@ -5387,21 +5370,29 @@ static void Cmd_waitstate(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_absorb(void) +static void Cmd_isdmgblockedbydisguise(void) { - CMD_ARGS(u8 battler); + CMD_ARGS(); - if (gBattleControllerExecFlags) + if (!IsMimikyuDisguised(gBattlerAttacker) + || gBattleMons[gBattlerAttacker].volatiles.transformed + || !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_DISGUISE)) + { + gBattlescriptCurrInstr = cmd->nextInstr; return; + } - u32 battler = GetBattlerForBattleScript(cmd->battler); - BtlController_EmitHealthBarUpdate(battler, B_COMM_TO_CONTROLLER, gBattleStruct->moveDamage[battler]); - MarkBattlerForControllerExec(battler); - - if (IsOnPlayerSide(battler) && gBattleStruct->moveDamage[battler] > 0) - gBattleResults.playerMonWasDamaged = TRUE; - - gBattlescriptCurrInstr = cmd->nextInstr; + gBattleScripting.battler = gBattlerAttacker; + if (GetBattlerPartyState(gBattlerAttacker)->changedSpecies == SPECIES_NONE) + GetBattlerPartyState(gBattlerAttacker)->changedSpecies = gBattleMons[gBattlerAttacker].species; + if (gBattleMons[gBattlerAttacker].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) + gBattleMons[gBattlerAttacker].species = SPECIES_MIMIKYU_BUSTED_TOTEM; + else + gBattleMons[gBattlerAttacker].species = SPECIES_MIMIKYU_BUSTED; + if (GetGenConfig(GEN_CONFIG_DISGUISE_HP_LOSS) >= GEN_8) + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 8); + BattleScriptPush(BattleScript_MoveEnd); + gBattlescriptCurrInstr = BattleScript_TargetFormChange; } static void Cmd_return(void) @@ -5450,18 +5441,15 @@ static void Cmd_setroost(void) CMD_ARGS(); gDisableStructs[gBattlerAttacker].roostActive = TRUE; - gBattleStruct->roostTypes[gBattlerAttacker][0] = gBattleMons[gBattlerAttacker].types[0]; - gBattleStruct->roostTypes[gBattlerAttacker][1] = gBattleMons[gBattlerAttacker].types[1]; - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_jumpifabilitypresent(void) { - CMD_ARGS(u16 ability, const u8 *jumpInstr); + CMD_ARGS(enum Ability ability, const u8 *jumpInstr); - u16 ability = cmd->ability; - u32 abilityBattler = IsAbilityOnField(ability); + enum Ability ability = cmd->ability; + enum Ability abilityBattler = IsAbilityOnField(ability); if (abilityBattler) { gBattlerAbility = abilityBattler - 1; @@ -5476,8 +5464,7 @@ static void Cmd_jumpifabilitypresent(void) static void Cmd_endselectionscript(void) { CMD_ARGS(); - - *(gBattlerAttacker + gBattleStruct->selectionScriptFinished) = TRUE; + gBattleStruct->battlerState[gBattlerAttacker].selectionScriptFinished = TRUE; } static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *nextInstr) @@ -5591,7 +5578,7 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent) return battler; } -static inline bool32 IsProtectivePadsProtected(u32 battler, enum ItemHoldEffect holdEffect) +static inline bool32 IsProtectivePadsProtected(u32 battler, enum HoldEffect holdEffect) { if (holdEffect != HOLD_EFFECT_PROTECTIVE_PADS) return FALSE; @@ -5602,7 +5589,7 @@ static inline bool32 IsProtectivePadsProtected(u32 battler, enum ItemHoldEffect static inline bool32 CanEjectButtonTrigger(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects moveEffect) { - if (GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_EJECT_BUTTON + if (GetBattlerHoldEffect(battlerDef) == HOLD_EFFECT_EJECT_BUTTON && battlerAtk != battlerDef && IsBattlerTurnDamaged(battlerDef) && IsBattlerAlive(battlerDef) @@ -5616,7 +5603,7 @@ static inline bool32 CanEjectButtonTrigger(u32 battlerAtk, u32 battlerDef, enum static inline bool32 CanEjectPackTrigger(u32 battlerAtk, u32 battlerDef, enum BattleMoveEffects moveEffect) { if (gDisableStructs[battlerDef].tryEjectPack - && GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_EJECT_PACK + && GetBattlerHoldEffect(battlerDef) == HOLD_EFFECT_EJECT_PACK && IsBattlerAlive(battlerDef) && CountUsablePartyMons(battlerDef) > 0 && !gProtectStructs[battlerDef].disableEjectPack @@ -5630,7 +5617,7 @@ static inline bool32 CanEjectPackTrigger(u32 battlerAtk, u32 battlerDef, enum Ba static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move) { bool32 effect = FALSE; - u32 abilityAtk = GetBattlerAbility(battlerAtk); + enum Ability abilityAtk = GetBattlerAbility(battlerAtk); switch (abilityAtk) { @@ -5695,7 +5682,7 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move if (!IsBattlerAlive(battlerAtk) || NoAliveMonsForEitherParty()) break; - u32 stat = STAT_ATK; + enum Stat stat = STAT_ATK; u32 numMonsFainted = NumFaintedBattlersByAttacker(battlerAtk); if (abilityAtk == ABILITY_BEAST_BOOST) @@ -5773,6 +5760,8 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move } } break; + default: + break; } return effect; @@ -5783,17 +5772,29 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) return FALSE; - u32 effect = FALSE; - u32 side = GetBattlerSide(gBattlerTarget); + bool32 effect = FALSE; + enum BattleSide side = GetBattlerSide(gBattlerTarget); switch (moveEffect) { case EFFECT_KNOCK_OFF: - if (gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff - && gBattleMons[gBattlerTarget].item != ITEM_NONE - && IsBattlerTurnDamaged(gBattlerTarget) + if (gBattleMons[gBattlerTarget].item != ITEM_NONE && IsBattlerAlive(gBattlerAttacker) - && !(B_KNOCK_OFF_REMOVAL >= GEN_5 && side == B_SIDE_PLAYER && !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))) + && !(B_KNOCK_OFF_REMOVAL >= GEN_5 && side == B_SIDE_PLAYER && !(gBattleTypeFlags & BATTLE_TYPE_TRAINER)) + && IsBattlerTurnDamaged(gBattlerTarget) + && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove) + && CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerTarget].item) + && !NoAliveMonsForEitherParty()) { + u32 side = GetBattlerSide(gBattlerTarget); + + if (GetBattlerAbility(gBattlerTarget) == ABILITY_STICKY_HOLD) + { + gBattlerAbility = gBattlerTarget; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_StickyHoldActivatesRet; + effect = TRUE; + break; + } gLastUsedItem = gBattleMons[gBattlerTarget].item; gBattleMons[gBattlerTarget].item = 0; if (gBattleMons[gBattlerTarget].ability != ABILITY_GORILLA_TACTICS) @@ -5813,11 +5814,9 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) gWishFutureKnock.knockedOffMons[side] |= 1u << gBattlerPartyIndexes[gBattlerTarget]; } - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = FALSE; BattleScriptCall(BattleScript_KnockedOff); effect = TRUE; } - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = FALSE; break; case EFFECT_STEAL_ITEM: if (!CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item) @@ -5881,7 +5880,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) } break; case EFFECT_SMACK_DOWN: - if (!IsBattlerGrounded(gBattlerTarget) + if (!IsBattlerGrounded(gBattlerTarget, GetBattlerAbility(gBattlerTarget), GetBattlerHoldEffect(gBattlerTarget)) && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerTarget) && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)) @@ -5899,16 +5898,14 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) && (!IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !gBattleStruct->noTargetPresent) { + s32 recoil = 0; if (B_RECOIL_IF_MISS_DMG >= GEN_5 || (B_CRASH_IF_TARGET_IMMUNE == GEN_4 && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_DOESNT_AFFECT_FOE)) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + recoil = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else if (B_RECOIL_IF_MISS_DMG == GEN_4 && (GetNonDynamaxMaxHP(gBattlerTarget) / 2) < gBattleStruct->moveDamage[gBattlerTarget]) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2; + recoil = GetNonDynamaxMaxHP(gBattlerTarget) / 2; else // Fallback if B_RECOIL_IF_MISS_DMG is set to gen3 or lower. - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2; - - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - + recoil = GetNonDynamaxMaxHP(gBattlerTarget) / 2; + SetPassiveDamageAmount(gBattlerAttacker, recoil); BattleScriptCall(BattleScript_RecoilIfMiss); effect = TRUE; } @@ -5916,7 +5913,13 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) case EFFECT_RECOIL: if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleScripting.savedDmg * max(1, GetMoveRecoil(gCurrentMove)) / 100); + enum Ability ability = GetBattlerAbility(gBattlerAttacker); + if (IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_ROCK_HEAD) + || IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_MAGIC_GUARD)) + break; + + SetPassiveDamageAmount(gBattlerAttacker, gBattleScripting.savedDmg * max(1, GetMoveRecoil(gCurrentMove)) / 100); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); BattleScriptCall(BattleScript_MoveEffectRecoil); effect = TRUE; } @@ -5925,7 +5928,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) case EFFECT_MISTY_EXPLOSION: if (!IsAbilityOnField(ABILITY_DAMP)) { - gBattleStruct->moveDamage[gBattlerAttacker] = 0; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = 0; BattleScriptCall(BattleScript_FaintAttackerForExplosion); effect = TRUE; } @@ -5933,9 +5936,11 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) case EFFECT_MAX_HP_50_RECOIL: if (IsBattlerAlive(gBattlerAttacker) && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) + && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) { - gBattleStruct->moveDamage[gBattlerAttacker] = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + s32 recoil = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + SetPassiveDamageAmount(gBattlerAttacker, recoil); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); BattleScriptCall(BattleScript_MaxHp50Recoil); effect = TRUE; } @@ -5943,7 +5948,14 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect) case EFFECT_CHLOROBLAST: if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { - gBattleStruct->moveDamage[gBattlerAttacker] = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + enum Ability ability = GetBattlerAbility(gBattlerAttacker); + if (IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_ROCK_HEAD) + || IsAbilityAndRecord(gBattlerAttacker, ability, ABILITY_MAGIC_GUARD)) + break; + + s32 recoil = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + SetPassiveDamageAmount(gBattlerAttacker, recoil); + TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->passiveHpUpdate[gBattlerAttacker], MOVE_NONE); BattleScriptCall(BattleScript_MoveEffectRecoil); effect = TRUE; } @@ -6033,8 +6045,9 @@ static void Cmd_moveend(void) { switch (gBattleScripting.moveendState) { - case MOVEEND_SUM_DAMAGE: // Sum and store damage dealt for multi strike recoil + case MOVEEND_SET_VALUES: gBattleScripting.savedDmg += gBattleStruct->moveDamage[gBattlerTarget]; + gBattleStruct->eventState.moveEndBattler = 0; gBattleScripting.moveendState++; break; case MOVEEND_PROTECT_LIKE_EFFECT: @@ -6045,25 +6058,21 @@ static void Cmd_moveend(void) { case PROTECT_SPIKY_SHIELD: if (moveEffect != EFFECT_COUNTER - && !IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker, TRUE)) + && !IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker)) && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 8); PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SPIKY_SHIELD); BattleScriptCall(BattleScript_SpikyShieldEffect); effect = 1; } break; case PROTECT_KINGS_SHIELD: - if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker, TRUE))) + if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker))) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; - i = gBattlerAttacker; - gBattlerAttacker = gBattlerTarget; - gBattlerTarget = i; // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable + SWAP(gBattlerAttacker, gBattlerTarget, i); // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable if (B_KINGS_SHIELD_LOWER_ATK >= GEN_8) gBattleScripting.moveEffect = MOVE_EFFECT_ATK_MINUS_1; else @@ -6073,49 +6082,40 @@ static void Cmd_moveend(void) } break; case PROTECT_BANEFUL_BUNKER: - if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker, TRUE)) + if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker)) && CanBePoisoned(gBattlerTarget, gBattlerAttacker, gLastUsedAbility, GetBattlerAbility(gBattlerAttacker))) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; gBattleScripting.moveEffect = MOVE_EFFECT_POISON; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_BANEFUL_BUNKER); BattleScriptCall(BattleScript_BanefulBunkerEffect); effect = 1; } break; case PROTECT_BURNING_BULWARK: - if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker, TRUE)) + if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker)) && CanBeBurned(gBattlerTarget, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker))) { - gEffectBattler = gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; gBattleScripting.moveEffect = MOVE_EFFECT_BURN; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_BURNING_BULWARK); BattleScriptCall(BattleScript_BanefulBunkerEffect); effect = 1; } break; case PROTECT_OBSTRUCT: - if (moveEffect != EFFECT_SUCKER_PUNCH // Why??? - && moveEffect != EFFECT_UPPER_HAND // Why??? - && !IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker, TRUE))) + if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker))) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; - i = gBattlerAttacker; - gBattlerAttacker = gBattlerTarget; - gBattlerTarget = i; // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable + SWAP(gBattlerAttacker, gBattlerTarget, i); // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable gBattleScripting.moveEffect = MOVE_EFFECT_DEF_MINUS_2; BattleScriptCall(BattleScript_KingsShieldEffect); effect = 1; } break; case PROTECT_SILK_TRAP: - if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker, TRUE))) + if (!IsProtectivePadsProtected(gBattlerAttacker, GetBattlerHoldEffect(gBattlerAttacker))) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; - i = gBattlerAttacker; - gBattlerAttacker = gBattlerTarget; - gBattlerTarget = i; // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable + SWAP(gBattlerAttacker, gBattlerTarget, i); // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable gBattleScripting.moveEffect = MOVE_EFFECT_SPD_MINUS_1; BattleScriptCall(BattleScript_KingsShieldEffect); effect = 1; @@ -6140,6 +6140,43 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; + + case MOVEEND_GRUDGE: + if (gBattleStruct->tryGrudge + && IsBattlerTurnDamaged(gBattlerTarget) + && !IsBattlerAlive(gBattlerTarget) + && IsBattlerAlive(gBattlerAttacker) + && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) + && !IsZMove(gCurrentMove) + && gCurrentMove != MOVE_STRUGGLE) + { + u32 moveIndex = gBattleStruct->chosenMovePositions[gBattlerAttacker]; + + gBattleStruct->tryGrudge = FALSE; + gBattleMons[gBattlerAttacker].pp[moveIndex] = 0; + BattleScriptCall(BattleScript_GrudgeTakesPp); + BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, moveIndex + REQUEST_PPMOVE1_BATTLE, 0, sizeof(gBattleMons[gBattlerAttacker].pp[moveIndex]), &gBattleMons[gBattlerAttacker].pp[moveIndex]); + MarkBattlerForControllerExec(gBattlerAttacker); + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].moves[moveIndex]) + } + gBattleScripting.moveendState++; + break; + + case MOVEEND_DESTINY_BOND: + if (gBattleStruct->tryDestinyBond + && IsBattlerTurnDamaged(gBattlerTarget) + && !IsBattlerAlive(gBattlerTarget) + && IsBattlerAlive(gBattlerAttacker) + && !(GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX) + && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget)) + { + gBattleStruct->tryDestinyBond = FALSE; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; + BattleScriptCall(BattleScript_DestinyBondTakesLife); + effect = TRUE; + } + gBattleScripting.moveendState++; + break; case MOVEEND_ABSORB: if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE || !IsBattlerTurnDamaged(gBattlerTarget)) @@ -6155,20 +6192,19 @@ static void Cmd_moveend(void) && gBattleStruct->moveDamage[gBattlerTarget] > 0 && IsBattlerAlive(gBattlerAttacker)) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100)); - gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); - - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE | HITMARKER_PASSIVE_HP_UPDATE; + s32 healAmount = (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100); + healAmount = GetDrainedBigRootHp(gBattlerAttacker, healAmount); effect = TRUE; if ((moveEffect == EFFECT_DREAM_EATER && GetGenConfig(GEN_DREAM_EATER_LIQUID_OOZE) < GEN_5) || GetBattlerAbility(gBattlerTarget) != ABILITY_LIQUID_OOZE) { + SetHealAmount(gBattlerAttacker, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB; BattleScriptCall(BattleScript_EffectAbsorb); } - else + else // Liquid Ooze damage { - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; + SetPassiveDamageAmount(gBattlerAttacker, healAmount); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB_OOZE; BattleScriptCall(BattleScript_EffectAbsorbLiquidOoze); } @@ -6221,7 +6257,7 @@ static void Cmd_moveend(void) if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, battler, 0, 0, 0)) effect = TRUE; } - if(!effect) + if (!effect) gBattleScripting.moveendState++; break; case MOVEEND_SYNCHRONIZE_ATTACKER: // attacker synchronize @@ -6230,10 +6266,24 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_ITEM_EFFECTS_TARGET: - if (ItemBattleEffects(ITEMEFFECT_TARGET, gBattlerTarget)) + { + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); + if (ItemBattleEffects(gBattlerTarget, gBattlerAttacker, holdEffect, IsOnTargetHitActivation) + || ItemBattleEffects(gBattlerTarget, gBattlerAttacker, holdEffect, IsOnStatusChangeActivation)) effect = TRUE; gBattleScripting.moveendState++; break; + } + case MOVEEND_ITEM_EFFECTS_ATTACKER_1: + { + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker); + if (ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnAttackerAfterHitActivation) + || ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnStatusChangeActivation) + || ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnHpThresholdActivation)) + effect = TRUE; + gBattleScripting.moveendState++; + break; + } case MOVEEND_SYMBIOSIS: for (i = 0; i < gBattlersCount; i++) { @@ -6253,12 +6303,6 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_ITEM_EFFECTS_ALL: // item effects for all battlers - if (ItemBattleEffects(ITEMEFFECT_MOVE_END, 0)) - effect = TRUE; - else - gBattleScripting.moveendState++; - break; case MOVEEND_ATTACKER_INVISIBLE: // make attacker sprite invisible if (IsSemiInvulnerable(gBattlerAttacker, CHECK_ALL) && gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION)) @@ -6296,12 +6340,6 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_KINGSROCK: // King's rock - // These effects will occur at each hit in a multi-strike move - if (ItemBattleEffects(ITEMEFFECT_KINGSROCK, 0)) - effect = TRUE; - gBattleScripting.moveendState++; - break; case MOVEEND_SUBSTITUTE: for (i = 0; i < gBattlersCount; i++) { @@ -6341,7 +6379,7 @@ static void Cmd_moveend(void) if (!IsOnPlayerSide(gBattlerAttacker)) UpdateStallMons(); if ((gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE)) - || (gBattleMons[gBattlerAttacker].volatiles.flinched) + || gBattleMons[gBattlerAttacker].volatiles.flinched || gBattleStruct->pledgeMove == TRUE // Is the battler that uses the first Pledge move in the combo || gProtectStructs[gBattlerAttacker].nonVolatileStatusImmobility) gBattleStruct->battlerState[gBattlerAttacker].stompingTantrumTimer = 2; @@ -6374,13 +6412,6 @@ static void Cmd_moveend(void) { gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos; gBattleStruct->lastMoveTarget[gBattlerAttacker] = gBattlerTarget; - if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) - { - gLastPrintedMoves[gBattlerAttacker] = gChosenMove; - gLastUsedMove = gCurrentMove; - if (IsMaxMove(gCurrentMove)) - gBattleStruct->dynamax.lastUsedBaseMove = gBattleStruct->dynamax.baseMoves[gBattlerAttacker]; - } } enum BattleMoveEffects originalEffect = GetMoveEffect(originallyUsedMove); if (IsBattlerAlive(gBattlerAttacker) @@ -6417,6 +6448,12 @@ static void Cmd_moveend(void) { gLastLandedMoves[gBattlerTarget] = gCurrentMove; gLastHitByType[gBattlerTarget] = GetBattleMoveType(gCurrentMove); + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + { + gLastUsedMove = gCurrentMove; + if (IsMaxMove(gCurrentMove)) + gBattleStruct->dynamax.lastUsedBaseMove = gBattleStruct->dynamax.baseMoves[gBattlerAttacker]; + } } } else @@ -6477,11 +6514,9 @@ static void Cmd_moveend(void) && IsDoubleBattle() && !gProtectStructs[gBattlerAttacker].chargingTurn && (moveTarget == MOVE_TARGET_BOTH - || moveTarget == MOVE_TARGET_FOES_AND_ALLY) - && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + || moveTarget == MOVE_TARGET_FOES_AND_ALLY)) { u32 nextTarget = GetNextTarget(moveTarget, FALSE); - gHitMarker |= HITMARKER_NO_PPDEDUCT; if (nextTarget != MAX_BATTLERS_COUNT) { @@ -6489,8 +6524,12 @@ static void Cmd_moveend(void) gBattleScripting.moveendState = 0; MoveValuesCleanUp(); - if (moveEffect == EFFECT_EXPLOSION || moveEffect == EFFECT_MISTY_EXPLOSION // Edge case for Explosion not changing targets - || moveEffect == EFFECT_SYNCHRONOISE) // So we don't go back to the Synchronoise script + // Edge cases for moves that shouldn't repeat their own script + if (moveEffect == EFFECT_EXPLOSION + || moveEffect == EFFECT_MISTY_EXPLOSION + || moveEffect == EFFECT_MAGNITUDE + || moveEffect == EFFECT_SYNCHRONOISE + || gBattleMoveEffects[moveEffect].battleScript == BattleScript_EffectTwoTurnsAttack) BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript); else BattleScriptPush(GetMoveBattleScript(gCurrentMove)); @@ -6520,14 +6559,17 @@ static void Cmd_moveend(void) return; } } - - gHitMarker |= HITMARKER_NO_ATTACKSTRING; - gHitMarker &= ~HITMARKER_NO_PPDEDUCT; } RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove); gBattleScripting.moveendState++; break; } + case MOVEEND_HP_THRESHHOLD_ITEMS_TARGET: + if (gMultiHitCounter + && ItemBattleEffects(gBattlerTarget, gBattlerAttacker, GetBattlerHoldEffect(gBattlerTarget), IsOnHpThresholdActivation)) + effect = TRUE; + gBattleScripting.moveendState++; + break; case MOVEEND_MULTIHIT_MOVE: { if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) @@ -6569,7 +6611,6 @@ static void Cmd_moveend(void) if (gSpecialStatuses[gBattlerAttacker].parentalBondState) gSpecialStatuses[gBattlerAttacker].parentalBondState--; - gHitMarker |= (HITMARKER_NO_PPDEDUCT | HITMARKER_NO_ATTACKSTRING); gBattleScripting.animTargetsHit = 0; gBattleScripting.moveendState = 0; gSpecialStatuses[gBattlerAttacker].multiHitOn = TRUE; @@ -6595,31 +6636,15 @@ static void Cmd_moveend(void) effect = HandleMoveEndMoveBlock(moveEffect); gBattleScripting.moveendState++; break; - case MOVEEND_ITEM_EFFECTS_ATTACKER: - // ITEMEFFECT_MOVE_END loops over all battlers, not just attacker. - // It will executre only the first mon with an applicable item. - // So presumably it is a bug - if (ItemBattleEffects(ITEMEFFECT_MOVE_END, gBattlerAttacker)) + case MOVEEND_ITEM_EFFECTS_ATTACKER_2: + { + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker); + if (ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnStatusChangeActivation) + || ItemBattleEffects(gBattlerAttacker, gBattlerTarget, holdEffect, IsOnHpThresholdActivation)) effect = TRUE; gBattleScripting.moveendState++; break; - case MOVEEND_ITEM_THROAT_SPRAY: - if (IsSoundMove(gCurrentMove) - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_THROAT_SPRAY - && IsBattlerAlive(gBattlerAttacker) - && IsAnyTargetAffected(gBattlerAttacker) - && CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerAttacker)) - && !NoAliveMonsForEitherParty()) // Don't activate if battle will end - { - gLastUsedItem = gBattleMons[gBattlerAttacker].item; - gBattleScripting.battler = gBattlerAttacker; - SET_STATCHANGER(STAT_SPATK, 1, FALSE); - effect = TRUE; - BattleScriptCall(BattleScript_AttackerItemStatRaise); - } - gBattleScripting.moveendState++; - break; + } case MOVEEND_ABILITY_BLOCK: effect = HandleMoveEndAbilityBlock(gBattlerAttacker, gBattlerTarget, gCurrentMove); gBattleScripting.moveendState++; @@ -6630,6 +6655,31 @@ static void Cmd_moveend(void) else gBattleScripting.moveendState++; break; + case MOVEEND_COLOR_CHANGE: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + u32 battler = gBattleStruct->eventState.moveEndBattler++; + if (battler == gBattlerAttacker) + continue; + if (AbilityBattleEffects(ABILITYEFFECT_COLOR_CHANGE, battler, GetBattlerAbility(battler), 0, 0)) + return; + } + gBattleStruct->eventState.moveEndBattler = 0; + gBattleScripting.moveendState++; + break; + case MOVEEND_KEE_MARANGA_HP_THRESHOLD_ITEM_TARGET: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + u32 battlerDef = gBattleStruct->eventState.moveEndBattler++; + if (battlerDef == gBattlerAttacker) + continue; + enum HoldEffect holdEffect = GetBattlerHoldEffect(battlerDef); + if (ItemBattleEffects(battlerDef, gBattlerAttacker, holdEffect, IsKeeMarangaBerryActivation) + || ItemBattleEffects(battlerDef, gBattlerAttacker, holdEffect, IsOnHpThresholdActivation)) + return; + } + gBattleScripting.moveendState++; + break; case MOVEEND_RED_CARD: { u32 redCardBattlers = 0, i; @@ -6637,7 +6687,7 @@ static void Cmd_moveend(void) { if (i == gBattlerAttacker) continue; - if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_RED_CARD) + if (GetBattlerHoldEffect(i) == HOLD_EFFECT_RED_CARD) redCardBattlers |= (1u << i); } if (redCardBattlers && IsBattlerAlive(gBattlerAttacker)) @@ -6677,7 +6727,7 @@ static void Cmd_moveend(void) } } if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + gBattleScripting.moveendState = MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE; else gBattleScripting.moveendState++; break; @@ -6726,12 +6776,12 @@ static void Cmd_moveend(void) } } if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + gBattleScripting.moveendState = MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE; else gBattleScripting.moveendState++; break; - case MOVEEND_LIFEORB_SHELLBELL: - if (ItemBattleEffects(ITEMEFFECT_LIFEORB_SHELLBELL, 0)) + case MOVEEND_LIFE_ORB_SHELL_BELL: + if (ItemBattleEffects(gBattlerAttacker, 0, GetBattlerHoldEffect(gBattlerAttacker), IsLifeOrbShellBellActivation)) effect = TRUE; gBattleScripting.moveendState++; break; @@ -6746,13 +6796,13 @@ static void Cmd_moveend(void) case MOVEEND_EMERGENCY_EXIT: // Special case, because moves hitting multiple opponents stop after switching out { // Because sorting the battlers by speed takes lots of cycles, - // we check if EE can be activated and cound how many. + // we check if EE can be activated and count how many. u32 numEmergencyExitBattlers = 0; u32 emergencyExitBattlers = 0; for (i = 0; i < gBattlersCount; i++) { - if (EmergencyExitCanBeTriggered(i)) + if (IsBattlerTurnDamaged(i) && EmergencyExitCanBeTriggered(i)) { emergencyExitBattlers |= 1u << i; numEmergencyExitBattlers++; @@ -6791,10 +6841,22 @@ static void Cmd_moveend(void) } } if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; + gBattleScripting.moveendState = MOVEEND_JUMP_TO_HIT_ESCAPE_PLUS_ONE; else gBattleScripting.moveendState++; break; + case MOVEEND_HIT_ESCAPE: + if (moveEffect == EFFECT_HIT_ESCAPE + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && IsBattlerTurnDamaged(gBattlerTarget) + && IsBattlerAlive(gBattlerAttacker) + && !NoAliveMonsForBattlerSide(gBattlerTarget)) + { + effect = TRUE; + BattleScriptCall(BattleScript_EffectHitEscape); + } + gBattleScripting.moveendState++; + break; case MOVEEND_EJECT_PACK: { // Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items. @@ -6830,10 +6892,6 @@ static void Cmd_moveend(void) if (!(ejectPackBattlers & 1u << battler)) continue; - // Hit escape moves activate before Eject Pack for user - if (moveEffect == EFFECT_HIT_ESCAPE && gBattlerAttacker == battler) - continue; - gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; effect = TRUE; @@ -6843,34 +6901,64 @@ static void Cmd_moveend(void) break; // Only the fastest Eject item activates } } - if (effect) - gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; - else - gBattleScripting.moveendState++; + gBattleScripting.moveendState++; break; - case MOVEEND_HIT_ESCAPE: - if (moveEffect == EFFECT_HIT_ESCAPE - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && IsBattlerTurnDamaged(gBattlerTarget) - && IsBattlerAlive(gBattlerAttacker) - && !NoAliveMonsForBattlerSide(gBattlerTarget)) + + case MOVEEND_ITEMS_EFFECTS_ALL: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) { - effect = TRUE; - BattleScriptCall(BattleScript_EffectHitEscape); + u32 battler = gBattleStruct->eventState.moveEndBattler++; + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (ItemBattleEffects(battler, 0, holdEffect, IsOnStatusChangeActivation) + || ItemBattleEffects(battler, 0, holdEffect, IsOnHpThresholdActivation)) + return; } + gBattleStruct->eventState.moveEndBattler = 0; + gBattleScripting.moveendState++; + break; + case MOVEEND_WHITE_HERB: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + u32 battler = gBattleStruct->eventState.moveEndBattler++; + if (!IsBattlerAlive(battler)) + continue; + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsWhiteHerbActivation)) + return; + } + gBattleStruct->eventState.moveEndBattler = 0; gBattleScripting.moveendState++; break; case MOVEEND_OPPORTUNIST: - if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0)) - effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers - else - gBattleScripting.moveendState++; + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + u32 battler = gBattleStruct->eventState.moveEndBattler++; + if (!IsBattlerAlive(battler)) + continue; + if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, GetBattlerAbility(battler), 0, 0)) + return; + } + gBattleStruct->eventState.moveEndBattler = 0; + gBattleScripting.moveendState++; + break; + case MOVEEND_MIRROR_HERB: + while (gBattleStruct->eventState.moveEndBattler < gBattlersCount) + { + u32 battler = gBattleStruct->eventState.moveEndBattler++; + if (!IsBattlerAlive(battler)) + continue; + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsMirrorHerbActivation)) + return; + } + gBattleStruct->eventState.moveEndBattler = 0; + gBattleScripting.moveendState++; break; case MOVEEND_PICKPOCKET: if (IsBattlerAlive(gBattlerAttacker) && gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item && !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker])) // But not knocked off - && IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove) // Pickpocket requires contact + && IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) // Pickpocket requires contact && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked { u8 battlers[4] = {0, 1, 2, 3}; @@ -6901,23 +6989,6 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; - case MOVEEND_WHITE_HERB: - for (i = 0; i < gBattlersCount; i++) - { - if (!IsBattlerAlive(i)) - continue; - - if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_WHITE_HERB - && RestoreWhiteHerbStats(i)) - { - BattleScriptCall(BattleScript_WhiteHerbRet); - effect = TRUE; - break; - } - } - if (!effect) - gBattleScripting.moveendState++; - break; case MOVEEND_THIRD_MOVE_BLOCK: switch (moveEffect) { @@ -6943,7 +7014,7 @@ static void Cmd_moveend(void) u32 item = gBattleMons[gBattlerAttacker].item; gBattleMons[gBattlerAttacker].item = ITEM_NONE; gBattleStruct->battlerState[gBattlerAttacker].canPickupItem = TRUE; - gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerAttacker]][GetBattlerSide(gBattlerAttacker)] = item; + GetBattlerPartyState(gBattlerAttacker)->usedHeldItem = item; CheckSetUnburden(gBattlerAttacker); BtlController_EmitSetMonData( gBattlerAttacker, @@ -6975,9 +7046,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_SAME_MOVE_TURNS: - if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] - || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT - || gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] || !IsAnyTargetAffected()) gBattleStruct->metronomeItemCounter[gBattlerAttacker] = 0; else if (gCurrentMove == gLastResultingMoves[gBattlerAttacker] && gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT) gBattleStruct->metronomeItemCounter[gBattlerAttacker]++; @@ -6999,42 +7068,28 @@ static void Cmd_moveend(void) && gBattleMons[gBattlerAttacker].volatiles.lockConfusionTurns != 1) // And won't end this turn CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE); // Cancel it - if (gBattleStruct->savedAttackerCount > 0) - { - if (TESTING) - Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!", __FILE__, __LINE__); - else - DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!"); - } - if (gBattleStruct->savedTargetCount > 0) - { - if (TESTING) - Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!", __FILE__, __LINE__); - else - DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!"); - } - + TryClearChargeVolatile(moveType); + ValidateSavedBattlerCounts(); gProtectStructs[gBattlerAttacker].shellTrap = FALSE; gBattleStruct->battlerState[gBattlerAttacker].ateBoost = FALSE; - gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE; - gSpecialStatuses[gBattlerTarget].berryReduced = FALSE; - gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE; gBattleScripting.moveEffect = MOVE_EFFECT_NONE; gBattleStruct->moldBreakerActive = FALSE; - gBattleStruct->isAtkCancelerForCalledMove = FALSE; gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->categoryOverride = FALSE; gBattleStruct->additionalEffectsCounter = 0; gBattleStruct->poisonPuppeteerConfusion = FALSE; gBattleStruct->fickleBeamBoosted = FALSE; + gBattleStruct->tryDestinyBond = FALSE; + gBattleStruct->tryGrudge = FALSE; gBattleStruct->battlerState[gBattlerAttacker].usedMicleBerry = FALSE; gBattleStruct->noTargetPresent = FALSE; + gBattleStruct->toxicChainPriority = FALSE; if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) gBattleStruct->pledgeMove = FALSE; if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) SetActiveGimmick(gBattlerAttacker, GIMMICK_NONE); - if (B_CHARGE >= GEN_9 && moveType == TYPE_ELECTRIC && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) - gBattleMons[gBattlerAttacker].volatiles.charge = FALSE; + if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0) + gBattleMons[gBattlerAttacker].volatiles.destinyBond--; if (moveEffect == EFFECT_ECHOED_VOICE && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)) gBattleStruct->incrementEchoedVoice = TRUE; // check if Stellar type boost should be used up @@ -7152,7 +7207,7 @@ static void Cmd_sethealblock(void) else { gBattleMons[gBattlerTarget].volatiles.healBlock = TRUE; - gDisableStructs[gBattlerTarget].healBlockTimer = gBattleTurnCounter + 5; + gDisableStructs[gBattlerTarget].healBlockTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -7179,7 +7234,7 @@ static void Cmd_getswitchedmondata(void) if (TESTING && gBattlerPartyIndexes[battler] == gBattleStruct->monToSwitchIntoId[battler] - && gBattleStruct->hpBefore[battler] != 0) // battler is alive + && IsBattlerAlive(battler)) Test_ExitWithResult(TEST_RESULT_ERROR, 0, ":L:%s:%d: battler is trying to switch to themself", __FILE__, __LINE__); gBattlerPartyIndexes[battler] = gBattleStruct->monToSwitchIntoId[battler]; @@ -7455,7 +7510,7 @@ static void Cmd_jumpifcantswitch(void) CMD_ARGS(u8 battler:7, u8 ignoreEscapePrevention:1, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (!cmd->ignoreEscapePrevention && !CanBattlerEscape(battler) && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SHED_SHELL) + if (!cmd->ignoreEscapePrevention && !CanBattlerEscape(battler) && GetBattlerHoldEffect(battler) != HOLD_EFFECT_SHED_SHELL) { gBattlescriptCurrInstr = cmd->jumpInstr; } @@ -7527,7 +7582,7 @@ static void Cmd_openpartyscreen(void) { if (((1u << i) & hitmarkerFaintBits)) { - u32 skipPartnerCheck = FALSE; + bool32 skipPartnerCheck = FALSE; if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBattlerSide(i) == B_SIDE_OPPONENT && TRAINER_BATTLE_PARAM.opponentB != TRAINER_NONE) @@ -7773,15 +7828,10 @@ static void UpdateSentMonFlags(u32 battler) gHitMarker &= ~HITMARKER_FAINTED(battler); gSpecialStatuses[battler].faintedHasReplacement = FALSE; - - if (!BattlerHasAi(battler)) - gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[battler]; } static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId) { - gBattleMons[battler].volatiles.destinyBond = FALSE; - gHitMarker &= ~HITMARKER_DESTINYBOND; gBattleScripting.battler = battler; gBattleCommunication[MULTISTRING_CHOOSER] = multistringId; @@ -7802,19 +7852,20 @@ void TryHazardsOnSwitchIn(u32 battler, u32 side, enum Hazards hazardType) case HAZARDS_NONE: break; case HAZARDS_SPIKES: - if (GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD + { + enum Ability ability = GetBattlerAbility(battler); + if (ability != ABILITY_MAGIC_GUARD && IsBattlerAffectedByHazards(battler, FALSE) - && IsBattlerGrounded(battler)) + && IsBattlerGrounded(battler, ability, GetBattlerHoldEffect(battler))) { - u8 spikesDmg = (5 - gSideTimers[side].spikesAmount) * 2; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (spikesDmg); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + s32 spikesDmg = GetNonDynamaxMaxHP(battler) / ((5 - gSideTimers[side].spikesAmount) * 2); + SetPassiveDamageAmount(battler, spikesDmg); SetDmgHazardsBattlescript(battler, B_MSG_PKMNHURTBYSPIKES); } break; + } case HAZARDS_STICKY_WEB: - if (IsBattlerAffectedByHazards(battler, FALSE) && IsBattlerGrounded(battler)) + if (IsBattlerAffectedByHazards(battler, FALSE) && IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler))) { gBattleScripting.battler = battler; SET_STATCHANGER(STAT_SPEED, 1, TRUE); @@ -7822,7 +7873,7 @@ void TryHazardsOnSwitchIn(u32 battler, u32 side, enum Hazards hazardType) } break; case HAZARDS_TOXIC_SPIKES: - if (!IsBattlerGrounded(battler)) + if (!IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler))) break; if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) // Absorb the toxic spikes. @@ -7856,16 +7907,16 @@ void TryHazardsOnSwitchIn(u32 battler, u32 side, enum Hazards hazardType) case HAZARDS_STEALTH_ROCK: if (IsBattlerAffectedByHazards(battler, FALSE) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD) { - gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_POINTED_STONES, battler); - if (gBattleStruct->moveDamage[battler] != 0) + gBattleStruct->passiveHpUpdate[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_POINTED_STONES, battler); + if (gBattleStruct->passiveHpUpdate[battler] != 0) SetDmgHazardsBattlescript(battler, B_MSG_STEALTHROCKDMG); } break; case HAZARDS_STEELSURGE: if (IsBattlerAffectedByHazards(battler, FALSE) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD) { - gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_SHARP_STEEL, battler); - if (gBattleStruct->moveDamage[battler] != 0) + gBattleStruct->passiveHpUpdate[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_SHARP_STEEL, battler); + if (gBattleStruct->passiveHpUpdate[battler] != 0) SetDmgHazardsBattlescript(battler, B_MSG_SHARPSTEELDMG); } break; @@ -7900,6 +7951,16 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gBattleStruct->battlerState[battler].storedLunarDance = FALSE; } } + else if (EmergencyExitCanBeTriggered(battler)) + { + gBattleScripting.battler = gBattlerAbility = battler; + gSpecialStatuses[battler].switchInItemDone = FALSE; + gBattleStruct->battlerState[battler].forcedSwitch = FALSE; + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + BattleScriptCall(BattleScript_EmergencyExit); + else + BattleScriptCall(BattleScript_EmergencyExitWild); + } else if (!gDisableStructs[battler].hazardsDone) { TryHazardsOnSwitchIn(battler, side, gBattleStruct->hazardsQueue[side][gBattleStruct->hazardsCounter]); @@ -7915,15 +7976,14 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) else if (gBattleMons[battler].hp != gBattleMons[battler].maxHP && gBattleStruct->zmove.healReplacement) { gBattleStruct->zmove.healReplacement = FALSE; - gBattleStruct->moveDamage[battler] = -1 * (gBattleMons[battler].maxHP); + SetHealAmount(battler, gBattleMons[battler].maxHP); gBattleScripting.battler = battler; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_HP_TRAP; BattleScriptCall(BattleScript_HealReplacementZMove); - return TRUE; } else { - u32 battlerAbility = GetBattlerAbility(battler); + enum Ability battlerAbility = GetBattlerAbility(battler); // There is a hack here to ensure the truant counter will be 0 when the battler's next turn starts. // The truant counter is not updated in the case where a mon switches in after a lost judgment in the battle arena. if (battlerAbility == ABILITY_TRUANT @@ -7933,9 +7993,10 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gDisableStructs[battler].truantSwitchInHack = 0; - if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler)) + if (DoSwitchInAbilities(battler)) return TRUE; - else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0)) + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnSwitchInActivation)) return TRUE; for (i = 0; i < gBattlersCount; i++) @@ -7943,24 +8004,43 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) if (i == battler) continue; - switch (GetBattlerAbility(i)) + enum Ability ability = GetBattlerAbility(i); + switch (ability) { case ABILITY_TRACE: case ABILITY_COMMANDER: - if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0)) + if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, ability, 0, 0)) return TRUE; break; case ABILITY_FORECAST: case ABILITY_FLOWER_GIFT: case ABILITY_PROTOSYNTHESIS: - if (AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, i, 0, 0, 0)) + if (AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, i, ability, 0, 0)) return TRUE; break; + default: + break; } if (TryClearIllusion(i, ABILITYEFFECT_ON_SWITCHIN)) return TRUE; } + for (i = 0; i < gBattlersCount; i++) + { + if (ItemBattleEffects(i, 0, GetBattlerHoldEffect(i), IsWhiteHerbActivation)) + return TRUE; + } + for (i = 0; i < gBattlersCount; i++) + { + if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, i, GetBattlerAbility(i), 0, 0)) + return TRUE; + } + for (i = 0; i < gBattlersCount; i++) + { + if (ItemBattleEffects(i, 0, GetBattlerHoldEffect(i), IsMirrorHerbActivation)) + return TRUE; + } + for (i = 0; i < gBattlersCount; i++) { if (gBattlerByTurnOrder[i] == battler) @@ -7969,7 +8049,9 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gBattleStruct->hpOnSwitchout[GetBattlerSide(i)] = gBattleMons[i].hp; } + gSpecialStatuses[battler].switchInItemDone = FALSE; gBattleStruct->battlerState[battler].forcedSwitch = FALSE; + gBattleStruct->battlerState[battler].wasAboveHalfHp = FALSE; return FALSE; } @@ -8020,7 +8102,7 @@ static void Cmd_switchineffects(void) return; } } - if (TrySwitchInEjectPack(ITEMEFFECT_NONE)) + if (TrySwitchInEjectPack(OTHER)) return; // All battlers done, end for (i = 0; i < gBattlersCount; i++) @@ -8032,7 +8114,7 @@ static void Cmd_switchineffects(void) break; default: UpdateSentMonFlags(battler); - if (!DoSwitchInEffectsForBattler(battler) && !TrySwitchInEjectPack(ITEMEFFECT_NONE)) + if (!DoSwitchInEffectsForBattler(battler) && !TrySwitchInEjectPack(OTHER)) gBattlescriptCurrInstr = cmd->nextInstr; break; } @@ -8335,6 +8417,7 @@ static void Cmd_yesnoboxstoplearningmove(void) } } +// TODO: passive damage hit anim for sub static void Cmd_hitanimation(void) { CMD_ARGS(u8 battler); @@ -8345,7 +8428,7 @@ static void Cmd_hitanimation(void) if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT)) { - if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) + if (gBattleStruct->passiveHpUpdate[battler] > 0 || !(DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)) || gDisableStructs[battler].substituteHP == 0) { @@ -8363,8 +8446,7 @@ static void Cmd_hitanimation(void) || gBattleStruct->noResultString[battlerDef] != CAN_DAMAGE) continue; - if (!(gHitMarker & HITMARKER_IGNORE_SUBSTITUTE) - || !(DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)) + if (!(DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)) || gDisableStructs[battlerDef].substituteHP == 0) { BtlController_EmitHitAnimation(battlerDef, B_COMM_TO_CONTROLLER); @@ -8549,9 +8631,9 @@ static void Cmd_hidepartystatussummary(void) static void ResetValuesForCalledMove(void) { if (gBattlerByTurnOrder[gCurrentTurnActionNumber] != gBattlerAttacker) - gBattleStruct->atkCancelerTracker = 0; + gBattleStruct->eventState.atkCanceler = 0; else - SetAtkCancelerForCalledMove(); + gBattleStruct->eventState.atkCanceler = CANCELER_VOLATILE_BLOCKED; gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker); @@ -8668,7 +8750,7 @@ static void Cmd_setgravity(void) else { gFieldStatuses |= STATUS_FIELD_GRAVITY; - gFieldTimers.gravityTimer = gBattleTurnCounter + 5; + gFieldTimers.gravityTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -8681,13 +8763,8 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId) && GetBattlerPartyState(battler)->ateBerry && !IsBattlerAtMaxHp(battler)) { - gBattleStruct->cheekPouchActivated = TRUE; - gBattleStruct->savedcheekPouchDamage = gBattleStruct->moveDamage[battler]; - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 3; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; gBattlerAbility = battler; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 3); BattleScriptPush(gBattlescriptCurrInstr + 2); gBattlescriptCurrInstr = BattleScript_CheekPouchActivates; return TRUE; @@ -8695,16 +8772,6 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId) return FALSE; } -// When Cheek Pouch activates mid-battle it overwrites the current damage, so restore it -static void TryRestoreDamageAfterCheekPouch(u32 battler) -{ - if (gBattleStruct->cheekPouchActivated) - { - gBattleStruct->moveDamage[battler] = gBattleStruct->savedcheekPouchDamage; - gBattleStruct->cheekPouchActivated = FALSE; - } -} - // Used by Bestow and Symbiosis to take an item from one battler and give to another. static void BestowItem(u32 battlerAtk, u32 battlerDef) { @@ -8726,8 +8793,8 @@ static bool32 TrySymbiosis(u32 battler, u32 itemId, bool32 moveEnd) { if (!gBattleStruct->itemLost[B_SIDE_PLAYER][gBattlerPartyIndexes[battler]].stolen && gBattleStruct->changedItems[battler] == ITEM_NONE - && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_EJECT_BUTTON - && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_EJECT_PACK + && GetBattlerHoldEffect(battler) != HOLD_EFFECT_EJECT_BUTTON + && GetBattlerHoldEffect(battler) != HOLD_EFFECT_EJECT_PACK && (B_SYMBIOSIS_GEMS < GEN_7 || !(gSpecialStatuses[battler].gemBoost)) && GetMoveEffect(gCurrentMove) != EFFECT_FLING //Fling and damage-reducing berries are handled separately. && !gSpecialStatuses[battler].berryReduced @@ -8766,9 +8833,9 @@ static void Cmd_removeitem(void) // Popped Air Balloon cannot be restored by any means. // Corroded items cannot be restored either. - if (GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_AIR_BALLOON - && GetMoveEffect(gCurrentMove) != EFFECT_CORROSIVE_GAS) - gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = itemId; // Remember if switched out + if (GetBattlerHoldEffect(battler) != HOLD_EFFECT_AIR_BALLOON + && GetMoveEffect(gCurrentMove) != EFFECT_CORROSIVE_GAS) + GetBattlerPartyState(battler)->usedHeldItem = itemId; // Remember if switched out gBattleMons[battler].item = ITEM_NONE; gBattleStruct->battlerState[battler].canPickupItem = TRUE; @@ -9195,18 +9262,18 @@ static void Cmd_useitemonopponent(void) bool32 CanUseLastResort(u8 battler) { - u32 i; - u32 knownMovesCount = 0, usedMovesCount = 0; - - for (i = 0; i < 4; i++) + u32 moveIndex; + for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if (gBattleMons[battler].moves[i] != MOVE_NONE) - knownMovesCount++; - if (i != gCurrMovePos && gDisableStructs[battler].usedMoves & (1u << i)) // Increment used move count for all moves except current Last Resort. - usedMovesCount++; + u32 move = gBattleMons[battler].moves[moveIndex]; + // Assumes that an empty slot cannot have a non-empty slot after it + if (move == MOVE_NONE) + break; + // If not Last Resort and has not been used, can't use Last Resort + if (GetMoveEffect(move) != EFFECT_LAST_RESORT && !(gDisableStructs[battler].usedMoves & (1u << moveIndex))) + return FALSE; } - - return (knownMovesCount >= 2 && usedMovesCount >= knownMovesCount - 1); + return moveIndex >= 2; // At least two usable moves that are either Last Resort or have been used } static void RemoveAllWeather(void) @@ -9387,7 +9454,7 @@ u32 IsFlowerVeilProtected(u32 battler) return 0; } -u32 IsLeafGuardProtected(u32 battler, u32 ability) +u32 IsLeafGuardProtected(u32 battler, enum Ability ability) { if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN)) return ability == ABILITY_LEAF_GUARD; @@ -9395,13 +9462,13 @@ u32 IsLeafGuardProtected(u32 battler, u32 ability) return 0; } -bool32 IsShieldsDownProtected(u32 battler, u32 ability) +bool32 IsShieldsDownProtected(u32 battler, enum Ability ability) { return (ability == ABILITY_SHIELDS_DOWN && GetFormIdFromFormSpeciesId(gBattleMons[battler].species) < GetFormIdFromFormSpeciesId(SPECIES_MINIOR_CORE_RED)); // Minior is not in core form } -u32 IsAbilityStatusProtected(u32 battler, u32 ability) +u32 IsAbilityStatusProtected(u32 battler, enum Ability ability) { return IsLeafGuardProtected(battler, ability) || IsShieldsDownProtected(battler, ability) @@ -9412,7 +9479,7 @@ static bool32 IsRototillerAffected(u32 battler) { if (!IsBattlerAlive(battler)) return FALSE; - if (!IsBattlerGrounded(battler)) + if (!IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler))) return FALSE; // Only grounded battlers affected if (!IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) return FALSE; // Only grass types affected @@ -9423,7 +9490,7 @@ static bool32 IsRototillerAffected(u32 battler) return TRUE; } -static bool32 IsElectricAbilityAffected(u32 battler, u32 ability) +static bool32 IsElectricAbilityAffected(u32 battler, enum Ability ability) { u32 moveType; @@ -9598,15 +9665,8 @@ static bool32 ChangeOrderTargetAfterAttacker(void) return TRUE; } -// will be deprecated next release cycle -static void Cmd_various(void) +static void Cmd_unused_0x78(void) { - CMD_ARGS(u8 battler, u8 id); - - if (gBattleControllerExecFlags) - return; - - gBattlescriptCurrInstr = cmd->nextInstr; } static void TryResetProtectUseCounter(u32 battler) @@ -9675,7 +9735,7 @@ static void Cmd_tryexplosion(void) if (gBattleControllerExecFlags) return; - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; BtlController_EmitHealthBarUpdate(gBattlerAttacker, B_COMM_TO_CONTROLLER, INSTANT_HP_BAR_DROP); MarkBattlerForControllerExec(gBattlerAttacker); gBattlescriptCurrInstr = cmd->nextInstr; @@ -9722,77 +9782,22 @@ static void Cmd_jumpifnexttargetvalid(void) static void Cmd_tryhealhalfhealth(void) { - CMD_ARGS(const u8 *failInstr, u8 battler); + CMD_ARGS(u8 battler, const u8 *failInstr); const u8 *failInstr = cmd->failInstr; if (cmd->battler == BS_ATTACKER) gBattlerTarget = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerTarget) / 2; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - gBattleStruct->moveDamage[gBattlerTarget] *= -1; - + SetHealAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerTarget) / 2); if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) gBattlescriptCurrInstr = failInstr; else gBattlescriptCurrInstr = cmd->nextInstr; } -static void SetMoveForMirrorMove(u32 move) +static void Cmd_unused_0x7e(void) { - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - // Edge case, we used Z Mirror Move, got the stat boost and now need to use the Z-move - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move)) - { - gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move; - gCurrentMove = GetTypeBasedZMove(move); - } - else - { - gCurrentMove = move; - } - - gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - ResetValuesForCalledMove(); - gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove); -} - -static void Cmd_trymirrormove(void) -{ - CMD_ARGS(); - - s32 i, validMovesCount; - u16 move; - u16 validMoves[MAX_BATTLERS_COUNT] = {0}; - - for (validMovesCount = 0, i = 0; i < gBattlersCount; i++) - { - if (i != gBattlerAttacker) - { - move = gBattleStruct->lastTakenMoveFrom[gBattlerAttacker][i]; - if (move != MOVE_NONE && move != MOVE_UNAVAILABLE) - { - validMoves[validMovesCount] = move; - validMovesCount++; - } - } - } - - move = gBattleStruct->lastTakenMove[gBattlerAttacker]; - if (move != MOVE_NONE && move != MOVE_UNAVAILABLE) - { - SetMoveForMirrorMove(move); - } - else if (validMovesCount != 0) - { - SetMoveForMirrorMove(validMoves[Random() % validMovesCount]); - } - else // no valid moves found - { - gBattlescriptCurrInstr = cmd->nextInstr; - } } static void Cmd_setfieldweather(void) @@ -9874,18 +9879,16 @@ static void Cmd_manipulatedamage(void) switch (cmd->mode) { case DMG_CHANGE_SIGN: - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] *= -1; break; case DMG_1_8_TARGET_HP: - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerTarget) / 8; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; + SetPassiveDamageAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerTarget) / 8); break; case DMG_FULL_ATTACKER_HP: - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerAttacker); + gBattleStruct->passiveHpUpdate[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerAttacker); break; case DMG_BIG_ROOT: - gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = -1 * GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->passiveHpUpdate[gBattlerAttacker]); break; } @@ -9894,21 +9897,18 @@ static void Cmd_manipulatedamage(void) static void Cmd_trysetrest(void) { - CMD_ARGS(const u8 *failInstr); + CMD_ARGS(); - const u8 *failInstr = cmd->failInstr; gBattlerTarget = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].maxHP * (-1); + SetHealAmount(gBattlerTarget, gBattleMons[gBattlerTarget].maxHP); + enum Ability ability = GetBattlerAbility(gBattlerTarget); + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); - if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) - { - gBattlescriptCurrInstr = failInstr; - } - else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN)) + if (IsBattlerTerrainAffected(gBattlerTarget, ability, holdEffect, STATUS_FIELD_ELECTRIC_TERRAIN)) { gBattlescriptCurrInstr = BattleScript_ElectricTerrainPrevents; } - else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_MISTY_TERRAIN)) + else if (IsBattlerTerrainAffected(gBattlerTarget, ability, holdEffect, STATUS_FIELD_MISTY_TERRAIN)) { gBattlescriptCurrInstr = BattleScript_MistyTerrainPrevents; } @@ -9926,16 +9926,8 @@ static void Cmd_trysetrest(void) } } -static void Cmd_jumpifnotfirstturn(void) +static void Cmd_unused_0x82(void) { - CMD_ARGS(const u8 *jumpInstr); - - const u8 *jumpInstr = cmd->jumpInstr; - - if (gDisableStructs[gBattlerAttacker].isFirstTurn && !(gSpecialStatuses[gBattlerAttacker].instructedChosenTarget)) - gBattlescriptCurrInstr = cmd->nextInstr; - else - gBattlescriptCurrInstr = jumpInstr; } static void Cmd_unused_0x83(void) @@ -9987,19 +9979,10 @@ static void Cmd_stockpile(void) switch (cmd->id) { case 0: - if (gDisableStructs[gBattlerAttacker].stockpileCounter >= 3) - { - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CANT_STOCKPILE; - } - else - { - gDisableStructs[gBattlerAttacker].stockpileCounter++; - gDisableStructs[gBattlerAttacker].stockpileBeforeDef = gBattleMons[gBattlerAttacker].statStages[STAT_DEF]; - gDisableStructs[gBattlerAttacker].stockpileBeforeSpDef = gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF]; - PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBattlerAttacker].stockpileCounter); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STOCKPILED; - } + gDisableStructs[gBattlerAttacker].stockpileCounter++; + gDisableStructs[gBattlerAttacker].stockpileBeforeDef = gBattleMons[gBattlerAttacker].statStages[STAT_DEF]; + gDisableStructs[gBattlerAttacker].stockpileBeforeSpDef = gBattleMons[gBattlerAttacker].statStages[STAT_SPDEF]; + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gBattlerAttacker].stockpileCounter); break; case 1: // Save def/sp def stats. if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) @@ -10015,20 +9998,12 @@ static void Cmd_stockpile(void) static void Cmd_stockpiletobasedamage(void) { - CMD_ARGS(const u8 *failInstr); + CMD_ARGS(); - const u8 *failInstr = cmd->failInstr; - if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0) - { - gBattlescriptCurrInstr = failInstr; - } - else - { - if (gBattleCommunication[MISS_TYPE] != B_MSG_PROTECTED) - gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter; + if (gBattleCommunication[MISS_TYPE] != B_MSG_PROTECTED) + gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter; - gBattlescriptCurrInstr = cmd->nextInstr; - } + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_stockpiletohpheal(void) @@ -10037,40 +10012,27 @@ static void Cmd_stockpiletohpheal(void) const u8 *failInstr = cmd->failInstr; - if (gDisableStructs[gBattlerAttacker].stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed) + if (gBattleMons[gBattlerAttacker].maxHP == gBattleMons[gBattlerAttacker].hp) { + gDisableStructs[gBattlerAttacker].stockpileCounter = 0; gBattlescriptCurrInstr = failInstr; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FAILED; + gBattlerTarget = gBattlerAttacker; } else { - if (gBattleMons[gBattlerAttacker].maxHP == gBattleMons[gBattlerAttacker].hp) + if (gDisableStructs[gBattlerAttacker].stockpileCounter > 0) { - gDisableStructs[gBattlerAttacker].stockpileCounter = 0; - gBattlescriptCurrInstr = failInstr; - gBattlerTarget = gBattlerAttacker; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWALLOW_FULL_HP; + SetHealAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter))); + gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter; } - else + else // Snatched move { - if (gDisableStructs[gBattlerAttacker].stockpileCounter > 0) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / (1 << (3 - gDisableStructs[gBattlerAttacker].stockpileCounter)); - gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter; - } - else // Snatched move - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - gBattleScripting.animTurn = 1; - } - - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; - - gBattlescriptCurrInstr = cmd->nextInstr; - gBattlerTarget = gBattlerAttacker; + SetHealAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); + gBattleScripting.animTurn = 1; } + + gBattlescriptCurrInstr = cmd->nextInstr; + gBattlerTarget = gBattlerAttacker; } } @@ -10092,17 +10054,8 @@ void BS_RemoveStockpileCounters(void) } } -// Sign change for drained HP handled in GetDrainedBigRootHp -static void Cmd_setdrainedhp(void) +static void Cmd_unused_0x88(void) { - CMD_ARGS(); - - gBattleStruct->moveDamage[gBattlerAttacker] = (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100); - - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - - gBattlescriptCurrInstr = cmd->nextInstr; } static u16 ReverseStatChangeMoveEffect(u16 moveEffect) @@ -10173,9 +10126,9 @@ static u16 ReverseStatChangeMoveEffect(u16 moveEffect) } } -static void TryPlayStatChangeAnimation(u32 battler, u32 ability, u32 stats, s32 statValue, u32 statId, bool32 certain) +static void TryPlayStatChangeAnimation(u32 battler, enum Ability ability, u32 stats, s32 statValue, u32 statId, bool32 certain) { - u32 currStat = 0; + enum Stat currStat = 0; u32 changeableStatsCount = 1; // current stat is counted automatically u32 statAnimId = statId; bool32 statChangeByTwo = statValue > 1 || statValue < -1; @@ -10261,12 +10214,12 @@ static void TryPlayStatChangeAnimation(u32 battler, u32 ability, u32 stats, s32 } } -static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr) +static u32 ChangeStatBuffs(u32 battler, s8 statValue, enum Stat statId, union StatChangeFlags flags, u32 stats, const u8 *BS_ptr) { u32 index, battlerAbility; - enum ItemHoldEffect battlerHoldEffect; + enum HoldEffect battlerHoldEffect; battlerAbility = GetBattlerAbility(battler); - battlerHoldEffect = GetBattlerHoldEffect(battler, TRUE); + battlerHoldEffect = GetBattlerHoldEffect(battler); gSpecialStatuses[battler].changedStatsBattlerId = gBattlerAttacker; if (battlerAbility == ABILITY_CONTRARY) @@ -10404,37 +10357,32 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChan statValue = -1; else if (gBattleMons[battler].statStages[statId] == 2 && statValue < -2) statValue = -2; - gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; - index = 1; + if (statValue == -2) { - gBattleTextBuff2[1] = B_BUFF_STRING; - gBattleTextBuff2[2] = STRINGID_STATHARSHLY; - gBattleTextBuff2[3] = STRINGID_STATHARSHLY >> 8; - index = 4; + PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATHARSHLY); } else if (statValue <= -3) { - gBattleTextBuff2[1] = B_BUFF_STRING; - gBattleTextBuff2[2] = STRINGID_SEVERELY & 0xFF; - gBattleTextBuff2[3] = STRINGID_SEVERELY >> 8; - index = 4; + PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_SEVERELY); + } + else + { + PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_EMPTYSTRING3); } - gBattleTextBuff2[index++] = B_BUFF_STRING; - gBattleTextBuff2[index++] = STRINGID_STATFELL; - gBattleTextBuff2[index++] = STRINGID_STATFELL >> 8; - gBattleTextBuff2[index] = B_BUFF_EOS; - gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == battler); // B_MSG_ATTACKER_STAT_FELL or B_MSG_DEFENDER_STAT_FELL + gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == battler); // B_MSG_ATTACKER_STAT_CHANGED or B_MSG_DEFENDER_STAT_CHANGED if (gBattleMons[battler].statStages[statId] == MIN_STAT_STAGE) { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_DECREASE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_CHANGE; + gBattleScripting.statChanger |= STAT_BUFF_NEGATIVE; } else if (!flags.onlyChecking) { gDisableStructs[battler].tryEjectPack = TRUE; gProtectStructs[battler].lashOutAffected = TRUE; + gBattleScripting.statChanger |= STAT_BUFF_NEGATIVE; } } } @@ -10445,32 +10393,26 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChan statValue = 1; else if (gBattleMons[battler].statStages[statId] == 10 && statValue > 2) statValue = 2; - gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; - index = 1; + if (statValue == 2) { - gBattleTextBuff2[1] = B_BUFF_STRING; - gBattleTextBuff2[2] = STRINGID_STATSHARPLY; - gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8; - index = 4; + PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATSHARPLY); } else if (statValue >= 3) { - gBattleTextBuff2[1] = B_BUFF_STRING; - gBattleTextBuff2[2] = STRINGID_DRASTICALLY & 0xFF; - gBattleTextBuff2[3] = STRINGID_DRASTICALLY >> 8; - index = 4; + PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_DRASTICALLY); + } + else + { + PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_EMPTYSTRING3); } - gBattleTextBuff2[index++] = B_BUFF_STRING; - gBattleTextBuff2[index++] = STRINGID_STATROSE; - gBattleTextBuff2[index++] = STRINGID_STATROSE >> 8; - gBattleTextBuff2[index] = B_BUFF_EOS; - gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == battler); // B_MSG_ATTACKER_STAT_ROSE or B_MSG_DEFENDER_STAT_ROSE + gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == battler); // B_MSG_ATTACKER_STAT_CHANGED or B_MSG_DEFENDER_STAT_CHANGED if (gBattleMons[battler].statStages[statId] == MAX_STAT_STAGE) { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_INCREASE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_CHANGE; + gBattleScripting.statChanger &= ~STAT_BUFF_NEGATIVE; } else if (!flags.onlyChecking) { @@ -10481,6 +10423,7 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChan statIncrease = statValue; gProtectStructs[battler].statRaised = TRUE; + gBattleScripting.statChanger &= ~STAT_BUFF_NEGATIVE; if (statIncrease) { @@ -10495,7 +10438,7 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChan { gProtectStructs[index].activateOpportunist = 2; // set stats to copy } - if (GetBattlerHoldEffect(index, TRUE) == HOLD_EFFECT_MIRROR_HERB) + if (GetBattlerHoldEffect(index) == HOLD_EFFECT_MIRROR_HERB) { gProtectStructs[index].eatMirrorHerb = 1; } @@ -10510,7 +10453,7 @@ static u32 ChangeStatBuffs(u32 battler, s8 statValue, u32 statId, union StatChan } } - if (gBattleCommunication[MULTISTRING_CHOOSER] == B_MSG_STAT_WONT_INCREASE) // same as B_MSG_STAT_WONT_DECREASE + if (gBattleCommunication[MULTISTRING_CHOOSER] == B_MSG_STAT_WONT_CHANGE) // at max or min { if (!flags.allowPtr) return STAT_CHANGE_DIDNT_WORK; @@ -10975,8 +10918,8 @@ static void Cmd_tryKO(void) CMD_ARGS(const u8 *failInstr); enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget, TRUE); - u16 targetAbility = GetBattlerAbility(gBattlerTarget); + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); + enum Ability targetAbility = GetBattlerAbility(gBattlerTarget); u32 rand = Random() % 100; u32 affectionScore = GetBattlerAffectionHearts(gBattlerTarget); u32 endured = NOT_ENDURED; @@ -11201,7 +11144,7 @@ static void Cmd_setmist(void) } else { - gSideTimers[GetBattlerSide(gBattlerAttacker)].mistTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].mistTimer = 5; gSideStatuses[GetBattlerSide(gBattlerAttacker)] |= SIDE_STATUS_MIST; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_MIST; } @@ -11303,7 +11246,7 @@ static void Cmd_setsubstitute(void) CMD_ARGS(); u32 factor = GetMoveEffect(gCurrentMove) == EFFECT_SHED_TAIL ? 2 : 4; - u32 hp; + s32 hp = 0; if (factor == 2) hp = (GetNonDynamaxMaxHP(gBattlerAttacker)+1) / factor; // shed tail rounds up @@ -11315,25 +11258,22 @@ static void Cmd_setsubstitute(void) if (gBattleMons[gBattlerAttacker].hp <= hp) { - gBattleStruct->moveDamage[gBattlerAttacker] = 0; + hp = 0; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SUBSTITUTE_FAILED; } else { - gBattleStruct->moveDamage[gBattlerAttacker] = hp; // one bit value will only work for Pokémon which max hp can go to 1020(which is more than possible in games) - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - gBattleMons[gBattlerAttacker].volatiles.substitute = TRUE; gBattleMons[gBattlerAttacker].volatiles.wrapped = FALSE; + // gDisableStructs[gBattlerAttacker].substituteHP = (factor == 2) ? (hp / 2) : hp; if (factor == 2) - gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker] / 2; + gDisableStructs[gBattlerAttacker].substituteHP = hp / 2; else - gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker]; + gDisableStructs[gBattlerAttacker].substituteHP = hp; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SUBSTITUTE; - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE; } + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = hp; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -11380,41 +11320,11 @@ static void Cmd_mimicattackcopy(void) } } -static bool32 InvalidMetronomeMove(u32 move) -{ - return GetMoveEffect(move) == EFFECT_PLACEHOLDER - || IsMoveMetronomeBanned(move); -} - -static void Cmd_metronome(void) +static void Cmd_setcalledmove(void) { CMD_ARGS(); - -#if B_METRONOME_MOVES >= GEN_9 - u32 moveCount = MOVES_COUNT_GEN9; -#elif B_METRONOME_MOVES >= GEN_8 - u32 moveCount = MOVES_COUNT_GEN8; -#elif B_METRONOME_MOVES >= GEN_7 - u32 moveCount = MOVES_COUNT_GEN7; -#elif B_METRONOME_MOVES >= GEN_6 - u32 moveCount = MOVES_COUNT_GEN6; -#elif B_METRONOME_MOVES >= GEN_5 - u32 moveCount = MOVES_COUNT_GEN5; -#elif B_METRONOME_MOVES >= GEN_4 - u32 moveCount = MOVES_COUNT_GEN4; -#elif B_METRONOME_MOVES >= GEN_3 - u32 moveCount = MOVES_COUNT_GEN3; -#elif B_METRONOME_MOVES >= GEN_2 - u32 moveCount = MOVES_COUNT_GEN2; -#else - u32 moveCount = MOVES_COUNT_GEN1; -#endif - - gCurrentMove = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove); - PrepareStringBattle(STRINGID_WAGGLINGAFINGER, gBattlerAttacker); - gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove); - gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - ResetValuesForCalledMove(); + gCurrentMove = gCalledMove; + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_unused_0x9f(void) @@ -11569,8 +11479,8 @@ static void Cmd_painsplitdmgcalc(void) { s32 hpDiff = (gBattleMons[gBattlerAttacker].hp + GetNonDynamaxHP(gBattlerTarget)) / 2; - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxHP(gBattlerTarget) - hpDiff; - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp - hpDiff; + gBattleStruct->passiveHpUpdate[gBattlerTarget] = GetNonDynamaxHP(gBattlerTarget) - hpDiff; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp - hpDiff; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -11765,49 +11675,8 @@ static void Cmd_copymovepermanently(void) } } -static void Cmd_trychoosesleeptalkmove(void) +static void Cmd_unused_0xA9(void) { - CMD_ARGS(const u8 *failInstr); - - u32 i, unusableMovesBits = 0, movePosition; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (IsMoveSleepTalkBanned(gBattleMons[gBattlerAttacker].moves[i]) - || gBattleMoveEffects[GetMoveEffect(gBattleMons[gBattlerAttacker].moves[i])].twoTurnEffect) - { - unusableMovesBits |= (1 << (i)); - } - } - - unusableMovesBits = CheckMoveLimitations(gBattlerAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP | MOVE_LIMITATION_CHOICE_ITEM)); - if (unusableMovesBits == ALL_MOVES_MASK) // all 4 moves cannot be chosen - { - gBattlescriptCurrInstr = cmd->nextInstr; - } - else // at least one move can be chosen - { - // Set Sleep Talk as used move, so it works with Last Resort. - gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos; - do - { - movePosition = MOD(Random(), MAX_MON_MOVES); - } while ((1u << movePosition) & unusableMovesBits); - - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gBattleMons[gBattlerAttacker].moves[movePosition])) - { - gBattleStruct->zmove.baseMoves[gBattlerAttacker] = gBattleMons[gBattlerAttacker].moves[movePosition]; - gCalledMove = GetTypeBasedZMove(gBattleMons[gBattlerAttacker].moves[movePosition]); - } - else - { - gCalledMove = gBattleMons[gBattlerAttacker].moves[movePosition]; - } - gCurrMovePos = movePosition; - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); - gBattlescriptCurrInstr = cmd->failInstr; - } } static inline bool32 IsDanamaxMonPresent(void) @@ -11824,41 +11693,12 @@ static inline bool32 IsDanamaxMonPresent(void) return FALSE; } -static void Cmd_trysetdestinybond(void) +static void Cmd_unused_AA(void) { - CMD_ARGS(const u8 *failInstr); - - if (IsDanamaxMonPresent()) - { - gBattlescriptCurrInstr = BattleScript_MoveBlockedByDynamax; - } - else if (DoesDestinyBondFail(gBattlerAttacker)) - { - gBattlescriptCurrInstr = cmd->failInstr; - } - else - { - gBattleMons[gBattlerAttacker].volatiles.destinyBond = TRUE; - gBattlescriptCurrInstr = cmd->nextInstr; - } } -static void TrySetDestinyBondToHappen(void) +static void Cmd_unused_0xab(void) { - if (gBattleMons[gBattlerTarget].volatiles.destinyBond - && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) - && !(gHitMarker & HITMARKER_GRUDGE)) - { - gHitMarker |= HITMARKER_DESTINYBOND; - } -} - -static void Cmd_trysetdestinybondtohappen(void) -{ - CMD_ARGS(); - - TrySetDestinyBondToHappen(); - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_settailwind(void) @@ -11870,7 +11710,7 @@ static void Cmd_settailwind(void) if (!(gSideStatuses[side] & SIDE_STATUS_TAILWIND)) { gSideStatuses[side] |= SIDE_STATUS_TAILWIND; - gSideTimers[side].tailwindTimer = gBattleTurnCounter + (B_TAILWIND_TURNS >= GEN_5 ? 4 : 3); + gSideTimers[side].tailwindTimer = (B_TAILWIND_TURNS >= GEN_5 ? 4 : 3); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -12003,7 +11843,7 @@ static void Cmd_healpartystatus(void) if (species != SPECIES_NONE && species != SPECIES_EGG) { - u16 ability; + enum Ability ability; bool32 isAttacker = gBattlerPartyIndexes[gBattlerAttacker] == i; bool32 isDoublesPartner = gBattlerPartyIndexes[partner] == i && IsBattlerAlive(partner); @@ -12057,10 +11897,7 @@ static void Cmd_cursetarget(void) else { gBattleMons[gBattlerTarget].volatiles.cursed = TRUE; - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 2); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -12198,7 +12035,7 @@ static void Cmd_setembargo(void) else { gBattleMons[gBattlerTarget].volatiles.embargo = TRUE; - gDisableStructs[gBattlerTarget].embargoTimer = gBattleTurnCounter + 5; + gDisableStructs[gBattlerTarget].embargoTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -12207,7 +12044,7 @@ static void Cmd_presentdamagecalculation(void) { CMD_ARGS(); - u32 rand = Random() & 0xFF; + u32 rand = RandomUniform(RNG_PRESENT, 0, 0xFF); /* Don't reroll present effect/power for the second hit of Parental Bond. * Not sure if this is the correct behaviour, but bulbapedia states @@ -12231,11 +12068,7 @@ static void Cmd_presentdamagecalculation(void) } else { - // TODO: Check if this is correct - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerTarget) / 4; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - gBattleStruct->moveDamage[gBattlerTarget] *= -1; + SetHealAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerTarget) / 4); gBattleStruct->presentBasePower = 0; } } @@ -12267,7 +12100,7 @@ static void Cmd_setsafeguard(void) else { gSideStatuses[GetBattlerSide(gBattlerAttacker)] |= SIDE_STATUS_SAFEGUARD; - gSideTimers[GetBattlerSide(gBattlerAttacker)].safeguardTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].safeguardTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SAFEGUARD; } @@ -12278,7 +12111,7 @@ static void Cmd_magnitudedamagecalculation(void) { CMD_ARGS(); - u32 magnitude = Random() % 100; + u32 magnitude = RandomUniform(RNG_MAGNITUDE, 0, 99); if (magnitude < 5) { @@ -12373,11 +12206,29 @@ static void Cmd_jumpifnopursuitswitchdmg(void) } } -static void Cmd_tryrestorehpberry(void) +static void Cmd_tryactivateitem(void) { - CMD_ARGS(); - if (TryRestoreHPBerries(gBattlerAttacker, ITEMEFFECT_TRY_HEALING)) - return; + CMD_ARGS(u8 battler, u8 flag); + u32 battler = GetBattlerForBattleScript(cmd->battler); + + switch ((enum ItemActivationState)cmd->flag) + { + case ACTIVATION_ON_USABLE_AGAIN: + case ACTIVATION_ON_PICK_UP: + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsForceTriggerItemActivation)) + return; + break; + case ACTIVATION_ON_HARVEST: + gLastUsedItem = gBattleMons[battler].item; + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnBerryActivation)) + return; + break; + case ACTIVATION_ON_HP_THRESHOLD: + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsOnHpThresholdActivation)) + return; + break; + } + gBattlescriptCurrInstr = cmd->nextInstr; } @@ -12393,10 +12244,7 @@ static void Cmd_halvehp(void) if (gBattleMons[gBattlerAttacker].hp > halfHp) { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 2); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -12431,8 +12279,8 @@ static void Cmd_rapidspinfree(void) { gBattleScripting.battler = gBattlerTarget; gBattleMons[gBattlerAttacker].volatiles.wrapped = FALSE; - gBattlerTarget = gBattleStruct->wrappedBy[gBattlerAttacker]; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[gBattlerAttacker]); + gBattlerTarget = gBattleMons[gBattlerAttacker].volatiles.wrappedBy; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].volatiles.wrappedMove); BattleScriptCall(BattleScript_WrapFree); } else if (gBattleMons[gBattlerAttacker].volatiles.leechSeed) @@ -12470,21 +12318,22 @@ static void Cmd_recoverbasedonsunlight(void) gBattlerTarget = gBattlerAttacker; if (gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP) { + s32 recoverAmount = 0; if (GetMoveEffect(gCurrentMove) == EFFECT_SHORE_UP) { if (HasWeatherEffect() && gBattleWeather & B_WEATHER_SANDSTORM) - gBattleStruct->moveDamage[gBattlerAttacker] = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; + recoverAmount = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; else - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; } else if (GetGenConfig(GEN_CONFIG_TIME_OF_DAY_HEALING_MOVES) != GEN_2) { - if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) + recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else if (gBattleWeather & B_WEATHER_SUN) - gBattleStruct->moveDamage[gBattlerAttacker] = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; + recoverAmount = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; else // not sunny weather - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; } else // B_TIME_OF_DAY_HEALING_MOVES == GEN_2 { @@ -12511,19 +12360,16 @@ static void Cmd_recoverbasedonsunlight(void) break; } - if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA) - gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) + recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 4; else if (gBattleWeather & B_WEATHER_SUN) - gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 2; + recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else // not sunny weather - gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 8; + recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 8; } - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; - + SetHealAmount(gBattlerAttacker, recoverAmount); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -12567,29 +12413,21 @@ static void Cmd_selectfirstvalidtarget(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_trysetfutureattack(void) +static void Cmd_setfutureattack(void) { - CMD_ARGS(const u8 *failInstr); + CMD_ARGS(); - if (gWishFutureKnock.futureSightCounter[gBattlerTarget] > gBattleTurnCounter) - { - gBattlescriptCurrInstr = cmd->failInstr; - } + gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove; + gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker; + gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker]; + gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3; + + if (gCurrentMove == MOVE_DOOM_DESIRE) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE; else - { - gSideStatuses[GetBattlerSide(gBattlerTarget)] |= SIDE_STATUS_FUTUREATTACK; - gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove; - gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker; - gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker]; - gWishFutureKnock.futureSightCounter[gBattlerTarget] = gBattleTurnCounter + 3; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FUTURE_SIGHT; - if (gCurrentMove == MOVE_DOOM_DESIRE) - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE; - else - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FUTURE_SIGHT; - - gBattlescriptCurrInstr = cmd->nextInstr; - } + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_trydobeatup(void) @@ -12693,9 +12531,10 @@ static void Cmd_trymemento(void) else { // Success, drop user's HP bar to 0 - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp; BtlController_EmitHealthBarUpdate(gBattlerAttacker, B_COMM_TO_CONTROLLER, INSTANT_HP_BAR_DROP); MarkBattlerForControllerExec(gBattlerAttacker); + gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -12711,52 +12550,12 @@ static void Cmd_setforcedtarget(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_setcharge(void) +static void Cmd_unused_0xcb(void) { - CMD_ARGS(u8 battler); - - u8 battler = GetBattlerForBattleScript(cmd->battler); - gBattleMons[battler].volatiles.charge = TRUE; - if (B_CHARGE < GEN_9) - gDisableStructs[battler].chargeTimer = 2; - else - gDisableStructs[battler].chargeTimer = 0; - gBattlescriptCurrInstr = cmd->nextInstr; } -// Nature Power -static void Cmd_callenvironmentattack(void) +static void Cmd_unused_0xCC(void) { - CMD_ARGS(); - - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gCurrentMove = GetNaturePowerMove(gBattlerAttacker); - gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - BattleScriptPush(GetMoveBattleScript(gCurrentMove)); - gBattlescriptCurrInstr = cmd->nextInstr; -} - -u32 GetNaturePowerMove(u32 battler) -{ - u32 move = gBattleEnvironmentInfo[gBattleEnvironment].naturePower; - if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) - move = MOVE_MOONBLAST; - else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) - move = MOVE_THUNDERBOLT; - else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) - move = MOVE_ENERGY_BALL; - else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) - move = MOVE_PSYCHIC; - else if (gBattleEnvironmentInfo[gBattleEnvironment].naturePower == MOVE_NONE) - move = MOVE_TRI_ATTACK; - - if (GetActiveGimmick(battler) == GIMMICK_Z_MOVE) - { - gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move; - move = GetTypeBasedZMove(move); - } - - return move; } static void Cmd_curestatuswithmove(void) @@ -12852,11 +12651,16 @@ static void Cmd_trysethelpinghand(void) { CMD_ARGS(const u8 *failInstr); + if (!IsDoubleBattle()) + { + gBattlescriptCurrInstr = cmd->failInstr; + return; + } + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); - if (IsDoubleBattle() - && !(gAbsentBattlerFlags & (1u << gBattlerTarget)) - && !HasBattlerActedThisTurn(gBattlerTarget)) + if (!(gAbsentBattlerFlags & (1u << gBattlerTarget)) + && !HasBattlerActedThisTurn(gBattlerTarget)) { gProtectStructs[gBattlerTarget].helpingHand++; gBattlescriptCurrInstr = cmd->nextInstr; @@ -12867,7 +12671,7 @@ static void Cmd_trysethelpinghand(void) } } -// Trick +// Trick // TODO: Sticky Hold static void Cmd_tryswapitems(void) { CMD_ARGS(const u8 *failInstr); @@ -12980,7 +12784,7 @@ static void Cmd_tryswapitems(void) static bool32 CanAbilityShieldActivateForBattler(u32 battler) { - if (GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD) + if (GetBattlerHoldEffectIgnoreAbility(battler) != HOLD_EFFECT_ABILITY_SHIELD) return FALSE; RecordItemEffectBattle(battler, HOLD_EFFECT_ABILITY_SHIELD); @@ -12996,7 +12800,7 @@ static void Cmd_trycopyability(void) u32 battler = GetBattlerForBattleScript(cmd->battler); u32 partner = BATTLE_PARTNER(battler); - u16 defAbility = gBattleMons[gBattlerTarget].ability; + enum Ability defAbility = gBattleMons[gBattlerTarget].ability; bool32 shouldConsiderPartner = IsBattlerAlive(partner) && GetMoveEffect(gCurrentMove) == EFFECT_DOODLE; if (gBattleMons[battler].ability == defAbility @@ -13014,6 +12818,7 @@ static void Cmd_trycopyability(void) } else { + RemoveAbilityFlags(battler); gBattleScripting.abilityPopupOverwrite = gBattleMons[battler].ability; gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = defAbility; gLastUsedAbility = defAbility; @@ -13029,9 +12834,9 @@ static void Cmd_trywish(void) { gBattlescriptCurrInstr = cmd->failInstr; } - else if (gWishFutureKnock.wishCounter[gBattlerAttacker] <= gBattleTurnCounter) + else if (gWishFutureKnock.wishCounter[gBattlerAttacker] == 0) { - gWishFutureKnock.wishCounter[gBattlerAttacker] = gBattleTurnCounter + 2; + gWishFutureKnock.wishCounter[gBattlerAttacker] = 2; gWishFutureKnock.wishPartyId[gBattlerAttacker] = gBattlerPartyIndexes[gBattlerAttacker]; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -13067,7 +12872,7 @@ static void Cmd_setgastroacid(void) { gBattlescriptCurrInstr = cmd->failInstr; } - else if (GetBattlerHoldEffectIgnoreAbility(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + else if (GetBattlerHoldEffectIgnoreAbility(gBattlerTarget) == HOLD_EFFECT_ABILITY_SHIELD) { RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); gBattlescriptCurrInstr = cmd->failInstr; @@ -13085,19 +12890,21 @@ static void Cmd_setgastroacid(void) static void Cmd_setyawn(void) { CMD_ARGS(const u8 *failInstr); + enum Ability ability = GetBattlerAbility(gBattlerTarget); + enum HoldEffect holdEffect = GetBattlerHoldEffect(gBattlerTarget); if (gBattleMons[gBattlerTarget].volatiles.yawn || gBattleMons[gBattlerTarget].status1 & STATUS1_ANY) { gBattlescriptCurrInstr = cmd->failInstr; } - else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN)) + else if (IsBattlerTerrainAffected(gBattlerTarget, ability, holdEffect, STATUS_FIELD_ELECTRIC_TERRAIN)) { // When Yawn is used while Electric Terrain is set and drowsiness is set from Yawn being used against target in the previous turn: // "But it failed" will display first. gBattlescriptCurrInstr = BattleScript_ElectricTerrainPrevents; } - else if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_MISTY_TERRAIN)) + else if (IsBattlerTerrainAffected(gBattlerTarget, ability, holdEffect, STATUS_FIELD_MISTY_TERRAIN)) { // When Yawn is used while Misty Terrain is set and drowsiness is set from Yawn being used against target in the previous turn: // "But it failed" will display first. @@ -13135,7 +12942,7 @@ static void HandleRoomMove(u32 statusFlag, u16 *timer, u8 stringId) else { gFieldStatuses |= statusFlag; - *timer = gBattleTurnCounter + 5; + *timer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = stringId; } } @@ -13189,6 +12996,8 @@ static void Cmd_tryswapabilities(void) if (!IsBattlerAlly(gBattlerAttacker, gBattlerTarget)) gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerAttacker].ability; gLastUsedAbility = gBattleMons[gBattlerTarget].ability; + RemoveAbilityFlags(gBattlerTarget); + RemoveAbilityFlags(gBattlerAttacker); gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = gBattleMons[gBattlerAttacker].ability; gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gLastUsedAbility; @@ -13276,10 +13085,10 @@ static void Cmd_trysetvolatile(void) switch (cmd->_volatile) { case VOLATILE_MAGNET_RISE: - gDisableStructs[battler].magnetRiseTimer = gBattleTurnCounter + 5; + gDisableStructs[battler].magnetRiseTimer = 5; break; case VOLATILE_LASER_FOCUS: - gDisableStructs[battler].laserFocusTimer = gBattleTurnCounter + 2; + gDisableStructs[battler].laserFocusTimer = 2; break; default: break; @@ -13288,53 +13097,8 @@ static void Cmd_trysetvolatile(void) } } -static void Cmd_assistattackselect(void) +static void Cmd_unused_0xde(void) { - CMD_ARGS(const u8 *failInstr); - - s32 chooseableMovesNo = 0; - struct Pokemon *party; - s32 monId, moveId; - u16 *validMoves = Alloc(sizeof(u16) * PARTY_SIZE * MAX_MON_MOVES); - - if (validMoves != NULL) - { - party = GetBattlerParty(gBattlerAttacker); - - for (monId = 0; monId < PARTY_SIZE; monId++) - { - if (monId == gBattlerPartyIndexes[gBattlerAttacker]) - continue; - if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE) - continue; - if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) - continue; - - for (moveId = 0; moveId < MAX_MON_MOVES; moveId++) - { - u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId); - - if (IsMoveAssistBanned(move)) - continue; - - validMoves[chooseableMovesNo++] = move; - } - } - } - - if (chooseableMovesNo) - { - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gCalledMove = validMoves[Random() % chooseableMovesNo]; - gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); - gBattlescriptCurrInstr = cmd->nextInstr; - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; - } - - TRY_FREE_AND_SET_NULL(validMoves); } static void Cmd_trysetmagiccoat(void) @@ -13414,6 +13178,8 @@ static void Cmd_switchoutabilities(void) MarkBattlerForControllerExec(battler); break; } + default: + break; } gBattlescriptCurrInstr = cmd->nextInstr; @@ -13431,18 +13197,8 @@ static void Cmd_jumpifhasnohp(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_jumpifnotcurrentmoveargtype(void) +static void Cmd_unused_0xE4(void) { - CMD_ARGS(u8 battler, const u8 *failInstr); - - u8 battler = GetBattlerForBattleScript(cmd->battler); - const u8 *failInstr = cmd->failInstr; - u32 type = GetMoveArgType(gCurrentMove); - - if (!IS_BATTLER_OF_TYPE(battler, type)) - gBattlescriptCurrInstr = failInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_pickup(void) @@ -13450,8 +13206,9 @@ static void Cmd_pickup(void) CMD_ARGS(); u32 i, j; - u16 species, heldItem, ability; + u16 species, heldItem; u8 lvlDivBy10; + enum Ability ability; if (!InBattlePike()) // No items in Battle Pike. { @@ -13540,7 +13297,7 @@ static void Cmd_settypebasedhalvers(void) if (!(gFieldStatuses & STATUS_FIELD_MUDSPORT)) { gFieldStatuses |= STATUS_FIELD_MUDSPORT; - gFieldTimers.mudSportTimer = gBattleTurnCounter + 5; + gFieldTimers.mudSportTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_ELECTRIC; worked = TRUE; } @@ -13562,7 +13319,7 @@ static void Cmd_settypebasedhalvers(void) if (!(gFieldStatuses & STATUS_FIELD_WATERSPORT)) { gFieldStatuses |= STATUS_FIELD_WATERSPORT; - gFieldTimers.waterSportTimer = gBattleTurnCounter + 5; + gFieldTimers.waterSportTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_FIRE; worked = TRUE; } @@ -13598,11 +13355,10 @@ bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move) bool32 DoesDisguiseBlockMove(u32 battler, u32 move) { - if (!(gBattleMons[battler].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) - || gBattleMons[battler].volatiles.transformed - || (!gProtectStructs[battler].confusionSelfDmg && (IsBattleMoveStatus(move) || gHitMarker & HITMARKER_PASSIVE_HP_UPDATE)) - || gHitMarker & HITMARKER_IGNORE_DISGUISE - || !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_DISGUISE)) + if (!IsMimikyuDisguised(battler) + || gBattleMons[battler].volatiles.transformed + || (!gProtectStructs[battler].confusionSelfDmg && IsBattleMoveStatus(move)) + || !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_DISGUISE)) return FALSE; else return TRUE; @@ -13625,9 +13381,9 @@ static void Cmd_tryrecycleitem(void) u16 *usedHeldItem; if (gCurrentMove == MOVE_NONE && GetBattlerAbility(gBattlerAttacker) == ABILITY_PICKUP) - usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerTarget]][GetBattlerSide(gBattlerTarget)]; + usedHeldItem = &GetBattlerPartyState(gBattlerTarget)->usedHeldItem; else - usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerAttacker]][GetBattlerSide(gBattlerAttacker)]; + usedHeldItem = &GetBattlerPartyState(gBattlerAttacker)->usedHeldItem; if (*usedHeldItem != ITEM_NONE && gBattleMons[gBattlerAttacker].item == ITEM_NONE) { gLastUsedItem = *usedHeldItem; @@ -14055,9 +13811,13 @@ static void Cmd_handleballthrow(void) if (shakes == maxShakes) // mon caught, copy of the code above { - if (IsCriticalCapture()) + enum NationalDexOrder natDexNo = SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species); + if ((B_CRITICAL_CAPTURE_IF_OWNED >= GEN_9 && GetSetPokedexFlag(natDexNo, FLAG_GET_CAUGHT)) + || IsCriticalCapture()) + { + gBattleSpritesDataPtr->animationData->isCriticalCapture = TRUE; gBattleSpritesDataPtr->animationData->criticalCaptureSuccess = TRUE; - + } TryBattleFormChange(gBattlerTarget, FORM_CHANGE_END_BATTLE); gBattlescriptCurrInstr = BattleScript_SuccessBallThrow; struct Pokemon *caughtMon = GetBattlerMon(gBattlerTarget); @@ -14473,12 +14233,8 @@ static void Cmd_trygivecaughtmonnick(void) } } -static void Cmd_subattackerhpbydmg(void) +static void Cmd_unused_0xf4(void) { - CMD_ARGS(); - - gBattleMons[gBattlerAttacker].hp -= gBattleStruct->moveDamage[gBattlerTarget]; - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_removeattackerstatus1(void) @@ -14550,7 +14306,7 @@ static void Cmd_settelekinesis(void) else { gBattleMons[gBattlerTarget].volatiles.telekinesis = TRUE; - gDisableStructs[gBattlerTarget].telekinesisTimer = gBattleTurnCounter + 3; + gDisableStructs[gBattlerTarget].telekinesisTimer = 3; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -14569,7 +14325,7 @@ static void Cmd_swapstatstages(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static u16 *GetBattlerStat(struct BattlePokemon *battler, u32 stat) +static u16 *GetBattlerStat(struct BattlePokemon *battler, enum Stat stat) { switch (stat) { @@ -14616,31 +14372,30 @@ static void Cmd_jumpifcaptivateaffected(void) static void Cmd_setnonvolatilestatus(void) { CMD_ARGS(u8 trigger); - gBattlescriptCurrInstr = cmd->nextInstr - 1; switch (cmd->trigger) { case TRIGGER_ON_ABILITY: if (gBattleScripting.moveEffect >= MOVE_EFFECT_CONFUSION) - SetMoveEffect(gBattleScripting.battler, gEffectBattler, FALSE, FALSE); + SetMoveEffect(gBattleScripting.battler, gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, EFFECT_PRIMARY); else - SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, TRIGGER_ON_ABILITY); + SetNonVolatileStatus(gEffectBattler, gBattleScripting.moveEffect, cmd->nextInstr, TRIGGER_ON_ABILITY); break; case TRIGGER_ON_MOVE: - SetNonVolatileStatus(gBattlerTarget, GetMoveNonVolatileStatus(gCurrentMove), TRIGGER_ON_MOVE); + SetNonVolatileStatus(gBattlerTarget, GetMoveNonVolatileStatus(gCurrentMove), cmd->nextInstr, TRIGGER_ON_MOVE); break; case TRIGGER_ON_PROTECT: - SetNonVolatileStatus(gBattlerAttacker, gBattleScripting.moveEffect, TRIGGER_ON_PROTECT); + SetNonVolatileStatus(gBattlerAttacker, gBattleScripting.moveEffect, cmd->nextInstr, TRIGGER_ON_PROTECT); break; } } -static void Cmd_tryworryseed(void) +static void Cmd_tryoverwriteability(void) { CMD_ARGS(const u8 *failInstr); if (gAbilitiesInfo[gBattleMons[gBattlerTarget].ability].cantBeOverwritten - || gBattleMons[gBattlerTarget].ability == ABILITY_INSOMNIA) + || gBattleMons[gBattlerTarget].ability == GetMoveOverwriteAbility(gCurrentMove)) { RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); gBattlescriptCurrInstr = cmd->failInstr; @@ -14655,8 +14410,9 @@ static void Cmd_tryworryseed(void) if (gDisableStructs[gBattlerTarget].neutralizingGas) gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; + RemoveAbilityFlags(gBattlerTarget); gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = ABILITY_INSOMNIA; + gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = GetMoveOverwriteAbility(gCurrentMove); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -14777,17 +14533,6 @@ void BS_CalcMetalBurstDmg(void) } } -void BS_JumpIfCantFling(void) -{ - NATIVE_ARGS(u8 battler, const u8 *jumpInstr); - - u32 battler = GetBattlerForBattleScript(cmd->battler); - if (!CanFling(battler)) - gBattlescriptCurrInstr = cmd->jumpInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_JumpIfMoreThanHalfHP(void) { NATIVE_ARGS(u8 battler, const u8 *jumpInstr); @@ -14826,6 +14571,7 @@ static bool32 CriticalCapture(u32 odds) { u32 numCaught; u32 totalDexCount; + u32 charmBoost = 1; if (B_CRITICAL_CAPTURE == FALSE) return FALSE; @@ -14835,23 +14581,25 @@ static bool32 CriticalCapture(u32 odds) else totalDexCount = NATIONAL_DEX_COUNT; - numCaught = GetNationalPokedexCount(FLAG_GET_CAUGHT); - - if (numCaught <= (totalDexCount * 30) / 650) - odds = 0; - else if (numCaught <= (totalDexCount * 150) / 650) - odds /= 2; - else if (numCaught <= (totalDexCount * 300) / 650) - ; // odds = (odds * 100) / 100; - else if (numCaught <= (totalDexCount * 450) / 650) - odds = (odds * 150) / 100; - else if (numCaught <= (totalDexCount * 600) / 650) - odds *= 2; - else - odds = (odds * 250) / 100; - if (CheckBagHasItem(ITEM_CATCHING_CHARM, 1)) - odds = (odds * (100 + B_CATCHING_CHARM_BOOST)) / 100; + charmBoost = (100 + B_CATCHING_CHARM_BOOST) / 100; + + numCaught = GetNationalPokedexCount(FLAG_GET_CAUGHT); + if (numCaught > (totalDexCount * 600) / 650) + odds = (odds * (250 * charmBoost)) / 100; + else if (numCaught > (totalDexCount * 450) / 650) + odds = (odds * (200 * charmBoost)) / 100; + else if (numCaught > (totalDexCount * 300) / 650) + odds = (odds * (150 * charmBoost)) / 100; + else if (numCaught > (totalDexCount * 150) / 650) + odds = (odds * (100 * charmBoost)) / 100; + else if (numCaught > (totalDexCount * 30) / 650) + odds = (odds * (50 * charmBoost)) / 100; + else + return FALSE; + + if (odds > 255) + odds = 255; odds /= 6; if (RandomUniform(RNG_BALLTHROW_CRITICAL, 0, MAX_u8) < odds) @@ -14893,19 +14641,22 @@ bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler) return FALSE; } -static bool8 IsFinalStrikeEffect(enum BattleMoveEffects moveEffect) +static bool32 IsFinalStrikeEffect(enum MoveEffect moveEffect) { - u32 i; - - for (i = 0; i < ARRAY_COUNT(sFinalStrikeOnlyEffects); i++) + switch (moveEffect) { - if (moveEffect == sFinalStrikeOnlyEffects[i]) - return TRUE; + case MOVE_EFFECT_REMOVE_ARG_TYPE: + case MOVE_EFFECT_REMOVE_STATUS: + case MOVE_EFFECT_RECOIL_HP_25: + case MOVE_EFFECT_PREVENT_ESCAPE: + case MOVE_EFFECT_WRAP: + return TRUE; + default: + return FALSE; } - return FALSE; } -static bool32 CanAbilityPreventStatLoss(u32 abilityDef) +static bool32 CanAbilityPreventStatLoss(enum Ability abilityDef) { switch (abilityDef) { @@ -14913,6 +14664,8 @@ static bool32 CanAbilityPreventStatLoss(u32 abilityDef) case ABILITY_FULL_METAL_BODY: case ABILITY_WHITE_SMOKE: return TRUE; + default: + break; } return FALSE; } @@ -15073,7 +14826,7 @@ u8 GetFirstFaintedPartyIndex(u8 battler) void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler) { - enum ItemHoldEffect holdEffect = GetMonHoldEffect(&gPlayerParty[expGetterMonId]); + enum HoldEffect holdEffect = GetMonHoldEffect(&gPlayerParty[expGetterMonId]); if (IsTradedMon(&gPlayerParty[expGetterMonId])) *expAmount = (*expAmount * 150) / 100; @@ -15153,7 +14906,7 @@ void BS_ItemRestoreHP(void) // Heal is applied as move damage if battler is active. if (battler != MAX_BATTLERS_COUNT && hp != 0) { - gBattleStruct->moveDamage[battler] = -healAmount; + gBattleStruct->passiveHpUpdate[battler] = -healAmount; gBattlescriptCurrInstr = cmd->restoreBattlerInstr; } else @@ -15337,7 +15090,7 @@ void BS_JumpIfShellTrap(void) void BS_JumpIfElectricAbilityAffected(void) { - NATIVE_ARGS(u8 battler, u16 ability, const u8 *jumpInstr); + NATIVE_ARGS(u8 battler, enum Ability ability, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); if (IsElectricAbilityAffected(battler, cmd->ability)) @@ -15381,13 +15134,6 @@ void BS_SetTerrain(void) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; } break; - case EFFECT_HIT_SET_TERRAIN: - if (!(gFieldStatuses & GetMoveTerrainFlag(gCurrentMove))) - { - statusFlag = GetMoveTerrainFlag(gCurrentMove); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; - } - break; default: break; } @@ -15411,7 +15157,7 @@ void BS_JumpIfTerrainAffected(void) NATIVE_ARGS(u8 battler, u32 flags, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (IsBattlerTerrainAffected(battler, cmd->flags)) + if (IsBattlerTerrainAffected(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler), cmd->flags)) gBattlescriptCurrInstr = cmd->jumpInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -15421,7 +15167,7 @@ void BS_TryReflectType(void) { NATIVE_ARGS(const u8 *failInstr); u16 targetBaseSpecies = GET_BASE_SPECIES_ID(gBattleMons[gBattlerTarget].species); - u32 targetTypes[3]; + enum Type targetTypes[3]; GetBattlerTypes(gBattlerTarget, FALSE, targetTypes); if (targetBaseSpecies == SPECIES_ARCEUS || targetBaseSpecies == SPECIES_SILVALLY) @@ -15484,27 +15230,17 @@ void BS_TrySetOctolock(void) } } -void BS_SetGlaiveRush(void) -{ - NATIVE_ARGS(); - gBattleMons[gBattlerAttacker].volatiles.glaiveRush = TRUE; - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_SetPledge(void) { NATIVE_ARGS(const u8 *jumpInstr); u32 partner = BATTLE_PARTNER(gBattlerAttacker); - u32 partnerMove = gBattleMons[partner].moves[gBattleStruct->chosenMovePositions[partner]]; + u32 partnerMove = GetChosenMoveFromPosition(partner); u32 i = 0; u32 k = 0; if (gBattleStruct->pledgeMove && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)) { - PrepareStringBattle(STRINGID_USEDMOVE, gBattlerAttacker); - gHitMarker |= HITMARKER_ATTACKSTRING_PRINTED; - if ((gCurrentMove == MOVE_GRASS_PLEDGE && partnerMove == MOVE_WATER_PLEDGE) || (gCurrentMove == MOVE_WATER_PLEDGE && partnerMove == MOVE_GRASS_PLEDGE)) { @@ -15589,13 +15325,13 @@ void BS_SetPledgeStatus(void) switch (cmd->sideStatus) { case SIDE_STATUS_RAINBOW: - gSideTimers[side].rainbowTimer = gBattleTurnCounter + 4; + gSideTimers[side].rainbowTimer = 4; break; case SIDE_STATUS_SEA_OF_FIRE: - gSideTimers[side].seaOfFireTimer = gBattleTurnCounter + 4; + gSideTimers[side].seaOfFireTimer = 4; break; case SIDE_STATUS_SWAMP: - gSideTimers[side].swampTimer = gBattleTurnCounter + 4; + gSideTimers[side].swampTimer = 4; } gBattlescriptCurrInstr = cmd->nextInstr; @@ -15658,45 +15394,15 @@ void BS_TryHealPulse(void) } else { + s32 healAmount = 0; if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MEGA_LAUNCHER && IsPulseMove(gCurrentMove)) - gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 75 / 100); + healAmount = GetNonDynamaxMaxHP(gBattlerTarget) * 75 / 100; else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && GetMoveEffectArg_MoveProperty(gCurrentMove) == MOVE_EFFECT_FLORAL_HEALING) - gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 2 / 3); + healAmount = GetNonDynamaxMaxHP(gBattlerTarget) * 2 / 3; else - gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) / 2); + healAmount = GetNonDynamaxMaxHP(gBattlerTarget) / 2; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = -1; - gBattlescriptCurrInstr = cmd->nextInstr; - } -} - -void BS_TryCopycat(void) -{ - NATIVE_ARGS(const u8 *failInstr); - - if (gLastUsedMove == MOVE_NONE || gLastUsedMove == MOVE_UNAVAILABLE || IsMoveCopycatBanned(gLastUsedMove) || IsZMove(gLastUsedMove)) - { - gBattlescriptCurrInstr = cmd->failInstr; - } - else - { - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gLastUsedMove)) - { - gBattleStruct->zmove.baseMoves[gBattlerAttacker] = gLastUsedMove; - gCalledMove = GetTypeBasedZMove(gLastUsedMove); - } - else if (IsMaxMove(gLastUsedMove)) - { - gCalledMove = gBattleStruct->dynamax.lastUsedBaseMove; - } - else - { - gCalledMove = gLastUsedMove; - } - - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); + SetHealAmount(gBattlerTarget, healAmount); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -15721,23 +15427,6 @@ void BS_TryDefog(void) } } -void BS_TryUpperHand(void) -{ - NATIVE_ARGS(const u8 *failInstr); - - u32 abilityDef = GetBattlerAbility(gBattlerTarget); - u32 prio = GetChosenMovePriority(gBattlerTarget, abilityDef); - - if (HasBattlerActedThisTurn(gBattlerTarget) - || gChosenMoveByBattler[gBattlerTarget] == MOVE_NONE - || IsBattleMoveStatus(gChosenMoveByBattler[gBattlerTarget]) - || prio < 1 - || prio > 3) // Fails if priority is less than 1 or greater than 3, if target already moved, or if using a status - gBattlescriptCurrInstr = cmd->failInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_TryTriggerStatusForm(void) { NATIVE_ARGS(); @@ -15789,15 +15478,6 @@ void BS_TryAllySwitch(void) } } -void BS_RunStatChangeItems(void) -{ - NATIVE_ARGS(u8 battler); - - // Change instruction before calling ItemBattleEffects. - gBattlescriptCurrInstr = cmd->nextInstr; - ItemBattleEffects(ITEMEFFECT_STATS_CHANGED, GetBattlerForBattleScript(cmd->battler)); -} - static void TryUpdateEvolutionTracker(u32 evolutionCondition, u32 upAmount, u16 usedMove) { u32 i, j; @@ -15853,20 +15533,6 @@ static void TryUpdateEvolutionTracker(u32 evolutionCondition, u32 upAmount, u16 } } -void BS_TryUpdateRecoilTracker(void) -{ - NATIVE_ARGS(); - TryUpdateEvolutionTracker(IF_RECOIL_DAMAGE_GE, gBattleStruct->moveDamage[gBattlerAttacker], MOVE_NONE); - gBattlescriptCurrInstr = cmd->nextInstr; -} - -void BS_TryUpdateLeadersCrestTracker(void) -{ - NATIVE_ARGS(); - TryUpdateEvolutionTracker(IF_DEFEAT_X_WITH_ITEMS, 1, MOVE_NONE); - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_TryTidyUp(void) { NATIVE_ARGS(u8 clear, const u8 *jumpInstr); @@ -15915,12 +15581,8 @@ void BS_TryActivateGulpMissile(void) && gBattleMons[gBattlerTarget].species != SPECIES_CRAMORANT && GetBattlerAbility(gBattlerTarget) == ABILITY_GULP_MISSILE) { - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - } + if (!IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) + SetPassiveDamageAmount(gBattlerTarget, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); switch(gBattleMons[gBattlerTarget].species) { @@ -15952,13 +15614,22 @@ void BS_TryQuash(void) // If the above condition is not true, it means we are faster than the foe, so we can set the quash bit gProtectStructs[gBattlerTarget].quash = TRUE; + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } // this implementation assumes turn order is correct when using Quash i = GetBattlerTurnOrderNum(gBattlerTarget); for (j = i + 1; j < gBattlersCount; j++) { + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; + // Gen 7- config makes target go last so that the order of quash targets is kept for the correct turn order // Gen 8+ config alters Turn Order of the target according to speed, dynamic speed should handle the rest - if (B_QUASH_TURN_ORDER < GEN_8 || GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1) + if (B_QUASH_TURN_ORDER < GEN_8 || GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); else break; @@ -15994,7 +15665,6 @@ void BS_CopyFoesStatIncrease(void) SET_STATCHANGER(stat + 1, gQueuedStatBoosts[battler].statChanges[stat], FALSE); gQueuedStatBoosts[battler].stats &= ~(1 << stat); - gBattlerTarget = battler; gBattlescriptCurrInstr = cmd->nextInstr; return; } @@ -16135,7 +15805,7 @@ void BS_TryWindRiderPower(void) NATIVE_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - u16 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); if (IsBattlerAlly(battler, gBattlerAttacker) && (ability == ABILITY_WIND_RIDER || ability == ABILITY_WIND_POWER)) { @@ -16325,7 +15995,7 @@ void BS_TrySpectralThiefSteal(void) bool32 contrary = GetBattlerAbility(gBattlerAttacker) == ABILITY_CONTRARY; gBattleStruct->stolenStats[0] = 0; // Stats to steal. gBattleScripting.animArg1 = 0; - for (u32 stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) { if (gBattleMons[gBattlerTarget].statStages[stat] > DEFAULT_STAT_STAGE && gBattleMons[gBattlerAttacker].statStages[stat] != MAX_STAT_STAGE) { @@ -16370,7 +16040,7 @@ void BS_SpectralThiefPrintStats(void) { NATIVE_ARGS(); - for (u32 stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) { if (gBattleStruct->stolenStats[0] & (1u << stat)) { @@ -16405,6 +16075,13 @@ void BS_ClearMoveResultFlags(void) gBattlescriptCurrInstr = cmd->nextInstr; } +void BS_ClearSpecialStatuses(void) +{ + NATIVE_ARGS(); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); + gBattlescriptCurrInstr = cmd->nextInstr; +} + void BS_JumpIfMoveResultFlags(void) { NATIVE_ARGS(u16 value, const u8 *jumpInstr); @@ -16429,7 +16106,7 @@ void BS_SwapStats(void) { NATIVE_ARGS(u8 stat); - u32 stat = cmd->stat; + enum Stat stat = cmd->stat; u32 temp; switch (stat) @@ -16452,6 +16129,8 @@ void BS_SwapStats(void) case STAT_SPDEF: SWAP(gBattleMons[gBattlerAttacker].spDefense, gBattleMons[gBattlerTarget].spDefense, temp); break; + default: + break; } PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); gBattlescriptCurrInstr = cmd->nextInstr; @@ -16460,40 +16139,25 @@ void BS_SwapStats(void) static void TrySetParalysis(const u8 *nextInstr, const u8 *failInstr) { if (CanBeParalyzed(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget))) - { - gBattlescriptCurrInstr = nextInstr - 1; - SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_PARALYSIS, TRIGGER_ON_MOVE); - } + SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_PARALYSIS, nextInstr, TRIGGER_ON_MOVE); else - { gBattlescriptCurrInstr = failInstr; - } } static void TrySetPoison(const u8 *nextInstr, const u8 *failInstr) { if (CanBePoisoned(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerAbility(gBattlerTarget))) - { - gBattlescriptCurrInstr = nextInstr - 1; - SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_POISON, TRIGGER_ON_MOVE); - } + SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_POISON, nextInstr, TRIGGER_ON_MOVE); else - { gBattlescriptCurrInstr = failInstr; - } } static void TrySetSleep(const u8 *nextInstr, const u8 *failInstr) { if (CanBeSlept(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), BLOCKED_BY_SLEEP_CLAUSE)) - { - gBattlescriptCurrInstr = nextInstr - 1; - SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_SLEEP, TRIGGER_ON_MOVE); - } + SetNonVolatileStatus(gBattlerTarget, MOVE_EFFECT_SLEEP, nextInstr, TRIGGER_ON_MOVE); else - { gBattlescriptCurrInstr = failInstr; - } } void BS_TrySetParalysis(void) @@ -16598,7 +16262,7 @@ void BS_TrySetTorment(void) && !IsAbilityOnSide(gBattlerTarget, ABILITY_AROMA_VEIL)) { gBattleMons[gBattlerTarget].volatiles.torment = TRUE; - gDisableStructs[gBattlerTarget].tormentTimer = gBattleTurnCounter + 3; // 3 turns excluding current turn + gDisableStructs[gBattlerTarget].tormentTimer = 3; gEffectBattler = gBattlerTarget; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16612,11 +16276,7 @@ void BS_TrySetTorment(void) void BS_HealOneSixth(void) { NATIVE_ARGS(const u8* failInstr); - gBattleStruct->moveDamage[gBattlerTarget] = gBattleMons[gBattlerTarget].maxHP / 6; - if (gBattleStruct->moveDamage[gBattlerTarget] == 0) - gBattleStruct->moveDamage[gBattlerTarget] = 1; - gBattleStruct->moveDamage[gBattlerTarget] *= -1; - + SetHealAmount(gBattlerTarget, gBattleMons[gBattlerTarget].maxHP / 6); if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) gBattlescriptCurrInstr = cmd->failInstr; // fail else @@ -16627,7 +16287,7 @@ void BS_HealOneSixth(void) void BS_TryRecycleBerry(void) { NATIVE_ARGS(const u8 *failInstr); - u16* usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerTarget]][GetBattlerSide(gBattlerTarget)]; + u16 *usedHeldItem = &GetBattlerPartyState(gBattlerTarget)->usedHeldItem; if (gBattleMons[gBattlerTarget].item == ITEM_NONE && gBattleStruct->changedItems[gBattlerTarget] == ITEM_NONE // Will not inherit an item && GetItemPocket(*usedHeldItem) == POCKET_BERRIES) @@ -16667,8 +16327,8 @@ void BS_JumpIfIntimidateAbilityPrevented(void) { NATIVE_ARGS(); - u32 hasAbility = FALSE; - u32 ability = GetBattlerAbility(gBattlerTarget); + bool32 hasAbility = FALSE; + enum Ability ability = GetBattlerAbility(gBattlerTarget); switch (ability) { @@ -16715,14 +16375,54 @@ void BS_JumpIfCanGigantamax(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfLastUsedItemHoldEffect(void) +void BS_TryFlingHoldEffect(void) { - NATIVE_ARGS(u8 holdEffect, u16 secondaryId, const u8 *jumpInstr); - if (GetItemHoldEffect(gLastUsedItem) == cmd->holdEffect - && (cmd->secondaryId == 0 || GetItemSecondaryId(gLastUsedItem) == cmd->secondaryId)) - gBattlescriptCurrInstr = cmd->jumpInstr; - else + NATIVE_ARGS(); + enum HoldEffect holdEffect = GetItemHoldEffect(gBattleStruct->flingItem); + gBattleStruct->flingItem = ITEM_NONE; + + if (IsMoveEffectBlockedByTarget(GetBattlerAbility(gBattlerTarget))) + { + gBattlescriptCurrInstr = BattleScript_FlingBlockedByShieldDust; + return; + } + + switch (holdEffect) + { + case HOLD_EFFECT_FLAME_ORB: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_BURN, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_TOXIC_ORB: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_TOXIC, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_LIGHT_BALL: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_PARALYSIS, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_TYPE_POWER: + if (GetItemSecondaryId(gLastUsedItem) != TYPE_POISON) + gBattlescriptCurrInstr = cmd->nextInstr; + else + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_POISON, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_FLINCH: + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, cmd->nextInstr, NO_FLAGS); + break; + case HOLD_EFFECT_MENTAL_HERB: + if (ItemBattleEffects(gBattlerTarget, 0, holdEffect, IsOnFlingActivation)) + return; + else + gBattlescriptCurrInstr = cmd->nextInstr; + break; + case HOLD_EFFECT_WHITE_HERB: + if (ItemBattleEffects(gBattlerTarget, 0, holdEffect, IsOnFlingActivation)) + return; + else + gBattlescriptCurrInstr = cmd->nextInstr; + break; + default: gBattlescriptCurrInstr = cmd->nextInstr; + break; + } } void BS_JumpIfNoWhiteOut(void) @@ -16741,16 +16441,17 @@ void BS_TryBoosterEnergy(void) for (u32 orderNum = 0; orderNum < gBattlersCount; orderNum++) { - u32 battlerByTurnOrder = gBattlerByTurnOrder[orderNum]; - if (GetBattlerHoldEffect(battlerByTurnOrder, TRUE) != HOLD_EFFECT_BOOSTER_ENERGY) + u32 battler = gBattlerByTurnOrder[orderNum]; + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (holdEffect != HOLD_EFFECT_BOOSTER_ENERGY) continue; - u32 ability = GetBattlerAbility(battlerByTurnOrder); + enum Ability ability = GetBattlerAbility(battler); if (!(ability == ABILITY_PROTOSYNTHESIS && cmd->onFieldStatus != ON_TERRAIN) && !(ability == ABILITY_QUARK_DRIVE && cmd->onFieldStatus != ON_WEATHER)) continue; - if (TryBoosterEnergy(battlerByTurnOrder, ability, ITEMEFFECT_NONE)) + if (ItemBattleEffects(battler, 0, holdEffect, IsOnEffectActivation)) return; } @@ -16784,7 +16485,7 @@ void BS_TryActivateAbilityShield(void) { NATIVE_ARGS(u8 battler); u32 battler = GetBattlerForBattleScript(cmd->battler); - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); gBattlescriptCurrInstr = cmd->nextInstr; @@ -16865,7 +16566,7 @@ void BS_JumpIfHoldEffect(void) { NATIVE_ARGS(u8 battler, u8 holdEffect, const u8 *jumpInstr, u8 equal); u32 battler = GetBattlerForBattleScript(cmd->battler); - if ((GetBattlerHoldEffect(battler, TRUE) == cmd->holdEffect) == cmd->equal) + if ((GetBattlerHoldEffect(battler) == cmd->holdEffect) == cmd->equal) { if (cmd->equal) gLastUsedItem = gBattleMons[battler].item; // For B_LAST_USED_ITEM @@ -16893,6 +16594,7 @@ void BS_SetLastUsedItem(void) { NATIVE_ARGS(u8 battler); gLastUsedItem = gBattleMons[GetBattlerForBattleScript(cmd->battler)].item; + gBattleStruct->flingItem = gLastUsedItem; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16906,7 +16608,7 @@ void BS_TrySetFairyLock(void) else { gFieldStatuses |= STATUS_FIELD_FAIRY_LOCK; - gFieldTimers.fairyLockTimer = gBattleTurnCounter + 2; + gFieldTimers.fairyLockTimer = 2; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -16915,9 +16617,9 @@ void BS_GetStatValue(void) { NATIVE_ARGS(u8 stat); u32 stat = cmd->stat; - gBattleStruct->moveDamage[gBattlerAttacker] = *(u16 *)(&gBattleMons[gBattlerTarget].attack) + (stat - 1); - gBattleStruct->moveDamage[gBattlerAttacker] *= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][0]; - gBattleStruct->moveDamage[gBattlerAttacker] /= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][1]; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] = *(u16 *)(&gBattleMons[gBattlerTarget].attack) + (stat - 1); + gBattleStruct->passiveHpUpdate[gBattlerAttacker] *= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][0]; + gBattleStruct->passiveHpUpdate[gBattlerAttacker] /= gStatStageRatios[gBattleMons[gBattlerTarget].statStages[stat]][1]; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16941,7 +16643,7 @@ void BS_TryFriskMessage(void) && gBattleMons[gBattlerTarget].item != ITEM_NONE) { gLastUsedItem = gBattleMons[gBattlerTarget].item; - RecordItemEffectBattle(gBattlerTarget, GetBattlerHoldEffect(gBattlerTarget, FALSE)); + RecordItemEffectBattle(gBattlerTarget, GetBattlerHoldEffectIgnoreNegation(gBattlerTarget)); // If Frisk identifies two mons' items, show the pop-up only once. if (gBattleStruct->friskedAbility) { @@ -17017,7 +16719,7 @@ void BS_TryAcupressure(void) { NATIVE_ARGS(const u8 *failInstr); u32 bits = 0; - for (u32 stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) { if (CompareStat(gBattlerTarget, stat, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerTarget))) bits |= 1u << stat; @@ -17398,7 +17100,7 @@ void BS_TryActivateReceiver(void) u32 partnerAbility = GetBattlerAbility(gBattlerAbility); if (IsBattlerAlive(gBattlerAbility) && (partnerAbility == ABILITY_RECEIVER || partnerAbility == ABILITY_POWER_OF_ALCHEMY) - && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD + && GetBattlerHoldEffectIgnoreAbility(battler) != HOLD_EFFECT_ABILITY_SHIELD && !gAbilitiesInfo[gBattleMons[battler].ability].cantBeCopied) { gBattleStruct->tracedAbility[gBattlerAbility] = gBattleMons[battler].ability; // re-using the variable for trace @@ -17458,7 +17160,7 @@ void BS_SetLuckyChant(void) if (!(gSideStatuses[side] & SIDE_STATUS_LUCKY_CHANT)) { gSideStatuses[side] |= SIDE_STATUS_LUCKY_CHANT; - gSideTimers[side].luckyChantTimer = gBattleTurnCounter + 5; + gSideTimers[side].luckyChantTimer = 5; gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -17467,44 +17169,6 @@ void BS_SetLuckyChant(void) } } -void BS_SuckerPunchCheck(void) -{ - NATIVE_ARGS(const u8 *failInstr); - if (gProtectStructs[gBattlerTarget].protected == PROTECT_OBSTRUCT) - gBattlescriptCurrInstr = cmd->failInstr; - else if (HasBattlerActedThisTurn(gBattlerTarget)) - gBattlescriptCurrInstr = cmd->failInstr; - else if (IsBattleMoveStatus(gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]]) && !gProtectStructs[gBattlerTarget].noValidMoves) - gBattlescriptCurrInstr = cmd->failInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; -} - -void BS_SetSimpleBeam(void) -{ - NATIVE_ARGS(const u8 *failInstr); - if (gAbilitiesInfo[gBattleMons[gBattlerTarget].ability].cantBeOverwritten - || gBattleMons[gBattlerTarget].ability == ABILITY_SIMPLE) - { - RecordAbilityBattle(gBattlerTarget, gBattleMons[gBattlerTarget].ability); - gBattlescriptCurrInstr = cmd->failInstr; - } - else if (CanAbilityShieldActivateForBattler(gBattlerTarget)) - { - gBattlescriptCurrInstr = BattleScript_MoveEnd; - BattleScriptCall(BattleScript_AbilityShieldProtects); - } - else - { - if (gDisableStructs[gBattlerTarget].neutralizingGas) - gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; - - gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = ABILITY_SIMPLE; - gBattlescriptCurrInstr = cmd->nextInstr; - } -} - void BS_TryEntrainment(void) { NATIVE_ARGS(const u8 *failInstr); @@ -17528,6 +17192,7 @@ void BS_TryEntrainment(void) } else { + RemoveAbilityFlags(gBattlerTarget); gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = gBattleMons[gBattlerAttacker].ability; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17554,32 +17219,6 @@ void BS_InvertStatStages(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_TryMeFirst(void) -{ - NATIVE_ARGS(const u8 *failInstr); - u16 move = gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]]; - if (IsBattleMoveStatus(move) || IsMoveMeFirstBanned(move) - || HasBattlerActedThisTurn(gBattlerTarget)) - { - gBattlescriptCurrInstr = cmd->failInstr; - } - else - { - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move)) - { - gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move; - gCalledMove = GetTypeBasedZMove(move); - } - else - { - gCalledMove = move; - } - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); - gBattlescriptCurrInstr = cmd->nextInstr; - } -} - void BS_TryElectrify(void) { NATIVE_ARGS(const u8 *failInstr); @@ -17597,9 +17236,9 @@ void BS_TryElectrify(void) void BS_TrySoak(void) { NATIVE_ARGS(const u8 *failInstr); - u32 types[3]; + enum Type types[3]; GetBattlerTypes(gBattlerTarget, FALSE, types); - u32 typeToSet = GetMoveArgType(gCurrentMove); + enum Type typeToSet = GetMoveArgType(gCurrentMove); if ((types[0] == typeToSet && types[1] == typeToSet) || GetActiveGimmick(gBattlerTarget) == GIMMICK_TERA) { @@ -17635,15 +17274,6 @@ void BS_HandleFormChange(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_TryLastResort(void) -{ - NATIVE_ARGS(const u8 *failInstr); - if (CanUseLastResort(gBattlerAttacker)) - gBattlescriptCurrInstr = cmd->nextInstr; - else - gBattlescriptCurrInstr = cmd->failInstr; -} - void BS_TryAutotomize(void) { NATIVE_ARGS(const u8 *failInstr); @@ -17692,7 +17322,6 @@ void BS_TryInstruct(void) else { gEffectBattler = gBattleStruct->lastMoveTarget[gBattlerTarget]; - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerTarget, gBattlerPartyIndexes[gBattlerTarget]); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17894,8 +17523,7 @@ void BS_SetAuroraVeil(void) { NATIVE_ARGS(); u32 side = GetBattlerSide(gBattlerAttacker); - if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL - || !(HasWeatherEffect() && gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) + if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL) { gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = 0; @@ -17903,10 +17531,10 @@ void BS_SetAuroraVeil(void) else { gSideStatuses[side] |= SIDE_STATUS_AURORA_VEIL; - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIGHT_CLAY) - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 8; + if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 8; else - gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = gBattleTurnCounter + 5; + gSideTimers[GetBattlerSide(gBattlerAttacker)].auroraVeilTimer = 5; if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) gBattleCommunication[MULTISTRING_CHOOSER] = 5; @@ -17981,8 +17609,14 @@ void BS_GetTotemBoost(void) void BS_ActivateItemEffects(void) { NATIVE_ARGS(); - if (ItemBattleEffects(ITEMEFFECT_TRY_HEALING, gBattlerTarget)) - return; + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (!IsBattlerAlive(battler)) + continue; + + if (ItemBattleEffects(battler, 0, GetBattlerHoldEffect(battler), IsForceTriggerItemActivation)) + return; + } gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17990,43 +17624,19 @@ void BS_TryRoomService(void) { NATIVE_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_ROOM_SERVICE && TryRoomService(battler)) - { - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; - } + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (holdEffect == HOLD_EFFECT_ROOM_SERVICE && ItemBattleEffects(battler, 0, holdEffect, IsOnEffectActivation)) + return; + gBattlescriptCurrInstr = cmd->failInstr; } void BS_TryTerrainSeed(void) { NATIVE_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SEEDS) - { - enum ItemEffect effect = ITEM_NO_EFFECT; - u16 item = gBattleMons[battler].item; - switch (GetBattlerHoldEffectParam(battler)) - { - case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, item, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_PARAM_GRASSY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, item, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_PARAM_MISTY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, item, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, item, ITEMEFFECT_NONE); - break; - } - - if (effect != ITEM_NO_EFFECT) - return; - } + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); + if (holdEffect == HOLD_EFFECT_TERRAIN_SEED && ItemBattleEffects(battler, 0, holdEffect, IsOnEffectActivation)) + return; gBattlescriptCurrInstr = cmd->failInstr; } @@ -18069,11 +17679,7 @@ void BS_TryHealQuarterHealth(void) { NATIVE_ARGS(u8 battler, const u8 *failInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 4; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; - + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 4); if (gBattleMons[battler].hp == gBattleMons[battler].maxHP) gBattlescriptCurrInstr = cmd->failInstr; // fail else @@ -18183,7 +17789,7 @@ void BS_TryToClearPrimalWeather(void) for (u32 i = 0; i < gBattlersCount; i++) { - u32 ability = GetBattlerAbility(i); + enum Ability ability = GetBattlerAbility(i); if (((ability == ABILITY_DESOLATE_LAND && gBattleWeather & B_WEATHER_SUN_PRIMAL) || (ability == ABILITY_PRIMORDIAL_SEA && gBattleWeather & B_WEATHER_RAIN_PRIMAL) || (ability == ABILITY_DELTA_STREAM && gBattleWeather & B_WEATHER_STRONG_WINDS)) @@ -18263,23 +17869,29 @@ void BS_JumpIfNotRototillerAffected(void) } } +// TODO: There might be a way to do it without a flag void BS_ConsumeBerry(void) { NATIVE_ARGS(u8 battler, bool8 fromBattler); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (gBattleScripting.overrideBerryRequirements == 2) - { - gBattlescriptCurrInstr = cmd->nextInstr; - return; - } if (cmd->fromBattler) gLastUsedItem = gBattleMons[battler].item; - GetBattlerPartyState(battler)->ateBerry = TRUE; - gBattleScripting.battler = gEffectBattler = gBattlerTarget = battler; // Cover all berry effect battler cases. e.g. ChangeStatBuffs uses target ID - if (ItemBattleEffects(ITEMEFFECT_USE_LAST_ITEM, battler)) + if (GetItemPocket(gLastUsedItem) != POCKET_BERRIES || gBattleScripting.overrideBerryRequirements == 2) + { + gBattleScripting.overrideBerryRequirements = 0; + gBattlescriptCurrInstr = cmd->nextInstr; return; + } + + gBattleScripting.overrideBerryRequirements = 1; + GetBattlerPartyState(battler)->ateBerry = TRUE; + if (ItemBattleEffects(battler, 0, GetItemHoldEffect(gLastUsedItem), IsOnBerryActivation)) + { + gBattleScripting.overrideBerryRequirements = 2; + return; + } gBattlescriptCurrInstr = cmd->nextInstr; } @@ -18330,9 +17942,7 @@ void BS_SetAttackerToStickyWebUser(void) void BS_CutOneThirdHpAndRaiseStats(void) { NATIVE_ARGS(const u8 *failInstr); - - bool8 atLeastOneStatBoosted = FALSE; - u16 hpFraction = max(1, GetNonDynamaxMaxHP(gBattlerAttacker) / 3); + bool32 atLeastOneStatBoosted = FALSE; u32 ability = GetBattlerAbility(gBattlerAttacker); for (u32 stat = 1; stat < NUM_STATS; stat++) @@ -18343,9 +17953,9 @@ void BS_CutOneThirdHpAndRaiseStats(void) break; } } - if (atLeastOneStatBoosted && gBattleMons[gBattlerAttacker].hp > hpFraction) + if (atLeastOneStatBoosted) { - gBattleStruct->moveDamage[gBattlerAttacker] = hpFraction; + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 3); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -18354,81 +17964,11 @@ void BS_CutOneThirdHpAndRaiseStats(void) } } -void BS_CheckPoltergeist(void) +void BS_SetPoltergeistMessage(void) { NATIVE_ARGS(const u8 *failInstr); - if (gBattleMons[gBattlerTarget].item == ITEM_NONE - || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM - || GetBattlerAbility(gBattlerTarget) == ABILITY_KLUTZ) - { - gBattlescriptCurrInstr = cmd->failInstr; - } - else - { - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].item); - gLastUsedItem = gBattleMons[gBattlerTarget].item; - gBattlescriptCurrInstr = cmd->nextInstr; - } -} - -void BS_TryNoRetreat(void) -{ - NATIVE_ARGS(const u8 *failInstr); - if (gDisableStructs[gBattlerTarget].noRetreat) - { - gBattlescriptCurrInstr = cmd->failInstr; - } - else - { - if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) - gDisableStructs[gBattlerTarget].noRetreat = TRUE; - gBattlescriptCurrInstr = cmd->nextInstr; - } -} - -void BS_CureCertainStatuses(void) -{ - NATIVE_ARGS(); - // Check infatuation - if (gBattleMons[gBattlerTarget].volatiles.infatuation) - { - gBattleMons[gBattlerTarget].volatiles.infatuation = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION - StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - } - // Check taunt - if (gDisableStructs[gBattlerTarget].tauntTimer != 0) - { - gDisableStructs[gBattlerTarget].tauntTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); - } - // Check encore - if (gDisableStructs[gBattlerTarget].encoreTimer != 0) - { - gDisableStructs[gBattlerTarget].encoredMove = 0; - gDisableStructs[gBattlerTarget].encoreTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; // STRINGID_PKMNENCOREENDED - } - // Check torment - if (gBattleMons[gBattlerTarget].volatiles.torment == TRUE) - { - gBattleMons[gBattlerTarget].volatiles.torment = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; - } - // Check heal block - if (gBattleMons[gBattlerTarget].volatiles.healBlock) - { - gBattleMons[gBattlerTarget].volatiles.healBlock = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK; - } - // Check disable - if (gDisableStructs[gBattlerTarget].disableTimer != 0) - { - gDisableStructs[gBattlerTarget].disableTimer = 0; - gDisableStructs[gBattlerTarget].disabledMove = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE; - } + PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].item); + gLastUsedItem = gBattleMons[gBattlerTarget].item; gBattlescriptCurrInstr = cmd->nextInstr; } diff --git a/src/battle_setup.c b/src/battle_setup.c index 86d3900f3c..1ad284d05e 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -42,6 +42,7 @@ #include "data.h" #include "vs_seeker.h" #include "item.h" +#include "field_name_box.h" #include "constants/battle_frontier.h" #include "constants/battle_setup.h" #include "constants/event_objects.h" @@ -51,9 +52,10 @@ #include "constants/trainers.h" #include "constants/trainer_hill.h" #include "constants/weather.h" -#include "wild_encounter.h" +#include "fishing.h" -enum { +enum TransitionType +{ TRANSITION_TYPE_NORMAL, TRANSITION_TYPE_CAVE, TRANSITION_TYPE_FLASH, @@ -259,7 +261,7 @@ static void Task_BattleStart(u8 taskId) } } -static void CreateBattleStartTask(u8 transition, u16 song) +static void CreateBattleStartTask(enum BattleTransition transition, u16 song) { u8 taskId = CreateTask(Task_BattleStart, 1); @@ -532,7 +534,7 @@ void StartGroudonKyogreBattle(void) void StartRegiBattle(void) { - u8 transitionId; + enum BattleTransition transitionId; u16 species; LockPlayerFieldControls(); @@ -626,7 +628,7 @@ enum BattleEnvironments BattleSetup_GetEnvironmentId(void) u16 tileBehavior; s16 x, y; - if (I_FISHING_ENVIRONMENT >= GEN_4 && gIsFishingEncounter) + if (ShouldUseFishingEnvironmentInBattle()) GetXYCoordsOneStepInFrontOfPlayer(&x, &y); else PlayerGetDestCoords(&x, &y); @@ -685,7 +687,7 @@ enum BattleEnvironments BattleSetup_GetEnvironmentId(void) return BATTLE_ENVIRONMENT_PLAIN; } -static u8 GetBattleTransitionTypeByMap(void) +static enum TransitionType GetBattleTransitionTypeByMap(void) { u16 tileBehavior; s16 x, y; @@ -748,7 +750,7 @@ static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons) return sum; } -u8 GetWildBattleTransition(void) +enum BattleTransition GetWildBattleTransition(void) { u8 transitionType = GetBattleTransitionTypeByMap(); u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); @@ -770,7 +772,7 @@ u8 GetWildBattleTransition(void) } } -u8 GetTrainerBattleTransition(void) +enum BattleTransition GetTrainerBattleTransition(void) { u8 minPartyCount = 1; u8 transitionType; @@ -813,7 +815,7 @@ u8 GetTrainerBattleTransition(void) } #define RANDOM_TRANSITION(table) (table[Random() % ARRAY_COUNT(table)]) -u8 GetSpecialBattleTransition(s32 id) +enum BattleTransition GetSpecialBattleTransition(enum BattleTransitionGroup id) { u16 var; u8 enemyLevel = GetMonData(&gEnemyParty[0], MON_DATA_LEVEL); @@ -831,6 +833,8 @@ u8 GetSpecialBattleTransition(s32 id) return RANDOM_TRANSITION(sBattleTransitionTable_BattlePyramid); case B_TRANSITION_GROUP_B_DOME: return RANDOM_TRANSITION(sBattleTransitionTable_BattleDome); + default: + break; } if (VarGet(VAR_FRONTIER_BATTLE_MODE) != FRONTIER_MODE_LINK_MULTIS) @@ -848,6 +852,8 @@ u8 GetSpecialBattleTransition(s32 id) return RANDOM_TRANSITION(sBattleTransitionTable_BattlePyramid); case B_TRANSITION_GROUP_B_DOME: return RANDOM_TRANSITION(sBattleTransitionTable_BattleDome); + default: + break; } if (VarGet(VAR_FRONTIER_BATTLE_MODE) != FRONTIER_MODE_LINK_MULTIS) @@ -1500,9 +1506,19 @@ static const u8 *ReturnEmptyStringIfNull(const u8 *string) static const u8 *GetIntroSpeechOfApproachingTrainer(void) { if (gApproachingTrainerId == 0) + { + if (OW_NAME_BOX_NPC_TRAINER) + gSpeakerName = GetTrainerNameFromId(TRAINER_BATTLE_PARAM.opponentA); + return ReturnEmptyStringIfNull(TRAINER_BATTLE_PARAM.introTextA); + } else + { + if (OW_NAME_BOX_NPC_TRAINER) + gSpeakerName = GetTrainerNameFromId(TRAINER_BATTLE_PARAM.opponentB); + return ReturnEmptyStringIfNull(TRAINER_BATTLE_PARAM.introTextB); + } } const u8 *GetTrainerALoseText(void) diff --git a/src/battle_terastal.c b/src/battle_terastal.c index 8799dc7ab2..f0e720c93e 100644 --- a/src/battle_terastal.c +++ b/src/battle_terastal.c @@ -14,7 +14,6 @@ #include "sprite.h" #include "util.h" #include "constants/abilities.h" -#include "constants/hold_effects.h" #include "constants/rgb.h" // Sets flags and variables upon a battler's Terastallization. @@ -62,7 +61,7 @@ void ApplyBattlerVisualsForTeraAnim(u32 battler) // Returns whether a battler can Terastallize. bool32 CanTerastallize(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); if (gBattleMons[battler].volatiles.transformed && GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_TERAPAGOS) return FALSE; @@ -109,20 +108,20 @@ bool32 CanTerastallize(u32 battler) } // Returns a battler's Tera type. -u32 GetBattlerTeraType(u32 battler) +enum Type GetBattlerTeraType(u32 battler) { return GetMonData(GetBattlerMon(battler), MON_DATA_TERA_TYPE); } // Uses up a type's Stellar boost. -void ExpendTypeStellarBoost(u32 battler, u32 type) +void ExpendTypeStellarBoost(u32 battler, enum Type type) { if (type < 32 && gBattleMons[battler].species != SPECIES_TERAPAGOS_STELLAR) // avoid OOB access gBattleStruct->stellarBoostFlags[GetBattlerSide(battler)] |= 1u << type; } // Checks whether a type's Stellar boost has been expended. -bool32 IsTypeStellarBoosted(u32 battler, u32 type) +bool32 IsTypeStellarBoosted(u32 battler, enum Type type) { if (type < 32) // avoid OOB access return !(gBattleStruct->stellarBoostFlags[GetBattlerSide(battler)] & (1u << type)); @@ -132,20 +131,19 @@ bool32 IsTypeStellarBoosted(u32 battler, u32 type) // Returns the STAB power multiplier to use when Terastallized. // Power multipliers from Smogon Research thread. -uq4_12_t GetTeraMultiplier(u32 battler, u32 type) +uq4_12_t GetTeraMultiplier(struct DamageContext *ctx) { - u32 teraType = GetBattlerTeraType(battler); - bool32 hasAdaptability = (GetBattlerAbility(battler) == ABILITY_ADAPTABILITY); + enum Type teraType = GetBattlerTeraType(ctx->battlerAtk); // Safety check. - if (GetActiveGimmick(battler) != GIMMICK_TERA) + if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_TERA) return UQ_4_12(1.0); // Stellar-type checks. if (teraType == TYPE_STELLAR) { - bool32 shouldBoost = IsTypeStellarBoosted(battler, type); - if (IS_BATTLER_OF_BASE_TYPE(battler, type)) + bool32 shouldBoost = IsTypeStellarBoosted(ctx->battlerAtk, ctx->moveType); + if (IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)) { if (shouldBoost) return UQ_4_12(2.0); @@ -158,18 +156,18 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type) return UQ_4_12(1.0); } // Base and Tera type. - if (type == teraType && IS_BATTLER_OF_BASE_TYPE(battler, type)) + if (ctx->moveType == teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)) { - if (hasAdaptability) + if (ctx->abilityAtk == ABILITY_ADAPTABILITY) return UQ_4_12(2.25); else return UQ_4_12(2.0); } // Base or Tera type only. - else if ((type == teraType && !IS_BATTLER_OF_BASE_TYPE(battler, type)) - || (type != teraType && IS_BATTLER_OF_BASE_TYPE(battler, type))) + else if ((ctx->moveType == teraType && !IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType)) + || (ctx->moveType != teraType && IS_BATTLER_OF_BASE_TYPE(ctx->battlerAtk, ctx->moveType))) { - if (hasAdaptability) + if (ctx->abilityAtk == ABILITY_ADAPTABILITY) return UQ_4_12(2.0); else return UQ_4_12(1.5); @@ -181,7 +179,7 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type) } } -u16 GetTeraTypeRGB(u32 type) +u16 GetTeraTypeRGB(enum Type type) { return gTypesInfo[type].teraTypeRGBValue; } diff --git a/src/battle_tower.c b/src/battle_tower.c index a03f0a130b..d589cb757a 100644 --- a/src/battle_tower.c +++ b/src/battle_tower.c @@ -40,6 +40,8 @@ #include "constants/trainers.h" #include "constants/event_objects.h" #include "constants/moves.h" +#include "test/battle.h" +#include "test/test_runner_battle.h" // EWRAM vars. EWRAM_DATA const struct BattleFrontierTrainer *gFacilityTrainers = NULL; @@ -1569,7 +1571,8 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 { u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball; u16 move; - u32 personality = 0, ability, friendship, j; + u32 personality = 0, friendship, j; + enum Ability ability; if (fmon->gender == TRAINER_MON_MALE) { @@ -1629,7 +1632,7 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 if (fmon->isShiny) { - u32 data = TRUE; + bool32 data = TRUE; SetMonData(dst, MON_DATA_IS_SHINY, &data); } if (fmon->dynamaxLevel > 0) @@ -1644,7 +1647,7 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 } if (fmon->teraType) { - u32 data = fmon->teraType; + enum Type data = fmon->teraType; SetMonData(dst, MON_DATA_TERA_TYPE, &data); } @@ -3556,18 +3559,20 @@ bool32 ValidateBattleTowerRecord(u8 recordId) // unused void TrySetLinkBattleTowerEnemyPartyLevel(void) { - if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)) + if (!IsMultibattleTest()) { - s32 i; - u8 enemyLevel = SetFacilityPtrsGetLevel(); - - for (i = 0; i < PARTY_SIZE; i++) + if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)) { - u32 species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES, NULL); - if (species) + u8 enemyLevel = SetFacilityPtrsGetLevel(); + + for (u32 i = 0; i < PARTY_SIZE; i++) { - SetMonData(&gEnemyParty[i], MON_DATA_EXP, &gExperienceTables[gSpeciesInfo[species].growthRate][enemyLevel]); - CalculateMonStats(&gEnemyParty[i]); + u32 species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES, NULL); + if (species) + { + SetMonData(&gEnemyParty[i], MON_DATA_EXP, &gExperienceTables[gSpeciesInfo[species].growthRate][enemyLevel]); + CalculateMonStats(&gEnemyParty[i]); + } } } } diff --git a/src/battle_transition.c b/src/battle_transition.c index 114248b93d..2b28bf7dc7 100644 --- a/src/battle_transition.c +++ b/src/battle_transition.c @@ -2280,7 +2280,7 @@ static bool8 Mugshot_SetGfx(struct Task *task) s16 i, j; u16 *tilemap, *tileset; const u16 *mugshotsMap = sMugshotsTilemap; - u8 mugshotColor = GetTrainerMugshotColorFromId(TRAINER_BATTLE_PARAM.opponentA); + enum MugshotColor mugshotColor = GetTrainerMugshotColorFromId(TRAINER_BATTLE_PARAM.opponentA); GetBg0TilesDst(&tilemap, &tileset); CpuSet(sEliteFour_Tileset, tileset, 0xF0); diff --git a/src/battle_tv.c b/src/battle_tv.c index 50871baa82..cecab5efb3 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -14,7 +14,7 @@ static bool8 IsNotSpecialBattleString(enum StringID stringId); static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3); static void TrySetBattleSeminarShow(void); -static void AddPointsOnFainting(bool8 targetFainted); +static void AddPointsOnFainting(void); static void AddPointsBasedOnWeather(u16 weatherFlags, u16 move, u8 moveSlot); static bool8 ShouldCalculateDamage(u16 move, s32 *dmg, u16 *powerOverride); @@ -124,12 +124,23 @@ static const u16 *const sPointsArray[] = // even if current Pokémon does not have corresponding move static const u16 sSpecialBattleStrings[] = { - STRINGID_PKMNPERISHCOUNTFELL, STRINGID_PKMNWISHCAMETRUE, STRINGID_PKMNLOSTPPGRUDGE, - STRINGID_PKMNTOOKFOE, STRINGID_PKMNABSORBEDNUTRIENTS, STRINGID_PKMNANCHOREDITSELF, - STRINGID_PKMNAFFLICTEDBYCURSE, STRINGID_PKMNSAPPEDBYLEECHSEED, STRINGID_PKMNLOCKEDINNIGHTMARE, - STRINGID_PKMNHURTBY, STRINGID_PKMNHURTBYBURN, STRINGID_PKMNHURTBYPOISON, - STRINGID_PKMNHURTBYSPIKES, STRINGID_ATTACKERFAINTED, STRINGID_TARGETFAINTED, - STRINGID_PKMNHITWITHRECOIL, STRINGID_PKMNCRASHED, TABLE_END + STRINGID_PKMNPERISHCOUNTFELL, + STRINGID_PKMNWISHCAMETRUE, + STRINGID_PKMNLOSTPPGRUDGE, + STRINGID_PKMNTOOKFOE, + STRINGID_PKMNABSORBEDNUTRIENTS, + STRINGID_PKMNANCHOREDITSELF, + STRINGID_PKMNAFFLICTEDBYCURSE, + STRINGID_PKMNSAPPEDBYLEECHSEED, + STRINGID_PKMNLOCKEDINNIGHTMARE, + STRINGID_PKMNHURTBY, + STRINGID_PKMNHURTBYBURN, + STRINGID_PKMNHURTBYPOISON, + STRINGID_PKMNHURTBYSPIKES, + STRINGID_BATTLERFAINTED, + STRINGID_PKMNHITWITHRECOIL, + STRINGID_PKMNCRASHED, + TABLE_END }; // code @@ -139,7 +150,7 @@ void BattleTv_SetDataBasedOnString(enum StringID stringId) u32 atkSide, defSide, effSide, scriptingSide; struct Pokemon *atkMon, *defMon; u8 moveSlot; - u32 atkFlank, defFlank, effFlank; + u32 atkFlank, defFlank, effFlank, flank; u8 *perishCount; u16 *statStringId, *finishedMoveId; @@ -452,8 +463,6 @@ void BattleTv_SetDataBasedOnString(enum StringID stringId) tvPtr->pos[atkSide][atkFlank].mudSportMonId = gBattlerPartyIndexes[gBattlerAttacker] + 1; tvPtr->pos[atkSide][atkFlank].mudSportMoveSlot = moveSlot; break; - case STRINGID_ATTACKERFAINTED: - AddPointsOnFainting(FALSE); case STRINGID_RETURNMON: if (tvPtr->pos[atkSide][atkFlank].waterSportMonId != 0) { @@ -466,26 +475,29 @@ void BattleTv_SetDataBasedOnString(enum StringID stringId) tvPtr->pos[atkSide][atkFlank].mudSportMoveSlot = 0; } break; - case STRINGID_TARGETFAINTED: - AddPointsOnFainting(TRUE); - if (tvPtr->pos[atkSide][defFlank].waterSportMonId != 0) + case STRINGID_BATTLERFAINTED: + AddPointsOnFainting(); + if (gBattlerAttacker == gBattleScripting.battler) + flank = atkFlank; + else + flank = defFlank; + + if (tvPtr->pos[atkSide][flank].waterSportMonId != 0) { - tvPtr->pos[atkSide][defFlank].waterSportMonId = 0; - tvPtr->pos[atkSide][defFlank].waterSportMoveSlot = 0; + tvPtr->pos[atkSide][flank].waterSportMonId = 0; + tvPtr->pos[atkSide][flank].waterSportMoveSlot = 0; } - if (tvPtr->pos[atkSide][defFlank].mudSportMonId != 0) + if (tvPtr->pos[atkSide][flank].mudSportMonId != 0) { - tvPtr->pos[atkSide][defFlank].mudSportMonId = 0; - tvPtr->pos[atkSide][defFlank].mudSportMoveSlot = 0; + tvPtr->pos[atkSide][flank].mudSportMonId = 0; + tvPtr->pos[atkSide][flank].mudSportMoveSlot = 0; } break; case STRINGID_PKMNRAISEDDEF: - case STRINGID_PKMNRAISEDDEFALITTLE: tvPtr->side[atkSide].reflectMonId = gBattlerPartyIndexes[gBattlerAttacker] + 1; tvPtr->side[atkSide].reflectMoveSlot = moveSlot; break; case STRINGID_PKMNRAISEDSPDEF: - case STRINGID_PKMNRAISEDSPDEFALITTLE: tvPtr->side[atkSide].lightScreenMonId = gBattlerPartyIndexes[gBattlerAttacker] + 1; tvPtr->side[atkSide].lightScreenMoveSlot = moveSlot; break; @@ -591,7 +603,7 @@ void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags, struct DisableStruc tvPtr->side[atkSide].usedMoveSlot = moveSlot; AddMovePoints(PTS_MOVE_EFFECT, moveSlot, move, 0); AddPointsBasedOnWeather(weatherFlags, move, moveSlot); - if (gBattleMons[gBattlerAttacker].volatiles.charge) + if (gBattleMons[gBattlerAttacker].volatiles.chargeTimer > 0) AddMovePoints(PTS_ELECTRIC, move, moveSlot, 0); if (move == MOVE_WISH) @@ -1066,7 +1078,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) } } -static void AddPointsOnFainting(bool8 targetFainted) +static void AddPointsOnFainting(void) { struct BattleTv *tvPtr = &gBattleStruct->tv; u32 atkSide = GetBattlerSide(gBattlerAttacker); @@ -1189,7 +1201,7 @@ static void AddPointsOnFainting(bool8 targetFainted) } break; case FNT_RECOIL: - if (targetFainted == TRUE) + if (gBattlerAttacker == gBattleScripting.battler) { AddMovePoints(PTS_FAINT_SET_UP, 0, atkSide, (gBattlerPartyIndexes[gBattlerAttacker]) * 4 + tvPtr->side[atkSide].usedMoveSlot); @@ -1260,10 +1272,10 @@ static void TrySetBattleSeminarShow(void) powerOverride = 0; if (ShouldCalculateDamage(gCurrentMove, &dmgByMove[i], &powerOverride)) { - struct DamageContext ctx; + struct DamageContext ctx = {0}; ctx.battlerAtk = gBattlerAttacker; ctx.battlerDef = gBattlerTarget; - ctx.move = gCurrentMove; + ctx.move = ctx.chosenMove = gCurrentMove; ctx.moveType = GetMoveType(gCurrentMove); ctx.isCrit = FALSE; ctx.randomFactor = FALSE; diff --git a/src/battle_util.c b/src/battle_util.c index 4772eb872c..b5b10ebcd7 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2,6 +2,7 @@ #include "battle.h" #include "battle_anim.h" #include "battle_arena.h" +#include "battle_environment.h" #include "battle_pyramid.h" #include "battle_util.h" #include "battle_controllers.h" @@ -9,6 +10,7 @@ #include "battle_setup.h" #include "battle_z_move.h" #include "battle_gimmick.h" +#include "battle_hold_effects.h" #include "generational_changes.h" #include "party_menu.h" #include "pokemon.h" @@ -42,7 +44,6 @@ #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" #include "constants/battle_string_ids.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/item_effects.h" #include "constants/moves.h" @@ -63,13 +64,20 @@ static bool32 TryRemoveScreens(u32 battler); static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler); static u32 GetFlingPowerFromItemId(u32 itemId); static void SetRandomMultiHitCounter(); -static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item); -static bool32 CanBeInfinitelyConfused(u32 battler); -static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abilityAffected, const u8 *battleScript, enum FunctionCallOption option); +static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, enum Ability abilityDef, enum Ability abilityAffected, const u8 *battleScript, enum FunctionCallOption option); static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option); static bool32 IsOpposingSideEmpty(u32 battler); static void ResetParadoxWeatherStat(u32 battler); static void ResetParadoxTerrainStat(u32 battler); +static bool32 CanBattlerFormChange(u32 battler, enum FormChanges method); + +// Submoves +static u32 GetMirrorMoveMove(void); +static u32 GetMetronomeMove(void); +static u32 GetAssistMove(void); +static u32 GetSleepTalkMove(void); +static u32 GetCopyCatMove(void); +static u32 GetMeFirstMove(void); ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12(u32 percent); ARM_FUNC NOINLINE static uq4_12_t PercentToUQ4_12_Floored(u32 percent); @@ -208,18 +216,18 @@ static const struct BattleWeatherInfo sBattleWeatherInfo[BATTLE_WEATHER_COUNT] = // Helper function for actual dmg calcs during battle. For simulated AI dmg, CalcTypeEffectivenessMultiplier should be used directly // This should stay a static function. Ideally everything else is handled through CalcTypeEffectivenessMultiplier just like AI -static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, bool32 recordAbilities) +static uq4_12_t CalcTypeEffectivenessMultiplierHelper(u32 move, enum Type moveType, u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, bool32 recordAbilities) { struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = moveType; ctx.updateFlags = recordAbilities; ctx.abilityAtk = abilityAtk; ctx.abilityDef = abilityDef; - ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); - ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); + ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk); + ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef); return CalcTypeEffectivenessMultiplier(&ctx); } @@ -277,6 +285,7 @@ static u32 CalcBeatUpPower(void) return (GetSpeciesBaseAttack(species) / 10) + 5; } +// Gen 3/4 static s32 CalcBeatUpDamage(struct DamageContext *ctx) { u32 partyIndex = gBattleStruct->beatUpSpecies[gBattleStruct->beatUpSlot++]; @@ -298,7 +307,7 @@ static s32 CalcBeatUpDamage(struct DamageContext *ctx) return dmg; } -static bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef, u32 abilityDef) +static bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef, enum Ability abilityDef) { if (!gSpecialStatuses[battlerDef].distortedTypeMatchups && gBattleMons[battlerDef].species == SPECIES_TERAPAGOS_TERASTAL @@ -321,9 +330,48 @@ static inline bool32 IsDragonDartsSecondHit(u32 effect) return FALSE; } +bool32 IsUnnerveBlocked(u32 battler, u32 itemId) +{ + if (GetItemPocket(itemId) != POCKET_BERRIES) + return FALSE; + + if (gBattleScripting.overrideBerryRequirements > 0) // Berries that aren't eaten naturally ignore unnerve + return FALSE; + + if (IsUnnerveAbilityOnOpposingSide(battler)) + return TRUE; + + return FALSE; +} + +static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler) +{ + for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + { + if (battler == battlerDef || IsBattlerAlly(battler, battlerDef)) + continue; + + if (!IsBattlerAlive(battlerDef)) + continue; + + enum Ability ability = GetBattlerAbility(battlerDef); + switch (ability) + { + case ABILITY_UNNERVE: + case ABILITY_AS_ONE_ICE_RIDER: + case ABILITY_AS_ONE_SHADOW_RIDER: + return TRUE; + default: + break; + } + } + + return FALSE; +} + bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) { - u32 ability = GetBattlerAbility(battlerAtk); + enum Ability ability = GetBattlerAbility(battlerAtk); enum BattleMoveEffects effect = GetMoveEffect(move); if (gSideTimers[defSide].followmeTimer == 0 @@ -337,7 +385,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) if (effect == EFFECT_PURSUIT && IsPursuitTargetSet()) return FALSE; - if (gSideTimers[defSide].followmePowder && !IsAffectedByPowderMove(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) + if (gSideTimers[defSide].followmePowder && !IsAffectedByPowderMove(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk))) return FALSE; return TRUE; @@ -347,10 +395,10 @@ bool32 HandleMoveTargetRedirection(void) { u32 redirectorOrderNum = MAX_BATTLERS_COUNT; u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - u32 moveType = GetBattleMoveType(gCurrentMove); + enum Type moveType = GetBattleMoveType(gCurrentMove); enum BattleMoveEffects moveEffect = GetMoveEffect(gCurrentMove); u32 side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); - u32 ability = GetBattlerAbility(gBattleStruct->moveTarget[gBattlerAttacker]); + enum Ability ability = GetBattlerAbility(gBattleStruct->moveTarget[gBattlerAttacker]); if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove) && moveTarget == MOVE_TARGET_SELECTED @@ -366,7 +414,7 @@ bool32 HandleMoveTargetRedirection(void) || (ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) { // Find first battler that redirects the move (in turn order) - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); u32 battler; for (battler = 0; battler < gBattlersCount; battler++) { @@ -385,17 +433,13 @@ bool32 HandleMoveTargetRedirection(void) redirectorOrderNum = GetBattlerTurnOrderNum(battler); } } - if (redirectorOrderNum != MAX_BATTLERS_COUNT) + if (redirectorOrderNum != MAX_BATTLERS_COUNT && gCurrentMove != MOVE_TEATIME) { - u16 battlerAbility; + enum Ability battlerAbility; battler = gBattlerByTurnOrder[redirectorOrderNum]; battlerAbility = GetBattlerAbility(battler); - - RecordAbilityBattle(battler, gBattleMons[battler].ability); - if (battlerAbility == ABILITY_LIGHTNING_ROD && gCurrentMove != MOVE_TEATIME) - gSpecialStatuses[battler].lightningRodRedirected = TRUE; - else if (battlerAbility == ABILITY_STORM_DRAIN) - gSpecialStatuses[battler].stormDrainRedirected = TRUE; + RecordAbilityBattle(battler, battlerAbility); + gSpecialStatuses[battler].abilityRedirected = TRUE; gBattlerTarget = battler; return TRUE; } @@ -417,7 +461,7 @@ void HandleAction_UseMove(void) return; } - gBattleStruct->atkCancelerTracker = 0; + gBattleStruct->eventState.atkCanceler = 0; ClearDamageCalcResults(); gMultiHitCounter = 0; gBattleScripting.savedDmg = 0; @@ -429,7 +473,6 @@ void HandleAction_UseMove(void) { gProtectStructs[gBattlerAttacker].noValidMoves = FALSE; gCurrentMove = gChosenMove = MOVE_STRUGGLE; - gHitMarker |= HITMARKER_NO_PPDEDUCT; gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE); } else if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns || gDisableStructs[gBattlerAttacker].rechargeTimer > 0) @@ -529,9 +572,10 @@ void HandleAction_UseMove(void) } else { - gBattlerTarget = *(gBattleStruct->moveTarget + gBattlerAttacker); + gBattlerTarget = gBattleStruct->moveTarget[gBattlerAttacker]; if (!IsBattlerAlive(gBattlerTarget) && moveTarget != MOVE_TARGET_OPPONENTS_FIELD + && IsDoubleBattle() && (!IsBattlerAlly(gBattlerAttacker, gBattlerTarget))) { gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget))); @@ -578,7 +622,7 @@ void HandleAction_UseMove(void) BattleArena_AddMindPoints(gBattlerAttacker); for (i = 0; i < MAX_BATTLERS_COUNT; i++) - gBattleStruct->hpBefore[i] = gBattleMons[i].hp; + gBattleStruct->battlerState[i].wasAboveHalfHp = gBattleMons[i].hp > gBattleMons[i].maxHP / 2; gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; } @@ -763,7 +807,7 @@ void HandleAction_Run(void) } else { - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_CAN_ALWAYS_RUN + if (GetBattlerHoldEffect(gBattlerAttacker) != HOLD_EFFECT_CAN_ALWAYS_RUN && GetBattlerAbility(gBattlerAttacker) != ABILITY_RUN_AWAY && !CanBattlerEscape(gBattlerAttacker)) { @@ -893,7 +937,7 @@ void HandleAction_TryFinish(void) { if (!HandleFaintedMonActions()) { - gBattleStruct->faintedActionsState = 0; + gBattleStruct->eventState.faintedAction = 0; gCurrentActionFuncId = B_ACTION_FINISHED; } } @@ -903,13 +947,7 @@ void HandleAction_NothingIsFainted(void) gCurrentTurnActionNumber++; gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE; - gHitMarker &= ~(HITMARKER_DESTINYBOND - | HITMARKER_IGNORE_SUBSTITUTE - | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_NO_PPDEDUCT - | HITMARKER_STATUS_ABILITY_EFFECT - | HITMARKER_PASSIVE_HP_UPDATE - | HITMARKER_OBEYS); + gHitMarker &= ~(HITMARKER_OBEYS); } void HandleAction_ActionFinished(void) @@ -919,15 +957,8 @@ void HandleAction_ActionFinished(void) gBattleStruct->monToSwitchIntoId[gBattlerByTurnOrder[gCurrentTurnActionNumber]] = gSelectedMonPartyId = PARTY_SIZE; gCurrentTurnActionNumber++; gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber]; - SpecialStatusesClear(); - gHitMarker &= ~(HITMARKER_DESTINYBOND - | HITMARKER_IGNORE_SUBSTITUTE - | HITMARKER_ATTACKSTRING_PRINTED - | HITMARKER_NO_PPDEDUCT - | HITMARKER_STATUS_ABILITY_EFFECT - | HITMARKER_PASSIVE_HP_UPDATE - | HITMARKER_OBEYS - | HITMARKER_IGNORE_DISGUISE); + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); + gHitMarker &= ~(HITMARKER_OBEYS); ClearDamageCalcResults(); gCurrentMove = MOVE_NONE; @@ -940,7 +971,6 @@ void HandleAction_ActionFinished(void) gBattleScripting.moveendState = 0; gBattleCommunication[3] = 0; gBattleCommunication[4] = 0; - gBattleScripting.multihitMoveEffect = 0; gBattleResources->battleScriptsStack->size = 0; gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_NONE; @@ -948,27 +978,34 @@ void HandleAction_ActionFinished(void) { // i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already // taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action + + struct BattleContext ctx = {0}; + for (i = 0; i < gBattlersCount; i++) + { + ctx.abilities[i] = GetBattlerAbility(i); + ctx.holdEffects[i] = GetBattlerHoldEffect(i); + } for (i = gCurrentTurnActionNumber; i < gBattlersCount - 1; i++) { for (j = i + 1; j < gBattlersCount; j++) { - u32 battler1 = gBattlerByTurnOrder[i]; - u32 battler2 = gBattlerByTurnOrder[j]; + ctx.battlerAtk = gBattlerByTurnOrder[i]; + ctx.battlerDef = gBattlerByTurnOrder[j]; - if (gProtectStructs[battler1].quash || gProtectStructs[battler2].quash - || gProtectStructs[battler1].shellTrap || gProtectStructs[battler2].shellTrap) + if (gProtectStructs[ctx.battlerAtk].quash || gProtectStructs[ctx.battlerDef].quash + || gProtectStructs[ctx.battlerAtk].shellTrap || gProtectStructs[ctx.battlerDef].shellTrap) continue; // We recalculate order only for action of the same priority. If any action other than switch/move has been taken, they should // have been executed before. The only recalculation needed is for moves/switch. Mega evolution is handled in src/battle_main.c/TryChangeOrder if ((gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)) { - if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) + if (GetWhichBattlerFaster(&ctx, FALSE) == -1) SwapTurnOrder(i, j); } else if ((gActionsByTurnOrder[i] == B_ACTION_SWITCH && gActionsByTurnOrder[j] == B_ACTION_SWITCH)) { - if (GetWhichBattlerFaster(battler1, battler2, TRUE) == -1) // If the actions chosen are switching, we recalc order but ignoring the moves + if (GetWhichBattlerFaster(&ctx, TRUE) == -1) // If the actions chosen are switching, we recalc order but ignoring the moves SwapTurnOrder(i, j); } } @@ -1102,9 +1139,10 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState) // If the target can be confused, confuse them. // Don't use CanBeConfused, can cause issues in edge cases. + enum Ability ability = GetBattlerAbility(otherSkyDropper); if (!(gBattleMons[otherSkyDropper].volatiles.confusionTurns > 0 - || IsAbilityAndRecord(otherSkyDropper, GetBattlerAbility(otherSkyDropper), ABILITY_OWN_TEMPO) - || IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN))) + || IsAbilityAndRecord(otherSkyDropper, ability, ABILITY_OWN_TEMPO) + || IsBattlerTerrainAffected(otherSkyDropper, ability, GetBattlerHoldEffect(otherSkyDropper), STATUS_FIELD_MISTY_TERRAIN))) { // Set confused status gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2; @@ -1177,13 +1215,12 @@ bool32 WasUnableToUseMove(u32 battler) { if (gProtectStructs[battler].nonVolatileStatusImmobility || gProtectStructs[battler].unableToUseMove - || gProtectStructs[battler].powderSelfDmg || gProtectStructs[battler].confusionSelfDmg) return TRUE; return FALSE; } -bool32 ShouldDefiantCompetitiveActivate(u32 battler, u32 ability) +bool32 ShouldDefiantCompetitiveActivate(u32 battler, enum Ability ability) { u32 side = GetBattlerSide(battler); if (ability != ABILITY_DEFIANT && ability != ABILITY_COMPETITIVE) @@ -1205,19 +1242,54 @@ void PrepareStringBattle(enum StringID stringId, u32 battler) // Support for Contrary ability. // If a move attempted to raise stat - print "won't increase". // If a move attempted to lower stat - print "won't decrease". - if (stringId == STRINGID_STATSWONTDECREASE && !(gBattleScripting.statChanger & STAT_BUFF_NEGATIVE)) - stringId = STRINGID_STATSWONTINCREASE; - else if (stringId == STRINGID_STATSWONTINCREASE && gBattleScripting.statChanger & STAT_BUFF_NEGATIVE) - stringId = STRINGID_STATSWONTDECREASE; + switch (stringId) + { + case STRINGID_ATTACKERSSTATROSE: + case STRINGID_DEFENDERSSTATROSE: + case STRINGID_STATSWONTINCREASE: + case STRINGID_USINGITEMSTATOFPKMNROSE: + if (gBattleScripting.statChanger & STAT_BUFF_NEGATIVE) + stringId = gStatDownStringIds[gBattleCommunication[MULTISTRING_CHOOSER]]; + break; + case STRINGID_ATTACKERSSTATFELL: + case STRINGID_DEFENDERSSTATFELL: + case STRINGID_STATSWONTDECREASE: + case STRINGID_USINGITEMSTATOFPKMNFELL: + if (!(gBattleScripting.statChanger & STAT_BUFF_NEGATIVE)) + stringId = gStatUpStringIds[gBattleCommunication[MULTISTRING_CHOOSER]]; + break; + case STRINGID_STATSWONTINCREASE2: + if (battlerAbility == ABILITY_CONTRARY) + stringId = STRINGID_STATSWONTDECREASE2; + break; + case STRINGID_STATSWONTDECREASE2: + if (battlerAbility == ABILITY_CONTRARY) + stringId = STRINGID_STATSWONTINCREASE2; + break; + case STRINGID_PKMNCUTSATTACKWITH: + if (GetGenConfig(GEN_CONFIG_UPDATED_INTIMIDATE) >= GEN_8 + && targetAbility == ABILITY_RATTLED + && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, targetAbility)) + { + gBattlerAbility = gBattlerTarget; + BattleScriptCall(BattleScript_AbilityRaisesDefenderStat); + SET_STATCHANGER(STAT_SPEED, 1, FALSE); + } + else if (targetAbility == ABILITY_CONTRARY) + { + stringId = STRINGID_DEFENDERSSTATROSE; + } + break; + case STRINGID_ITDOESNTAFFECT: + case STRINGID_PKMNUNAFFECTED: + TryInitializeTrainerSlideEnemyMonUnaffected(gBattlerTarget); + break; + default: + break; + } - else if (stringId == STRINGID_STATSWONTDECREASE2 && battlerAbility == ABILITY_CONTRARY) - stringId = STRINGID_STATSWONTINCREASE2; - else if (stringId == STRINGID_STATSWONTINCREASE2 && battlerAbility == ABILITY_CONTRARY) - stringId = STRINGID_STATSWONTDECREASE2; - - // Check Defiant and Competitive stat raise whenever a stat is lowered. - else if ((stringId == STRINGID_DEFENDERSSTATFELL || stringId == STRINGID_PKMNCUTSATTACKWITH) - && ShouldDefiantCompetitiveActivate(gBattlerTarget, targetAbility)) + if ((stringId == STRINGID_PKMNCUTSATTACKWITH || stringId == STRINGID_DEFENDERSSTATFELL) + && ShouldDefiantCompetitiveActivate(gBattlerTarget, targetAbility)) { gBattlerAbility = gBattlerTarget; BattleScriptCall(BattleScript_AbilityRaisesDefenderStat); @@ -1226,18 +1298,6 @@ void PrepareStringBattle(enum StringID stringId, u32 battler) else SET_STATCHANGER(STAT_SPATK, 2, FALSE); } - else if (GetGenConfig(GEN_CONFIG_UPDATED_INTIMIDATE) >= GEN_8 - && stringId == STRINGID_PKMNCUTSATTACKWITH - && targetAbility == ABILITY_RATTLED - && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, targetAbility)) - { - gBattlerAbility = gBattlerTarget; - BattleScriptCall(BattleScript_AbilityRaisesDefenderStat); - SET_STATCHANGER(STAT_SPEED, 1, FALSE); - } - - if ((stringId == STRINGID_ITDOESNTAFFECT || stringId == STRINGID_PKMNUNAFFECTED)) - TryInitializeTrainerSlideEnemyMonUnaffected(gBattlerTarget); BtlController_EmitPrintString(battler, B_COMM_TO_CONTROLLER, stringId); MarkBattlerForControllerExec(battler); @@ -1345,7 +1405,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) u32 limitations = 0; u8 moveId = gBattleResources->bufferB[battler][2] & ~RET_GIMMICK; u32 move = gBattleMons[battler].moves[moveId]; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); u16 *choicedMove = &gBattleStruct->choicedMove[battler]; enum BattleMoveEffects moveEffect = GetMoveEffect(move); @@ -1416,7 +1476,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].throatChopTimer > gBattleTurnCounter && IsSoundMove(move)) + if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].throatChopTimer > 0 && IsSoundMove(move)) { gCurrentMove = move; if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -1607,7 +1667,7 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) { u32 move; enum BattleMoveEffects moveEffect; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); u16 *choicedMove = &gBattleStruct->choicedMove[battler]; s32 i; @@ -1657,7 +1717,7 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_BELCH && IsBelchPreventingMove(battler, move)) unusableMoves |= 1u << i; // Throat Chop - else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer > gBattleTurnCounter && IsSoundMove(move)) + else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer > 0 && IsSoundMove(move)) unusableMoves |= 1u << i; // Stuff Cheeks else if (check & MOVE_LIMITATION_STUFF_CHEEKS && moveEffect == EFFECT_STUFF_CHEEKS && GetItemPocket(gBattleMons[battler].item) != POCKET_BERRIES) @@ -1757,10 +1817,8 @@ void TryToRevertMimicryAndFlags(void) bool32 BattleArenaTurnEnd(void) { - gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); - if ((gBattleTypeFlags & BATTLE_TYPE_ARENA) - && gBattleStruct->arenaTurnCounter == 2 + && gBattleStruct->eventState.arenaTurn == 2 && IsBattlerAlive(B_POSITION_PLAYER_LEFT) && IsBattlerAlive(B_POSITION_OPPONENT_LEFT)) { for (u32 battler = 0; battler < 2; battler++) @@ -1770,25 +1828,22 @@ bool32 BattleArenaTurnEnd(void) BattleScriptExecute(BattleScript_ArenaDoJudgment); return TRUE; } - - gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_IGNORE_BIDE); - return FALSE; } // Ingrain, Leech Seed, Strength Sap and Aqua Ring s32 GetDrainedBigRootHp(u32 battler, s32 hp) { - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_BIG_ROOT) + if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_BIG_ROOT) hp = (hp * 1300) / 1000; if (hp == 0) hp = 1; - return hp * -1; + return hp; } // Should always be the last check. Otherwise the ability might be wrongly recorded. -bool32 IsAbilityAndRecord(u32 battler, u32 battlerAbility, u32 abilityToCheck) +bool32 IsAbilityAndRecord(u32 battler, enum Ability battlerAbility, enum Ability abilityToCheck) { if (battlerAbility != abilityToCheck) return FALSE; @@ -1797,7 +1852,6 @@ bool32 IsAbilityAndRecord(u32 battler, u32 battlerAbility, u32 abilityToCheck) return TRUE; } -#define FAINTED_ACTIONS_MAX_CASE 6 bool32 HandleFaintedMonActions(void) { if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) @@ -1805,38 +1859,38 @@ bool32 HandleFaintedMonActions(void) do { s32 i; - switch (gBattleStruct->faintedActionsState) + switch (gBattleStruct->eventState.faintedAction) { - case 0: - gBattleStruct->faintedActionsBattlerId = 0; - gBattleStruct->faintedActionsState++; + case FAINTED_ACTIONS_NO_MONS_TO_SWITCH: + gBattleStruct->eventState.faintedActionBattler = 0; + gBattleStruct->eventState.faintedAction++; for (i = 0; i < gBattlersCount; i++) { if (gAbsentBattlerFlags & (1u << i) && !HasNoMonsToSwitch(i, PARTY_SIZE, PARTY_SIZE)) gAbsentBattlerFlags &= ~(1u << i); } // fall through - case 1: + case FAINTED_ACTIONS_GIVE_EXP: do { - gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId; - if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0 - && !(gBattleStruct->givenExpMons & (1u << gBattlerPartyIndexes[gBattleStruct->faintedActionsBattlerId])) - && !(gAbsentBattlerFlags & (1u << gBattleStruct->faintedActionsBattlerId))) + gBattlerFainted = gBattlerTarget = gBattleStruct->eventState.faintedActionBattler; + if (gBattleMons[gBattleStruct->eventState.faintedActionBattler].hp == 0 + && !(gBattleStruct->givenExpMons & (1u << gBattlerPartyIndexes[gBattleStruct->eventState.faintedActionBattler])) + && !(gAbsentBattlerFlags & (1u << gBattleStruct->eventState.faintedActionBattler))) { BattleScriptExecute(BattleScript_GiveExp); - gBattleStruct->faintedActionsState = 2; + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_SET_ABSENT_FLAGS; return TRUE; } - } while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount); - gBattleStruct->faintedActionsState = 3; + } while (++gBattleStruct->eventState.faintedActionBattler != gBattlersCount); + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_WAIT_STATE; break; - case 2: + case FAINTED_ACTIONS_SET_ABSENT_FLAGS: OpponentSwitchInResetSentPokesToOpponentValue(gBattlerFainted); - if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount) - gBattleStruct->faintedActionsState = 3; + if (++gBattleStruct->eventState.faintedActionBattler == gBattlersCount) + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_WAIT_STATE; else - gBattleStruct->faintedActionsState = 1; + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_GIVE_EXP; // Don't switch mons until all pokemon performed their actions or the battle's over. if (B_FAINT_SWITCH_IN >= GEN_4 && gBattleOutcome == 0 @@ -1844,11 +1898,11 @@ bool32 HandleFaintedMonActions(void) && gCurrentTurnActionNumber != gBattlersCount) { gAbsentBattlerFlags |= 1u << gBattlerFainted; - if (gBattleStruct->faintedActionsState != 1) + if (gBattleStruct->eventState.faintedAction != FAINTED_ACTIONS_GIVE_EXP) return FALSE; } break; - case 3: + case FAINTED_ACTIONS_WAIT_STATE: // Don't switch mons until all pokemon performed their actions or the battle's over. if (B_FAINT_SWITCH_IN >= GEN_4 && gBattleOutcome == 0 @@ -1857,33 +1911,33 @@ bool32 HandleFaintedMonActions(void) { return FALSE; } - gBattleStruct->faintedActionsBattlerId = 0; - gBattleStruct->faintedActionsState++; + gBattleStruct->eventState.faintedActionBattler = 0; + gBattleStruct->eventState.faintedAction++; // fall through - case 4: + case FAINTED_ACTIONS_HANDLE_FAINTED_MON: do { - gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId; - if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0 - && !(gAbsentBattlerFlags & (1u << gBattleStruct->faintedActionsBattlerId))) + gBattlerFainted = gBattlerTarget = gBattleStruct->eventState.faintedActionBattler; + if (gBattleMons[gBattleStruct->eventState.faintedActionBattler].hp == 0 + && !(gAbsentBattlerFlags & (1u << gBattleStruct->eventState.faintedActionBattler))) { BattleScriptExecute(BattleScript_HandleFaintedMon); - gBattleStruct->faintedActionsState = 5; + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_HANDLE_NEXT_BATTLER; return TRUE; } - } while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount); - gBattleStruct->faintedActionsState = FAINTED_ACTIONS_MAX_CASE; + } while (++gBattleStruct->eventState.faintedActionBattler != gBattlersCount); + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_MAX_CASE; break; - case 5: - if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount) - gBattleStruct->faintedActionsState = FAINTED_ACTIONS_MAX_CASE; + case FAINTED_ACTIONS_HANDLE_NEXT_BATTLER: + if (++gBattleStruct->eventState.faintedActionBattler == gBattlersCount) + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_MAX_CASE; else - gBattleStruct->faintedActionsState = 4; + gBattleStruct->eventState.faintedAction = FAINTED_ACTIONS_HANDLE_FAINTED_MON; break; case FAINTED_ACTIONS_MAX_CASE: break; } - } while (gBattleStruct->faintedActionsState != FAINTED_ACTIONS_MAX_CASE); + } while (gBattleStruct->eventState.faintedAction != FAINTED_ACTIONS_MAX_CASE); return FALSE; } @@ -1914,7 +1968,7 @@ static inline bool32 TryFormChangeBeforeMove(void) static inline bool32 TryActivatePowderStatus(u32 move) { - u32 partnerMove = gBattleMons[BATTLE_PARTNER(gBattlerAttacker)].moves[gBattleStruct->chosenMovePositions[BATTLE_PARTNER(gBattlerAttacker)]]; + u32 partnerMove = GetChosenMoveFromPosition(BATTLE_PARTNER(gBattlerAttacker)); if (!gBattleMons[gBattlerAttacker].volatiles.powder) return FALSE; if (GetBattleMoveType(move) == TYPE_FIRE && !gBattleStruct->pledgeMove) @@ -1926,61 +1980,54 @@ static inline bool32 TryActivatePowderStatus(u32 move) return FALSE; } -void SetAtkCancelerForCalledMove(void) +static enum MoveCanceler CancelerClearFlags(struct BattleContext *ctx) { - gBattleStruct->atkCancelerTracker = CANCELER_VOLATILE_BLOCKED; - gBattleStruct->isAtkCancelerForCalledMove = TRUE; -} - -static enum MoveCanceler CancelerFlags(void) -{ - gBattleMons[gBattlerAttacker].volatiles.destinyBond = FALSE; - gBattleMons[gBattlerAttacker].volatiles.grudge = FALSE; - gBattleMons[gBattlerAttacker].volatiles.glaiveRush = FALSE; + gBattleMons[ctx->battlerAtk].volatiles.grudge = FALSE; + gBattleMons[ctx->battlerAtk].volatiles.glaiveRush = FALSE; return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerStanceChangeOne(void) +static enum MoveCanceler CancelerStanceChangeOne(struct BattleContext *ctx) { - if (B_STANCE_CHANGE_FAIL < GEN_7 && TryFormChangeBeforeMove()) + if (B_STANCE_CHANGE_FAIL < GEN_7 && gChosenMove == ctx->currentMove && TryFormChangeBeforeMove()) return MOVE_STEP_BREAK; return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerSkyDrop(void) +static enum MoveCanceler CancelerSkyDrop(struct BattleContext *ctx) { // If Pokemon is being held in Sky Drop - if (gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable == STATE_SKY_DROP) + if (gBattleMons[ctx->battlerAtk].volatiles.semiInvulnerable == STATE_SKY_DROP) { gBattlescriptCurrInstr = BattleScript_MoveEnd; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerRecharge(void) +static enum MoveCanceler CancelerRecharge(struct BattleContext *ctx) { - if (gDisableStructs[gBattlerAttacker].rechargeTimer > 0) + if (gDisableStructs[ctx->battlerAtk].rechargeTimer > 0) { - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerAsleepOrFrozen(void) +static enum MoveCanceler CancelerAsleepOrFrozen(struct BattleContext *ctx) { - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) + if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) { - if (UproarWakeUpCheck(gBattlerAttacker)) + if (UproarWakeUpCheck(ctx->battlerAtk)) { - TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; - gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE; - gEffectBattler = gBattlerAttacker; + TryDeactivateSleepClause(GetBattlerSide(ctx->battlerAtk), gBattlerPartyIndexes[ctx->battlerAtk]); + gBattleMons[ctx->battlerAtk].status1 &= ~STATUS1_SLEEP; + gBattleMons[ctx->battlerAtk].volatiles.nightmare = FALSE; + gEffectBattler = ctx->battlerAtk; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP_UPROAR; BattleScriptCall(BattleScript_MoveUsedWokeUp); return MOVE_STEP_REMOVES_STATUS; @@ -1988,191 +2035,209 @@ static enum MoveCanceler CancelerAsleepOrFrozen(void) else { u8 toSub; - if (IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_EARLY_BIRD)) + if (IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_EARLY_BIRD)) toSub = 2; else toSub = 1; - if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) < toSub) - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; + if ((gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) < toSub) + gBattleMons[ctx->battlerAtk].status1 &= ~STATUS1_SLEEP; else - gBattleMons[gBattlerAttacker].status1 -= toSub; - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) + gBattleMons[ctx->battlerAtk].status1 -= toSub; + + enum BattleMoveEffects moveEffect = GetMoveEffect(ctx->currentMove); + if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) { - enum BattleMoveEffects moveEffect = GetMoveEffect(gChosenMove); if (moveEffect != EFFECT_SNORE && moveEffect != EFFECT_SLEEP_TALK) { - gProtectStructs[gBattlerAttacker].nonVolatileStatusImmobility = TRUE; + gProtectStructs[ctx->battlerAtk].nonVolatileStatusImmobility = TRUE; gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_REMOVES_STATUS; + return MOVE_STEP_FAILURE; } } else { - TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); - gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE; + TryDeactivateSleepClause(GetBattlerSide(ctx->battlerAtk), gBattlerPartyIndexes[ctx->battlerAtk]); + gBattleMons[ctx->battlerAtk].volatiles.nightmare = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP; BattleScriptCall(BattleScript_MoveUsedWokeUp); return MOVE_STEP_REMOVES_STATUS; } } } - else if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE && !MoveThawsUser(gCurrentMove)) + else if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_FREEZE && !MoveThawsUser(ctx->currentMove)) { if (!RandomPercentage(RNG_FROZEN, 20)) { - gProtectStructs[gBattlerAttacker].nonVolatileStatusImmobility = TRUE; + gProtectStructs[ctx->battlerAtk].nonVolatileStatusImmobility = TRUE; gBattlescriptCurrInstr = BattleScript_MoveUsedIsFrozen; - gHitMarker |= (HITMARKER_NO_ATTACKSTRING | HITMARKER_UNABLE_TO_USE_MOVE); + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; } else // unfreeze { - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FREEZE; + gBattleMons[ctx->battlerAtk].status1 &= ~STATUS1_FREEZE; BattleScriptCall(BattleScript_MoveUsedUnfroze); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED; } - return MOVE_STEP_REMOVES_STATUS; + return MOVE_STEP_REMOVES_STATUS; // Move failure but also removes status } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerObedience(void) +static enum MoveCanceler CancelerObedience(struct BattleContext *ctx) { - enum Obedience obedienceResult = GetAttackerObedienceForAction(); - if (!(gHitMarker & HITMARKER_NO_PPDEDUCT) // Don't check obedience after first hit of multi target move or multi hit moves - && !gBattleMons[gBattlerAttacker].volatiles.multipleTurns) + if (!gBattleMons[ctx->battlerAtk].volatiles.multipleTurns) { + enum Obedience obedienceResult = GetAttackerObedienceForAction(); switch (obedienceResult) { case OBEYS: gHitMarker |= HITMARKER_OBEYS; - break; + return MOVE_STEP_SUCCESS; case DISOBEYS_LOAFS: // Randomly select, then print a disobedient string // B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS); gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - break; + gBattleStruct->moveResultFlags[ctx->battlerDef] |= MOVE_RESULT_MISSED; + return MOVE_STEP_FAILURE; case DISOBEYS_HITS_SELF: - gBattlerTarget = gBattlerAttacker; - struct DamageContext ctx; - ctx.battlerAtk = ctx.battlerDef = gBattlerAttacker; - ctx.move = MOVE_NONE; - ctx.moveType = TYPE_MYSTERY; - ctx.isCrit = FALSE; - ctx.randomFactor = FALSE; - ctx.updateFlags = TRUE; - ctx.isSelfInflicted = TRUE; - ctx.fixedBasePower = 40; - gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&ctx); + gBattlerTarget = ctx->battlerAtk; + struct DamageContext dmgCtx = {0}; + dmgCtx.battlerAtk = dmgCtx.battlerDef = ctx->battlerAtk; + dmgCtx.move = dmgCtx.chosenMove = MOVE_NONE; + dmgCtx.moveType = TYPE_MYSTERY; + dmgCtx.isCrit = FALSE; + dmgCtx.randomFactor = FALSE; + dmgCtx.updateFlags = TRUE; + dmgCtx.isSelfInflicted = TRUE; + dmgCtx.fixedBasePower = 40; + gBattleStruct->moveDamage[ctx->battlerAtk] = CalculateMoveDamage(&dmgCtx); gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gHitMarker |= HITMARKER_OBEYS; - break; + return MOVE_STEP_FAILURE; // Move doesn't fail but mon hits itself case DISOBEYS_FALL_ASLEEP: if (IsSleepClauseEnabled()) - gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; + gBattleStruct->battlerState[ctx->battlerAtk].sleepClauseEffectExempt = TRUE; gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; + gBattleStruct->moveResultFlags[ctx->battlerDef] |= MOVE_RESULT_MISSED; + return MOVE_STEP_FAILURE; break; case DISOBEYS_WHILE_ASLEEP: gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - break; + gBattleStruct->moveResultFlags[ctx->battlerDef] |= MOVE_RESULT_MISSED; + return MOVE_STEP_FAILURE; case DISOBEYS_RANDOM_MOVE: - gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; - SetAtkCancelerForCalledMove(); - gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; + gCurrentMove = gCalledMove = gBattleMons[ctx->battlerAtk].moves[gCurrMovePos]; + BattleScriptCall(BattleScript_IgnoresAndUsesRandomMove); gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gHitMarker |= HITMARKER_OBEYS; - break; + return MOVE_STEP_BREAK; } - return MOVE_STEP_BREAK; } gHitMarker |= HITMARKER_OBEYS; return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerTruant(void) +static enum MoveCanceler CancelerPowerPoints(struct BattleContext *ctx) { - if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) + if (gBattleMons[ctx->battlerAtk].pp[gCurrMovePos] == 0 + && ctx->currentMove != MOVE_STRUGGLE + && !gSpecialStatuses[ctx->battlerAtk].dancerUsedMove + && !gBattleMons[ctx->battlerAtk].volatiles.multipleTurns) { - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gBattlescriptCurrInstr = BattleScript_NoPPForMove; + gBattleStruct->moveResultFlags[ctx->battlerDef] |= MOVE_RESULT_MISSED; + return MOVE_STEP_FAILURE; + } + + return MOVE_STEP_SUCCESS; +} + +static enum MoveCanceler CancelerTruant(struct BattleContext *ctx) +{ + if (GetBattlerAbility(ctx->battlerAtk) == ABILITY_TRUANT && gDisableStructs[ctx->battlerAtk].truantCounter) + { + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING; - gBattlerAbility = gBattlerAttacker; + gBattlerAbility = ctx->battlerAtk; gBattlescriptCurrInstr = BattleScript_TruantLoafingAround; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - return MOVE_STEP_BREAK; + gBattleStruct->moveResultFlags[ctx->battlerDef] |= MOVE_RESULT_MISSED; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerFlinch(void) +static enum MoveCanceler CancelerFlinch(struct BattleContext *ctx) { - if (gBattleMons[gBattlerAttacker].volatiles.flinched) + if (gBattleMons[ctx->battlerAtk].volatiles.flinched) { - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerDisabled(void) +static enum MoveCanceler CancelerDisabled(struct BattleContext *ctx) { - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].disabledMove == gCurrentMove && gDisableStructs[gBattlerAttacker].disabledMove != MOVE_NONE) + if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE + && gDisableStructs[ctx->battlerAtk].disabledMove == ctx->currentMove + && gDisableStructs[ctx->battlerAtk].disabledMove != MOVE_NONE) { - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + gBattleScripting.battler = ctx->battlerAtk; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerVolatileBlocked(void) +static enum MoveCanceler CancelerVolatileBlocked(struct BattleContext *ctx) { - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gBattleMons[gBattlerAttacker].volatiles.healBlock && IsHealBlockPreventingMove(gBattlerAttacker, gCurrentMove)) + if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE + && gBattleMons[ctx->battlerAtk].volatiles.healBlock + && IsHealBlockPreventingMove(ctx->battlerAtk, ctx->currentMove)) { - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + gBattleScripting.battler = ctx->battlerAtk; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } - else if (gFieldStatuses & STATUS_FIELD_GRAVITY && IsGravityPreventingMove(gCurrentMove)) + else if (gFieldStatuses & STATUS_FIELD_GRAVITY && IsGravityPreventingMove(ctx->currentMove)) { - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + gBattleScripting.battler = ctx->battlerAtk; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } - else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer > gBattleTurnCounter && IsSoundMove(gCurrentMove)) + else if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].throatChopTimer > 0 && IsSoundMove(ctx->currentMove)) { - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerTaunted(void) +static enum MoveCanceler CancelerTaunted(struct BattleContext *ctx) { - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].tauntTimer && IsBattleMoveStatus(gCurrentMove)) + if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].tauntTimer && IsBattleMoveStatus(ctx->currentMove)) { - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2180,108 +2245,106 @@ static enum MoveCanceler CancelerTaunted(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerImprisoned(void) +static enum MoveCanceler CancelerImprisoned(struct BattleContext *ctx) { - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && GetImprisonedMovesCount(gBattlerAttacker, gCurrentMove)) + if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && GetImprisonedMovesCount(ctx->battlerAtk, ctx->currentMove)) { - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerConfused(void) +static enum MoveCanceler CancelerConfused(struct BattleContext *ctx) { - if (gBattleStruct->isAtkCancelerForCalledMove) - return MOVE_STEP_SUCCESS; - - if (gBattleMons[gBattlerAttacker].volatiles.confusionTurns) + if (gBattleMons[ctx->battlerAtk].volatiles.confusionTurns) { - if (!gBattleMons[gBattlerAttacker].volatiles.infiniteConfusion) - gBattleMons[gBattlerAttacker].volatiles.confusionTurns--; - if (gBattleMons[gBattlerAttacker].volatiles.confusionTurns) + if (!gBattleMons[ctx->battlerAtk].volatiles.infiniteConfusion) + gBattleMons[ctx->battlerAtk].volatiles.confusionTurns--; + if (gBattleMons[ctx->battlerAtk].volatiles.confusionTurns) { // confusion dmg if (RandomPercentage(RNG_CONFUSION, (GetGenConfig(GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE) >= GEN_7 ? 33 : 50))) { gBattleCommunication[MULTISTRING_CHOOSER] = TRUE; - gBattlerTarget = gBattlerAttacker; - struct DamageContext ctx; - ctx.battlerAtk = ctx.battlerDef = gBattlerAttacker; - ctx.move = MOVE_NONE; - ctx.moveType = TYPE_MYSTERY; - ctx.isCrit = FALSE; - ctx.randomFactor = FALSE; - ctx.updateFlags = TRUE; - ctx.isSelfInflicted = TRUE; - ctx.fixedBasePower = 40; - gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&ctx); - gProtectStructs[gBattlerAttacker].confusionSelfDmg = TRUE; + struct DamageContext dmgCtx = {0}; + dmgCtx.battlerAtk = dmgCtx.battlerDef = ctx->battlerAtk; + dmgCtx.move = dmgCtx.chosenMove = MOVE_NONE; + dmgCtx.moveType = TYPE_MYSTERY; + dmgCtx.isCrit = FALSE; + dmgCtx.randomFactor = FALSE; + dmgCtx.updateFlags = TRUE; + dmgCtx.isSelfInflicted = TRUE; + dmgCtx.fixedBasePower = 40; + gBattleStruct->passiveHpUpdate[ctx->battlerAtk] = CalculateMoveDamage(&dmgCtx); + gProtectStructs[ctx->battlerAtk].confusionSelfDmg = TRUE; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfused; + return MOVE_STEP_FAILURE; } else { gBattleCommunication[MULTISTRING_CHOOSER] = FALSE; BattleScriptCall(BattleScript_MoveUsedIsConfused); + return MOVE_STEP_BREAK; } } else // snapped out of confusion { BattleScriptCall(BattleScript_MoveUsedIsConfusedNoMore); + return MOVE_STEP_BREAK; } - return MOVE_STEP_BREAK; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerParalyzed(void) +static enum MoveCanceler CancelerParalyzed(struct BattleContext *ctx) { - if (!gBattleStruct->isAtkCancelerForCalledMove - && (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) - && !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) + if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_PARALYSIS + && !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) && !RandomPercentage(RNG_PARALYSIS, 75)) { - gProtectStructs[gBattlerAttacker].nonVolatileStatusImmobility = TRUE; + gProtectStructs[ctx->battlerAtk].nonVolatileStatusImmobility = TRUE; // This is removed in FRLG and Emerald for some reason //CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerInfatuation(void) +static enum MoveCanceler CancelerInfatuation(struct BattleContext *ctx) { - if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].volatiles.infatuation) + if (gBattleMons[ctx->battlerAtk].volatiles.infatuation) { - gBattleScripting.battler = gBattleMons[gBattlerAttacker].volatiles.infatuation - 1; + gBattleScripting.battler = gBattleMons[ctx->battlerAtk].volatiles.infatuation - 1; if (!RandomPercentage(RNG_INFATUATION, 50)) { BattleScriptCall(BattleScript_MoveUsedIsInLove); + return MOVE_STEP_BREAK; } else { BattleScriptPush(BattleScript_MoveUsedIsInLoveCantAttack); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove; + return MOVE_STEP_FAILURE; } - return MOVE_STEP_BREAK; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerBide(void) +static enum MoveCanceler CancelerBide(struct BattleContext *ctx) { - if (gBattleMons[gBattlerAttacker].volatiles.bideTurns) + if (gBattleMons[ctx->battlerAtk].volatiles.bideTurns) { - if (--gBattleMons[gBattlerAttacker].volatiles.bideTurns) + if (--gBattleMons[ctx->battlerAtk].volatiles.bideTurns) { gBattlescriptCurrInstr = BattleScript_BideStoringEnergy; } @@ -2289,70 +2352,58 @@ static enum MoveCanceler CancelerBide(void) { // This is removed in FRLG and Emerald for some reason //gBattleMons[gBattlerAttacker].volatiles.multipleTurns = FALSE; - if (gBideDmg[gBattlerAttacker]) + if (gBideDmg[ctx->battlerAtk]) { gCurrentMove = MOVE_BIDE; - gBattlerTarget = gBideTarget[gBattlerAttacker]; - if (gAbsentBattlerFlags & (1u << gBattlerTarget)) + gBattlerTarget = gBideTarget[ctx->battlerAtk]; + if (gAbsentBattlerFlags & (1u << ctx->battlerDef)) gBattlerTarget = GetBattleMoveTarget(MOVE_BIDE, MOVE_TARGET_SELECTED + 1); gBattlescriptCurrInstr = BattleScript_BideAttack; + return MOVE_STEP_BREAK; // Jumps to a different script but no failure } else { gBattlescriptCurrInstr = BattleScript_BideNoEnergyToAttack; + return MOVE_STEP_FAILURE; } } + } + return MOVE_STEP_SUCCESS; +} + +static enum MoveCanceler CancelerZMoves(struct BattleContext *ctx) +{ + if (GetActiveGimmick(ctx->battlerAtk) == GIMMICK_Z_MOVE) + { + // attacker has a queued z move + RecordItemEffectBattle(ctx->battlerAtk, HOLD_EFFECT_Z_CRYSTAL); + SetGimmickAsActivated(ctx->battlerAtk, GIMMICK_Z_MOVE); + + gBattleScripting.battler = ctx->battlerAtk; + if (GetMoveCategory(ctx->currentMove) == DAMAGE_CATEGORY_STATUS) + BattleScriptCall(BattleScript_ZMoveActivateStatus); + else + BattleScriptCall(BattleScript_ZMoveActivateDamaging); + return MOVE_STEP_BREAK; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerThaw(void) +static enum MoveCanceler CancelerChoiceLock(struct BattleContext *ctx) { - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE) - { - if (!(IsMoveEffectRemoveSpeciesType(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) - { - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FREEZE; - BattleScriptCall(BattleScript_MoveUsedUnfroze); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED_BY_MOVE; - } - return MOVE_STEP_REMOVES_STATUS; - } - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE && MoveThawsUser(gCurrentMove)) - { - if (!(IsMoveEffectRemoveSpeciesType(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) - { - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FROSTBITE; - BattleScriptCall(BattleScript_MoveUsedUnfrostbite); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FROSTBITE_HEALED_BY_MOVE; - } - return MOVE_STEP_REMOVES_STATUS; - } - return MOVE_STEP_SUCCESS; -} - -static enum MoveCanceler CancelerStanceChangeTwo(void) -{ - if (B_STANCE_CHANGE_FAIL >= GEN_7 && !gBattleStruct->isAtkCancelerForCalledMove && TryFormChangeBeforeMove()) - return MOVE_STEP_BREAK; - return MOVE_STEP_SUCCESS; -} - -static enum MoveCanceler CancelerChoiceLock(void) -{ - u16 *choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker]; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); + u16 *choicedMoveAtk = &gBattleStruct->choicedMove[ctx->battlerAtk]; + enum HoldEffect holdEffect = GetBattlerHoldEffect(ctx->battlerAtk); if (gChosenMove != MOVE_STRUGGLE && (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE) - && (IsHoldEffectChoice(holdEffect) || GetBattlerAbility(gBattlerAttacker) == ABILITY_GORILLA_TACTICS)) + && (IsHoldEffectChoice(holdEffect) || ctx->abilities[ctx->battlerAtk] == ABILITY_GORILLA_TACTICS)) *choicedMoveAtk = gChosenMove; u32 moveIndex; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if (gBattleMons[gBattlerAttacker].moves[moveIndex] == *choicedMoveAtk) + if (gBattleMons[ctx->battlerAtk].moves[moveIndex] == *choicedMoveAtk) break; } @@ -2362,72 +2413,434 @@ static enum MoveCanceler CancelerChoiceLock(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerWeatherPrimal(void) +static enum MoveCanceler CancelerCallSubmove(struct BattleContext *ctx) +{ + bool32 noEffect = FALSE; + u32 calledMove = MOVE_NONE; + const u8 *battleScript = NULL; + battleScript = BattleScript_SubmoveAttackstring; + + switch(GetMoveEffect(ctx->currentMove)) + { + case EFFECT_MIRROR_MOVE: + calledMove = GetMirrorMoveMove(); + break; + case EFFECT_METRONOME: + calledMove = GetMetronomeMove(); + battleScript = BattleScript_MetronomeAttackstring; + break; + case EFFECT_ASSIST: + calledMove = GetAssistMove(); + break; + case EFFECT_NATURE_POWER: + calledMove = GetNaturePowerMove(ctx->battlerAtk); + battleScript = BattleScript_NaturePowerAttackstring; + break; + case EFFECT_SLEEP_TALK: + calledMove = GetSleepTalkMove(); + battleScript = BattleScript_SleepTalkAttackstring; + break; + case EFFECT_COPYCAT: + calledMove = GetCopyCatMove(); + break; + case EFFECT_ME_FIRST: + calledMove = GetMeFirstMove(); + break; + default: + noEffect = TRUE; + break; + } + + if (noEffect) + { + gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT; + return MOVE_STEP_SUCCESS; + } + + if (calledMove != MOVE_NONE) + { + if (GetActiveGimmick(ctx->battlerAtk) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(calledMove)) + calledMove = GetTypeBasedZMove(calledMove); + if (GetMoveEffect(ctx->currentMove) == EFFECT_COPYCAT && IsMaxMove(calledMove)) + calledMove = gBattleStruct->dynamax.lastUsedBaseMove; + + gBattleStruct->submoveAnnouncement = SUBMOVE_SUCCESS; + gCalledMove = calledMove; + BattleScriptCall(battleScript); + return MOVE_STEP_BREAK; + } + + gBattleStruct->submoveAnnouncement = SUBMOVE_FAILURE; + return MOVE_STEP_SUCCESS; +} + +static enum MoveCanceler CancelerThaw(struct BattleContext *ctx) +{ + if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_FREEZE) + { + if (!(IsMoveEffectRemoveSpeciesType(ctx->currentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(ctx->battlerAtk, TYPE_FIRE))) + { + gBattleMons[ctx->battlerAtk].status1 &= ~STATUS1_FREEZE; + BattleScriptCall(BattleScript_MoveUsedUnfroze); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED_BY_MOVE; + } + return MOVE_STEP_REMOVES_STATUS; + } + if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_FROSTBITE && MoveThawsUser(ctx->currentMove)) + { + if (!(IsMoveEffectRemoveSpeciesType(ctx->currentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(ctx->battlerAtk, TYPE_FIRE))) + { + gBattleMons[ctx->battlerAtk].status1 &= ~STATUS1_FROSTBITE; + BattleScriptCall(BattleScript_MoveUsedUnfrostbite); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FROSTBITE_HEALED_BY_MOVE; + } + return MOVE_STEP_REMOVES_STATUS; + } + return MOVE_STEP_SUCCESS; +} + +static enum MoveCanceler CancelerStanceChangeTwo(struct BattleContext *ctx) +{ + if (B_STANCE_CHANGE_FAIL >= GEN_7 && gChosenMove == ctx->currentMove && TryFormChangeBeforeMove()) + return MOVE_STEP_BREAK; + return MOVE_STEP_SUCCESS; +} + +static enum MoveCanceler CancelerAttackstring(struct BattleContext *ctx) +{ + BattleScriptCall(BattleScript_Attackstring); + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + gLastPrintedMoves[gBattlerAttacker] = gChosenMove; + return MOVE_STEP_BREAK; +} + +static enum MoveCanceler CancelerPPDeduction(struct BattleContext *ctx) +{ + if (gBattleMons[ctx->battlerAtk].volatiles.multipleTurns + || gSpecialStatuses[ctx->battlerAtk].dancerUsedMove + || ctx->currentMove == MOVE_STRUGGLE) + return MOVE_STEP_SUCCESS; + + s32 ppToDeduct = 1; + u32 moveTarget = GetBattlerMoveTargetType(ctx->battlerAtk, ctx->currentMove); + u32 movePosition = gCurrMovePos; + + if (gBattleStruct->submoveAnnouncement == SUBMOVE_SUCCESS) + movePosition = gChosenMovePos; + + if (moveTarget == MOVE_TARGET_BOTH + || moveTarget == MOVE_TARGET_FOES_AND_ALLY + || moveTarget == MOVE_TARGET_ALL_BATTLERS + || MoveForcesPressure(ctx->currentMove)) + { + for (u32 i = 0; i < gBattlersCount; i++) + { + if (!IsBattlerAlly(i, ctx->battlerAtk) && IsBattlerAlive(i)) + ppToDeduct += (GetBattlerAbility(i) == ABILITY_PRESSURE); + } + } + else if (moveTarget != MOVE_TARGET_OPPONENTS_FIELD) + { + if (ctx->battlerAtk != ctx->battlerDef && ctx->abilities[ctx->battlerDef] == ABILITY_PRESSURE) + ppToDeduct++; + } + + // For item Metronome, echoed voice + if (ctx->currentMove != gLastResultingMoves[ctx->battlerAtk] || WasUnableToUseMove(ctx->battlerAtk)) + gBattleStruct->metronomeItemCounter[ctx->battlerAtk] = 0; + + if (gBattleMons[ctx->battlerAtk].pp[movePosition] > ppToDeduct) + gBattleMons[ctx->battlerAtk].pp[movePosition] -= ppToDeduct; + else + gBattleMons[ctx->battlerAtk].pp[movePosition] = 0; + + if (MOVE_IS_PERMANENT(ctx->battlerAtk, movePosition)) + { + BtlController_EmitSetMonData( + ctx->battlerAtk, + B_COMM_TO_CONTROLLER, + REQUEST_PPMOVE1_BATTLE + movePosition, + 0, + sizeof(gBattleMons[ctx->battlerAtk].pp[movePosition]), + &gBattleMons[ctx->battlerAtk].pp[movePosition]); + MarkBattlerForControllerExec(ctx->battlerAtk); + } + + if (gBattleStruct->submoveAnnouncement != SUBMOVE_NO_EFFECT) + { + if (gBattleStruct->submoveAnnouncement == SUBMOVE_FAILURE) + { + gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT; + gBattlescriptCurrInstr = BattleScript_ButItFailed; + return MOVE_STEP_FAILURE; + } + else if (CancelerVolatileBlocked(ctx) == MOVE_STEP_FAILURE) // Check Gravity/Heal Block/Throat Chop for Submove + { + gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT; + return MOVE_STEP_FAILURE; + } + else + { + gBattleStruct->submoveAnnouncement = SUBMOVE_NO_EFFECT; + gBattlerTarget = GetBattleMoveTarget(ctx->currentMove, NO_TARGET_OVERRIDE); + gBattleScripting.animTurn = 0; + gBattleScripting.animTargetsHit = 0; + + // Possibly better to just move type setting and redirection to attackcanceler as a new case at this point + SetTypeBeforeUsingMove(ctx->currentMove, ctx->battlerAtk); + HandleMoveTargetRedirection(); + gBattlescriptCurrInstr = GetMoveBattleScript(ctx->currentMove); + return MOVE_STEP_BREAK; + } + } + + return MOVE_STEP_SUCCESS; +} + +static enum MoveCanceler CancelerWeatherPrimal(struct BattleContext *ctx) { enum MoveCanceler effect = MOVE_STEP_SUCCESS; - if (HasWeatherEffect() && GetMovePower(gCurrentMove) > 0) + if (HasWeatherEffect() && GetMovePower(ctx->currentMove) > 0) { - u32 moveType = GetBattleMoveType(gCurrentMove); - if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (GetGenConfig(GEN_CONFIG_POWDER_RAIN) >= GEN_7 || !TryActivatePowderStatus(gCurrentMove))) + enum Type moveType = GetBattleMoveType(ctx->currentMove); + if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (GetGenConfig(GEN_CONFIG_POWDER_RAIN) >= GEN_7 || !TryActivatePowderStatus(ctx->currentMove))) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN; - effect = MOVE_STEP_BREAK; + effect = MOVE_STEP_FAILURE; } else if (moveType == TYPE_WATER && (gBattleWeather & B_WEATHER_SUN_PRIMAL)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_EVAPORATED_IN_SUN; - effect = MOVE_STEP_BREAK; + effect = MOVE_STEP_FAILURE; } - if (effect == MOVE_STEP_BREAK) + if (effect == MOVE_STEP_FAILURE) { - gBattleScripting.moveEffect = MOVE_EFFECT_NONE; - gProtectStructs[gBattlerAttacker].chargingTurn = FALSE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); + gProtectStructs[ctx->battlerAtk].chargingTurn = FALSE; + CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - BattleScriptCall(BattleScript_PrimalWeatherBlocksMove); + gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove; } } return effect; } -static enum MoveCanceler CancelerDynamaxBlocked(void) +static enum MoveCanceler CancelerMoveFailure(struct BattleContext *ctx) { - if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove)) + const u8 *battleScript = NULL; + + switch (GetMoveEffect(ctx->currentMove)) + { + case EFFECT_FAIL_IF_NOT_ARG_TYPE: + if (!IS_BATTLER_OF_TYPE(ctx->battlerAtk, GetMoveArgType(ctx->currentMove))) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_AURA_WHEEL: + if (gBattleMons[ctx->battlerAtk].species != SPECIES_MORPEKO_FULL_BELLY + && gBattleMons[ctx->battlerAtk].species != SPECIES_MORPEKO_HANGRY) + battleScript = BattleScript_PokemonCantUseTheMove; + break; + case EFFECT_AURORA_VEIL: + if (!(gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW) && HasWeatherEffect())) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_CLANGOROUS_SOUL: + if (gBattleMons[ctx->battlerAtk].hp <= max(1, GetNonDynamaxMaxHP(ctx->battlerAtk) / 3)) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_COUNTER: + case EFFECT_MIRROR_COAT: + case EFFECT_METAL_BURST: + // TODO: Needs a refactor because the moves currently don't work according to new gens + break; + case EFFECT_DESTINY_BOND: + if (DoesDestinyBondFail(ctx->battlerAtk)) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_FIRST_TURN_ONLY: + if (!gDisableStructs[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_MAT_BLOCK: + if (!gDisableStructs[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_FLING: + if (!CanFling(ctx->battlerAtk)) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_FOLLOW_ME: + if (B_UPDATED_MOVE_DATA >= GEN_8 && !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE)) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_FUTURE_SIGHT: + if (gWishFutureKnock.futureSightCounter[ctx->battlerDef] > 0) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_LAST_RESORT: + if (!CanUseLastResort(ctx->battlerAtk)) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_NO_RETREAT: + if (gBattleMons[ctx->battlerDef].volatiles.noRetreat) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_POLTERGEIST: + if (gBattleMons[ctx->battlerDef].item == ITEM_NONE + || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM + || ctx->abilities[ctx->battlerDef] == ABILITY_KLUTZ) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_PROTECT: + // TODO + break; + case EFFECT_REST: + if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP + || ctx->abilities[ctx->battlerAtk] == ABILITY_COMATOSE) + battleScript = BattleScript_RestIsAlreadyAsleep; + else if (gBattleMons[ctx->battlerAtk].hp == gBattleMons[ctx->battlerAtk].maxHP) + battleScript = BattleScript_AlreadyAtFullHp; + else if (ctx->abilities[ctx->battlerAtk] == ABILITY_INSOMNIA + || ctx->abilities[ctx->battlerAtk] == ABILITY_VITAL_SPIRIT + || ctx->abilities[ctx->battlerAtk] == ABILITY_PURIFYING_SALT) + battleScript = BattleScript_InsomniaProtects; + break; + case EFFECT_SUCKER_PUNCH: + if (HasBattlerActedThisTurn(ctx->battlerDef) + || (IsBattleMoveStatus(GetChosenMoveFromPosition(ctx->battlerDef)) && !gProtectStructs[ctx->battlerDef].noValidMoves)) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_UPPER_HAND: + { + u32 prio = GetChosenMovePriority(ctx->battlerDef, ctx->abilities[ctx->battlerDef]); + if (prio < 1 || prio > 3 // Fails if priority is less than 1 or greater than 3, if target already moved, or if using a status + || HasBattlerActedThisTurn(ctx->battlerDef) + || gChosenMoveByBattler[ctx->battlerDef] == MOVE_NONE + || IsBattleMoveStatus(gChosenMoveByBattler[ctx->battlerDef])) + battleScript = BattleScript_ButItFailed; + break; + } + case EFFECT_SNORE: + if (!(gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) + && ctx->abilities[ctx->battlerAtk] != ABILITY_COMATOSE) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_STEEL_ROLLER: + if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_STOCKPILE: + if (gDisableStructs[ctx->battlerAtk].stockpileCounter >= 3) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_STUFF_CHEEKS: + if (GetItemPocket(gBattleMons[ctx->battlerAtk].item) != POCKET_BERRIES) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_SWALLOW: + case EFFECT_SPIT_UP: + if (gDisableStructs[ctx->battlerAtk].stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed) + battleScript = BattleScript_ButItFailed; + break; + case EFFECT_TELEPORT: + // TODO: follow up: Can't make sense of teleport logic + break; + case EFFECT_LOW_KICK: + case EFFECT_HEAT_CRASH: + if (GetActiveGimmick(ctx->battlerDef) == GIMMICK_DYNAMAX) + battleScript = BattleScript_MoveBlockedByDynamax; + break; + default: + break; + } + + if (battleScript != NULL) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - BattleScriptCall(BattleScript_MoveBlockedByDynamax); - return MOVE_STEP_BREAK; + gBattlescriptCurrInstr = battleScript; + return MOVE_STEP_FAILURE; } + return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerPowderStatus(void) +static enum MoveCanceler CancelerPowderStatus(struct BattleContext *ctx) { - if (TryActivatePowderStatus(gCurrentMove)) + if (TryActivatePowderStatus(ctx->currentMove)) { - gProtectStructs[gBattlerAttacker].powderSelfDmg = TRUE; - if (!IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + if (!IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) + SetPassiveDamageAmount(ctx->battlerAtk, GetNonDynamaxMaxHP(ctx->battlerAtk) / 4); - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE - || HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE)) + // This might be incorrect + if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE + || HasTrainerUsedGimmick(ctx->battlerAtk, GIMMICK_Z_MOVE)) gBattlescriptCurrInstr = BattleScript_MoveUsedPowder; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerProtean(void) +bool32 IsDazzlingAbility(enum Ability ability) { - u32 moveType = GetBattleMoveType(gCurrentMove); - if (ProteanTryChangeType(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), gCurrentMove, moveType)) + switch (ability) + { + case ABILITY_DAZZLING: return TRUE; + case ABILITY_QUEENLY_MAJESTY: return TRUE; + case ABILITY_ARMOR_TAIL: return TRUE; + default: break; + } + return FALSE; +} + +static enum MoveCanceler CancelerPriorityBlock(struct BattleContext *ctx) +{ + bool32 effect = FALSE; + s32 priority = GetChosenMovePriority(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk]); + u32 blockAbility = ABILITY_NONE; // ability of battler who is blocking + u32 blockedByBattler = ctx->battlerDef; + + if (priority <= 0 || IsBattlerAlly(ctx->battlerAtk, ctx->battlerDef)) + return MOVE_STEP_SUCCESS; + + if (IsDazzlingAbility(ctx->abilities[ctx->battlerDef])) + { + blockAbility = ctx->abilities[ctx->battlerDef]; + effect = TRUE; + } + else if (IsDoubleBattle() && IsBattlerAlive(BATTLE_PARTNER(ctx->battlerDef))) + { + blockAbility = GetBattlerAbility(BATTLE_PARTNER(ctx->battlerDef)); + if (IsDazzlingAbility(blockAbility)) + { + blockedByBattler = BATTLE_PARTNER(ctx->battlerDef); + effect = TRUE; + } + } + + if (effect) + { + gMultiHitCounter = 0; // Prevent multi-hit moves from hitting more than once after move has been absorbed. + gLastUsedAbility = blockAbility; + RecordAbilityBattle(blockedByBattler, blockAbility); + gBattleScripting.battler = gBattlerAbility = blockedByBattler; + gBattlescriptCurrInstr = BattleScript_DazzlingProtected; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + return MOVE_STEP_FAILURE; + } + + return MOVE_STEP_SUCCESS; +} + +static enum MoveCanceler CancelerProtean(struct BattleContext *ctx) +{ + enum Type moveType = GetBattleMoveType(ctx->currentMove); + if (ProteanTryChangeType(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ctx->currentMove, moveType)) { if (GetGenConfig(GEN_PROTEAN_LIBERO) >= GEN_9) - gDisableStructs[gBattlerAttacker].usedProteanLibero = TRUE; + gDisableStructs[ctx->battlerAtk].usedProteanLibero = TRUE; PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); - gBattlerAbility = gBattlerAttacker; - PrepareStringBattle(STRINGID_EMPTYSTRING3, gBattlerAttacker); + gBattlerAbility = ctx->battlerAtk; + PrepareStringBattle(STRINGID_EMPTYSTRING3, ctx->battlerAtk); gBattleCommunication[MSG_DISPLAY] = 1; BattleScriptCall(BattleScript_ProteanActivates); return MOVE_STEP_BREAK; @@ -2435,48 +2848,32 @@ static enum MoveCanceler CancelerProtean(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerPsychicTerrain(void) -{ - if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_PSYCHIC_TERRAIN) - && GetChosenMovePriority(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)) > 0 - && GetMoveTarget(gCurrentMove) != MOVE_TARGET_ALL_BATTLERS - && GetMoveTarget(gCurrentMove) != MOVE_TARGET_OPPONENTS_FIELD - && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget)) - { - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); - gBattlescriptCurrInstr = BattleScript_MoveUsedPsychicTerrainPrevents; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; - } - return MOVE_STEP_SUCCESS; -} - -static enum MoveCanceler CancelerExplodingDamp(void) +static enum MoveCanceler CancelerExplodingDamp(struct BattleContext *ctx) { u32 dampBattler = IsAbilityOnField(ABILITY_DAMP); - if (dampBattler && IsMoveDampBanned(gCurrentMove)) + if (dampBattler && IsMoveDampBanned(ctx->currentMove)) { gBattleScripting.battler = dampBattler - 1; gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - return MOVE_STEP_BREAK; + return MOVE_STEP_FAILURE; } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerMultihitMoves(void) +static enum MoveCanceler CancelerMultihitMoves(struct BattleContext *ctx) { - if (GetMoveEffect(gCurrentMove) == EFFECT_MULTI_HIT) + if (GetMoveEffect(ctx->currentMove) == EFFECT_MULTI_HIT) { - u32 ability = GetBattlerAbility(gBattlerAttacker); + enum Ability ability = ctx->abilities[ctx->battlerAtk]; if (ability == ABILITY_SKILL_LINK) { gMultiHitCounter = 5; } else if (ability == ABILITY_BATTLE_BOND - && gCurrentMove == MOVE_WATER_SHURIKEN - && gBattleMons[gBattlerAttacker].species == SPECIES_GRENINJA_ASH) + && ctx->currentMove == MOVE_WATER_SHURIKEN + && gBattleMons[ctx->battlerAtk].species == SPECIES_GRENINJA_ASH) { gMultiHitCounter = 3; } @@ -2487,28 +2884,28 @@ static enum MoveCanceler CancelerMultihitMoves(void) PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) } - else if (GetMoveStrikeCount(gCurrentMove) > 1) + else if (GetMoveStrikeCount(ctx->currentMove) > 1) { - if (GetMoveEffect(gCurrentMove) == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) + if (GetMoveEffect(ctx->currentMove) == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(ctx->battlerAtk) == HOLD_EFFECT_LOADED_DICE) { gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 10); } else { - gMultiHitCounter = GetMoveStrikeCount(gCurrentMove); + gMultiHitCounter = GetMoveStrikeCount(ctx->currentMove); - if (GetMoveEffect(gCurrentMove) == EFFECT_DRAGON_DARTS - && !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(gBattlerTarget), gCurrentMove) - && CanTargetPartner(gBattlerAttacker, gBattlerTarget) - && TargetFullyImmuneToCurrMove(gBattlerAttacker, gBattlerTarget)) - gBattlerTarget = BATTLE_PARTNER(gBattlerTarget); + if (GetMoveEffect(ctx->currentMove) == EFFECT_DRAGON_DARTS + && !IsAffectedByFollowMe(ctx->battlerAtk, GetBattlerSide(ctx->battlerDef), ctx->currentMove) + && CanTargetPartner(ctx->battlerAtk, ctx->battlerDef) + && TargetFullyImmuneToCurrMove(ctx->battlerAtk, ctx->battlerDef)) + gBattlerTarget = BATTLE_PARTNER(ctx->battlerDef); } PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0) } - else if (GetMoveEffect(gCurrentMove) == EFFECT_BEAT_UP) + else if (GetMoveEffect(ctx->currentMove) == EFFECT_BEAT_UP) { - struct Pokemon* party = GetBattlerParty(gBattlerAttacker); + struct Pokemon* party = GetBattlerParty(ctx->battlerAtk); int i; gBattleStruct->beatUpSlot = 0; gMultiHitCounter = 0; @@ -2540,42 +2937,10 @@ static enum MoveCanceler CancelerMultihitMoves(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceler CancelerZMoves(void) +static enum MoveCanceler CancelerMultiTargetMoves(struct BattleContext *ctx) { - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) - { - // For Z-Mirror Move, so it doesn't play the animation twice. - bool32 alreadyUsed = HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE); - - // attacker has a queued z move - RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_Z_CRYSTAL); - SetGimmickAsActivated(gBattlerAttacker, GIMMICK_Z_MOVE); - - gBattleScripting.battler = gBattlerAttacker; - if (gProtectStructs[gBattlerAttacker].powderSelfDmg) - { - if (!alreadyUsed) - BattleScriptCall(BattleScript_ZMoveActivatePowder); - } - else if (GetMoveCategory(gCurrentMove) == DAMAGE_CATEGORY_STATUS) - { - if (!alreadyUsed) - BattleScriptCall(BattleScript_ZMoveActivateStatus); - } - else - { - if (!alreadyUsed) - BattleScriptCall(BattleScript_ZMoveActivateDamaging); - } - return MOVE_STEP_BREAK; // The original move is cancelled, not the z move - } - return MOVE_STEP_SUCCESS; -} - -static enum MoveCanceler CancelerMultiTargetMoves(void) -{ - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); + u32 moveTarget = GetBattlerMoveTargetType(ctx->battlerAtk, ctx->currentMove); + enum Ability abilityAtk = ctx->abilities[ctx->battlerAtk]; if (IsSpreadMove(moveTarget)) { @@ -2584,88 +2949,97 @@ static enum MoveCanceler CancelerMultiTargetMoves(void) if (gBattleStruct->bouncedMoveIsUsed && !IsOnPlayerSide(battlerDef)) continue; - u32 abilityDef = GetBattlerAbility(battlerDef); + enum Ability abilityDef = GetBattlerAbility(battlerDef); - if (gBattlerAttacker == battlerDef + if (ctx->battlerAtk == battlerDef || !IsBattlerAlive(battlerDef) - || (GetMoveEffect(gCurrentMove) == EFFECT_SYNCHRONOISE && !DoBattlersShareType(gBattlerAttacker, battlerDef)) - || (moveTarget == MOVE_TARGET_BOTH && gBattlerAttacker == BATTLE_PARTNER(battlerDef)) - || IsBattlerProtected(gBattlerAttacker, battlerDef, gCurrentMove)) // Missing Invulnerable check + || (GetMoveEffect(ctx->currentMove) == EFFECT_SYNCHRONOISE && !DoBattlersShareType(ctx->battlerAtk, battlerDef)) + || (moveTarget == MOVE_TARGET_BOTH && ctx->battlerAtk == BATTLE_PARTNER(battlerDef)) + || IsBattlerProtected(ctx->battlerAtk, battlerDef, ctx->currentMove)) // Missing Invulnerable check { gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_NO_EFFECT; gBattleStruct->noResultString[battlerDef] = WILL_FAIL; } - else if (CanAbilityBlockMove(gBattlerAttacker, battlerDef, abilityAtk, abilityDef, gCurrentMove, CHECK_TRIGGER) - || (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN) && GetBattleMovePriority(gBattlerAttacker, abilityAtk, gCurrentMove) > 0)) + else if (CanAbilityBlockMove(ctx->battlerAtk, battlerDef, abilityAtk, abilityDef, ctx->currentMove, CHECK_TRIGGER)) { gBattleStruct->moveResultFlags[battlerDef] = 0; gBattleStruct->noResultString[battlerDef] = WILL_FAIL; } - else if (CanAbilityAbsorbMove(gBattlerAttacker, battlerDef, abilityDef, gCurrentMove, GetBattleMoveType(gCurrentMove), CHECK_TRIGGER)) + else if (CanAbilityAbsorbMove(ctx->battlerAtk, battlerDef, abilityDef, ctx->currentMove, GetBattleMoveType(gCurrentMove), CHECK_TRIGGER)) { gBattleStruct->moveResultFlags[battlerDef] = 0; gBattleStruct->noResultString[battlerDef] = CHECK_ACCURACY; } else { - CalcTypeEffectivenessMultiplierHelper(gCurrentMove, GetBattleMoveType(gCurrentMove), gBattlerAttacker, battlerDef, abilityAtk, abilityDef, TRUE); // Sets moveResultFlags + CalcTypeEffectivenessMultiplierHelper(ctx->currentMove, GetBattleMoveType(ctx->currentMove), ctx->battlerAtk, battlerDef, abilityAtk, abilityDef, TRUE); // Sets moveResultFlags gBattleStruct->noResultString[battlerDef] = CAN_DAMAGE; } } if (moveTarget == MOVE_TARGET_BOTH) - gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER_SIDE, gBattlerAttacker); + gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER_SIDE, ctx->battlerAtk); else - gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER, gBattlerAttacker); + gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER, ctx->battlerAtk); } return MOVE_STEP_SUCCESS; } -static enum MoveCanceler (*const sMoveSuccessOrderCancelers[])(void) = +static enum MoveCanceler (*const sMoveSuccessOrderCancelers[])(struct BattleContext *ctx) = { - [CANCELER_FLAGS] = CancelerFlags, + [CANCELER_CLEAR_FLAGS] = CancelerClearFlags, [CANCELER_STANCE_CHANGE_1] = CancelerStanceChangeOne, [CANCELER_SKY_DROP] = CancelerSkyDrop, [CANCELER_RECHARGE] = CancelerRecharge, [CANCELER_ASLEEP_OR_FROZEN] = CancelerAsleepOrFrozen, [CANCELER_OBEDIENCE] = CancelerObedience, + [CANCELER_POWER_POINTS] = CancelerPowerPoints, [CANCELER_TRUANT] = CancelerTruant, [CANCELER_FLINCH] = CancelerFlinch, - [CANCELER_INFATUATION] = CancelerInfatuation, [CANCELER_DISABLED] = CancelerDisabled, [CANCELER_VOLATILE_BLOCKED] = CancelerVolatileBlocked, [CANCELER_TAUNTED] = CancelerTaunted, [CANCELER_IMPRISONED] = CancelerImprisoned, [CANCELER_CONFUSED] = CancelerConfused, [CANCELER_PARALYZED] = CancelerParalyzed, + [CANCELER_INFATUATION] = CancelerInfatuation, [CANCELER_BIDE] = CancelerBide, + [CANCELER_Z_MOVES] = CancelerZMoves, + [CANCELER_CHOICE_LOCK] = CancelerChoiceLock, + [CANCELER_CALLSUBMOVE] = CancelerCallSubmove, [CANCELER_THAW] = CancelerThaw, [CANCELER_STANCE_CHANGE_2] = CancelerStanceChangeTwo, - [CANCELER_CHOICE_LOCK] = CancelerChoiceLock, + [CANCELER_ATTACKSTRING] = CancelerAttackstring, + [CANCELER_PPDEDUCTION] = CancelerPPDeduction, [CANCELER_WEATHER_PRIMAL] = CancelerWeatherPrimal, - [CANCELER_DYNAMAX_BLOCKED] = CancelerDynamaxBlocked, + [CANCELER_MOVE_FAILURE] = CancelerMoveFailure, [CANCELER_POWDER_STATUS] = CancelerPowderStatus, + [CANCELER_PRIORITY_BLOCK] = CancelerPriorityBlock, [CANCELER_PROTEAN] = CancelerProtean, - [CANCELER_PSYCHIC_TERRAIN] = CancelerPsychicTerrain, [CANCELER_EXPLODING_DAMP] = CancelerExplodingDamp, [CANCELER_MULTIHIT_MOVES] = CancelerMultihitMoves, - [CANCELER_Z_MOVES] = CancelerZMoves, [CANCELER_MULTI_TARGET_MOVES] = CancelerMultiTargetMoves, }; -enum MoveCanceler AtkCanceler_MoveSuccessOrder(void) +enum MoveCanceler AtkCanceler_MoveSuccessOrder(struct BattleContext *ctx) { enum MoveCanceler effect = MOVE_STEP_SUCCESS; - while (gBattleStruct->atkCancelerTracker < CANCELER_END && effect == MOVE_STEP_SUCCESS) + while (gBattleStruct->eventState.atkCanceler < CANCELER_END && effect == MOVE_STEP_SUCCESS) { - effect = sMoveSuccessOrderCancelers[gBattleStruct->atkCancelerTracker](); - gBattleStruct->atkCancelerTracker++; + effect = sMoveSuccessOrderCancelers[gBattleStruct->eventState.atkCanceler](ctx); + gBattleStruct->eventState.atkCanceler++; } if (effect == MOVE_STEP_REMOVES_STATUS) { - BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerAttacker].status1); - MarkBattlerForControllerExec(gBattlerAttacker); + BtlController_EmitSetMonData( + ctx->battlerAtk, + B_COMM_TO_CONTROLLER, + REQUEST_STATUS_BATTLE, + 0, + 4, + &gBattleMons[gBattlerAttacker].status1); + MarkBattlerForControllerExec(ctx->battlerAtk); } return effect; @@ -2858,7 +3232,7 @@ bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability) gBattleWeather = sBattleWeatherInfo[battleWeatherId].flag; if (gBattleWeather & B_WEATHER_PRIMAL_ANY) gWishFutureKnock.weatherDuration = 0; - else if (rock != 0 && GetBattlerHoldEffect(battler, TRUE) == rock) + else if (rock != 0 && GetBattlerHoldEffect(battler) == rock) gWishFutureKnock.weatherDuration = 8; else gWishFutureKnock.weatherDuration = 5; @@ -2887,10 +3261,10 @@ bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag) gDisableStructs[i].terrainAbilityDone = FALSE; ResetParadoxTerrainStat(i); } - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_TERRAIN_EXTENDER) - gFieldTimers.terrainTimer = gBattleTurnCounter + 8; + if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_TERRAIN_EXTENDER) + gFieldTimers.terrainTimer = 8; else - gFieldTimers.terrainTimer = gBattleTurnCounter + 5; + gFieldTimers.terrainTimer = 5; gBattleScripting.battler = battler; return TRUE; } @@ -2962,7 +3336,7 @@ static void ForewarnChooseMove(u32 battler) bool32 ChangeTypeBasedOnTerrain(u32 battler) { - u32 battlerType; + enum Type battlerType; if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) battlerType = TYPE_ELECTRIC; @@ -2980,7 +3354,7 @@ bool32 ChangeTypeBasedOnTerrain(u32 battler) return TRUE; } -static inline u8 GetSideFaintCounter(u32 side) +static inline u8 GetSideFaintCounter(enum BattleSide side) { return (side == B_SIDE_PLAYER) ? gBattleResults.playerFaintCounter : gBattleResults.opponentFaintCounter; } @@ -2998,10 +3372,9 @@ static inline uq4_12_t GetSupremeOverlordModifier(u32 battler) bool32 HadMoreThanHalfHpNowDoesnt(u32 battler) { - u32 cutoff = gBattleMons[battler].maxHP / 2; // Had more than half of hp before, now has less - return gBattleStruct->hpBefore[battler] > cutoff - && gBattleMons[battler].hp <= cutoff; + return gBattleStruct->battlerState[battler].wasAboveHalfHp + && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 2; } #define ANIM_STAT_HP 0 @@ -3012,7 +3385,7 @@ bool32 HadMoreThanHalfHpNowDoesnt(u32 battler) #define ANIM_STAT_SPEED 5 #define ANIM_STAT_ACC 6 #define ANIM_STAT_EVASION 7 -static void ChooseStatBoostAnimation(u32 battler) +void ChooseStatBoostAnimation(u32 battler) { u32 stat; bool32 statBuffMoreThan1 = FALSE; @@ -3052,44 +3425,19 @@ static void ChooseStatBoostAnimation(u32 battler) #undef ANIM_STAT_ACC #undef ANIM_STAT_EVASION -bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option) +bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option) { const u8 *battleScriptBlocksMove = NULL; - u32 battlerAbility = battlerDef; - s32 atkPriority = 0; - - if (option == AI_CHECK) - atkPriority = GetBattleMovePriority(battlerAtk, abilityAtk, move); - else - atkPriority = GetChosenMovePriority(battlerAtk, abilityAtk); switch (abilityDef) { case ABILITY_SOUNDPROOF: if (IsSoundMove(move) && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER)) - { - if (gBattleMons[battlerAtk].volatiles.multipleTurns) - gHitMarker |= HITMARKER_NO_PPDEDUCT; battleScriptBlocksMove = BattleScript_SoundproofProtected; - } break; case ABILITY_BULLETPROOF: if (IsBallisticMove(move)) - { - if (gBattleMons[battlerAtk].volatiles.multipleTurns) - gHitMarker |= HITMARKER_NO_PPDEDUCT; battleScriptBlocksMove = BattleScript_SoundproofProtected; - } - break; - case ABILITY_DAZZLING: - case ABILITY_QUEENLY_MAJESTY: - case ABILITY_ARMOR_TAIL: - if (atkPriority > 0 && !IsBattlerAlly(battlerAtk, battlerDef)) - { - if (gBattleMons[battlerAtk].volatiles.multipleTurns) - gHitMarker |= HITMARKER_NO_PPDEDUCT; - battleScriptBlocksMove = BattleScript_DazzlingProtected; - } break; case ABILITY_GOOD_AS_GOLD: if (IsBattleMoveStatus(move)) @@ -3098,44 +3446,43 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a battleScriptBlocksMove = BattleScript_GoodAsGoldActivates; } break; + default: + break; } - if (atkPriority > 0) + if (battleScriptBlocksMove == NULL) { - // Prankster check - if (battleScriptBlocksMove == NULL - && IsBattleMoveStatus(move) - && BlocksPrankster(move, battlerAtk, battlerDef, TRUE) - && !(IsBattleMoveStatus(move) && (abilityDef == ABILITY_MAGIC_BOUNCE || gProtectStructs[battlerDef].bounceMove))) + s32 atkPriority = 0; + if (option == AI_CHECK) + atkPriority = GetBattleMovePriority(battlerAtk, abilityAtk, move); + else + atkPriority = GetChosenMovePriority(battlerAtk, abilityAtk); + + if (atkPriority <= 0) + { + // Not a priority move + } + else if (IsBattleMoveStatus(move) + && BlocksPrankster(move, battlerAtk, battlerDef, TRUE) + && !(IsBattleMoveStatus(move) && (abilityDef == ABILITY_MAGIC_BOUNCE || gProtectStructs[battlerDef].bounceMove))) { if (option == RUN_SCRIPT && !IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, move))) CancelMultiTurnMoves(battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); // Don't cancel moves that can hit two targets bc one target might not be protected - battleScriptBlocksMove = BattleScript_DoesntAffectTargetAtkString; } - - // Check def partner ability - u32 partnerDef = BATTLE_PARTNER(battlerDef); - if (battleScriptBlocksMove == NULL - && IsDoubleBattle() - && IsBattlerAlive(partnerDef) - && !IsBattlerAlly(battlerAtk, partnerDef)) + else if (IsBattlerTerrainAffected(battlerDef, abilityDef, GetBattlerHoldEffect(battlerDef), STATUS_FIELD_PSYCHIC_TERRAIN) // Not an ability but similar conditions + && !IsBattlerAlly(battlerAtk, battlerDef) + && GetMoveTarget(move) != MOVE_TARGET_ALL_BATTLERS + && GetMoveTarget(move) != MOVE_TARGET_OPPONENTS_FIELD) { - if (option == AI_CHECK) - abilityDef = gAiLogicData->abilities[partnerDef]; - else - abilityDef = GetBattlerAbility(partnerDef); - - switch (abilityDef) + battleScriptBlocksMove = BattleScript_MoveUsedPsychicTerrainPrevents; + if (option == RUN_SCRIPT) { - case ABILITY_DAZZLING: - case ABILITY_QUEENLY_MAJESTY: - case ABILITY_ARMOR_TAIL: - if (gBattleMons[battlerAtk].volatiles.multipleTurns) - gHitMarker |= HITMARKER_NO_PPDEDUCT; - battlerAbility = partnerDef; - battleScriptBlocksMove = BattleScript_DazzlingProtected; - break; + gMultiHitCounter = 0; // Prevent multi-hit moves from hitting more than once after move has been absorbed. + if (!IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, move))) + CancelMultiTurnMoves(battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); // Don't cancel moves that can hit two targets bc one target might not be protected + gBattlescriptCurrInstr = BattleScript_MoveUsedPsychicTerrainPrevents; + return TRUE; // Early return since we don't want to set remaining values } } } @@ -3145,21 +3492,21 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a if (option == RUN_SCRIPT) { - gMultiHitCounter = 0; // Prevent multi-hit moves from hitting more than once after move has been absorbed. + gMultiHitCounter = 0; // Prevent multi-hit moves from hitting more than once after move has been absorbed. gLastUsedAbility = abilityDef; RecordAbilityBattle(battlerDef, abilityDef); - gBattleScripting.battler = gBattlerAbility = battlerAbility; + gBattleScripting.battler = gBattlerAbility = battlerDef; gBattlescriptCurrInstr = battleScriptBlocksMove; } return TRUE; } -bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType, enum FunctionCallOption option) +bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, u32 move, enum Type moveType, enum FunctionCallOption option) { enum MoveAbsorbed effect = MOVE_ABSORBED_BY_NO_ABILITY; const u8 *battleScript = NULL; - u32 statId = 0; + enum Stat statId = 0; u32 statAmount = 1; switch (abilityDef) @@ -3240,40 +3587,23 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 gBattleStruct->pledgeMove = FALSE; if (IsBattlerAtMaxHp(battlerDef) || (B_HEAL_BLOCKING >= GEN_5 && gBattleMons[battlerDef].volatiles.healBlock)) { - if ((gProtectStructs[battlerAtk].notFirstStrike)) - battleScript = BattleScript_MonMadeMoveUseless; - else - battleScript = BattleScript_MonMadeMoveUseless_PPLoss; + battleScript = BattleScript_MonMadeMoveUseless; } else { - if (gProtectStructs[battlerAtk].notFirstStrike) - battleScript = BattleScript_MoveHPDrain; - else - battleScript = BattleScript_MoveHPDrain_PPLoss; - - gBattleStruct->moveDamage[battlerDef] = GetNonDynamaxMaxHP(battlerDef) / 4; - if (gBattleStruct->moveDamage[battlerDef] == 0) - gBattleStruct->moveDamage[battlerDef] = 1; - gBattleStruct->moveDamage[battlerDef] *= -1; + battleScript = BattleScript_MoveHPDrain; + SetHealAmount(battlerDef, GetNonDynamaxMaxHP(battlerDef) / 4); } break; case MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY: gBattleStruct->pledgeMove = FALSE; if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, abilityDef)) { - if ((gProtectStructs[battlerAtk].notFirstStrike)) - battleScript = BattleScript_MonMadeMoveUseless; - else - battleScript = BattleScript_MonMadeMoveUseless_PPLoss; + battleScript = BattleScript_MonMadeMoveUseless; } else { - if (gProtectStructs[battlerAtk].notFirstStrike) - battleScript = BattleScript_MoveStatDrain; - else - battleScript = BattleScript_MoveStatDrain_PPLoss; - + battleScript = BattleScript_MoveStatDrain; SET_STATCHANGER(statId, statAmount, FALSE); if (B_ABSORBING_ABILITY_STRING < GEN_5) PREPARE_STAT_BUFFER(gBattleTextBuff1, statId); @@ -3284,19 +3614,13 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 if (!gDisableStructs[battlerDef].flashFireBoosted) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FLASH_FIRE_BOOST; - if (gProtectStructs[battlerAtk].notFirstStrike) - battleScript = BattleScript_FlashFireBoost; - else - battleScript = BattleScript_FlashFireBoost_PPLoss; + battleScript = BattleScript_FlashFireBoost; gDisableStructs[battlerDef].flashFireBoosted = TRUE; } else { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FLASH_FIRE_NO_BOOST; - if (gProtectStructs[battlerAtk].notFirstStrike) - battleScript = BattleScript_FlashFireBoost; - else - battleScript = BattleScript_FlashFireBoost_PPLoss; + battleScript = BattleScript_FlashFireBoost; } break; } @@ -3313,7 +3637,7 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 return effect; } -static inline u32 SetStartingFieldStatus(u32 flag, u32 message, u32 anim, u16 *timer) +static inline bool32 SetStartingFieldStatus(u32 flag, u32 message, u32 anim, u16 *timer) { if (!(gFieldStatuses & flag)) { @@ -3321,17 +3645,17 @@ static inline u32 SetStartingFieldStatus(u32 flag, u32 message, u32 anim, u16 *t gFieldStatuses |= flag; gBattleScripting.animArg1 = anim; if (gBattleStruct->startingStatusTimer) - *timer = gBattleTurnCounter + gBattleStruct->startingStatusTimer; + *timer = gBattleStruct->startingStatusTimer; else *timer = 0; // Infinite - return 1; + return TRUE; } - return 0; + return FALSE; } -static inline u32 SetStartingSideStatus(u32 flag, u32 side, u32 message, u32 anim, u16 *timer) +static inline bool32 SetStartingSideStatus(u32 flag, u32 side, u32 message, u32 anim, u16 *timer) { if (!(gSideStatuses[side] & flag)) { @@ -3340,20 +3664,254 @@ static inline u32 SetStartingSideStatus(u32 flag, u32 side, u32 message, u32 ani gSideStatuses[side] |= flag; gBattleScripting.animArg1 = anim; if (gBattleStruct->startingStatusTimer) - *timer = gBattleTurnCounter + gBattleStruct->startingStatusTimer; + *timer = gBattleStruct->startingStatusTimer; else *timer = 0; // Infinite - return 1; + return TRUE; } - return 0; + return FALSE; } -u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg) +bool32 TryFieldEffects(enum FieldEffectCases caseId) +{ + bool32 effect = FALSE; + bool32 isTerrain = FALSE; + + if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) + return FALSE; + + switch (caseId) + { + case FIELD_EFFECT_TRAINER_STATUSES: // starting field/side/etc statuses with a variable + switch ((enum StartingStatus) gBattleStruct->startingStatus) + { + case STARTING_STATUS_NONE: + break; + case STARTING_STATUS_ELECTRIC_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_ELECTRIC_TERRAIN, + B_MSG_TERRAIN_SET_ELECTRIC, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_MISTY_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_MISTY_TERRAIN, + B_MSG_TERRAIN_SET_MISTY, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_GRASSY_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_GRASSY_TERRAIN, + B_MSG_TERRAIN_SET_GRASSY, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_PSYCHIC_TERRAIN: + effect = SetStartingFieldStatus( + STATUS_FIELD_PSYCHIC_TERRAIN, + B_MSG_TERRAIN_SET_PSYCHIC, + 0, + &gFieldTimers.terrainTimer); + isTerrain = TRUE; + break; + case STARTING_STATUS_TRICK_ROOM: + effect = SetStartingFieldStatus( + STATUS_FIELD_TRICK_ROOM, + B_MSG_SET_TRICK_ROOM, + B_ANIM_TRICK_ROOM, + &gFieldTimers.trickRoomTimer); + break; + case STARTING_STATUS_MAGIC_ROOM: + effect = SetStartingFieldStatus( + STATUS_FIELD_MAGIC_ROOM, + B_MSG_SET_MAGIC_ROOM, + B_ANIM_MAGIC_ROOM, + &gFieldTimers.magicRoomTimer); + break; + case STARTING_STATUS_WONDER_ROOM: + effect = SetStartingFieldStatus( + STATUS_FIELD_WONDER_ROOM, + B_MSG_SET_WONDER_ROOM, + B_ANIM_WONDER_ROOM, + &gFieldTimers.wonderRoomTimer); + break; + case STARTING_STATUS_TAILWIND_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_TAILWIND, + B_SIDE_PLAYER, + B_MSG_SET_TAILWIND, + B_ANIM_TAILWIND, + &gSideTimers[B_SIDE_PLAYER].tailwindTimer); + break; + case STARTING_STATUS_TAILWIND_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_TAILWIND, + B_SIDE_OPPONENT, + B_MSG_SET_TAILWIND, + B_ANIM_TAILWIND, + &gSideTimers[B_SIDE_OPPONENT].tailwindTimer); + break; + case STARTING_STATUS_RAINBOW_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_RAINBOW, + B_SIDE_PLAYER, + B_MSG_SET_RAINBOW, + B_ANIM_RAINBOW, + &gSideTimers[B_SIDE_PLAYER].rainbowTimer); + break; + case STARTING_STATUS_RAINBOW_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_RAINBOW, + B_SIDE_OPPONENT, + B_MSG_SET_RAINBOW, + B_ANIM_RAINBOW, + &gSideTimers[B_SIDE_OPPONENT].rainbowTimer); + break; + case STARTING_STATUS_SEA_OF_FIRE_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_SEA_OF_FIRE, + B_SIDE_PLAYER, + B_MSG_SET_SEA_OF_FIRE, + B_ANIM_SEA_OF_FIRE, + &gSideTimers[B_SIDE_PLAYER].seaOfFireTimer); + break; + case STARTING_STATUS_SEA_OF_FIRE_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_SEA_OF_FIRE, + B_SIDE_OPPONENT, + B_MSG_SET_SEA_OF_FIRE, + B_ANIM_SEA_OF_FIRE, + &gSideTimers[B_SIDE_OPPONENT].seaOfFireTimer); + break; + case STARTING_STATUS_SWAMP_PLAYER: + effect = SetStartingSideStatus( + SIDE_STATUS_SWAMP, + B_SIDE_PLAYER, + B_MSG_SET_SWAMP, + B_ANIM_SWAMP, + &gSideTimers[B_SIDE_PLAYER].swampTimer); + break; + case STARTING_STATUS_SWAMP_OPPONENT: + effect = SetStartingSideStatus( + SIDE_STATUS_SWAMP, + B_SIDE_OPPONENT, + B_MSG_SET_SWAMP, + B_ANIM_SWAMP, + &gSideTimers[B_SIDE_OPPONENT].swampTimer); + break; + } + if (effect) + { + if (isTerrain) + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + else + BattleScriptPushCursorAndCallback(BattleScript_OverworldStatusStarts); + } + break; + case FIELD_EFFECT_OVERWORLD_TERRAIN: // terrain starting from overworld weather + if (B_THUNDERSTORM_TERRAIN == TRUE + && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + && GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM) + { + // overworld weather started rain, so just do electric terrain anim + gFieldStatuses = STATUS_FIELD_ELECTRIC_TERRAIN; + gFieldTimers.terrainTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + effect = TRUE; + } + else if (B_OVERWORLD_FOG >= GEN_8 + && (GetCurrentWeather() == WEATHER_FOG_HORIZONTAL || GetCurrentWeather() == WEATHER_FOG_DIAGONAL) + && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + { + gFieldStatuses = STATUS_FIELD_MISTY_TERRAIN; + gFieldTimers.terrainTimer = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + effect = TRUE; + } + break; + case FIELD_EFFECT_OVERWORLD_WEATHER: + if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) + { + switch (GetCurrentWeather()) + { + case WEATHER_RAIN: + case WEATHER_RAIN_THUNDERSTORM: + case WEATHER_DOWNPOUR: + if (!(gBattleWeather & B_WEATHER_RAIN)) + { + gBattleWeather = B_WEATHER_RAIN_NORMAL; + gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; + effect = TRUE; + } + break; + case WEATHER_SANDSTORM: + if (!(gBattleWeather & B_WEATHER_SANDSTORM)) + { + gBattleWeather = B_WEATHER_SANDSTORM; + gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; + effect = TRUE; + } + break; + case WEATHER_DROUGHT: + if (!(gBattleWeather & B_WEATHER_SUN)) + { + gBattleWeather = B_WEATHER_SUN_NORMAL; + gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; + effect = TRUE; + } + break; + case WEATHER_SNOW: + if (!(gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) + { + if (B_OVERWORLD_SNOW >= GEN_9) + { + gBattleWeather = B_WEATHER_SNOW; + gBattleScripting.animArg1 = B_ANIM_SNOW_CONTINUES; + } + else + { + gBattleWeather = B_WEATHER_HAIL; + gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; + } + effect = TRUE; + } + break; + case WEATHER_FOG_DIAGONAL: + case WEATHER_FOG_HORIZONTAL: + if (B_OVERWORLD_FOG == GEN_4 && !(gBattleWeather & B_WEATHER_FOG)) + { + gBattleWeather = B_WEATHER_FOG; + gBattleScripting.animArg1 = B_ANIM_FOG_CONTINUES; + effect = TRUE; + } + break; + } + } + if (effect) + { + gBattleCommunication[MULTISTRING_CHOOSER] = GetCurrentWeather(); + BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts); + } + break; + } + + return effect; +} + +u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ability, u32 special, u32 moveArg) { u32 effect = 0; - u32 moveType = 0, move = 0; + enum Type moveType = 0; + u32 move = 0; u32 side = 0; u32 i = 0, j = 0; u32 partner = 0; @@ -3380,212 +3938,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 switch (caseID) { - case ABILITYEFFECT_SWITCH_IN_STATUSES: // starting field/side/etc statuses with a variable - { - gBattleScripting.battler = battler; - switch (gBattleStruct->startingStatus) - { - case STARTING_STATUS_ELECTRIC_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_ELECTRIC_TERRAIN, - B_MSG_TERRAIN_SET_ELECTRIC, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_MISTY_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_MISTY_TERRAIN, - B_MSG_TERRAIN_SET_MISTY, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_GRASSY_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_GRASSY_TERRAIN, - B_MSG_TERRAIN_SET_GRASSY, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_PSYCHIC_TERRAIN: - effect = SetStartingFieldStatus(STATUS_FIELD_PSYCHIC_TERRAIN, - B_MSG_TERRAIN_SET_PSYCHIC, - 0, - &gFieldTimers.terrainTimer); - effect = (effect == 1) ? 2 : 0; - break; - case STARTING_STATUS_TRICK_ROOM: - effect = SetStartingFieldStatus(STATUS_FIELD_TRICK_ROOM, - B_MSG_SET_TRICK_ROOM, - B_ANIM_TRICK_ROOM, - &gFieldTimers.trickRoomTimer); - break; - case STARTING_STATUS_MAGIC_ROOM: - effect = SetStartingFieldStatus(STATUS_FIELD_MAGIC_ROOM, - B_MSG_SET_MAGIC_ROOM, - B_ANIM_MAGIC_ROOM, - &gFieldTimers.magicRoomTimer); - break; - case STARTING_STATUS_WONDER_ROOM: - effect = SetStartingFieldStatus(STATUS_FIELD_WONDER_ROOM, - B_MSG_SET_WONDER_ROOM, - B_ANIM_WONDER_ROOM, - &gFieldTimers.wonderRoomTimer); - break; - case STARTING_STATUS_TAILWIND_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_TAILWIND, - B_SIDE_PLAYER, - B_MSG_SET_TAILWIND, - B_ANIM_TAILWIND, - &gSideTimers[B_SIDE_PLAYER].tailwindTimer); - break; - case STARTING_STATUS_TAILWIND_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_TAILWIND, - B_SIDE_OPPONENT, - B_MSG_SET_TAILWIND, - B_ANIM_TAILWIND, - &gSideTimers[B_SIDE_OPPONENT].tailwindTimer); - break; - case STARTING_STATUS_RAINBOW_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_RAINBOW, - B_SIDE_PLAYER, - B_MSG_SET_RAINBOW, - B_ANIM_RAINBOW, - &gSideTimers[B_SIDE_PLAYER].rainbowTimer); - break; - case STARTING_STATUS_RAINBOW_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_RAINBOW, - B_SIDE_OPPONENT, - B_MSG_SET_RAINBOW, - B_ANIM_RAINBOW, - &gSideTimers[B_SIDE_OPPONENT].rainbowTimer); - break; - case STARTING_STATUS_SEA_OF_FIRE_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_SEA_OF_FIRE, - B_SIDE_PLAYER, - B_MSG_SET_SEA_OF_FIRE, - B_ANIM_SEA_OF_FIRE, - &gSideTimers[B_SIDE_PLAYER].seaOfFireTimer); - break; - case STARTING_STATUS_SEA_OF_FIRE_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_SEA_OF_FIRE, - B_SIDE_OPPONENT, - B_MSG_SET_SEA_OF_FIRE, - B_ANIM_SEA_OF_FIRE, - &gSideTimers[B_SIDE_OPPONENT].seaOfFireTimer); - break; - case STARTING_STATUS_SWAMP_PLAYER: - effect = SetStartingSideStatus(SIDE_STATUS_SWAMP, - B_SIDE_PLAYER, - B_MSG_SET_SWAMP, - B_ANIM_SWAMP, - &gSideTimers[B_SIDE_PLAYER].swampTimer); - break; - case STARTING_STATUS_SWAMP_OPPONENT: - effect = SetStartingSideStatus(SIDE_STATUS_SWAMP, - B_SIDE_OPPONENT, - B_MSG_SET_SWAMP, - B_ANIM_SWAMP, - &gSideTimers[B_SIDE_OPPONENT].swampTimer); - break; - } - - if (effect == 1) - BattleScriptPushCursorAndCallback(BattleScript_OverworldStatusStarts); - else if (effect == 2) - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - } - break; - case ABILITYEFFECT_SWITCH_IN_TERRAIN: // terrain starting from overworld weather - if (B_THUNDERSTORM_TERRAIN == TRUE - && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) - && GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM) - { - // overworld weather started rain, so just do electric terrain anim - gFieldStatuses = STATUS_FIELD_ELECTRIC_TERRAIN; - gFieldTimers.terrainTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - effect++; - } - else if (B_OVERWORLD_FOG >= GEN_8 - && (GetCurrentWeather() == WEATHER_FOG_HORIZONTAL || GetCurrentWeather() == WEATHER_FOG_DIAGONAL) - && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) - { - gFieldStatuses = STATUS_FIELD_MISTY_TERRAIN; - gFieldTimers.terrainTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - effect++; - } - break; - case ABILITYEFFECT_SWITCH_IN_WEATHER: - gBattleScripting.battler = battler; - if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) - { - switch (GetCurrentWeather()) - { - case WEATHER_RAIN: - case WEATHER_RAIN_THUNDERSTORM: - case WEATHER_DOWNPOUR: - if (!(gBattleWeather & B_WEATHER_RAIN)) - { - gBattleWeather = B_WEATHER_RAIN_NORMAL; - gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; - effect++; - } - break; - case WEATHER_SANDSTORM: - if (!(gBattleWeather & B_WEATHER_SANDSTORM)) - { - gBattleWeather = B_WEATHER_SANDSTORM; - gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; - effect++; - } - break; - case WEATHER_DROUGHT: - if (!(gBattleWeather & B_WEATHER_SUN)) - { - gBattleWeather = B_WEATHER_SUN_NORMAL; - gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; - effect++; - } - break; - case WEATHER_SNOW: - if (!(gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) - { - if (B_OVERWORLD_SNOW >= GEN_9) - { - gBattleWeather = B_WEATHER_SNOW; - gBattleScripting.animArg1 = B_ANIM_SNOW_CONTINUES; - } - else - { - gBattleWeather = B_WEATHER_HAIL; - gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; - } - effect++; - } - break; - case WEATHER_FOG_DIAGONAL: - case WEATHER_FOG_HORIZONTAL: - if (B_OVERWORLD_FOG == GEN_4) - { - if (!(gBattleWeather & B_WEATHER_FOG)) - { - gBattleWeather = B_WEATHER_FOG; - gBattleScripting.animArg1 = B_ANIM_FOG_CONTINUES; - effect++; - } - break; - } - } - } - if (effect != 0) - { - gBattleCommunication[MULTISTRING_CHOOSER] = GetCurrentWeather(); - BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts); - } - break; case ABILITYEFFECT_ON_SWITCHIN: gBattleScripting.battler = battler; switch (gLastUsedAbility) @@ -3598,7 +3950,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (gSpecialStatuses[battler].switchInAbilityDone) break; - if (GetBattlerHoldEffectIgnoreAbility(battler, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + if (GetBattlerHoldEffectIgnoreAbility(battler) == HOLD_EFFECT_ABILITY_SHIELD) break; side = (BATTLE_OPPOSITE(GetBattlerPosition(battler))) & BIT_SIDE; @@ -3685,7 +4037,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_SLOW_START: if (!gSpecialStatuses[battler].switchInAbilityDone) { - gDisableStructs[battler].slowStartTimer = gBattleTurnCounter + 5; + gDisableStructs[battler].slowStartTimer = 5; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_SLOWSTART; gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg); @@ -3754,7 +4106,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 ctx.battlerAtk = i; ctx.battlerDef = battler; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = moveType; ctx.isAnticipation = TRUE; modifier = CalcTypeEffectivenessMultiplier(&ctx); @@ -3799,7 +4151,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_DOWNLOAD: if (!gSpecialStatuses[battler].switchInAbilityDone) { - u32 statId, opposingBattler; + enum Stat statId; + u32 opposingBattler; u32 opposingDef = 0, opposingSpDef = 0; opposingBattler = BATTLE_OPPOSITE(battler); @@ -4094,6 +4447,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_VESSEL_OF_RUIN: if (!gSpecialStatuses[battler].switchInAbilityDone) { + gBattleMons[battler].volatiles.vesselOfRuin = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK); gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_RuinAbilityActivates); @@ -4103,6 +4457,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_SWORD_OF_RUIN: if (!gSpecialStatuses[battler].switchInAbilityDone) { + gBattleMons[battler].volatiles.swordOfRuin = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_DEF); gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_RuinAbilityActivates); @@ -4112,6 +4467,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_TABLETS_OF_RUIN: if (!gSpecialStatuses[battler].switchInAbilityDone) { + gBattleMons[battler].volatiles.tabletsOfRuin = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK); gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_RuinAbilityActivates); @@ -4121,6 +4477,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_BEADS_OF_RUIN: if (!gSpecialStatuses[battler].switchInAbilityDone) { + gBattleMons[battler].volatiles.beadsOfRuin = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPDEF); gSpecialStatuses[battler].switchInAbilityDone = TRUE; BattleScriptPushCursorAndCallback(BattleScript_RuinAbilityActivates); @@ -4175,7 +4532,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { gEffectBattler = partner; gSpecialStatuses[battler].switchInAbilityDone = TRUE; - gBattleStruct->moveDamage[partner] = (GetNonDynamaxMaxHP(partner) / 4) * -1; + SetHealAmount(partner, GetNonDynamaxMaxHP(partner) / 4); BattleScriptPushCursorAndCallback(BattleScript_HospitalityActivates); effect++; } @@ -4186,7 +4543,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK: if (!gSpecialStatuses[battler].switchInAbilityDone) { - u32 stat; + enum Stat stat; if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK) stat = STAT_ATK; @@ -4217,17 +4574,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; - case ABILITY_ICE_FACE: - if (IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW) - && gBattleMons[battler].species == SPECIES_EISCUE_NOICE - && !(gBattleMons[battler].volatiles.transformed)) - { - // TODO: Convert this to a proper FORM_CHANGE type. - gBattleMons[battler].species = SPECIES_EISCUE_ICE; - BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); - effect++; - } - break; case ABILITY_COMMANDER: partner = BATTLE_PARTNER(battler); if (!gSpecialStatuses[battler].switchInAbilityDone @@ -4251,6 +4597,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + default: + break; } break; case ABILITYEFFECT_ENDTURN: @@ -4265,8 +4613,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && PickupHasValidTarget(battler)) { gBattlerTarget = RandomUniformExcept(RNG_PICKUP, 0, gBattlersCount - 1, CantPickupItem); - gLastUsedItem = GetUsedHeldItem(gBattlerTarget); - BattleScriptPushCursorAndCallback(BattleScript_PickupActivates); + gLastUsedItem = GetBattlerPartyState(gBattlerTarget)->usedHeldItem; + BattleScriptExecute(BattleScript_PickupActivates); effect++; } break; @@ -4274,10 +4622,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if ((IsBattlerWeatherAffected(battler, B_WEATHER_SUN) || RandomPercentage(RNG_HARVEST, 50)) && gBattleMons[battler].item == ITEM_NONE && gBattleStruct->changedItems[battler] == ITEM_NONE // Will not inherit an item - && GetItemPocket(GetUsedHeldItem(battler)) == POCKET_BERRIES) + && GetItemPocket(GetBattlerPartyState(battler)->usedHeldItem) == POCKET_BERRIES) { - gLastUsedItem = GetUsedHeldItem(battler); - BattleScriptPushCursorAndCallback(BattleScript_HarvestActivates); + gLastUsedItem = GetBattlerPartyState(battler)->usedHeldItem; + BattleScriptExecute(BattleScript_HarvestActivates); effect++; } break; @@ -4288,11 +4636,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER && !gBattleMons[battler].volatiles.healBlock) { - BattleScriptPushCursorAndCallback(BattleScript_IceBodyHeal); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; + BattleScriptExecute(BattleScript_IceBodyHeal); + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / 16); effect++; } break; @@ -4305,11 +4650,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !IsBattlerAtMaxHp(battler) && !gBattleMons[battler].volatiles.healBlock) { - BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / (gLastUsedAbility == ABILITY_RAIN_DISH ? 16 : 8); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; + s32 healAmount = gLastUsedAbility == ABILITY_RAIN_DISH ? 16 : 8; + SetHealAmount(battler, GetNonDynamaxMaxHP(battler) / healAmount); + BattleScriptExecute(BattleScript_RainDishActivates); effect++; } break; @@ -4343,7 +4686,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 gBattleMons[battler].status1 = 0; gBattleMons[battler].volatiles.nightmare = FALSE; gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates); + BattleScriptExecute(BattleScript_ShedSkinActivates); BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); MarkBattlerForControllerExec(battler); effect++; @@ -4352,8 +4695,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_SPEED_BOOST: if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && gDisableStructs[battler].isFirstTurn != 2) { + SaveBattlerAttacker(gBattlerAttacker); SET_STATCHANGER(STAT_SPEED, 1, FALSE); - BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates); + BattleScriptExecute(BattleScript_AttackerAbilityStatRaiseEnd2); gBattleScripting.battler = battler; effect++; } @@ -4385,7 +4729,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 i = RandomUniformExcept(RNG_MOODY_DECREASE, STAT_ATK, statsNum - 1, MoodyCantLowerStat); SET_STATCHANGER2(gBattleScripting.savedStatChanger, i, 1, TRUE); } - BattleScriptPushCursorAndCallback(BattleScript_MoodyActivates); + BattleScriptExecute(BattleScript_MoodyActivates); effect++; } break; @@ -4393,24 +4737,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 gDisableStructs[gBattlerAttacker].truantCounter ^= 1; break; case ABILITY_SLOW_START: - if (gDisableStructs[battler].slowStartTimer == gBattleTurnCounter) + if (gDisableStructs[battler].slowStartTimer > 0 && --gDisableStructs[battler].slowStartTimer == 0) { BattleScriptExecute(BattleScript_SlowStartEnds); effect++; } break; case ABILITY_BAD_DREAMS: - BattleScriptPushCursorAndCallback(BattleScript_BadDreamsActivates); + BattleScriptExecute(BattleScript_BadDreamsActivates); effect++; break; case ABILITY_SOLAR_POWER: if (IsBattlerWeatherAffected(battler, B_WEATHER_SUN)) { SOLAR_POWER_HP_DROP: - BattleScriptPushCursorAndCallback(BattleScript_SolarPowerActivates); - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; + SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 8); + BattleScriptExecute(BattleScript_SolarPowerActivates); effect++; } break; @@ -4420,7 +4762,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && gBattleMons[gBattleScripting.battler].status1 & STATUS1_ANY && RandomPercentage(RNG_HEALER, 30)) { - BattleScriptPushCursorAndCallback(BattleScript_HealerActivates); + BattleScriptExecute(BattleScript_HealerActivates); effect++; } break; @@ -4433,7 +4775,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (TryBattleFormChange(battler, FORM_CHANGE_BATTLE_HP_PERCENT)) { gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeEnd3); + BattleScriptExecute(BattleScript_BattlerFormChangeEnd2); effect++; } break; @@ -4441,7 +4783,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (TryBattleFormChange(battler, FORM_CHANGE_BATTLE_HP_PERCENT)) { gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_PowerConstruct); + BattleScriptExecute(BattleScript_PowerConstruct); effect++; } break; @@ -4456,7 +4798,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); MarkBattlerForControllerExec(battler); gHasFetchedBall = TRUE; - BattleScriptPushCursorAndCallback(BattleScript_BallFetch); + BattleScriptExecute(BattleScript_BallFetch); effect++; } break; @@ -4466,7 +4808,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_TURN_END)) { gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeEnd3NoPopup); + BattleScriptExecute(BattleScript_BattlerFormChangeEnd3NoPopup); effect++; } break; @@ -4475,39 +4817,75 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { gBattleScripting.battler = battler; gDisableStructs[battler].cudChew = FALSE; - gLastUsedItem = gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]; - gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = ITEM_NONE; - BattleScriptPushCursorAndCallback(BattleScript_CudChewActivates); + gLastUsedItem = GetBattlerPartyState(battler)->usedHeldItem; + GetBattlerPartyState(battler)->usedHeldItem = ITEM_NONE; + BattleScriptExecute(BattleScript_CudChewActivates); effect++; } - else if (!gDisableStructs[battler].cudChew && GetItemPocket(GetUsedHeldItem(battler)) == POCKET_BERRIES) + else if (!gDisableStructs[battler].cudChew && GetItemPocket(GetBattlerPartyState(battler)->usedHeldItem) == POCKET_BERRIES) { gDisableStructs[battler].cudChew = TRUE; } break; + default: + break; } } break; + case ABILITYEFFECT_COLOR_CHANGE: + switch (gLastUsedAbility) + { + case ABILITY_COLOR_CHANGE: + if (IsBattlerTurnDamaged(battler) + && IsBattlerAlive(battler) + && !IS_BATTLER_OF_TYPE(battler, moveType) + && move != MOVE_STRUGGLE + && moveType != TYPE_STELLAR + && moveType != TYPE_MYSTERY) + { + gEffectBattler = gBattlerAbility = battler; + SET_BATTLER_TYPE(battler, moveType); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); + BattleScriptCall(BattleScript_ColorChangeActivates); + effect++; + } + break; + case ABILITY_BERSERK: + if (IsBattlerTurnDamaged(battler) + && IsBattlerAlive(battler) + && HadMoreThanHalfHpNowDoesnt(battler) + && CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) + { + gEffectBattler = gBattlerAbility = battler; + SET_STATCHANGER(STAT_SPATK, 1, FALSE); + BattleScriptCall(BattleScript_BerserkActivates); + effect++; + } + break; + case ABILITY_ANGER_SHELL: + if (IsBattlerTurnDamaged(battler) + && IsBattlerAlive(battler) + && HadMoreThanHalfHpNowDoesnt(battler)) + { + gEffectBattler = gBattlerAbility = battler; + BattleScriptCall(BattleScript_AngerShellActivates); + effect++; + } + break; + default: + break; + } + break; case ABILITYEFFECT_MOVE_END: // Think contact abilities. switch (gLastUsedAbility) { - case ABILITY_STICKY_HOLD: - if (gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff && IsBattlerAlive(gBattlerTarget)) - { - gBattleStruct->battlerState[gBattlerTarget].itemCanBeKnockedOff = FALSE; - gBattlerAbility = gBattlerTarget; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; - effect++; - } - break; case ABILITY_JUSTIFIED: if (IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) && moveType == TYPE_DARK && CompareStat(battler, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { - gEffectBattler = battler; + gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_ATK, 1, FALSE); BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet); effect++; @@ -4519,7 +4897,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST) && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { - gEffectBattler = battler; + gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_SPEED, 1, FALSE); BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet); effect++; @@ -4531,7 +4909,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && moveType == TYPE_WATER && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { - gEffectBattler = battler; + gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_DEF, 2, FALSE); BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet); effect++; @@ -4543,26 +4921,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerAlive(battler) && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) { - gEffectBattler = battler; + gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_DEF, 1, FALSE); BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet); effect++; } break; - case ABILITY_BERSERK: - if (IsBattlerTurnDamaged(battler) - && IsBattlerAlive(battler) - && HadMoreThanHalfHpNowDoesnt(battler) - && (gMultiHitCounter == 0 || gMultiHitCounter == 1) - && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) - && CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility)) - { - gEffectBattler = battler; - SET_STATCHANGER(STAT_SPATK, 1, FALSE); - BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet); - effect++; - } - break; case ABILITY_WEAK_ARMOR: if (IsBattlerTurnDamaged(battler) && IsBattlerAlive(battler) @@ -4596,18 +4960,19 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_MUMMY: if (IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move) && gDisableStructs[gBattlerAttacker].overwrittenAbility != GetBattlerAbility(gBattlerTarget) && gBattleMons[gBattlerAttacker].ability != ABILITY_MUMMY && gBattleMons[gBattlerAttacker].ability != ABILITY_LINGERING_AROMA && !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSuppressed) { - if (GetBattlerHoldEffectIgnoreAbility(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + if (GetBattlerHoldEffectIgnoreAbility(gBattlerAttacker) == HOLD_EFFECT_ABILITY_SHIELD) { RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_ABILITY_SHIELD); break; } + RemoveAbilityFlags(gBattlerAttacker); gLastUsedAbility = gBattleMons[gBattlerAttacker].ability; gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gBattleMons[gBattlerTarget].ability; BattleScriptCall(BattleScript_MummyActivates); @@ -4618,21 +4983,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_WANDERING_SPIRIT: if (IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move) && !(GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSwapped) { - if (GetBattlerHoldEffectIgnoreAbility(gBattlerAttacker, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + if (GetBattlerHoldEffectIgnoreAbility(gBattlerAttacker) == HOLD_EFFECT_ABILITY_SHIELD) { RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_ABILITY_SHIELD); break; } - if (GetBattlerHoldEffectIgnoreAbility(gBattlerTarget, TRUE) == HOLD_EFFECT_ABILITY_SHIELD) + if (GetBattlerHoldEffectIgnoreAbility(gBattlerTarget) == HOLD_EFFECT_ABILITY_SHIELD) { RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_ABILITY_SHIELD); break; } + RemoveAbilityFlags(gBattlerAttacker); gLastUsedAbility = gBattleMons[gBattlerAttacker].ability; gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gBattleMons[gBattlerTarget].ability; gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = gLastUsedAbility; @@ -4652,33 +5018,17 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; - case ABILITY_COLOR_CHANGE: - if (move != MOVE_STRUGGLE - && !IsBattleMoveStatus(move) - && IsBattlerTurnDamaged(battler) - && !IS_BATTLER_OF_TYPE(battler, moveType) - && moveType != TYPE_STELLAR - && moveType != TYPE_MYSTERY - && IsBattlerAlive(battler)) - { - SET_BATTLER_TYPE(battler, moveType); - PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); - BattleScriptCall(BattleScript_ColorChangeActivates); - effect++; - } - break; case ABILITY_GOOEY: case ABILITY_TANGLING_HAIR: if (IsBattlerAlive(gBattlerAttacker) && (CompareStat(gBattlerAttacker, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN, gLastUsedAbility) || GetBattlerAbility(gBattlerAttacker) == ABILITY_MIRROR_ARMOR) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)) { SET_STATCHANGER(STAT_SPEED, 1, TRUE); PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptCall(BattleScript_GooeyActivates); - gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; effect++; } break; @@ -4687,11 +5037,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (IsBattlerAlive(gBattlerAttacker) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)) { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / (B_ROUGH_SKIN_DMG >= GEN_4 ? 8 : 16); - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / (B_ROUGH_SKIN_DMG >= GEN_4 ? 8 : 16)); PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptCall(BattleScript_RoughSkinActivates); effect++; @@ -4701,7 +5049,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !IsBattlerAlive(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)) { if ((battler = IsAbilityOnField(ABILITY_DAMP))) { @@ -4711,9 +5059,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 else { gBattleScripting.battler = gBattlerTarget; - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); BattleScriptCall(BattleScript_AftermathDmg); } effect++; @@ -4729,15 +5075,15 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 break; gBattleScripting.battler = gBattlerTarget; - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget]; + SetPassiveDamageAmount(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerTarget]); BattleScriptCall(BattleScript_AftermathDmg); effect++; } break; case ABILITY_EFFECT_SPORE: { - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); - enum ItemHoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); + enum HoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker); if (IsAffectedByPowderMove(gBattlerAttacker, abilityAtk, holdEffectAtk)) { u32 poison, paralysis, sleep; @@ -4784,12 +5130,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { POISON_POINT: { - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); if (IsBattlerAlive(gBattlerAttacker) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && CanBePoisoned(gBattlerTarget, gBattlerAttacker, gLastUsedAbility, abilityAtk) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, abilityAtk, GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, abilityAtk, GetBattlerHoldEffect(gBattlerAttacker), move)) { gEffectBattler = gBattlerAttacker; gBattleScripting.battler = gBattlerTarget; @@ -4806,12 +5152,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { STATIC: { - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); if (IsBattlerAlive(gBattlerAttacker) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && CanBeParalyzed(gBattlerTarget, gBattlerAttacker, abilityAtk) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, abilityAtk, GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, abilityAtk, GetBattlerHoldEffect(gBattlerAttacker), move)) { gEffectBattler = gBattlerAttacker; gBattleScripting.battler = gBattlerTarget; @@ -4826,7 +5172,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_FLAME_BODY: if (IsBattlerAlive(gBattlerAttacker) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move) && IsBattlerTurnDamaged(gBattlerTarget) && CanBeBurned(gBattlerTarget, gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)) && (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_FLAME_BODY, 30) : RandomChance(RNG_FLAME_BODY, 1, 3))) @@ -4848,7 +5194,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !(gBattleMons[gBattlerAttacker].volatiles.infatuation) && AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget) && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_OBLIVIOUS) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move) && !IsAbilityOnSide(gBattlerAttacker, ABILITY_AROMA_VEIL)) { gBattleMons[gBattlerAttacker].volatiles.infatuation = INFATUATED_WITH(gBattlerTarget); @@ -4880,7 +5226,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && (moveType == TYPE_FIRE || moveType == TYPE_WATER)) { - gEffectBattler = battler; + gEffectBattler = gBattlerAbility = battler; SET_STATCHANGER(STAT_SPEED, 6, FALSE); BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet); effect++; @@ -4908,7 +5254,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(battler) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move) && !gBattleMons[gBattlerAttacker].volatiles.perishSong) { if (!gBattleMons[battler].volatiles.perishSong) @@ -4928,12 +5274,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerAlive(gBattlerAttacker) && gBattleMons[gBattlerTarget].species != SPECIES_CRAMORANT) { - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - } + if (!IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD)) + SetPassiveDamageAmount(gBattlerAttacker, GetNonDynamaxMaxHP(gBattlerAttacker) / 4); switch(gBattleMons[gBattlerTarget].species) { @@ -4966,24 +5308,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && moveType == TYPE_FIRE) { - gEffectBattler = gBattlerTarget; + gEffectBattler = gBattlerAbility = gBattlerTarget; SET_STATCHANGER(STAT_ATK, 1, FALSE); BattleScriptCall(BattleScript_TargetAbilityStatRaiseRet); effect++; } break; - case ABILITY_ANGER_SHELL: - if (!gProtectStructs[gBattlerAttacker].confusionSelfDmg - && IsBattlerTurnDamaged(gBattlerTarget) - && (gMultiHitCounter == 0 || gMultiHitCounter == 1) // Activates after all hits from a multi-hit move. - && IsBattlerAlive(gBattlerTarget) - && HadMoreThanHalfHpNowDoesnt(gBattlerTarget) - && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))) - { - BattleScriptCall(BattleScript_AngerShellActivates); - effect++; - } - break; case ABILITY_WIND_POWER: if (!IsWindMove(gCurrentMove)) break; @@ -5012,6 +5342,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + default: + break; } break; case ABILITYEFFECT_MOVE_END_ATTACKER: // Same as above, but for attacker @@ -5021,7 +5353,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (IsBattlerAlive(gBattlerTarget) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && CanBePoisoned(gBattlerAttacker, gBattlerTarget, gLastUsedAbility, GetBattlerAbility(gBattlerTarget)) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move) && IsBattlerTurnDamaged(gBattlerTarget) // Need to actually hit the target && RandomPercentage(RNG_POISON_TOUCH, 30)) { @@ -5034,13 +5366,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_TOXIC_CHAIN: - if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) - && IsBattlerAlive(gBattlerTarget) - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && CanBePoisoned(gBattlerAttacker, gBattlerTarget, gLastUsedAbility, GetBattlerAbility(gBattlerTarget)) - && IsBattlerTurnDamaged(gBattlerTarget) // Need to actually hit the target - && RandomWeighted(RNG_TOXIC_CHAIN, 7, 3)) + if (gBattleStruct->toxicChainPriority) { + gBattleStruct->toxicChainPriority = FALSE; gEffectBattler = gBattlerTarget; gBattleScripting.battler = gBattlerAttacker; gBattleScripting.moveEffect = MOVE_EFFECT_TOXIC; @@ -5056,10 +5384,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerTurnDamaged(gBattlerTarget) && !MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_FLINCH)) { - gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH; - BattleScriptPushCursor(); - SetMoveEffect(gBattlerAttacker, gBattlerTarget, FALSE, FALSE); - BattleScriptPop(); + SetMoveEffect(gBattlerAttacker, gBattlerTarget, MOVE_EFFECT_FLINCH, gBattlescriptCurrInstr, EFFECT_PRIMARY); effect++; } break; @@ -5082,10 +5407,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptCall(BattleScript_AbilityStatusEffect); - gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; effect++; } break; + default: + break; } break; case ABILITYEFFECT_MOVE_END_OTHER: // Abilities that activate on *another* battler's moveend: Dancer, Soul-Heart, Receiver, Symbiosis @@ -5106,39 +5432,36 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 // Set the target to the original target of the mon that first used a Dance move gBattlerTarget = gBattleScripting.savedBattler & 0x3; - // Edge case for dance moves that hit multiply targets - gHitMarker &= ~HITMARKER_NO_ATTACKSTRING; - // Make sure that the target isn't an ally - if it is, target the original user if (IsBattlerAlly(gBattlerTarget, gBattlerAttacker)) gBattlerTarget = (gBattleScripting.savedBattler & 0xF0) >> 4; - gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; BattleScriptExecute(BattleScript_DancerActivates); effect++; } break; + default: + break; } break; case ABILITYEFFECT_OPPORTUNIST: - /* Similar to ABILITYEFFECT_IMMUNITY in that it loops through all battlers. - * Is called after ABILITYEFFECT_ON_SWITCHIN to copy any boosts - * from switch in abilities e.g. intrepid sword, as - */ - for (battler = 0; battler < gBattlersCount; battler++) + case ABILITYEFFECT_OPPORTUNIST_FIRST_TURN: + switch (ability) { - switch (GetBattlerAbility(battler)) + case ABILITY_OPPORTUNIST: + if (gProtectStructs[battler].activateOpportunist == 2) { - case ABILITY_OPPORTUNIST: - if (gProtectStructs[battler].activateOpportunist == 2) - { - gBattleScripting.battler = battler; - gProtectStructs[battler].activateOpportunist--; - ChooseStatBoostAnimation(battler); - BattleScriptPushCursorAndCallback(BattleScript_OpportunistCopyStatChange); - effect = 1; - } - break; + gBattleScripting.battler = battler; + gProtectStructs[battler].activateOpportunist--; + ChooseStatBoostAnimation(battler); + if (caseID == ABILITYEFFECT_OPPORTUNIST_FIRST_TURN) + BattleScriptPushCursorAndCallback(BattleScript_OpportunistCopyStatChangeEnd3); + else + BattleScriptCall(BattleScript_OpportunistCopyStatChange); + effect = 1; } + break; + default: + break; } break; case ABILITYEFFECT_IMMUNITY: @@ -5214,13 +5537,17 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 break; case ABILITYEFFECT_NEUTRALIZINGGAS: + case ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN: // Prints message only. separate from ABILITYEFFECT_ON_SWITCHIN bc activates before entry hazards if (gLastUsedAbility == ABILITY_NEUTRALIZING_GAS && !gDisableStructs[battler].neutralizingGas) { gDisableStructs[battler].neutralizingGas = TRUE; gBattlerAbility = battler; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS; - BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg); + if (caseID == ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN) + BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg); + else + BattleScriptCall(BattleScript_SwitchInAbilityMsgRet); effect++; } break; @@ -5232,33 +5559,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { case ABILITY_FORECAST: case ABILITY_FLOWER_GIFT: - if ((IsBattlerWeatherAffected(battler, gBattleWeather) + case ABILITY_ICE_FACE: + { + u32 battlerWeatherAffected = IsBattlerWeatherAffected(battler, gBattleWeather); + if (battlerWeatherAffected && !CanBattlerFormChange(battler, FORM_CHANGE_BATTLE_WEATHER)) + { + // If Hail/Snow activates when in Eiscue is in base, prevent reversion when Eiscue Noice gets broken + gDisableStructs[battler].weatherAbilityDone = TRUE; + } + + if (((!gDisableStructs[battler].weatherAbilityDone && battlerWeatherAffected) || gBattleWeather == B_WEATHER_NONE || !HasWeatherEffect()) // Air Lock active && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_WEATHER)) { gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); - effect++; - } - break; - case ABILITY_ICE_FACE: - { - u32 battlerWeatherAffected = IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW); - if (battlerWeatherAffected && gBattleMons[battler].species == SPECIES_EISCUE) - { - // If Hail/Snow activates when in Eiscue is in base, prevent reversion when Eiscue Noice gets broken gDisableStructs[battler].weatherAbilityDone = TRUE; - } - if (!gDisableStructs[battler].weatherAbilityDone - && battlerWeatherAffected - && gBattleMons[battler].species == SPECIES_EISCUE_NOICE - && !(gBattleMons[battler].volatiles.transformed)) - { - // TODO: Convert this to a proper FORM_CHANGE type. - gBattleScripting.battler = battler; - gDisableStructs[battler].weatherAbilityDone = TRUE; - gBattleMons[battler].species = SPECIES_EISCUE_ICE; BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); effect++; } @@ -5278,6 +5594,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + default: + break; } break; case ABILITYEFFECT_ON_TERRAIN: // For ability effects that activate when the field terrain changes. @@ -5310,6 +5628,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + default: + break; } break; } @@ -5324,7 +5644,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 bool32 TryPrimalReversion(u32 battler) { - if (GetBattlerHoldEffect(battler, FALSE) == HOLD_EFFECT_PRIMAL_ORB + if (GetBattlerHoldEffectIgnoreNegation(battler) == HOLD_EFFECT_PRIMAL_ORB && GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) != gBattleMons[battler].species) { gBattleScripting.battler = battler; @@ -5347,7 +5667,7 @@ bool32 IsNeutralizingGasOnField(void) return FALSE; } -bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability) +bool32 IsMoldBreakerTypeAbility(u32 battler, enum Ability ability) { if (gBattleMons[battler].volatiles.gastroAcid) return FALSE; @@ -5381,14 +5701,14 @@ u32 GetBattlerAbilityIgnoreMoldBreaker(u32 battler) return GetBattlerAbilityInternal(battler, TRUE, FALSE); } -u32 GetBattlerAbility(u32 battler) +enum Ability GetBattlerAbility(u32 battler) { return GetBattlerAbilityInternal(battler, FALSE, FALSE); } u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityShield) { - bool32 hasAbilityShield = !noAbilityShield && GetBattlerHoldEffectIgnoreAbility(battler, TRUE) == HOLD_EFFECT_ABILITY_SHIELD; + bool32 hasAbilityShield = !noAbilityShield && GetBattlerHoldEffectIgnoreAbility(battler) == HOLD_EFFECT_ABILITY_SHIELD; bool32 abilityCantBeSuppressed = gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed; if (abilityCantBeSuppressed) @@ -5419,7 +5739,7 @@ u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityS return gBattleMons[battler].ability; } -u32 IsAbilityOnSide(u32 battler, u32 ability) +u32 IsAbilityOnSide(u32 battler, enum Ability ability) { if (IsBattlerAlive(battler) && GetBattlerAbility(battler) == ability) return battler + 1; @@ -5429,12 +5749,12 @@ u32 IsAbilityOnSide(u32 battler, u32 ability) return 0; } -u32 IsAbilityOnOpposingSide(u32 battler, u32 ability) +u32 IsAbilityOnOpposingSide(u32 battler, enum Ability ability) { return IsAbilityOnSide(BATTLE_OPPOSITE(battler), ability); } -u32 IsAbilityOnField(u32 ability) +u32 IsAbilityOnField(enum Ability ability) { u32 i; @@ -5447,7 +5767,7 @@ u32 IsAbilityOnField(u32 ability) return 0; } -u32 IsAbilityOnFieldExcept(u32 battler, u32 ability) +u32 IsAbilityOnFieldExcept(u32 battler, enum Ability ability) { u32 i; @@ -5465,17 +5785,18 @@ u32 IsAbilityPreventingEscape(u32 battler) if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return 0; + bool32 isBattlerGrounded = IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler)); for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { if (battler == battlerDef || IsBattlerAlly(battler, battlerDef)) continue; - u32 ability = GetBattlerAbility(battlerDef); + enum Ability ability = GetBattlerAbility(battlerDef); if (ability == ABILITY_SHADOW_TAG && (B_SHADOW_TAG_ESCAPE <= GEN_3 || GetBattlerAbility(battler) != ABILITY_SHADOW_TAG)) return battlerDef + 1; - if (ability == ABILITY_ARENA_TRAP && IsBattlerGrounded(battler)) + if (ability == ABILITY_ARENA_TRAP && isBattlerGrounded) return battlerDef + 1; if (ability == ABILITY_MAGNET_PULL && IS_BATTLER_OF_TYPE(battler, TYPE_STEEL)) @@ -5520,75 +5841,14 @@ void BattleScriptPushCursorAndCallback(const u8 *BS_ptr) gBattleMainFunc = RunBattleScriptCommands; } -bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag) +bool32 IsBattlerTerrainAffected(u32 battler, enum Ability ability, enum HoldEffect holdEffect, u32 terrainFlag) { if (!(gFieldStatuses & terrainFlag)) return FALSE; if (IsSemiInvulnerable(battler, CHECK_ALL)) return FALSE; - return IsBattlerGrounded(battler); -} - -bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, u32 abilityDef, enum SleepClauseBlock isBlockedBySleepClause) -{ - if (IsSleepClauseActiveForSide(GetBattlerSide(battlerDef)) && isBlockedBySleepClause != NOT_BLOCKED_BY_SLEEP_CLAUSE) - return FALSE; - - if (isBlockedBySleepClause == NOT_BLOCKED_BY_SLEEP_CLAUSE) - gBattleStruct->sleepClauseNotBlocked = TRUE; - - bool32 effect = FALSE; - if (CanSetNonVolatileStatus( - battlerAtk, - battlerDef, - ABILITY_NONE, // attacker ability does not matter - abilityDef, - MOVE_EFFECT_SLEEP, // also covers yawn - CHECK_TRIGGER)) - effect = TRUE; - - gBattleStruct->sleepClauseNotBlocked = FALSE; - return effect; -} - -bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef) -{ - if (CanSetNonVolatileStatus( - battlerAtk, - battlerDef, - abilityAtk, - abilityDef, - MOVE_EFFECT_TOXIC, // also covers poison - CHECK_TRIGGER)) - return TRUE; - return FALSE; -} - -bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, u32 abilityDef) -{ - if (CanSetNonVolatileStatus( - battlerAtk, - battlerDef, - ABILITY_NONE, // attacker ability does not matter - abilityDef, - MOVE_EFFECT_BURN, - CHECK_TRIGGER)) - return TRUE; - return FALSE; -} - -bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, u32 abilityDef) -{ - if (CanSetNonVolatileStatus( - battlerAtk, - battlerDef, - ABILITY_NONE, // attacker ability does not matter - abilityDef, - MOVE_EFFECT_PARALYSIS, - CHECK_TRIGGER)) - return TRUE; - return FALSE; + return IsBattlerGrounded(battler, ability, holdEffect); } u32 GetHighestStatId(u32 battler) @@ -5693,7 +5953,69 @@ u32 GetParadoxBoostedStatId(u32 battler) return gDisableStructs[battler].paradoxBoostedStat; } -bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef) +bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, enum SleepClauseBlock isBlockedBySleepClause) +{ + if (IsSleepClauseActiveForSide(GetBattlerSide(battlerDef)) && isBlockedBySleepClause != NOT_BLOCKED_BY_SLEEP_CLAUSE) + return FALSE; + + if (isBlockedBySleepClause == NOT_BLOCKED_BY_SLEEP_CLAUSE) + gBattleStruct->sleepClauseNotBlocked = TRUE; + + bool32 effect = FALSE; + if (CanSetNonVolatileStatus( + battlerAtk, + battlerDef, + ABILITY_NONE, // attacker ability does not matter + abilityDef, + MOVE_EFFECT_SLEEP, // also covers yawn + CHECK_TRIGGER)) + effect = TRUE; + + gBattleStruct->sleepClauseNotBlocked = FALSE; + return effect; +} + +bool32 CanBePoisoned(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef) +{ + if (CanSetNonVolatileStatus( + battlerAtk, + battlerDef, + abilityAtk, + abilityDef, + MOVE_EFFECT_TOXIC, // also covers poison + CHECK_TRIGGER)) + return TRUE; + return FALSE; +} + +// TODO: check order of battlerAtk and battlerDef +bool32 CanBeBurned(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef) +{ + if (CanSetNonVolatileStatus( + battlerAtk, + battlerDef, + ABILITY_NONE, // attacker ability does not matter + abilityDef, + MOVE_EFFECT_BURN, + CHECK_TRIGGER)) + return TRUE; + return FALSE; +} + +bool32 CanBeParalyzed(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef) +{ + if (CanSetNonVolatileStatus( + battlerAtk, + battlerDef, + ABILITY_NONE, // attacker ability does not matter + abilityDef, + MOVE_EFFECT_PARALYSIS, + CHECK_TRIGGER)) + return TRUE; + return FALSE; +} + +bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef) { if (CanSetNonVolatileStatus( battlerAtk, @@ -5705,9 +6027,8 @@ bool32 CanBeFrozen(u32 battlerAtk, u32 battlerDef, u32 abilityDef) return TRUE; return FALSE; } - -// Unused, technically also redundant -bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef) +// Unused, technically also redundant because it is just a copy of CanBeFrozen +bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef) { if (CanSetNonVolatileStatus( battlerAtk, @@ -5720,7 +6041,7 @@ bool32 CanGetFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef) return FALSE; } -bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, enum MoveEffect effect, enum FunctionCallOption option) +bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum MoveEffect effect, enum FunctionCallOption option) { const u8 *battleScript = NULL; u32 sideBattler = ABILITY_NONE; @@ -5744,13 +6065,11 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u abilityAffected = TRUE; battlerDef = sideBattler - 1; abilityDef = ABILITY_PASTEL_VEIL; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABILITY_PASTEL_VEIL; battleScript = BattleScript_ImmunityProtected; } else if (abilityDef == ABILITY_IMMUNITY) { abilityAffected = TRUE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABILITY_PREVENTS_MOVE_POISON; battleScript = BattleScript_ImmunityProtected; } break; @@ -5772,7 +6091,6 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u else if (abilityDef == ABILITY_LIMBER) { abilityAffected = TRUE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABILITY_PREVENTS_MOVE_PARALYSIS; battleScript = BattleScript_ImmunityProtected; } break; @@ -5788,7 +6106,6 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u else if (abilityDef == ABILITY_WATER_VEIL || abilityDef == ABILITY_WATER_BUBBLE) { abilityAffected = TRUE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABILITY_PREVENTS_MOVE_BURN; battleScript = BattleScript_ImmunityProtected; } else if (abilityDef == ABILITY_THERMAL_EXCHANGE) @@ -5810,7 +6127,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u { battleScript = BattleScript_SleepClauseBlocked; } - else if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_ELECTRIC_TERRAIN)) + else if (IsBattlerTerrainAffected(battlerDef, abilityDef, GetBattlerHoldEffect(battlerDef), STATUS_FIELD_ELECTRIC_TERRAIN)) { battleScript = BattleScript_ElectricTerrainPrevents; } @@ -5819,7 +6136,6 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u abilityAffected = TRUE; battlerDef = sideBattler - 1; abilityDef = ABILITY_SWEET_VEIL; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STATUS_HAD_NO_EFFECT; battleScript = BattleScript_ImmunityProtected; } else if (abilityDef == ABILITY_VITAL_SPIRIT || abilityDef == ABILITY_INSOMNIA) @@ -5858,7 +6174,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u abilityAffected = TRUE; battleScript = BattleScript_AbilityProtectsDoesntAffect; } - else if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN)) + else if (IsBattlerTerrainAffected(battlerDef, abilityDef, GetBattlerHoldEffect(battlerDef), STATUS_FIELD_MISTY_TERRAIN)) { battleScript = BattleScript_MistyTerrainPrevents; } @@ -5894,7 +6210,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u return TRUE; } -static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, u32 abilityDef, u32 abilityAffected, const u8 *battleScript, enum FunctionCallOption option) +static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, enum Ability abilityDef, enum Ability abilityAffected, const u8 *battleScript, enum FunctionCallOption option) { if (battleScript != NULL) { @@ -5940,29 +6256,25 @@ static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum Func bool32 CanBeConfused(u32 battler) { + enum Ability ability = GetBattlerAbility(battler); if (gBattleMons[battler].volatiles.confusionTurns > 0 - || IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN) - || IsAbilityAndRecord(battler, GetBattlerAbility(battler),ABILITY_OWN_TEMPO)) + || IsBattlerTerrainAffected(battler, ability, GetBattlerHoldEffect(battler), STATUS_FIELD_MISTY_TERRAIN) + || IsAbilityAndRecord(battler, ability, ABILITY_OWN_TEMPO)) return FALSE; return TRUE; } // second argument is 1/X of current hp compared to max hp -bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId) +bool32 HasEnoughHpToEatBerry(u32 battler, enum Ability ability, u32 hpFraction, u32 itemId) { - bool32 isBerry = (GetItemPocket(itemId) == POCKET_BERRIES); - if (!IsBattlerAlive(battler)) return FALSE; if (gBattleScripting.overrideBerryRequirements) return TRUE; - // Unnerve prevents consumption of opponents' berries. - if (isBerry && IsUnnerveAbilityOnOpposingSide(battler)) - return FALSE; if (gBattleMons[battler].hp <= gBattleMons[battler].maxHP / hpFraction) return TRUE; - if (hpFraction <= 4 && isBerry + if (hpFraction <= 4 && GetItemPocket(itemId) == POCKET_BERRIES && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 2 && IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_GLUTTONY)) return TRUE; @@ -5970,1425 +6282,10 @@ bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId) return FALSE; } -static enum ItemEffect HealConfuseBerry(u32 battler, u32 itemId, u32 flavorId, enum ItemCaseId caseID) -{ - if (HasEnoughHpToEatBerry(battler, (B_CONFUSE_BERRIES_HEAL >= GEN_7 ? 4 : 2), itemId) - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId); - - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / GetBattlerItemHoldEffectParam(battler, itemId); - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; - - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - { - gBattleStruct->moveDamage[battler] *= 2; - gBattlerAbility = battler; - } - gBattleScripting.battler = battler; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - { - if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) - BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); - else - BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); - } - else - { - if (GetFlavorRelationByPersonality(gBattleMons[battler].personality, flavorId) < 0) - BattleScriptCall(BattleScript_BerryConfuseHealRet); - else - BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); - } - - return ITEM_HP_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect StatRaiseBerry(u32 battler, u32 itemId, u32 statId, enum ItemCaseId caseID) -{ - u32 ability = GetBattlerAbility(battler); - if (CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ability) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId)) - { - BufferStatChange(battler, statId, STRINGID_STATROSE); - gEffectBattler = gBattleScripting.battler = battler; - if (ability == ABILITY_RIPEN) - SET_STATCHANGER(statId, 2, FALSE); - else - SET_STATCHANGER(statId, 1, FALSE); - - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; - gBattleScripting.animArg2 = 0; - - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - else - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect RandomStatRaiseBerry(u32 battler, u32 itemId, enum ItemCaseId caseID) -{ - s32 stat; - enum StringID stringId; - u32 battlerAbility = GetBattlerAbility(battler); - - for (stat = STAT_ATK; stat < NUM_STATS; stat++) - { - if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_LESS_THAN, battlerAbility)) - break; - } - if (stat != NUM_STATS && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, itemId), itemId)) - { - u32 savedAttacker = gBattlerAttacker; - // MoodyCantRaiseStat requires that the battler is set to gBattlerAttacker - gBattlerAttacker = gBattleScripting.battler = battler; - stat = RandomUniformExcept(RNG_RANDOM_STAT_UP, STAT_ATK, NUM_STATS - 1, MoodyCantRaiseStat); - gBattlerAttacker = savedAttacker; - - PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); - stringId = (battlerAbility == ABILITY_CONTRARY) ? STRINGID_STATFELL : STRINGID_STATROSE; - gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; - gBattleTextBuff2[1] = B_BUFF_STRING; - gBattleTextBuff2[2] = STRINGID_STATSHARPLY; - gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8; - gBattleTextBuff2[4] = B_BUFF_STRING; - gBattleTextBuff2[5] = stringId; - gBattleTextBuff2[6] = stringId >> 8; - gBattleTextBuff2[7] = EOS; - gEffectBattler = battler; - if (battlerAbility == ABILITY_RIPEN) - SET_STATCHANGER(stat, 4, FALSE); - else - SET_STATCHANGER(stat, 2, FALSE); - - gBattleScripting.animArg1 = STAT_ANIM_PLUS2 + stat; - gBattleScripting.animArg2 = 0; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - else - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect TrySetMicleBerry(u32 battler, u32 itemId, enum ItemCaseId caseID) -{ - if (HasEnoughHpToEatBerry(battler, 4, itemId)) - { - gBattleStruct->battlerState[battler].usedMicleBerry = TRUE; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - { - BattleScriptExecute(BattleScript_MicleBerryActivateEnd2); - } - else - { - BattleScriptCall(BattleScript_MicleBerryActivateRet); - } - return ITEM_EFFECT_OTHER; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect TrySetEnigmaBerry(u32 battler) -{ - if (IsBattlerAlive(battler) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && ((IsBattlerTurnDamaged(battler) && gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements) - && !(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP) - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - gBattleScripting.battler = battler; - gBattleStruct->moveDamage[battler] = (gBattleMons[battler].maxHP * 25 / 100) * -1; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[battler] *= 2; - - BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); - return ITEM_HP_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect DamagedStatBoostBerryEffect(u32 battler, u8 statId, enum DamageCategory category) -{ - u32 ability = GetBattlerAbility(battler); - if (IsBattlerAlive(battler) - && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ability) - && (gBattleScripting.overrideBerryRequirements - || (!DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && GetBattleMoveCategory(gCurrentMove) == category - && battler != gBattlerAttacker - && IsBattlerTurnDamaged(battler))) - ) - { - BufferStatChange(battler, statId, STRINGID_STATROSE); - - gEffectBattler = battler; - if (ability == ABILITY_RIPEN) - SET_STATCHANGER(statId, 2, FALSE); - else - SET_STATCHANGER(statId, 1, FALSE); - - gBattleScripting.battler = battler; - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; - gBattleScripting.animArg2 = 0; - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, u32 statId, u32 itemId, enum ItemCaseId caseID) -{ - if (gFieldStatuses & terrainFlag && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(battler))) - { - BufferStatChange(battler, statId, STRINGID_STATROSE); - gLastUsedItem = itemId; // For surge abilities - gEffectBattler = gBattleScripting.battler = battler; - SET_STATCHANGER(statId, 1, FALSE); - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + statId; - gBattleScripting.animArg2 = 0; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN) - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - else - BattleScriptCall(BattleScript_ConsumableStatRaiseRet); - return ITEM_STATS_CHANGE; - } - return ITEM_NO_EFFECT; -} - -static enum ItemEffect ConsumeBerserkGene(u32 battler, enum ItemCaseId caseID) -{ - if (CanBeInfinitelyConfused(battler)) - gBattleMons[battler].volatiles.infiniteConfusion = TRUE; - - BufferStatChange(battler, STAT_ATK, STRINGID_STATROSE); - gBattlerAttacker = gEffectBattler = battler; - SET_STATCHANGER(STAT_ATK, 2, FALSE); - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; - gBattleScripting.animArg2 = 0; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BerserkGeneRetEnd2); - else - BattleScriptCall(BattleScript_BerserkGeneRet); - return ITEM_STATS_CHANGE; -} - -static u32 ItemRestorePp(u32 battler, u32 itemId, enum ItemCaseId caseID) -{ - struct Pokemon *mon = GetBattlerMon(battler); - u32 i, changedPP = 0; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - u32 move = GetMonData(mon, MON_DATA_MOVE1 + i); - u32 currentPP = GetMonData(mon, MON_DATA_PP1 + i); - u32 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES); - u32 maxPP = CalculatePPWithBonus(move, ppBonuses, i); - if (move && (currentPP == 0 || (gBattleScripting.overrideBerryRequirements && currentPP != maxPP))) - { - u32 ppRestored = GetBattlerItemHoldEffectParam(battler, itemId); - - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - { - ppRestored *= 2; - gBattlerAbility = battler; - } - if (currentPP + ppRestored > maxPP) - changedPP = maxPP; - else - changedPP = currentPP + ppRestored; - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, move); - - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BerryPPHealEnd2); - else - BattleScriptCall(BattleScript_BerryPPHealRet); - - gBattleScripting.battler = battler; - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); - MarkBattlerForControllerExec(battler); - if (MOVE_IS_PERMANENT(battler, i)) - gBattleMons[battler].pp[i] = changedPP; - return ITEM_PP_CHANGE; - } - } - return 0; -} - -static u32 ItemHealHp(u32 battler, u32 itemId, enum ItemCaseId caseID, bool32 percentHeal) -{ - if (!(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP) - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock) - && HasEnoughHpToEatBerry(battler, 2, itemId)) - { - if (percentHeal) - gBattleStruct->moveDamage[battler] = (GetNonDynamaxMaxHP(battler) * GetBattlerItemHoldEffectParam(battler, itemId) / 100) * -1; - else - gBattleStruct->moveDamage[battler] = GetBattlerItemHoldEffectParam(battler, itemId) * -1; - - // check ripen - if (GetItemPocket(itemId) == POCKET_BERRIES && GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[battler] *= 2; - - gBattlerAbility = battler; // in SWSH, berry juice shows ability pop up but has no effect. This is mimicked here - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_ItemHealHP_RemoveItemEnd2); - else - BattleScriptCall(BattleScript_ItemHealHP_RemoveItemRet); - - return ITEM_HP_CHANGE; - } - return 0; -} - -static bool32 UnnerveOn(u32 battler, u32 itemId) -{ - if (gBattleScripting.overrideBerryRequirements > 0) // Berries that aren't eaten naturally ignore unnerve - return FALSE; - - if (GetItemPocket(itemId) == POCKET_BERRIES && IsUnnerveAbilityOnOpposingSide(battler)) - return TRUE; - return FALSE; -} - -static bool32 GetMentalHerbEffect(u32 battler) -{ - bool32 ret = FALSE; - - // Check infatuation - if (gBattleMons[battler].volatiles.infatuation) - { - gBattleMons[battler].volatiles.infatuation = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION - StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); - ret = TRUE; - } - if (B_MENTAL_HERB >= GEN_5) - { - // Check taunt - if (gDisableStructs[battler].tauntTimer != 0) - { - gDisableStructs[battler].tauntTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT; - PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT); - ret = TRUE; - } - // Check encore - if (gDisableStructs[battler].encoreTimer != 0) - { - gDisableStructs[battler].encoredMove = 0; - gDisableStructs[battler].encoreTimer = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; // STRINGID_PKMNENCOREENDED - ret = TRUE; - } - // Check torment - if (gBattleMons[battler].volatiles.torment == TRUE) - { - gBattleMons[battler].volatiles.torment = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; - ret = TRUE; - } - // Check heal block - if (gBattleMons[battler].volatiles.healBlock) - { - gBattleMons[battler].volatiles.healBlock = FALSE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK; - ret = TRUE; - } - // Check disable - if (gDisableStructs[battler].disableTimer != 0) - { - gDisableStructs[battler].disableTimer = 0; - gDisableStructs[battler].disabledMove = 0; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE; - ret = TRUE; - } - } - return ret; -} - -static u32 TryConsumeMirrorHerb(u32 battler, enum ItemCaseId caseID) -{ - u32 effect = 0; - - if (gProtectStructs[battler].eatMirrorHerb) - { - gLastUsedItem = gBattleMons[battler].item; - gBattleScripting.battler = battler; - gProtectStructs[battler].eatMirrorHerb = 0; - ChooseStatBoostAnimation(battler); - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_MirrorHerbCopyStatChangeEnd2); - else - BattleScriptCall(BattleScript_MirrorHerbCopyStatChange); - effect = ITEM_STATS_CHANGE; - } - return effect; -} - -u32 TryBoosterEnergy(u32 battler, u32 ability, enum ItemCaseId caseID) -{ - if (gDisableStructs[battler].boosterEnergyActivated || gBattleMons[battler].volatiles.transformed) - return ITEM_NO_EFFECT; - - if (((ability == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect())) - || ((ability == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN))) - { - gDisableStructs[battler].paradoxBoostedStat = GetParadoxHighestStatId(battler); - PREPARE_STAT_BUFFER(gBattleTextBuff1, gDisableStructs[battler].paradoxBoostedStat); - gBattlerAbility = gBattleScripting.battler = battler; - gDisableStructs[battler].boosterEnergyActivated = TRUE; - gLastUsedItem = ITEM_BOOSTER_ENERGY; - RecordAbilityBattle(battler, ability); - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BoosterEnergyEnd2); - else - BattleScriptCall(BattleScript_BoosterEnergyRet); - return ITEM_EFFECT_OTHER; - } - - return ITEM_NO_EFFECT; -} - -u32 RestoreWhiteHerbStats(u32 battler) -{ - u32 i, effect = 0; - - for (i = 0; i < NUM_BATTLE_STATS; i++) - { - if (gBattleMons[battler].statStages[i] < DEFAULT_STAT_STAGE) - { - gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; - effect = ITEM_STATS_CHANGE; - } - } - if (effect != 0) - { - gLastUsedItem = gBattleMons[battler].item; - gBattleScripting.battler = battler; - gPotentialItemEffectBattler = battler; - } - return effect; -} - -static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect) -{ - u8 effect = 0; - - switch (holdEffect) - { - case HOLD_EFFECT_MICLE_BERRY: - if (B_HP_BERRIES >= GEN_4) - effect = TrySetMicleBerry(battler, gLastUsedItem, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_RESTORE_HP: - if (B_HP_BERRIES >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, ITEMEFFECT_NONE, FALSE); - break; - case HOLD_EFFECT_RESTORE_PCT_HP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, ITEMEFFECT_NONE, TRUE); - break; - case HOLD_EFFECT_RESTORE_PP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemRestorePp(battler, gLastUsedItem, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_SPICY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SPICY, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_DRY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_DRY, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_SWEET: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SWEET, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_BITTER: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_BITTER, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CONFUSE_SOUR: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SOUR, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_ATK, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_DEF, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_SPEED_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPEED, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_SP_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPATK, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_SP_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_ENIGMA_BERRY: // consume and heal if hit by super effective move - effect = TrySetEnigmaBerry(battler); - break; - case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move - effect = DamagedStatBoostBerryEffect(battler, STAT_DEF, DAMAGE_CATEGORY_PHYSICAL); - break; - case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move - effect = DamagedStatBoostBerryEffect(battler, STAT_SPDEF, DAMAGE_CATEGORY_SPECIAL); - break; - case HOLD_EFFECT_RANDOM_STAT_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = RandomStatRaiseBerry(battler, gLastUsedItem, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_CURE_PAR: - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; - BattleScriptCall(BattleScript_BerryCureParRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_PSN: - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptCall(BattleScript_BerryCurePsnRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_BRN: - if (gBattleMons[battler].status1 & STATUS1_BURN && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_BURN; - BattleScriptCall(BattleScript_BerryCureBrnRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_FRZ: - if (gBattleMons[battler].status1 & STATUS1_FREEZE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FREEZE; - BattleScriptCall(BattleScript_BerryCureFrzRet); - effect = ITEM_STATUS_CHANGE; - } - if (gBattleMons[battler].status1 & STATUS1_FROSTBITE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; - BattleScriptCall(BattleScript_BerryCureFrbRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_SLP: - if (gBattleMons[battler].status1 & STATUS1_SLEEP && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].volatiles.nightmare = FALSE; - BattleScriptCall(BattleScript_BerryCureSlpRet); - effect = ITEM_STATUS_CHANGE; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - break; - case HOLD_EFFECT_CURE_CONFUSION: - if (gBattleMons[battler].volatiles.confusionTurns > 0 && !UnnerveOn(battler, gLastUsedItem)) - { - RemoveConfusionStatus(battler); - BattleScriptCall(BattleScript_BerryCureConfusionRet); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_MENTAL_HERB: - if (GetMentalHerbEffect(battler)) - { - gBattleScripting.savedBattler = gBattlerAttacker; - gBattlerAttacker = battler; - BattleScriptCall(BattleScript_MentalHerbCureRet); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_CURE_STATUS: - if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0) && !UnnerveOn(battler, gLastUsedItem)) - { - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) - StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); - - if (gBattleMons[battler].status1 & STATUS1_SLEEP) - { - gBattleMons[battler].volatiles.nightmare = FALSE; - StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) - StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); - - if (gBattleMons[battler].status1 & STATUS1_BURN) - StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - - if (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE) - StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - - if (gBattleMons[battler].volatiles.confusionTurns > 0) - StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); - - gBattleMons[battler].status1 = 0; - RemoveConfusionStatus(battler); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PROBLEM; - BattleScriptCall(BattleScript_BerryCureChosenStatusRet); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CRITICAL_UP: // lansat berry - if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) - && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) - { - gBattleMons[battler].volatiles.focusEnergy = TRUE; - gBattleScripting.battler = battler; - gPotentialItemEffectBattler = battler; - BattleScriptCall(BattleScript_BerryFocusEnergyRet); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_BERSERK_GENE: - effect = ConsumeBerserkGene(battler, ITEMEFFECT_NONE); - break; - case HOLD_EFFECT_MIRROR_HERB: - effect = TryConsumeMirrorHerb(battler, ITEMEFFECT_NONE); - break; - default: - break; - } - - return effect; -} - -static inline bool32 TryCureStatus(u32 battler, enum ItemCaseId caseId) -{ - u32 effect = ITEM_NO_EFFECT; - u32 string = 0; - - if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0) && !UnnerveOn(battler, gLastUsedItem)) - { - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); - string++; - } - if (gBattleMons[battler].status1 & STATUS1_SLEEP) - { - gBattleMons[battler].volatiles.nightmare = FALSE; - StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); - string++; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); - string++; - } - if (gBattleMons[battler].status1 & STATUS1_BURN) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); - string++; - } - if (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - string++; - } - if (gBattleMons[battler].volatiles.confusionTurns > 0) - { - StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); - string++; - } - if (string <= 1) - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CURED_PROBLEM; - else - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_NORMALIZED_STATUS; - gBattleMons[battler].status1 = 0; - RemoveConfusionStatus(battler); - if (caseId == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseId == ITEMEFFECT_NORMAL) - BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); - else - BattleScriptCall(BattleScript_BerryCureChosenStatusRet); - effect = ITEM_STATUS_CHANGE; - } - - return effect; -} - -u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler) -{ - u32 moveType = 0; - enum ItemEffect effect = ITEM_NO_EFFECT; - enum ItemHoldEffect battlerHoldEffect = 0, atkHoldEffect = 0; - u32 atkHoldEffectParam = 0; - u32 atkItem = 0; - - if (caseID != ITEMEFFECT_USE_LAST_ITEM) - { - gLastUsedItem = gBattleMons[battler].item; - battlerHoldEffect = GetBattlerHoldEffect(battler, TRUE); - } - - atkItem = gBattleMons[gBattlerAttacker].item; - atkHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - atkHoldEffectParam = GetBattlerHoldEffectParam(gBattlerAttacker); - - switch (caseID) - { - case ITEMEFFECT_NONE: - break; - case ITEMEFFECT_ON_SWITCH_IN: - case ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN: - if (!gSpecialStatuses[battler].switchInItemDone) - { - switch (battlerHoldEffect) - { - case HOLD_EFFECT_DOUBLE_PRIZE: - if (IsOnPlayerSide(battler) && !gBattleStruct->moneyMultiplierItem) - { - gBattleStruct->moneyMultiplier *= 2; - gBattleStruct->moneyMultiplierItem = 1; - } - break; - case HOLD_EFFECT_WHITE_HERB: - effect = RestoreWhiteHerbStats(battler); - if (effect != 0) - BattleScriptExecute(BattleScript_WhiteHerbEnd2); - break; - case HOLD_EFFECT_CONFUSE_SPICY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SPICY, caseID); - break; - case HOLD_EFFECT_CONFUSE_DRY: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_DRY, caseID); - break; - case HOLD_EFFECT_CONFUSE_SWEET: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SWEET, caseID); - break; - case HOLD_EFFECT_CONFUSE_BITTER: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_BITTER, caseID); - break; - case HOLD_EFFECT_CONFUSE_SOUR: - if (B_BERRIES_INSTANT >= GEN_4) - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SOUR, caseID); - break; - case HOLD_EFFECT_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_ATK, caseID); - break; - case HOLD_EFFECT_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_DEF, caseID); - break; - case HOLD_EFFECT_SPEED_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPEED, caseID); - break; - case HOLD_EFFECT_SP_ATTACK_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPATK, caseID); - break; - case HOLD_EFFECT_SP_DEFENSE_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, caseID); - break; - case HOLD_EFFECT_CRITICAL_UP: - if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) - && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) - { - gBattleMons[battler].volatiles.focusEnergy = TRUE; - gBattleScripting.battler = battler; - BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_RANDOM_STAT_UP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = RandomStatRaiseBerry(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_CURE_PAR: - if (B_BERRIES_INSTANT >= GEN_4 - && gBattleMons[battler].status1 & STATUS1_PARALYSIS - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; - BattleScriptExecute(BattleScript_BerryCurePrlzEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_PSN: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_PSN_ANY) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptExecute(BattleScript_BerryCurePsnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_BRN: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_BURN) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_BURN; - BattleScriptExecute(BattleScript_BerryCureBrnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_FRZ: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_FREEZE) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FREEZE; - BattleScriptExecute(BattleScript_BerryCureFrzEnd2); - effect = ITEM_STATUS_CHANGE; - } - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_FROSTBITE) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; - BattleScriptExecute(BattleScript_BerryCureFrbEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_SLP: - if (B_BERRIES_INSTANT >= GEN_4 - && (gBattleMons[battler].status1 & STATUS1_SLEEP) - && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].volatiles.nightmare = FALSE; - BattleScriptExecute(BattleScript_BerryCureSlpEnd2); - effect = ITEM_STATUS_CHANGE; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - break; - case HOLD_EFFECT_CURE_STATUS: - if (B_BERRIES_INSTANT >= GEN_4) - effect = TryCureStatus(battler, caseID); - break; - case HOLD_EFFECT_RESTORE_HP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, caseID, FALSE); - break; - case HOLD_EFFECT_RESTORE_PCT_HP: - if (B_BERRIES_INSTANT >= GEN_4) - effect = ItemHealHp(battler, gLastUsedItem, caseID, TRUE); - break; - case HOLD_EFFECT_RESTORE_PP: - effect = ItemRestorePp(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_AIR_BALLOON: - effect = ITEM_EFFECT_OTHER; - gBattleScripting.battler = battler; - BattleScriptPushCursorAndCallback(BattleScript_AirBaloonMsgIn); - RecordItemEffectBattle(battler, HOLD_EFFECT_AIR_BALLOON); - break; - case HOLD_EFFECT_ROOM_SERVICE: - if (TryRoomService(battler)) - { - BattleScriptExecute(BattleScript_ConsumableStatRaiseEnd2); - effect = ITEM_STATS_CHANGE; - } - break; - case HOLD_EFFECT_SEEDS: - switch (GetBattlerHoldEffectParam(battler)) - { - case HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_ELECTRIC_TERRAIN, STAT_DEF, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_PARAM_GRASSY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_GRASSY_TERRAIN, STAT_DEF, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_PARAM_MISTY_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_MISTY_TERRAIN, STAT_SPDEF, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN: - effect = TryHandleSeed(battler, STATUS_FIELD_PSYCHIC_TERRAIN, STAT_SPDEF, gLastUsedItem, caseID); - break; - } - break; - case HOLD_EFFECT_BERSERK_GENE: - effect = ConsumeBerserkGene(battler, caseID); - break; - case HOLD_EFFECT_MIRROR_HERB: - effect = TryConsumeMirrorHerb(battler, caseID); - break; - case HOLD_EFFECT_BOOSTER_ENERGY: - effect = TryBoosterEnergy(battler, GetBattlerAbility(battler), caseID); - break; - default: - break; - } - if (effect != 0) - { - gSpecialStatuses[battler].switchInItemDone = TRUE; - gBattlerAttacker = gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - } - } - break; - case ITEMEFFECT_NORMAL: - case ITEMEFFECT_TRY_HEALING: - if (gBattleMons[battler].hp) - { - switch (battlerHoldEffect) - { - case HOLD_EFFECT_RESTORE_HP: - effect = ItemHealHp(battler, gLastUsedItem, caseID, FALSE); - break; - case HOLD_EFFECT_RESTORE_PCT_HP: - effect = ItemHealHp(battler, gLastUsedItem, caseID, TRUE); - break; - case HOLD_EFFECT_RESTORE_PP: - effect = ItemRestorePp(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_WHITE_HERB: - effect = RestoreWhiteHerbStats(battler); - if (effect != 0) - BattleScriptExecute(BattleScript_WhiteHerbEnd2); - break; - case HOLD_EFFECT_BLACK_SLUDGE: - if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) - { - goto LEFTOVERS; - } - else if (!IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) - { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - BattleScriptExecute(BattleScript_ItemHurtEnd2); - effect = ITEM_HP_CHANGE; - RecordItemEffectBattle(battler, battlerHoldEffect); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - } - break; - case HOLD_EFFECT_LEFTOVERS: - LEFTOVERS: - if (gBattleMons[battler].hp < gBattleMons[battler].maxHP - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - gBattleStruct->moveDamage[battler] *= -1; - BattleScriptExecute(BattleScript_ItemHealHP_End2); - effect = ITEM_HP_CHANGE; - RecordItemEffectBattle(battler, battlerHoldEffect); - } - break; - case HOLD_EFFECT_CONFUSE_SPICY: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SPICY, caseID); - break; - case HOLD_EFFECT_CONFUSE_DRY: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_DRY, caseID); - break; - case HOLD_EFFECT_CONFUSE_SWEET: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SWEET, caseID); - break; - case HOLD_EFFECT_CONFUSE_BITTER: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_BITTER, caseID); - break; - case HOLD_EFFECT_CONFUSE_SOUR: - effect = HealConfuseBerry(battler, gLastUsedItem, FLAVOR_SOUR, caseID); - break; - case HOLD_EFFECT_ATTACK_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_ATK, caseID); - break; - case HOLD_EFFECT_DEFENSE_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_DEF, caseID); - break; - case HOLD_EFFECT_SPEED_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPEED, caseID); - break; - case HOLD_EFFECT_SP_ATTACK_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPATK, caseID); - break; - case HOLD_EFFECT_SP_DEFENSE_UP: - effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, caseID); - break; - case HOLD_EFFECT_CRITICAL_UP: - if (!(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) - && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) - { - gBattleMons[battler].volatiles.focusEnergy = TRUE; - gBattleScripting.battler = battler; - BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_RANDOM_STAT_UP: - effect = RandomStatRaiseBerry(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_CURE_PAR: - if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_PARALYSIS; - BattleScriptExecute(BattleScript_BerryCurePrlzEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_PSN: - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptExecute(BattleScript_BerryCurePsnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_BRN: - if (gBattleMons[battler].status1 & STATUS1_BURN && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_BURN; - BattleScriptExecute(BattleScript_BerryCureBrnEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_FRZ: - if (gBattleMons[battler].status1 & STATUS1_FREEZE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FREEZE; - BattleScriptExecute(BattleScript_BerryCureFrzEnd2); - effect = ITEM_STATUS_CHANGE; - } - if (gBattleMons[battler].status1 & STATUS1_FROSTBITE && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_FROSTBITE; - BattleScriptExecute(BattleScript_BerryCureFrbEnd2); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_CURE_SLP: - if (gBattleMons[battler].status1 & STATUS1_SLEEP && !UnnerveOn(battler, gLastUsedItem)) - { - gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].volatiles.nightmare = FALSE; - BattleScriptExecute(BattleScript_BerryCureSlpEnd2); - effect = ITEM_STATUS_CHANGE; - TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - } - break; - case HOLD_EFFECT_CURE_CONFUSION: - if (gBattleMons[battler].volatiles.confusionTurns > 0 && !UnnerveOn(battler, gLastUsedItem)) - { - RemoveConfusionStatus(battler); - BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_CURE_STATUS: - effect = TryCureStatus(battler, caseID); - break; - case HOLD_EFFECT_MENTAL_HERB: - if (GetMentalHerbEffect(battler)) - { - gBattleScripting.savedBattler = gBattlerAttacker; - gBattlerAttacker = battler; - BattleScriptExecute(BattleScript_MentalHerbCureEnd2); - effect = ITEM_EFFECT_OTHER; - } - break; - case HOLD_EFFECT_MICLE_BERRY: - effect = TrySetMicleBerry(battler, gLastUsedItem, caseID); - break; - case HOLD_EFFECT_BERSERK_GENE: - effect = ConsumeBerserkGene(battler, caseID); - break; - case HOLD_EFFECT_MIRROR_HERB: - effect = TryConsumeMirrorHerb(battler, caseID); - break; - default: - break; - } - - if (effect != 0) - { - gBattlerAttacker = gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - } - } - break; - case ITEMEFFECT_USE_LAST_ITEM: - effect = ItemEffectMoveEnd(battler, GetItemHoldEffect(gLastUsedItem)); - gBattleScripting.overrideBerryRequirements = 2; // to exit VARIOUS_CONSUME_BERRIES - if (effect) - { - gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - break; - } - break; - case ITEMEFFECT_MOVE_END: - for (battler = 0; battler < gBattlersCount; battler++) - { - // If item can be knocked off berry activation will be blocked, but not other items - if (gBattleStruct->battlerState[battler].itemCanBeKnockedOff - && (GetItemPocket(gBattleMons[battler].item) == POCKET_BERRIES - || GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RESTORE_HP)) - continue; - - gLastUsedItem = gBattleMons[battler].item; - effect = ItemEffectMoveEnd(battler, GetBattlerHoldEffect(battler, TRUE)); - if (effect) - { - gPotentialItemEffectBattler = gBattleScripting.battler = battler; - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - break; - } - } - break; - case ITEMEFFECT_KINGSROCK: - // Occur on each hit of a multi-strike move - switch (atkHoldEffect) - { - case HOLD_EFFECT_FLINCH: - if (!MoveIgnoresKingsRock(gCurrentMove) - && !MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_FLINCH) - && IsBattlerTurnDamaged(gBattlerTarget) - && IsBattlerAlive(gBattlerTarget)) - { - u16 ability = GetBattlerAbility(gBattlerAttacker); - if (B_SERENE_GRACE_BOOST >= GEN_5 && ability == ABILITY_SERENE_GRACE) - atkHoldEffectParam *= 2; - if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_RAINBOW && gCurrentMove != MOVE_SECRET_POWER) - atkHoldEffectParam *= 2; - if (ability != ABILITY_STENCH && RandomPercentage(RNG_HOLD_EFFECT_FLINCH, atkHoldEffectParam)) - { - gBattleScripting.moveEffect = MOVE_EFFECT_FLINCH; - BattleScriptPushCursor(); - SetMoveEffect(gBattlerAttacker, gBattlerTarget, FALSE, FALSE); - BattleScriptPop(); - } - } - break; - case HOLD_EFFECT_BLUNDER_POLICY: - if (gBattleStruct->blunderPolicy - && IsBattlerAlive(gBattlerAttacker) - && CompareStat(gBattlerAttacker, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, GetBattlerAbility(gBattlerAttacker))) - { - gBattleStruct->blunderPolicy = FALSE; - gLastUsedItem = atkItem; - SET_STATCHANGER(STAT_SPEED, 2, FALSE); - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_AttackerItemStatRaise); - } - break; - default: - break; - } - break; - case ITEMEFFECT_LIFEORB_SHELLBELL: - // Occur after the final hit of a multi-strike move - switch (atkHoldEffect) - { - case HOLD_EFFECT_SHELL_BELL: - if (gBattleScripting.savedDmg > 0 - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) - && gBattlerAttacker != gBattlerTarget - && !IsBattlerAtMaxHp(gBattlerAttacker) - && IsBattlerAlive(gBattlerAttacker) - && GetMoveEffect(gCurrentMove) != EFFECT_FUTURE_SIGHT - && GetMoveEffect(gCurrentMove) != EFFECT_PAIN_SPLIT - && (B_HEAL_BLOCKING < GEN_5 || !gBattleMons[battler].volatiles.healBlock)) - { - gLastUsedItem = atkItem; - gPotentialItemEffectBattler = gBattlerAttacker; - gBattleScripting.battler = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerAttacker] = (gBattleScripting.savedDmg / atkHoldEffectParam) * -1; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = -1; - BattleScriptCall(BattleScript_ItemHealHP_Ret); - effect = ITEM_HP_CHANGE; - } - break; - case HOLD_EFFECT_LIFE_ORB: - if (IsBattlerAlive(gBattlerAttacker) - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleScripting.savedDmg > 0) - && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_MAGIC_GUARD) - && !IsFutureSightAttackerInParty(gBattlerAttacker, gBattlerTarget, gCurrentMove)) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 10; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_ItemHurtRet); - gLastUsedItem = atkItem; - } - break; - default: - break; - } - break; - case ITEMEFFECT_TARGET: - if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) - { - moveType = GetBattleMoveType(gCurrentMove); - switch (battlerHoldEffect) - { - case HOLD_EFFECT_AIR_BALLOON: - if (IsBattlerTurnDamaged(gBattlerTarget)) - { - effect = ITEM_EFFECT_OTHER; - BattleScriptCall(BattleScript_AirBaloonMsgPop); - } - break; - case HOLD_EFFECT_ROCKY_HELMET: - if (IsBattlerTurnDamaged(gBattlerTarget) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove) - && IsBattlerAlive(gBattlerAttacker) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 6; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_RockyHelmetActivates); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - RecordItemEffectBattle(battler, HOLD_EFFECT_ROCKY_HELMET); - } - break; - case HOLD_EFFECT_WEAKNESS_POLICY: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_SUPER_EFFECTIVE) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_WeaknessPolicy); - } - break; - case HOLD_EFFECT_SNOWBALL: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_ICE) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_ATK, 1, FALSE); - } - break; - case HOLD_EFFECT_LUMINOUS_MOSS: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_WATER) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_SPDEF, 1, FALSE); - } - break; - case HOLD_EFFECT_CELL_BATTERY: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_ELECTRIC) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_ATK, 1, FALSE); - } - break; - case HOLD_EFFECT_ABSORB_BULB: - if (IsBattlerAlive(battler) - && IsBattlerTurnDamaged(gBattlerTarget) - && moveType == TYPE_WATER) - { - effect = ITEM_STATS_CHANGE; - BattleScriptCall(BattleScript_TargetItemStatRaise); - SET_STATCHANGER(STAT_SPATK, 1, FALSE); - } - break; - case HOLD_EFFECT_ENIGMA_BERRY: // consume and heal if hit by super effective move - effect = TrySetEnigmaBerry(battler); - break; - case HOLD_EFFECT_JABOCA_BERRY: // consume and damage attacker if used physical move - if (IsBattlerAlive(gBattlerAttacker) - && IsBattlerTurnDamaged(gBattlerTarget) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IsBattleMovePhysical(gCurrentMove) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[gBattlerAttacker] *= 2; - - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_JabocaRowapBerryActivates); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - RecordItemEffectBattle(battler, HOLD_EFFECT_JABOCA_BERRY); - } - break; - case HOLD_EFFECT_ROWAP_BERRY: // consume and damage attacker if used special move - if (IsBattlerAlive(gBattlerAttacker) - && IsBattlerTurnDamaged(gBattlerTarget) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IsBattleMoveSpecial(gCurrentMove) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; - if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) - gBattleStruct->moveDamage[gBattlerAttacker] = 1; - if (GetBattlerAbility(battler) == ABILITY_RIPEN) - gBattleStruct->moveDamage[gBattlerAttacker] *= 2; - - effect = ITEM_HP_CHANGE; - BattleScriptCall(BattleScript_JabocaRowapBerryActivates); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - RecordItemEffectBattle(battler, HOLD_EFFECT_ROWAP_BERRY); - } - break; - case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move - effect = DamagedStatBoostBerryEffect(battler, STAT_DEF, DAMAGE_CATEGORY_PHYSICAL); - break; - case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move - effect = DamagedStatBoostBerryEffect(battler, STAT_SPDEF, DAMAGE_CATEGORY_SPECIAL); - break; - case HOLD_EFFECT_CURE_STATUS: // only Toxic Chain's interaction with Knock Off - case HOLD_EFFECT_CURE_PSN: - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem) && GetBattlerAbility(gBattlerAttacker) == ABILITY_TOXIC_CHAIN && GetMoveEffect(gCurrentMove) == EFFECT_KNOCK_OFF) - { - gBattleScripting.battler = battler; - gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); - BattleScriptExecute(BattleScript_BerryCurePsnEnd2); - BtlController_EmitSetMonData(battler, 0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - effect = ITEM_STATUS_CHANGE; - } - break; - case HOLD_EFFECT_STICKY_BARB: - if (IsBattlerTurnDamaged(gBattlerTarget) - && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IsBattlerAlive(gBattlerAttacker) - && CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item) - && gBattleMons[gBattlerAttacker].item == ITEM_NONE) - { - // No sticky hold checks. - gEffectBattler = battler; // gEffectBattler = target - StealTargetItem(gBattlerAttacker, gBattlerTarget); // Attacker takes target's barb - BattleScriptCall(BattleScript_StickyBarbTransfer); - effect = ITEM_EFFECT_OTHER; - } - break; - default: - break; - } - } - break; - case ITEMEFFECT_ORBS: - { - u16 battlerAbility = GetBattlerAbility(battler); - switch (battlerHoldEffect) - { - case HOLD_EFFECT_TOXIC_ORB: - if (CanBePoisoned(battler, battler, battlerAbility, battlerAbility)) // Can corrosion trigger toxic orb on itself? - { - effect = ITEM_STATUS_CHANGE; - gBattleMons[battler].status1 = STATUS1_TOXIC_POISON; - BattleScriptExecute(BattleScript_ToxicOrb); - RecordItemEffectBattle(battler, battlerHoldEffect); - } - break; - case HOLD_EFFECT_FLAME_ORB: - if (CanBeBurned(battler, battler, battlerAbility)) - { - effect = ITEM_STATUS_CHANGE; - gBattleMons[battler].status1 = STATUS1_BURN; - BattleScriptExecute(BattleScript_FlameOrb); - RecordItemEffectBattle(battler, battlerHoldEffect); - } - break; - case HOLD_EFFECT_STICKY_BARB: // Not an orb per se, but similar effect, and needs to NOT activate with pickpocket - if (battlerAbility != ABILITY_MAGIC_GUARD) - { - gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 8; - if (gBattleStruct->moveDamage[battler] == 0) - gBattleStruct->moveDamage[battler] = 1; - BattleScriptExecute(BattleScript_ItemHurtEnd2); - effect = ITEM_HP_CHANGE; - RecordItemEffectBattle(battler, battlerHoldEffect); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - } - break; - default: - break; - } - - if (effect == ITEM_STATUS_CHANGE) - { - BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); - MarkBattlerForControllerExec(battler); - } - } - break; - case ITEMEFFECT_STATS_CHANGED: - switch (battlerHoldEffect) - { - case HOLD_EFFECT_WHITE_HERB: - effect = RestoreWhiteHerbStats(battler); - if (effect != 0) - BattleScriptCall(BattleScript_WhiteHerbRet); - break; - default: - break; - } - break; - } - - // Berry was successfully used on a Pokemon. - if (effect && (gLastUsedItem >= FIRST_BERRY_INDEX && gLastUsedItem <= LAST_BERRY_INDEX)) - GetBattlerPartyState(battler)->ateBerry = TRUE; - - return effect; -} - void ClearVariousBattlerFlags(u32 battler) { gDisableStructs[battler].furyCutterCounter = 0; - gBattleMons[battler].volatiles.destinyBond = FALSE; + gBattleMons[battler].volatiles.destinyBond = 0; gBattleMons[battler].volatiles.glaiveRush = FALSE; gBattleMons[battler].volatiles.grudge = FALSE; } @@ -7426,7 +6323,7 @@ u32 GetBattleMoveTarget(u16 move, u8 setTarget) { u8 targetBattler = 0; u32 moveTarget, side; - u32 moveType = GetBattleMoveType(move); + enum Type moveType = GetBattleMoveType(move); if (setTarget != NO_TARGET_OVERRIDE) moveTarget = setTarget - 1; @@ -7444,7 +6341,7 @@ u32 GetBattleMoveTarget(u16 move, u8 setTarget) } else { - u32 battlerAbilityOnField = 0; + enum Ability battlerAbilityOnField = 0; targetBattler = SetRandomTarget(gBattlerAttacker); if (moveType == TYPE_ELECTRIC && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) @@ -7458,7 +6355,7 @@ u32 GetBattleMoveTarget(u16 move, u8 setTarget) { targetBattler = battlerAbilityOnField - 1; RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); - gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + gSpecialStatuses[targetBattler].abilityRedirected = TRUE; } } else if (moveType == TYPE_WATER && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) @@ -7472,7 +6369,7 @@ u32 GetBattleMoveTarget(u16 move, u8 setTarget) { targetBattler = battlerAbilityOnField - 1; RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); - gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + gSpecialStatuses[targetBattler].abilityRedirected = TRUE; } } } @@ -7481,7 +6378,7 @@ u32 GetBattleMoveTarget(u16 move, u8 setTarget) case MOVE_TARGET_BOTH: case MOVE_TARGET_FOES_AND_ALLY: targetBattler = GetOpposingSideBattler(gBattlerAttacker); - if (!IsBattlerAlive(targetBattler)) + if (IsDoubleBattle() && !IsBattlerAlive(targetBattler)) targetBattler ^= BIT_FLANK; break; case MOVE_TARGET_OPPONENTS_FIELD: @@ -7616,27 +6513,24 @@ u8 GetAttackerObedienceForAction() } } -enum ItemHoldEffect GetBattlerHoldEffect(u32 battler, bool32 checkNegating) +enum HoldEffect GetBattlerHoldEffect(u32 battler) { - return GetBattlerHoldEffectInternal(battler, checkNegating, TRUE); + return GetBattlerHoldEffectInternal(battler, GetBattlerAbility(battler)); } -enum ItemHoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating) +enum HoldEffect GetBattlerHoldEffectIgnoreAbility(u32 battler) { - return GetBattlerHoldEffectInternal(battler, checkNegating, FALSE); + return GetBattlerHoldEffectInternal(battler, ABILITY_NONE); } -enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegating, bool32 checkAbility) +enum HoldEffect GetBattlerHoldEffectInternal(u32 battler, u32 ability) { - if (checkNegating) - { - if (gBattleMons[battler].volatiles.embargo) - return HOLD_EFFECT_NONE; - if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) - return HOLD_EFFECT_NONE; - if (checkAbility && GetBattlerAbility(battler) == ABILITY_KLUTZ && !gBattleMons[battler].volatiles.gastroAcid) - return HOLD_EFFECT_NONE; - } + if (gBattleMons[battler].volatiles.embargo) + return HOLD_EFFECT_NONE; + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) + return HOLD_EFFECT_NONE; + if (ability == ABILITY_KLUTZ && !gBattleMons[battler].volatiles.gastroAcid) + return HOLD_EFFECT_NONE; gPotentialItemEffectBattler = battler; @@ -7646,12 +6540,13 @@ enum ItemHoldEffect GetBattlerHoldEffectInternal(u32 battler, bool32 checkNegati return GetItemHoldEffect(gBattleMons[battler].item); } -static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item) +enum HoldEffect GetBattlerHoldEffectIgnoreNegation(u32 battler) { - if (item == ITEM_ENIGMA_BERRY_E_READER) - return gEnigmaBerries[battler].holdEffectParam; + gPotentialItemEffectBattler = battler; + if (gBattleMons[battler].item == ITEM_ENIGMA_BERRY_E_READER) + return gEnigmaBerries[battler].holdEffect; else - return GetItemHoldEffectParam(item); + return GetItemHoldEffect(gBattleMons[battler].item); } u32 GetBattlerHoldEffectParam(u32 battler) @@ -7662,7 +6557,7 @@ u32 GetBattlerHoldEffectParam(u32 battler) return GetItemHoldEffectParam(gBattleMons[battler].item); } -bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move) +bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move) { if (holdEffectAtk == HOLD_EFFECT_PROTECTIVE_PADS) { @@ -7673,7 +6568,7 @@ bool32 CanBattlerAvoidContactEffects(u32 battlerAtk, u32 battlerDef, u32 ability return !IsMoveMakingContact(battlerAtk, battlerDef, abilityAtk, holdEffectAtk, move); } -bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, enum ItemHoldEffect holdEffectAtk, u32 move) +bool32 IsMoveMakingContact(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum HoldEffect holdEffectAtk, u32 move) { if (!(MoveMakesContact(move) || (GetMoveEffect(move) == EFFECT_SHELL_SIDE_ARM && gBattleStruct->shellSideArmCategory[battlerAtk][battlerDef] == DAMAGE_CATEGORY_PHYSICAL))) @@ -7710,7 +6605,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) if (IsZMove(move) || IsMaxMove(move)) return FALSE; // Z-Moves and Max Moves bypass protection (except Max Guard). if (GetBattlerAbility(battlerAtk) == ABILITY_UNSEEN_FIST - && IsMoveMakingContact(battlerAtk, battlerDef, ABILITY_UNSEEN_FIST, GetBattlerHoldEffect(battlerAtk, TRUE), move)) + && IsMoveMakingContact(battlerAtk, battlerDef, ABILITY_UNSEEN_FIST, GetBattlerHoldEffect(battlerAtk), move)) return FALSE; } @@ -7791,11 +6686,9 @@ enum IronBallCheck }; // Only called directly when calculating damage type effectiveness, and Iron Ball's type effectiveness mechanics -static bool32 IsBattlerGroundedInverseCheck(u32 battler, u32 ability, enum InverseBattleCheck checkInverse, enum IronBallCheck checkIronBall, bool32 isAnticipation) +static bool32 IsBattlerGroundedInverseCheck(u32 battler, enum Ability ability, enum HoldEffect holdEffect, enum InverseBattleCheck checkInverse, bool32 isAnticipation) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); - - if (!(checkIronBall == IGNORE_IRON_BALL) && holdEffect == HOLD_EFFECT_IRON_BALL) + if (holdEffect == HOLD_EFFECT_IRON_BALL) return TRUE; if (gFieldStatuses & STATUS_FIELD_GRAVITY && isAnticipation == FALSE) return TRUE; @@ -7811,14 +6704,14 @@ static bool32 IsBattlerGroundedInverseCheck(u32 battler, u32 ability, enum Inver return FALSE; if (ability == ABILITY_LEVITATE) return FALSE; - if (IS_BATTLER_OF_TYPE(battler, TYPE_FLYING) && (!(checkInverse == INVERSE_BATTLE) || !FlagGet(B_FLAG_INVERSE_BATTLE))) + if (IS_BATTLER_OF_TYPE(battler, TYPE_FLYING) && (checkInverse != INVERSE_BATTLE || !FlagGet(B_FLAG_INVERSE_BATTLE))) return FALSE; return TRUE; } -bool32 IsBattlerGrounded(u32 battler) +bool32 IsBattlerGrounded(u32 battler, enum Ability ability, enum HoldEffect holdEffect) { - return IsBattlerGroundedInverseCheck(battler, GetBattlerAbility(battler), NOT_INVERSE_BATTLE, CHECK_IRON_BALL, FALSE); + return IsBattlerGroundedInverseCheck(battler, ability, holdEffect, NOT_INVERSE_BATTLE, FALSE); } u32 GetMoveSlot(u16 *moves, u32 move) @@ -7837,8 +6730,8 @@ u32 GetBattlerWeight(u32 battler) { u32 i; u32 weight = GetSpeciesWeight(gBattleMons[battler].species); - u32 ability = GetBattlerAbility(battler); - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); + enum Ability ability = GetBattlerAbility(battler); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); if (ability == ABILITY_HEAVY_METAL) weight *= 2; @@ -7869,7 +6762,7 @@ u32 GetBattlerWeight(u32 battler) u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc) { - u32 i; + enum Stat i; u32 count = 0; for (i = 0; i < NUM_BATTLE_STATS; i++) @@ -8026,7 +6919,7 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter) return basePower; } -static inline u32 IsFieldMudSportAffected(u32 moveType) +static inline u32 IsFieldMudSportAffected(enum Type moveType) { if (moveType == TYPE_ELECTRIC && (gFieldStatuses & STATUS_FIELD_MUDSPORT)) return TRUE; @@ -8043,7 +6936,7 @@ static inline u32 IsFieldMudSportAffected(u32 moveType) return FALSE; } -static inline u32 IsFieldWaterSportAffected(u32 moveType) +static inline u32 IsFieldWaterSportAffected(enum Type moveType) { if (moveType == TYPE_FIRE && (gFieldStatuses & STATUS_FIELD_WATERSPORT)) return TRUE; @@ -8072,7 +6965,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) u32 weight, hpFraction, speed; if (GetActiveGimmick(battlerAtk) == GIMMICK_Z_MOVE) - return GetZMovePower(gBattleStruct->zmove.baseMoves[battlerAtk]); + return GetZMovePower(gCurrentMove); if (GetActiveGimmick(battlerAtk) == GIMMICK_DYNAMAX) return GetMaxMovePower(move); @@ -8166,7 +7059,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) case EFFECT_ACROBATICS: if (gBattleMons[battlerAtk].item == ITEM_NONE // Edge case, because removal of items happens after damage calculation. - || (gSpecialStatuses[battlerAtk].gemBoost && GetBattlerHoldEffect(battlerAtk, FALSE) == HOLD_EFFECT_GEMS)) + || (gSpecialStatuses[battlerAtk].gemBoost && GetBattlerHoldEffect(battlerAtk) == HOLD_EFFECT_GEMS)) basePower *= 2; break; case EFFECT_LOW_KICK: @@ -8197,21 +7090,21 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower += (CountBattlerStatIncreases(battlerAtk, TRUE) * 20); break; case EFFECT_ELECTRO_BALL: - speed = GetBattlerTotalSpeedStat(battlerAtk) / GetBattlerTotalSpeedStat(battlerDef); + speed = GetBattlerTotalSpeedStat(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk) / GetBattlerTotalSpeedStat(battlerDef, ctx->abilityDef, ctx->holdEffectDef); if (speed >= ARRAY_COUNT(sSpeedDiffPowerTable)) speed = ARRAY_COUNT(sSpeedDiffPowerTable) - 1; basePower = sSpeedDiffPowerTable[speed]; break; case EFFECT_GYRO_BALL: { - u32 attackerSpeed = GetBattlerTotalSpeedStat(battlerAtk); + u32 attackerSpeed = GetBattlerTotalSpeedStat(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk); if (attackerSpeed == 0) { basePower = 1; } else { - basePower = ((25 * GetBattlerTotalSpeedStat(battlerDef)) / attackerSpeed) + 1; + basePower = ((25 * GetBattlerTotalSpeedStat(battlerDef, ctx->abilityDef, ctx->holdEffectDef)) / attackerSpeed) + 1; if (basePower > 150) basePower = 150; } @@ -8252,7 +7145,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower *= 2; break; case EFFECT_MISTY_EXPLOSION: - if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_MISTY_TERRAIN)) + if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_MISTY_TERRAIN)) basePower = uq4_12_multiply(basePower, UQ_4_12(1.5)); break; case EFFECT_DYNAMAX_DOUBLE_DMG: @@ -8279,15 +7172,15 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower = uq4_12_multiply(basePower, UQ_4_12(1.5)); break; case EFFECT_TERRAIN_PULSE: - if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_TERRAIN_ANY)) + if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_TERRAIN_ANY)) basePower *= 2; break; case EFFECT_EXPANDING_FORCE: - if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN)) + if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_PSYCHIC_TERRAIN)) basePower = uq4_12_multiply(basePower, UQ_4_12(1.5)); break; case EFFECT_RISING_VOLTAGE: - if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_ELECTRIC_TERRAIN)) + if (IsBattlerTerrainAffected(battlerDef, ctx->abilityDef, ctx->holdEffectDef, STATUS_FIELD_ELECTRIC_TERRAIN)) basePower *= 2; break; case EFFECT_BEAT_UP: @@ -8299,7 +7192,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower = uq4_12_multiply(basePower, UQ_4_12(1.5)); break; case EFFECT_MAX_MOVE: - basePower = GetMaxMovePower(gBattleMons[battlerAtk].moves[gBattleStruct->chosenMovePositions[battlerAtk]]); + basePower = GetMaxMovePower(GetChosenMoveFromPosition(battlerAtk)); break; case EFFECT_RAGE_FIST: basePower += 50 * GetBattlerPartyState(battlerAtk)->timesGotHit; @@ -8341,7 +7234,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) u32 battlerAtk = ctx->battlerAtk; u32 battlerDef = ctx->battlerDef; u32 move = ctx->move; - u32 moveType = ctx->moveType; + enum Type moveType = ctx->moveType; enum BattleMoveEffects moveEffect = GetMoveEffect(move); uq4_12_t holdEffectModifier; @@ -8392,17 +7285,17 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) if (gSpecialStatuses[battlerAtk].gemBoost) modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12(gSpecialStatuses[battlerAtk].gemParam))); - if (gBattleMons[battlerAtk].volatiles.charge && moveType == TYPE_ELECTRIC) + if (moveType == TYPE_ELECTRIC && gBattleMons[battlerAtk].volatiles.chargeTimer > 0) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); - if (GetMoveEffect(gChosenMove) == EFFECT_ME_FIRST) + if (GetMoveEffect(ctx->chosenMove) == EFFECT_ME_FIRST) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); - if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_GRASSY_TERRAIN) && moveType == TYPE_GRASS) + if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_GRASSY_TERRAIN) && moveType == TYPE_GRASS) modifier = uq4_12_multiply(modifier, (B_TERRAIN_TYPE_BOOST >= GEN_8 ? UQ_4_12(1.3) : UQ_4_12(1.5))); - if (IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN) && moveType == TYPE_DRAGON) + if (IsBattlerTerrainAffected(battlerDef, ctx->abilityDef, ctx->holdEffectDef, STATUS_FIELD_MISTY_TERRAIN) && moveType == TYPE_DRAGON) modifier = uq4_12_multiply(modifier, UQ_4_12(0.5)); - if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_ELECTRIC_TERRAIN) && moveType == TYPE_ELECTRIC) + if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_ELECTRIC_TERRAIN) && moveType == TYPE_ELECTRIC) modifier = uq4_12_multiply(modifier, (B_TERRAIN_TYPE_BOOST >= GEN_8 ? UQ_4_12(1.3) : UQ_4_12(1.5))); - if (IsBattlerTerrainAffected(battlerAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && moveType == TYPE_PSYCHIC) + if (IsBattlerTerrainAffected(battlerAtk, ctx->abilityAtk, ctx->holdEffectAtk, STATUS_FIELD_PSYCHIC_TERRAIN) && moveType == TYPE_PSYCHIC) modifier = uq4_12_multiply(modifier, (B_TERRAIN_TYPE_BOOST >= GEN_8 ? UQ_4_12(1.3) : UQ_4_12(1.5))); if (IsFieldMudSportAffected(ctx->moveType)) modifier = uq4_12_multiply(modifier, UQ_4_12(B_SPORT_DMG_REDUCTION >= GEN_5 ? 0.33 : 0.5)); @@ -8506,6 +7399,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) case ABILITY_SUPREME_OVERLORD: modifier = uq4_12_multiply(modifier, GetSupremeOverlordModifier(battlerAtk)); break; + default: + break; } // field abilities @@ -8534,6 +7429,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) if (moveType == TYPE_STEEL) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; + default: + break; } } @@ -8555,7 +7452,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) break; case ABILITY_PROTOSYNTHESIS: { - u32 defHighestStat = GetParadoxBoostedStatId(battlerDef); + enum Stat defHighestStat = GetParadoxBoostedStatId(battlerDef); if (((ctx->weather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battlerDef].boosterEnergyActivated) && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) && !(gBattleMons[battlerDef].volatiles.transformed)) @@ -8571,6 +7468,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); } break; + default: + break; } holdEffectParamAtk = GetBattlerHoldEffectParam(battlerAtk); @@ -8643,6 +7542,26 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) return uq4_12_multiply_by_int_half_down(modifier, basePower); } +static bool32 IsRuinStatusActive(u32 fieldEffect) +{ + bool32 isNeutralizingGasOnField = IsNeutralizingGasOnField(); + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + // Mold Breaker doesn't ignore Ruin field status but Gastro Acid and Neutralizing Gas do + if (gBattleMons[battler].volatiles.gastroAcid) + continue; + if (GetBattlerHoldEffectIgnoreAbility(battler) != HOLD_EFFECT_ABILITY_SHIELD + && isNeutralizingGasOnField + && gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS) + continue; + + if (GetBattlerVolatile(battler, fieldEffect)) + return TRUE; + } + + return FALSE; +} + static inline uq4_12_t ApplyOffensiveBadgeBoost(uq4_12_t modifier, u32 battler, u32 move) { if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_ATTACK, battler) && IsBattleMovePhysical(move)) @@ -8670,7 +7589,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) u32 battlerAtk = ctx->battlerAtk; u32 battlerDef = ctx->battlerDef; u32 move = ctx->move; - u32 moveType = ctx->moveType; + enum Type moveType = ctx->moveType; enum BattleMoveEffects moveEffect = GetMoveEffect(move); atkBaseSpeciesId = GET_BASE_SPECIES_ID(gBattleMons[battlerAtk].species); @@ -8744,7 +7663,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case ABILITY_SLOW_START: - if (gDisableStructs[battlerAtk].slowStartTimer > gBattleTurnCounter) + if (gDisableStructs[battlerAtk].slowStartTimer > 0) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5)); break; case ABILITY_SOLAR_POWER: @@ -8778,7 +7697,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) case ABILITY_PLUS: if (IsBattleMoveSpecial(move) && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) { - u32 partnerAbility = GetBattlerAbility(BATTLE_PARTNER(battlerAtk)); + enum Ability partnerAbility = GetBattlerAbility(BATTLE_PARTNER(battlerAtk)); if (partnerAbility == ABILITY_MINUS || (B_PLUS_MINUS_INTERACTION >= GEN_5 && partnerAbility == ABILITY_PLUS)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); @@ -8787,7 +7706,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) case ABILITY_MINUS: if (IsBattleMoveSpecial(move) && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) { - u32 partnerAbility = GetBattlerAbility(BATTLE_PARTNER(battlerAtk)); + enum Ability partnerAbility = GetBattlerAbility(BATTLE_PARTNER(battlerAtk)); if (partnerAbility == ABILITY_PLUS || (B_PLUS_MINUS_INTERACTION >= GEN_5 && partnerAbility == ABILITY_MINUS)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); @@ -8833,7 +7752,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) case ABILITY_PROTOSYNTHESIS: if (!(gBattleMons[battlerAtk].volatiles.transformed)) { - u32 atkHighestStat = GetParadoxBoostedStatId(battlerAtk); + enum Stat atkHighestStat = GetParadoxBoostedStatId(battlerAtk); if (((ctx->weather & B_WEATHER_SUN) && HasWeatherEffect()) || gDisableStructs[battlerAtk].boosterEnergyActivated) { if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) @@ -8844,7 +7763,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) case ABILITY_QUARK_DRIVE: if (!(gBattleMons[battlerAtk].volatiles.transformed)) { - u32 atkHighestStat = GetParadoxBoostedStatId(battlerAtk); + enum Stat atkHighestStat = GetParadoxBoostedStatId(battlerAtk); if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerAtk].boosterEnergyActivated) { if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) @@ -8860,6 +7779,8 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && IsBattleMoveSpecial(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3333)); break; + default: + break; } // target's abilities @@ -8881,6 +7802,8 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) RecordAbilityBattle(battlerDef, ABILITY_PURIFYING_SALT); } break; + default: + break; } // ally's abilities @@ -8892,14 +7815,16 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) if (gBattleMons[BATTLE_PARTNER(battlerAtk)].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerAtk), B_WEATHER_SUN) && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; + default: + break; } } - // field abilities - if (IsAbilityOnField(ABILITY_VESSEL_OF_RUIN) && ctx->abilityAtk != ABILITY_VESSEL_OF_RUIN && IsBattleMoveSpecial(move)) + // Ruin field effects + if (IsBattleMoveSpecial(move) && !gBattleMons[ctx->battlerAtk].volatiles.vesselOfRuin && IsRuinStatusActive(VOLATILE_VESSEL_OF_RUIN)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75)); - if (IsAbilityOnField(ABILITY_TABLETS_OF_RUIN) && ctx->abilityAtk != ABILITY_TABLETS_OF_RUIN && IsBattleMovePhysical(move)) + if (IsBattleMovePhysical(move) && !gBattleMons[ctx->battlerAtk].volatiles.tabletsOfRuin && IsRuinStatusActive(VOLATILE_TABLETS_OF_RUIN)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75)); // attacker's hold effect @@ -9048,6 +7973,8 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) if (gBattleMons[battlerDef].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && !usesDefStat) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; + default: + break; } // ally's abilities @@ -9059,14 +7986,16 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) if (gBattleMons[BATTLE_PARTNER(battlerDef)].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerDef), B_WEATHER_SUN) && !usesDefStat) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; + default: + break; } } - // field abilities - if (IsAbilityOnField(ABILITY_SWORD_OF_RUIN) && ctx->abilityDef != ABILITY_SWORD_OF_RUIN && usesDefStat) + // Ruin field effects + if (usesDefStat && !gBattleMons[ctx->battlerDef].volatiles.swordOfRuin && IsRuinStatusActive(VOLATILE_SWORD_OF_RUIN)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75)); - if (IsAbilityOnField(ABILITY_BEADS_OF_RUIN) && ctx->abilityDef != ABILITY_BEADS_OF_RUIN && !usesDefStat) + if (!usesDefStat && !gBattleMons[ctx->battlerDef].volatiles.beadsOfRuin && IsRuinStatusActive(VOLATILE_BEADS_OF_RUIN)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75)); // target's hold effects @@ -9267,7 +8196,7 @@ static inline uq4_12_t GetCollisionCourseElectroDriftModifier(u32 move, uq4_12_t return UQ_4_12(1.0); } -static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, bool32 isCrit, u32 abilityAtk) +static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, bool32 isCrit, enum Ability abilityAtk) { switch (abilityAtk) { @@ -9283,6 +8212,8 @@ static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typ if (typeEffectivenessModifier <= UQ_4_12(0.5)) return UQ_4_12(2.0); break; + default: + break; } return UQ_4_12(1.0); } @@ -9337,6 +8268,8 @@ static inline uq4_12_t GetDefenderAbilitiesModifier(struct DamageContext *ctx) recordAbility = TRUE; } break; + default: + break; } if (recordAbility && ctx->updateFlags) @@ -9355,11 +8288,13 @@ static inline uq4_12_t GetDefenderPartnerAbilitiesModifier(u32 battlerPartnerDef case ABILITY_FRIEND_GUARD: return UQ_4_12(0.75); break; + default: + break; } return UQ_4_12(1.0); } -static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, enum ItemHoldEffect holdEffectAtk) +static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, enum HoldEffect holdEffectAtk) { u32 metronomeTurns; uq4_12_t metronomeBoostBase; @@ -9390,7 +8325,7 @@ static inline uq4_12_t GetDefenderItemsModifier(struct DamageContext *ctx) switch (ctx->holdEffectDef) { case HOLD_EFFECT_RESIST_BERRY: - if (UnnerveOn(ctx->battlerDef, gBattleMons[ctx->battlerDef].item)) + if (IsUnnerveBlocked(ctx->battlerDef, gBattleMons[ctx->battlerDef].item)) return UQ_4_12(1.0); if (ctx->moveType == GetBattlerHoldEffectParam(ctx->battlerDef) && (ctx->moveType == TYPE_NORMAL || ctx->typeEffectivenessModifier >= UQ_4_12(2.0))) { @@ -9498,7 +8433,7 @@ static inline s32 DoMoveDamageCalcVars(struct DamageContext *ctx) s32 ApplyModifiersAfterDmgRoll(struct DamageContext *ctx, s32 dmg) { if (GetActiveGimmick(ctx->battlerAtk) == GIMMICK_TERA) - DAMAGE_APPLY_MODIFIER(GetTeraMultiplier(ctx->battlerAtk, ctx->moveType)); + DAMAGE_APPLY_MODIFIER(GetTeraMultiplier(ctx)); else DAMAGE_APPLY_MODIFIER(GetSameTypeAttackBonusModifier(ctx)); DAMAGE_APPLY_MODIFIER(ctx->typeEffectivenessModifier); @@ -9561,8 +8496,8 @@ static inline s32 DoMoveDamageCalc(struct DamageContext *ctx) ctx->abilityAtk = GetBattlerAbility(ctx->battlerAtk); ctx->abilityDef = GetBattlerAbility(ctx->battlerDef); - ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef, TRUE); - ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk, TRUE); + ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef); + ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk); return DoMoveDamageCalcVars(ctx); } @@ -9575,7 +8510,7 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageContext *ctx) u32 battlerAtk = ctx->battlerAtk; u32 battlerDef = ctx->battlerDef; u32 move = ctx->move; - u32 moveType = ctx->moveType; + enum Type moveType = ctx->moveType; struct Pokemon *party = GetBattlerParty(battlerAtk); struct Pokemon *partyMon = &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]]; @@ -9650,8 +8585,8 @@ s32 CalculateMoveDamage(struct DamageContext *ctx) ctx->weather = GetWeather(); ctx->abilityAtk = GetBattlerAbility(ctx->battlerAtk); ctx->abilityDef = GetBattlerAbility(ctx->battlerDef); - ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk, TRUE); - ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef, TRUE); + ctx->holdEffectAtk = GetBattlerHoldEffect(ctx->battlerAtk); + ctx->holdEffectDef = GetBattlerHoldEffect(ctx->battlerDef); ctx->typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(ctx); @@ -9671,7 +8606,7 @@ s32 CalculateMoveDamageVars(struct DamageContext *ctx) return DoMoveDamageCalcVars(ctx); } -static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *modifier, u32 defType) +static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *modifier, enum Type defType) { uq4_12_t mod = GetTypeModifier(ctx->moveType, defType); @@ -9698,7 +8633,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m mod = UQ_4_12(1.0); if (GetMoveEffect(ctx->move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(ctx->move) && !ctx->isAnticipation) mod = UQ_4_12(2.0); - if (ctx->moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(ctx->battlerDef) && mod == UQ_4_12(0.0)) + if (ctx->moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(ctx->battlerDef, ctx->abilityDef, ctx->holdEffectDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); if (ctx->moveType == TYPE_STELLAR && GetActiveGimmick(ctx->battlerDef) == GIMMICK_TERA) mod = UQ_4_12(2.0); @@ -9724,7 +8659,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m *modifier = uq4_12_multiply(*modifier, mod); } -static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t resultingModifier, u32 illusionSpecies) +static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, enum Type moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t resultingModifier, u32 illusionSpecies) { // Check if the type effectiveness would've been different if the pokemon really had the types as the disguise. uq4_12_t presumedModifier = UQ_4_12(1.0); @@ -9732,13 +8667,13 @@ static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, struct DamageContext ctx = {0}; ctx.battlerAtk = battlerAtk; ctx.battlerDef = battlerDef; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = moveType; ctx.updateFlags = FALSE; ctx.abilityAtk = GetBattlerAbility(battlerAtk); ctx.abilityDef = ABILITY_ILLUSION; - ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); - ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); + ctx.holdEffectAtk = GetBattlerHoldEffect(battlerAtk); + ctx.holdEffectDef = GetBattlerHoldEffect(battlerDef); MulByTypeEffectiveness(&ctx, &presumedModifier, GetSpeciesType(illusionSpecies, 0)); if (GetSpeciesType(illusionSpecies, 1) != GetSpeciesType(illusionSpecies, 0)) @@ -9775,7 +8710,7 @@ void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags) static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageContext *ctx, uq4_12_t modifier) { u32 illusionSpecies; - u32 types[3]; + enum Type types[3]; GetBattlerTypes(ctx->battlerDef, FALSE, types); MulByTypeEffectiveness(ctx, &modifier, types[0]); @@ -9795,7 +8730,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont if (B_GLARE_GHOST < GEN_4 && ctx->move == MOVE_GLARE && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GHOST)) modifier = UQ_4_12(0.0); } - else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, INVERSE_BATTLE, CHECK_IRON_BALL, ctx->isAnticipation) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move))) + else if (ctx->moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, ctx->holdEffectDef, INVERSE_BATTLE, ctx->isAnticipation) && !(MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move))) { modifier = UQ_4_12(0.0); if (ctx->updateFlags && ctx->abilityDef == ABILITY_LEVITATE) @@ -9813,8 +8748,8 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont } // Thousand Arrows ignores type modifiers for flying mons - if (!IsBattlerGrounded(ctx->battlerDef) - && MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move) + if (MoveIgnoresTypeIfFlyingAndUngrounded(ctx->move) + && !IsBattlerGrounded(ctx->battlerDef, ctx->abilityDef, ctx->holdEffectDef) && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING)) { modifier = UQ_4_12(1.0); @@ -9823,9 +8758,9 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct DamageCont // Iron Ball ignores type modifiers for flying-type mons if it is the only source of grounding if (B_IRON_BALL >= GEN_5 && ctx->moveType == TYPE_GROUND + && ctx->holdEffectDef == HOLD_EFFECT_IRON_BALL && IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_FLYING) - && GetBattlerHoldEffect(ctx->battlerDef, TRUE) == HOLD_EFFECT_IRON_BALL - && !IsBattlerGroundedInverseCheck(ctx->battlerDef, ctx->abilityDef, NOT_INVERSE_BATTLE, IGNORE_IRON_BALL, FALSE) + && !IsBattlerGrounded(ctx->battlerDef, ctx->abilityDef, HOLD_EFFECT_NONE) // We want to ignore Iron Ball so skip item check && !FlagGet(B_FLAG_INVERSE_BATTLE)) { modifier = UQ_4_12(1.0); @@ -9871,15 +8806,15 @@ uq4_12_t CalcTypeEffectivenessMultiplier(struct DamageContext *ctx) return modifier; } -uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef) +uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, enum Ability abilityDef) { uq4_12_t modifier = UQ_4_12(1.0); - u32 moveType = GetBattleMoveType(move); + enum Type moveType = GetBattleMoveType(move); if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { struct DamageContext ctx = {0}; - ctx.move = move; + ctx.move = ctx.chosenMove = move; ctx.moveType = moveType; ctx.updateFlags = FALSE; ctx.abilityDef = abilityDef; @@ -9912,19 +8847,19 @@ static uq4_12_t GetInverseTypeMultiplier(uq4_12_t multiplier) } } -uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType) +uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, enum Type moveType) { uq4_12_t modifier = UQ_4_12(1.0); - u16 abilityDef = GetMonAbility(mon); + enum Ability abilityDef = GetMonAbility(mon); u16 speciesDef = GetMonData(mon, MON_DATA_SPECIES); - u8 type1 = GetSpeciesType(speciesDef, 0); - u8 type2 = GetSpeciesType(speciesDef, 1); + enum Type type1 = GetSpeciesType(speciesDef, 0); + enum Type type2 = GetSpeciesType(speciesDef, 1); if (moveType == TYPE_MYSTERY) return modifier; struct DamageContext ctx = {0}; - ctx.move = MOVE_POUND; + ctx.move = ctx.chosenMove = MOVE_POUND; ctx.moveType = moveType; ctx.updateFlags = FALSE; @@ -9939,14 +8874,14 @@ uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType) return modifier; } -uq4_12_t GetTypeModifier(u32 atkType, u32 defType) +uq4_12_t GetTypeModifier(enum Type atkType, enum Type defType) { if (B_FLAG_INVERSE_BATTLE != 0 && FlagGet(B_FLAG_INVERSE_BATTLE)) return GetInverseTypeMultiplier(gTypeEffectivenessTable[atkType][defType]); return gTypeEffectivenessTable[atkType][defType]; } -s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, u8 type2, u32 maxHp) +s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, enum Type type1, enum Type type2, u32 maxHp) { s32 dmg = 0; uq4_12_t modifier = UQ_4_12(1.0); @@ -9992,7 +8927,7 @@ s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, s32 GetStealthHazardDamage(enum TypeSideHazard hazardType, u32 battler) { - u32 types[3]; + enum Type types[3]; GetBattlerTypes(battler, FALSE, types); u32 maxHp = gBattleMons[battler].maxHP; @@ -10001,14 +8936,10 @@ s32 GetStealthHazardDamage(enum TypeSideHazard hazardType, u32 battler) bool32 IsPartnerMonFromSameTrainer(u32 battler) { - if (!IsOnPlayerSide(battler) && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) - return FALSE; - else if (IsOnPlayerSide(battler) && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) - return FALSE; - else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) - return FALSE; + if (!IsOnPlayerSide(battler)) + return !(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS); else - return TRUE; + return !(gBattleTypeFlags & BATTLE_TYPE_MULTI); } bool32 DoesSpeciesUseHoldItemToChangeForm(u16 species, u16 heldItemId) @@ -10038,7 +8969,7 @@ bool32 DoesSpeciesUseHoldItemToChangeForm(u16 species, u16 heldItemId) bool32 CanMegaEvolve(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Check if Player has a Mega Ring. if (!TESTING @@ -10076,7 +9007,7 @@ bool32 CanMegaEvolve(u32 battler) bool32 CanUltraBurst(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Check if Player has a Z-Ring if (!TESTING && (GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT @@ -10263,7 +9194,7 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method) return targetSpecies; } -bool32 CanBattlerFormChange(u32 battler, enum FormChanges method) +static bool32 CanBattlerFormChange(u32 battler, enum FormChanges method) { // Can't change form if transformed. if (gBattleMons[battler].volatiles.transformed @@ -10297,7 +9228,7 @@ bool32 TryRevertPartyMonFormChange(u32 partyIndex) bool32 changedForm = FALSE; // Appeared in battle and didn't faint - if ((gBattleStruct->appearedInBattle & (1u << partyIndex)) && GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP, NULL) != 0) + if (gBattleStruct->partyState[B_SIDE_PLAYER][partyIndex].sentOut && GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP, NULL) != 0) changedForm = TryFormChange(partyIndex, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE_ENVIRONMENT); if (!changedForm) @@ -10358,7 +9289,7 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method) if (restoreSpecies) { - u32 abilityForm = gBattleMons[battler].ability; + enum Ability abilityForm = gBattleMons[battler].ability; // Reverts the original species TryToSetBattleFormChangeMoves(&party[monId], method); u32 changedSpecies = GetBattlerPartyState(battler)->changedSpecies; @@ -10377,7 +9308,7 @@ bool32 TryBattleFormChange(u32 battler, enum FormChanges method) bool32 DoBattlersShareType(u32 battler1, u32 battler2) { s32 i; - u32 types1[3], types2[3]; + enum Type types1[3], types2[3]; GetBattlerTypes(battler1, FALSE, types1); GetBattlerTypes(battler2, FALSE, types2); @@ -10398,7 +9329,7 @@ bool32 DoBattlersShareType(u32 battler1, u32 battler2) bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId) { u16 species = gBattleMons[battler].species; - enum ItemHoldEffect holdEffect = GetItemHoldEffect(itemId); + enum HoldEffect holdEffect = GetItemHoldEffect(itemId); if (ItemIsMail(itemId)) return FALSE; @@ -10423,7 +9354,7 @@ u32 GetBattlerVisualSpecies(u32 battler) return gBattleMons[battler].species; } -bool32 TryClearIllusion(u32 battler, u32 caseID) +bool32 TryClearIllusion(u32 battler, enum AbilityEffect caseID) { if (gBattleStruct->illusion[battler].state != ILLUSION_ON) return FALSE; @@ -10467,10 +9398,10 @@ u32 GetIllusionMonPartyId(struct Pokemon *party, struct Pokemon *mon, struct Pok s32 partyStart=0; // Adjust party search range for Multibattles and Player vs two-trainers - if((GetBattlerSide(battler) == B_SIDE_PLAYER && (gBattleTypeFlags & BATTLE_TYPE_MULTI)) + if ((GetBattlerSide(battler) == B_SIDE_PLAYER && (gBattleTypeFlags & BATTLE_TYPE_MULTI)) || (GetBattlerSide(battler) == B_SIDE_OPPONENT && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS))) { - if((GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) || (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT)) + if ((GetBattlerPosition(battler) == B_POSITION_PLAYER_LEFT) || (GetBattlerPosition(battler) == B_POSITION_OPPONENT_LEFT)) { partyEnd = 3; partyStart = 0; @@ -10528,7 +9459,7 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battler) return FALSE; } -u32 TryImmunityAbilityHealStatus(u32 battler, u32 caseID) +u32 TryImmunityAbilityHealStatus(u32 battler, enum AbilityEffect caseID) { u32 effect = 0; switch (GetBattlerAbilityIgnoreMoldBreaker(battler)) @@ -10595,28 +9526,28 @@ u32 TryImmunityAbilityHealStatus(u32 battler, u32 caseID) { case 1: // status cleared gBattleMons[battler].status1 = 0; - if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); else BattleScriptCall(BattleScript_AbilityCuredStatus); break; case 2: // get rid of confusion RemoveConfusionStatus(battler); - if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); else BattleScriptCall(BattleScript_AbilityCuredStatus); break; case 3: // get rid of infatuation gBattleMons[battler].volatiles.infatuation = 0; - if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); else BattleScriptCall(BattleScript_AbilityCuredStatus); break; case 4: // get rid of taunt gDisableStructs[battler].tauntTimer = 0; - if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) + if (caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES) BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3); else BattleScriptCall(BattleScript_AbilityCuredStatus); @@ -10734,29 +9665,6 @@ static bool32 TryRemoveScreens(u32 battler) return removed; } -static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler) -{ - for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) - { - if (battler == battlerDef || IsBattlerAlly(battler, battlerDef)) - continue; - - if (!IsBattlerAlive(battlerDef)) - continue; - - u32 ability = GetBattlerAbility(battlerDef); - switch (ability) - { - case ABILITY_UNNERVE: - case ABILITY_AS_ONE_ICE_RIDER: - case ABILITY_AS_ONE_SHADOW_RIDER: - return TRUE; - } - } - - return FALSE; -} - // Photon Geyser, Light That Burns the Sky, Tera Blast enum DamageCategory GetCategoryBasedOnStats(u32 battler) { @@ -10811,7 +9719,10 @@ void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast) u16 speeds[MAX_BATTLERS_COUNT] = {0}; for (i = 0; i < gBattlersCount; i++) - speeds[i] = GetBattlerTotalSpeedStat(battlers[i]); + { + u32 battler = battlers[i]; + speeds[i] = GetBattlerTotalSpeedStat(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler)); + } for (i = 1; i < gBattlersCount; i++) { @@ -10868,7 +9779,7 @@ void TryRestoreHeldItems(void) bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item) { - u8 stealerSide = GetBattlerSide(battlerStealing); + enum BattleSide stealerSide = GetBattlerSide(battlerStealing); if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL) return FALSE; @@ -10925,7 +9836,7 @@ void TrySaveExchangedItem(u32 battler, u16 stolenItem) bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes) { bool32 ret = TRUE; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, TRUE); + enum HoldEffect holdEffect = GetBattlerHoldEffect(battler); if (toxicSpikes && holdEffect == HOLD_EFFECT_HEAVY_DUTY_BOOTS && !IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) { ret = FALSE; @@ -10944,8 +9855,8 @@ bool32 TestIfSheerForceAffected(u32 battler, u16 move) return GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move); } -// This function is the body of "jumpifstat", but can be used dynamically in a function. It considers Contrary. -bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind, u32 ability) +// This function is the body of "jumpifstat", but can be used dynamically in a function +bool32 CompareStat(u32 battler, enum Stat statId, u8 cmpTo, u8 cmpKind, enum Ability ability) { bool32 ret = FALSE; u8 statValue = gBattleMons[battler].statStages[statId]; @@ -10996,49 +9907,6 @@ bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind, u32 ability) return ret; } -void BufferStatChange(u32 battler, u8 statId, enum StringID stringId) -{ - bool32 hasContrary = (GetBattlerAbility(battler) == ABILITY_CONTRARY); - - PREPARE_STAT_BUFFER(gBattleTextBuff1, statId); - if (stringId == STRINGID_STATFELL) - { - if (hasContrary) - PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE) - else - PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL) - } - else if (stringId == STRINGID_STATROSE) - { - if (hasContrary) - PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATFELL) - else - PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE) - } - else - { - PREPARE_STRING_BUFFER(gBattleTextBuff2, stringId) - } -} - -bool32 TryRoomService(u32 battler) -{ - if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && CompareStat(battler, STAT_SPEED, MIN_STAT_STAGE, CMP_GREATER_THAN, GetBattlerAbility(battler))) - { - BufferStatChange(battler, STAT_SPEED, STRINGID_STATFELL); - gEffectBattler = gBattleScripting.battler = battler; - SET_STATCHANGER(STAT_SPEED, 1, TRUE); - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_SPEED; - gBattleScripting.animArg2 = 0; - gLastUsedItem = gBattleMons[battler].item; - return TRUE; - } - else - { - return FALSE; - } -} - bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget) { if (GetGenConfig(GEN_CONFIG_PRANKSTER_DARK_TYPES) < GEN_7) @@ -11057,17 +9925,12 @@ bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 ch return TRUE; } -u16 GetUsedHeldItem(u32 battler) -{ - return gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)]; -} - bool32 CantPickupItem(u32 battler) { // Used by RandomUniformExcept() for RNG_PICKUP if (battler == gBattlerAttacker && (GetGenConfig(GEN_PICKUP_WILD) < GEN_9 || gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK))) return TRUE; - return !(IsBattlerAlive(battler) && GetUsedHeldItem(battler) && gBattleStruct->battlerState[battler].canPickupItem); + return !(IsBattlerAlive(battler) && GetBattlerPartyState(battler)->usedHeldItem && gBattleStruct->battlerState[battler].canPickupItem); } bool32 PickupHasValidTarget(u32 battler) @@ -11086,7 +9949,7 @@ bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags) if (gBattleWeather & weatherFlags && HasWeatherEffect()) { // given weather is active -> check if its sun, rain against utility umbrella (since only 1 weather can be active at once) - if (gBattleWeather & (B_WEATHER_SUN | B_WEATHER_RAIN) && GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA) + if (gBattleWeather & (B_WEATHER_SUN | B_WEATHER_RAIN) && GetBattlerHoldEffect(battler) == HOLD_EFFECT_UTILITY_UMBRELLA) return FALSE; // utility umbrella blocks sun, rain effects return TRUE; @@ -11096,12 +9959,13 @@ bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags) // Gets move target before redirection effects etc. are applied // Possible return values are defined in battle.h following MOVE_TARGET_SELECTED +// TODO: Add args: ability and hold effect u32 GetBattlerMoveTargetType(u32 battler, u32 move) { enum BattleMoveEffects effect = GetMoveEffect(move); if (effect == EFFECT_CURSE && !IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return MOVE_TARGET_USER; - if (effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(battler, STATUS_FIELD_PSYCHIC_TERRAIN)) + if (effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler), STATUS_FIELD_PSYCHIC_TERRAIN)) return MOVE_TARGET_BOTH; if (effect == EFFECT_TERA_STARSTORM && gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR) return MOVE_TARGET_BOTH; @@ -11124,7 +9988,7 @@ bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move) static void SetRandomMultiHitCounter() { - if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) + if (GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_LOADED_DICE) gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 5); else if (GetGenConfig(GEN_CONFIG_MULTI_HIT_CHANCE) >= GEN_5) gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3); // 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits. @@ -11184,17 +10048,6 @@ void RemoveConfusionStatus(u32 battler) gBattleMons[battler].volatiles.infiniteConfusion = FALSE; } -static bool32 CanBeInfinitelyConfused(u32 battler) -{ - if (GetBattlerAbility(battler) == ABILITY_OWN_TEMPO - || IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN) - || gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SAFEGUARD) - { - return FALSE; - } - return TRUE; -} - u8 GetBattlerGender(u32 battler) { return GetGenderFromSpeciesAndPersonality(gBattleMons[battler].species, @@ -11217,7 +10070,7 @@ bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2) return (gender1 != MON_GENDERLESS && gender2 != MON_GENDERLESS && gender1 == gender2); } -u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect) +u32 CalcSecondaryEffectChance(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect) { bool8 hasSereneGrace = (battlerAbility == ABILITY_SERENE_GRACE); bool8 hasRainbow = (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_RAINBOW) != 0; @@ -11234,7 +10087,7 @@ u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct Addi return secondaryEffectChance; } -bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect) +bool32 MoveEffectIsGuaranteed(u32 battler, enum Ability battlerAbility, const struct AdditionalEffect *additionalEffect) { return additionalEffect->chance == 0 || CalcSecondaryEffectChance(battler, battlerAbility, additionalEffect) >= 100; } @@ -11368,13 +10221,13 @@ bool8 IsMonBannedFromSkyBattles(u16 species) } } -void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]) +void GetBattlerTypes(u32 battler, bool32 ignoreTera, enum Type types[static 3]) { // Terastallization. bool32 isTera = GetActiveGimmick(battler) == GIMMICK_TERA; if (!ignoreTera && isTera) { - u32 teraType = GetBattlerTeraType(battler); + enum Type teraType = GetBattlerTeraType(battler); if (teraType != TYPE_STELLAR) { types[0] = types[1] = types[2] = teraType; @@ -11398,14 +10251,14 @@ void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]) } } -u32 GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera) +enum Type GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera) { - u32 types[3]; + enum Type types[3]; GetBattlerTypes(battler, ignoreTera, types); return types[typeIndex]; } -void RemoveBattlerType(u32 battler, u8 type) +void RemoveBattlerType(u32 battler, enum Type type) { u32 i; if (GetActiveGimmick(battler) == GIMMICK_TERA) // don't remove type if Terastallized @@ -11483,9 +10336,9 @@ bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef) && battlerDef != BATTLE_PARTNER(battlerAtk)); } -static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerDef, u32 moveType) +static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerDef, enum Type moveType) { - u32 abilityDef = GetBattlerAbility(battlerDef); + enum Ability abilityDef = GetBattlerAbility(battlerDef); return CanAbilityBlockMove(battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), abilityDef, gCurrentMove, CHECK_TRIGGER) || CanAbilityAbsorbMove(battlerAtk, battlerDef, abilityDef, gCurrentMove, moveType, CHECK_TRIGGER); @@ -11493,14 +10346,14 @@ static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerAtk, u32 battlerD bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef) { - u32 moveType = GetBattleMoveType(gCurrentMove); + enum Type moveType = GetBattleMoveType(gCurrentMove); return ((CalcTypeEffectivenessMultiplierHelper(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) || IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove) || !BreaksThroughSemiInvulnerablity(battlerDef, gCurrentMove) || DoesBattlerHaveAbilityImmunity(battlerAtk, battlerDef, moveType)); } -u32 GetBattleMoveType(u32 move) +enum Type GetBattleMoveType(u32 move) { if (gMain.inBattle && gBattleStruct->dynamicMoveType) return gBattleStruct->dynamicMoveType & DYNAMIC_TYPE_MASK; @@ -11570,22 +10423,18 @@ void ClearDamageCalcResults(void) bool32 DoesDestinyBondFail(u32 battler) { - if (GetGenConfig(GEN_CONFIG_DESTINY_BOND_FAIL) >= GEN_7 - && GetMoveEffect(gLastLandedMoves[battler]) == EFFECT_DESTINY_BOND - && GetMoveEffect(gLastResultingMoves[battler]) == EFFECT_DESTINY_BOND) - return TRUE; - return FALSE; + return GetGenConfig(GEN_CONFIG_DESTINY_BOND_FAIL) >= GEN_7 && gBattleMons[battler].volatiles.destinyBond; } // This check has always to be the last in a condtion statement because of the recording of AI data. -bool32 IsMoveEffectBlockedByTarget(u32 ability) +bool32 IsMoveEffectBlockedByTarget(enum Ability ability) { if (ability == ABILITY_SHIELD_DUST) { RecordAbilityBattle(gBattlerTarget, ability); return TRUE; } - else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_COVERT_CLOAK) + else if (GetBattlerHoldEffect(gBattlerTarget) == HOLD_EFFECT_COVERT_CLOAK) { RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_COVERT_CLOAK); return TRUE; @@ -11624,40 +10473,29 @@ bool32 HasWeatherEffect(void) if (!IsBattlerAlive(battler)) continue; - u32 ability = GetBattlerAbility(battler); + enum Ability ability = GetBattlerAbility(battler); switch (ability) { case ABILITY_CLOUD_NINE: case ABILITY_AIR_LOCK: return FALSE; + default: + break; } } return TRUE; } -bool32 IsAnyTargetAffected(u32 battlerAtk) -{ - for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) - { - if (battlerAtk == battlerDef) - continue; - - if (!(gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT)) - return TRUE; - } - return FALSE; -} - void UpdateStallMons(void) { if (IsBattlerTurnDamaged(gBattlerTarget) || IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) || GetMoveCategory(gCurrentMove) == DAMAGE_CATEGORY_STATUS) return; if (!IsDoubleBattle() || GetMoveTarget(gCurrentMove) == MOVE_TARGET_SELECTED) { - u32 moveType = GetBattleMoveType(gCurrentMove); // Probably doesn't handle dynamic move types right now - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); - u32 abilityDef = GetBattlerAbility(gBattlerTarget); + enum Type moveType = GetBattleMoveType(gCurrentMove); // Probably doesn't handle dynamic move types right now + enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker); + enum Ability abilityDef = GetBattlerAbility(gBattlerTarget); if (CanAbilityAbsorbMove(gBattlerAttacker, gBattlerTarget, abilityDef, gCurrentMove, moveType, CHECK_TRIGGER)) { gAiBattleData->playerStallMons[gBattlerPartyIndexes[gBattlerTarget]]++; @@ -11674,18 +10512,7 @@ void UpdateStallMons(void) // Handling for moves that target multiple opponents in doubles not handled currently } -bool32 TryRestoreHPBerries(u32 battler, enum ItemCaseId caseId) -{ - if (gItemsInfo[gBattleMons[battler].item].pocket == POCKET_BERRIES - || GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RESTORE_HP) // Edge case for Berry Juice - { - if (ItemBattleEffects(caseId, battler)) - return TRUE; - } - return FALSE; -} - -bool32 TrySwitchInEjectPack(enum ItemCaseId caseID) +bool32 TrySwitchInEjectPack(enum EjectPackTiming timing) { // Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items. u32 ejectPackBattlers = 0; @@ -11694,7 +10521,7 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID) for (u32 i = 0; i < gBattlersCount; i++) { if (gDisableStructs[i].tryEjectPack - && GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_EJECT_PACK + && GetBattlerHoldEffect(i) == HOLD_EFFECT_EJECT_PACK && IsBattlerAlive(i) && CountUsablePartyMons(i) > 0) { @@ -11722,9 +10549,9 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID) gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; - if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN) + if (timing == FIRST_TURN) BattleScriptPushCursorAndCallback(BattleScript_EjectPackActivate_End3); - else if (caseID == ITEMEFFECT_NORMAL) + else if (timing == END_TURN) BattleScriptExecute(BattleScript_EjectPackActivate_End2); else BattleScriptCall(BattleScript_EjectPackActivate_Ret); @@ -11874,10 +10701,10 @@ void RemoveHazardFromField(u32 side, enum Hazards hazardType) } } -bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option) +bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abilityAtk, enum Ability abilityDef, u32 move, enum FunctionCallOption option) { bool32 effect = FALSE; - u32 ability = ABILITY_NONE; + enum Ability ability = ABILITY_NONE; enum BattleMoveEffects moveEffect = GetMoveEffect(move); u32 nonVolatileStatus = GetMoveNonVolatileStatus(move); @@ -11958,7 +10785,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u return effect; } -u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect) +u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, enum Ability atkAbility, enum Ability defAbility, enum HoldEffect atkHoldEffect, enum HoldEffect defHoldEffect) { u32 calc, moveAcc; s8 buff, accStage, evasionStage; @@ -12010,23 +10837,27 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (IsBattleMovePhysical(move)) calc = (calc * 80) / 100; // 1.2 hustle loss break; + default: + break; } // Target's ability switch (defAbility) { case ABILITY_SAND_VEIL: - if (HasWeatherEffect() && gBattleWeather & B_WEATHER_SANDSTORM) + if (gBattleWeather & B_WEATHER_SANDSTORM && HasWeatherEffect()) calc = (calc * 80) / 100; // 1.2 sand veil loss break; case ABILITY_SNOW_CLOAK: - if (HasWeatherEffect() && (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW))) + if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && HasWeatherEffect()) calc = (calc * 80) / 100; // 1.2 snow cloak loss break; case ABILITY_TANGLED_FEET: if (gBattleMons[battlerDef].volatiles.confusionTurns) calc = (calc * 50) / 100; // 1.5 tangled feet loss break; + default: + break; } // Attacker's ally's ability @@ -12037,6 +10868,8 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (IsBattlerAlive(atkAlly)) calc = (calc * 110) / 100; // 1.1 ally's victory star boost break; + default: + break; } // Attacker's hold effect @@ -12049,6 +10882,8 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (HasBattlerActedThisTurn(battlerDef)) calc = (calc * (100 + atkParam)) / 100; break; + default: + break; } // Target's hold effect @@ -12057,10 +10892,13 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u case HOLD_EFFECT_EVASION_UP: calc = (calc * (100 - defParam)) / 100; break; + default: + break; } if (gBattleStruct->battlerState[battlerAtk].usedMicleBerry) { + // TODO: Is this true? if (atkAbility == ABILITY_RIPEN) calc = (calc * 140) / 100; // ripen gives 40% acc boost else @@ -12132,7 +10970,7 @@ static bool32 IsOpposingSideEmpty(u32 battler) return TRUE; } -bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum ItemHoldEffect holdEffect) +bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum HoldEffect holdEffect) { if ((GetGenConfig(GEN_CONFIG_POWDER_OVERCOAT) >= GEN_6 && ability == ABILITY_OVERCOAT) || (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) @@ -12140,3 +10978,237 @@ bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum ItemHoldEffect hold return FALSE; return TRUE; } + +static u32 GetMirrorMoveMove(void) +{ + s32 i, validMovesCount; + u16 move = MOVE_NONE; + u16 validMoves[MAX_BATTLERS_COUNT] = {0}; + + for (validMovesCount = 0, i = 0; i < gBattlersCount; i++) + { + if (i != gBattlerAttacker) + { + move = gBattleStruct->lastTakenMoveFrom[gBattlerAttacker][i]; + if (move != MOVE_NONE && move != MOVE_UNAVAILABLE) + { + validMoves[validMovesCount] = move; + validMovesCount++; + } + } + } + + move = gBattleStruct->lastTakenMove[gBattlerAttacker]; + if ((move == MOVE_NONE || move == MOVE_UNAVAILABLE) && validMovesCount != 0) + move = validMoves[Random() % validMovesCount]; + + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move)) + move = GetTypeBasedZMove(move); + + return move; +} + +static bool32 InvalidMetronomeMove(u32 move) +{ + return GetMoveEffect(move) == EFFECT_PLACEHOLDER + || IsMoveMetronomeBanned(move); +} + +static u32 GetMetronomeMove(void) +{ + u32 move = MOVE_NONE; + +#if B_METRONOME_MOVES >= GEN_9 + u32 moveCount = MOVES_COUNT_GEN9; +#elif B_METRONOME_MOVES >= GEN_8 + u32 moveCount = MOVES_COUNT_GEN8; +#elif B_METRONOME_MOVES >= GEN_7 + u32 moveCount = MOVES_COUNT_GEN7; +#elif B_METRONOME_MOVES >= GEN_6 + u32 moveCount = MOVES_COUNT_GEN6; +#elif B_METRONOME_MOVES >= GEN_5 + u32 moveCount = MOVES_COUNT_GEN5; +#elif B_METRONOME_MOVES >= GEN_4 + u32 moveCount = MOVES_COUNT_GEN4; +#elif B_METRONOME_MOVES >= GEN_3 + u32 moveCount = MOVES_COUNT_GEN3; +#elif B_METRONOME_MOVES >= GEN_2 + u32 moveCount = MOVES_COUNT_GEN2; +#else + u32 moveCount = MOVES_COUNT_GEN1; +#endif + + move = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove); + return move; +} + +static u32 GetAssistMove(void) +{ + u32 move = MOVE_NONE; + s32 chooseableMovesNo = 0; + struct Pokemon *party; + u16 *validMoves = Alloc(sizeof(u16) * PARTY_SIZE * MAX_MON_MOVES); + + if (validMoves != NULL) + { + party = GetBattlerParty(gBattlerAttacker); + + for (u32 monId = 0; monId < PARTY_SIZE; monId++) + { + if (monId == gBattlerPartyIndexes[gBattlerAttacker]) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE) + continue; + if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG) + continue; + + for (u32 moveId = 0; moveId < MAX_MON_MOVES; moveId++) + { + u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId); + + if (IsMoveAssistBanned(move)) + continue; + + validMoves[chooseableMovesNo++] = move; + } + } + } + + if (chooseableMovesNo) + move = validMoves[Random() % chooseableMovesNo]; + + TRY_FREE_AND_SET_NULL(validMoves); + + return move; +} + +u32 GetNaturePowerMove(u32 battler) +{ + u32 move = gBattleEnvironmentInfo[gBattleEnvironment].naturePower; + if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN) + move = MOVE_MOONBLAST; + else if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN) + move = MOVE_THUNDERBOLT; + else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN) + move = MOVE_ENERGY_BALL; + else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN) + move = MOVE_PSYCHIC; + else if (gBattleEnvironmentInfo[gBattleEnvironment].naturePower == MOVE_NONE) + move = MOVE_TRI_ATTACK; + + return move; +} + +static u32 GetSleepTalkMove(void) +{ + u32 move = MOVE_NONE; + + u32 i, unusableMovesBits = 0, movePosition; + + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_COMATOSE + && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)) + return move; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (IsMoveSleepTalkBanned(gBattleMons[gBattlerAttacker].moves[i]) + || gBattleMoveEffects[GetMoveEffect(gBattleMons[gBattlerAttacker].moves[i])].twoTurnEffect) + unusableMovesBits |= (1 << (i)); + } + + unusableMovesBits = CheckMoveLimitations(gBattlerAttacker, unusableMovesBits, ~(MOVE_LIMITATION_PP | MOVE_LIMITATION_CHOICE_ITEM)); + if (unusableMovesBits == ALL_MOVES_MASK) // all 4 moves cannot be chosen + return move; + + // Set Sleep Talk as used move, so it works with Last Resort. + gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos; + do + { + movePosition = MOD(Random(), MAX_MON_MOVES); + } while ((1u << movePosition) & unusableMovesBits); + + move = gBattleMons[gBattlerAttacker].moves[movePosition]; + gCurrMovePos = movePosition; + + return move; +} + +static u32 GetCopyCatMove(void) +{ + if (gLastUsedMove == MOVE_NONE + || gLastUsedMove == MOVE_UNAVAILABLE + || IsMoveCopycatBanned(gLastUsedMove) + || IsZMove(gLastUsedMove)) + return MOVE_NONE; + + return gLastUsedMove; +} + +static u32 GetMeFirstMove(void) +{ + u32 move = GetChosenMoveFromPosition(gBattlerTarget); + + if (IsBattleMoveStatus(move) + || IsMoveMeFirstBanned(move) + || HasBattlerActedThisTurn(gBattlerTarget)) + return MOVE_NONE; + + return move; +} + +void RemoveAbilityFlags(u32 battler) +{ + switch (GetBattlerAbility(battler)) + { + case ABILITY_FLASH_FIRE: + gDisableStructs[battler].flashFireBoosted = FALSE; + break; + case ABILITY_VESSEL_OF_RUIN: + gBattleMons[battler].volatiles.vesselOfRuin = FALSE; + break; + case ABILITY_TABLETS_OF_RUIN: + gBattleMons[battler].volatiles.tabletsOfRuin = FALSE; + break; + case ABILITY_SWORD_OF_RUIN: + gBattleMons[battler].volatiles.swordOfRuin = FALSE; + break; + case ABILITY_BEADS_OF_RUIN: + gBattleMons[battler].volatiles.beadsOfRuin = FALSE; + break; + default: + break; + } +} + +bool32 IsAnyTargetTurnDamaged(u32 battlerAtk) +{ + for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + { + if (battlerDef == battlerAtk) + continue; + if (IsBattlerTurnDamaged(battlerDef)) + return TRUE; + } + return FALSE; +} + +bool32 IsAllowedToUseBag(void) +{ + switch(VarGet(B_VAR_NO_BAG_USE)) + { + case NO_BAG_RESTRICTION: + return TRUE; + case NO_BAG_AGAINST_TRAINER: //True in wild battle; False in trainer battle + return (!(gBattleTypeFlags & BATTLE_TYPE_TRAINER)); + case NO_BAG_IN_BATTLE: + return FALSE; + default: + return TRUE; // Undefined Behavior + } +} + +bool32 IsMimikyuDisguised(u32 battler) +{ + return gBattleMons[battler].species == SPECIES_MIMIKYU_DISGUISED + || gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED; +} diff --git a/src/battle_z_move.c b/src/battle_z_move.c index 638e9ef901..4b517ccc8f 100644 --- a/src/battle_z_move.c +++ b/src/battle_z_move.c @@ -36,7 +36,6 @@ #include "constants/songs.h" #include "constants/items.h" #include "constants/species.h" -#include "constants/hold_effects.h" #include "constants/battle_string_ids.h" #include "constants/battle_move_effects.h" #include "constants/abilities.h" @@ -113,7 +112,7 @@ bool32 IsZMove(u32 move) bool32 CanUseZMove(u32 battler) { - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); // Check if Player has Z-Power Ring. if (!TESTING && (battler == B_POSITION_PLAYER_LEFT @@ -144,7 +143,7 @@ bool32 CanUseZMove(u32 battler) u32 GetUsableZMove(u32 battler, u32 move) { u32 item = gBattleMons[battler].item; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); if (holdEffect == HOLD_EFFECT_Z_CRYSTAL) { @@ -161,14 +160,13 @@ u32 GetUsableZMove(u32 battler, u32 move) void ActivateZMove(u32 battler) { - gBattleStruct->zmove.baseMoves[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; SetActiveGimmick(battler, GIMMICK_Z_MOVE); } bool32 IsViableZMove(u32 battler, u32 move) { u32 item; - enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); + enum HoldEffect holdEffect = GetBattlerHoldEffectIgnoreNegation(battler); int moveSlotIndex; item = gBattleMons[battler].item; @@ -420,7 +418,7 @@ static void ZMoveSelectionDisplayPpNumber(u32 battler) static void ZMoveSelectionDisplayMoveType(u16 zMove, u32 battler) { u8 *txtPtr, *end; - u32 zMoveType = GetBattleMoveType(zMove); + enum Type zMoveType = GetBattleMoveType(zMove); txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType); *(txtPtr)++ = EXT_CTRL_CODE_BEGIN; @@ -438,7 +436,7 @@ static void ZMoveSelectionDisplayMoveType(u16 zMove, u32 battler) void SetZEffect(void) { u32 i; - u32 effect = GetMoveZEffect(gBattleStruct->zmove.baseMoves[gBattlerAttacker]); + u32 effect = GetMoveZEffect(gChosenMove); if (effect == Z_EFFECT_CURSE) { @@ -508,7 +506,7 @@ void SetZEffect(void) case Z_EFFECT_RECOVER_HP: if (gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP) { - gBattleStruct->moveDamage[gBattlerAttacker] = (-1) * gBattleMons[gBattlerAttacker].maxHP; + SetHealAmount(gBattlerAttacker, gBattleMons[gBattlerAttacker].maxHP); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_RECOVER_HP; BattleScriptPush(gBattlescriptCurrInstr + Z_EFFECT_BS_LENGTH); gBattlescriptCurrInstr = BattleScript_RecoverHPZMove; diff --git a/src/berry_crush.c b/src/berry_crush.c index a571511ee2..e3927d8780 100644 --- a/src/berry_crush.c +++ b/src/berry_crush.c @@ -4,6 +4,7 @@ #include "berry_powder.h" #include "bg.h" #include "decompress.h" +#include "digit_obj_util.h" #include "dynamic_placeholder_text_util.h" #include "event_data.h" #include "gpu_regs.h" @@ -17,11 +18,10 @@ #include "malloc.h" #include "math_util.h" #include "menu.h" +#include "minigame_countdown.h" #include "overworld.h" #include "palette.h" -#include "minigame_countdown.h" #include "random.h" -#include "digit_obj_util.h" #include "save.h" #include "scanline_effect.h" #include "script.h" @@ -1157,18 +1157,7 @@ static void SetNamesAndTextSpeed(struct BerryCrushGame *game) game->players[i].name[PLAYER_NAME_LENGTH] = EOS; } - switch (gSaveBlock2Ptr->optionsTextSpeed) - { - case OPTIONS_TEXT_SPEED_SLOW: - game->textSpeed = 8; - break; - case OPTIONS_TEXT_SPEED_MID: - game->textSpeed = 4; - break; - case OPTIONS_TEXT_SPEED_FAST: - game->textSpeed = 1; - break; - } + game->textSpeed = GetPlayerTextSpeedDelay(); } static s32 ShowGameDisplay(void) diff --git a/src/bg.c b/src/bg.c index bfc719a25f..9080adf22c 100644 --- a/src/bg.c +++ b/src/bg.c @@ -911,8 +911,6 @@ void CopyBgTilemapBufferToVram(u32 bg) void CopyToBgTilemapBufferRect(u32 bg, const void *src, u8 destX, u8 destY, u8 width, u8 height) { - u16 destX16; - u16 destY16; u16 mode; if (!IsInvalidBg(bg) && !IsTileMapOutsideWram(bg)) @@ -922,11 +920,11 @@ void CopyToBgTilemapBufferRect(u32 bg, const void *src, u8 destX, u8 destY, u8 w case BG_TYPE_NORMAL: { const u16 *srcCopy = src; - for (destY16 = destY; destY16 < (destY + height); destY16++) + for (u32 j = destY; j < (destY + height); j++) { - for (destX16 = destX; destX16 < (destX + width); destX16++) + for (u32 i = destX; i < (destX + width); i++) { - ((u16 *)sGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *srcCopy++; + ((u16 *)sGpuBgConfigs2[bg].tilemap)[((j * 0x20) + i)] = *srcCopy++; } } break; @@ -935,11 +933,11 @@ void CopyToBgTilemapBufferRect(u32 bg, const void *src, u8 destX, u8 destY, u8 w { const u8 *srcCopy = src; mode = GetBgMetricAffineMode(bg, 0x1); - for (destY16 = destY; destY16 < (destY + height); destY16++) + for (u32 j = destY; j < (destY + height); j++) { - for (destX16 = destX; destX16 < (destX + width); destX16++) + for (u32 i = destX; i < (destX + width); i++) { - ((u8 *)sGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *srcCopy++; + ((u8 *)sGpuBgConfigs2[bg].tilemap)[((j * mode) + i)] = *srcCopy++; } } break; @@ -958,7 +956,6 @@ void CopyRectToBgTilemapBufferRect(u32 bg, const void *src, u8 srcX, u8 srcY, u8 u16 screenWidth, screenHeight, screenSize; u16 var; const void *srcPtr; - u16 i, j; if (!IsInvalidBg(bg) && !IsTileMapOutsideWram(bg)) { @@ -969,11 +966,11 @@ void CopyRectToBgTilemapBufferRect(u32 bg, const void *src, u8 srcX, u8 srcY, u8 { case BG_TYPE_NORMAL: srcPtr = src + ((srcY * srcWidth) + srcX) * 2; - for (i = destY; i < (destY + rectHeight); i++) + for (u32 j = destY; j < (destY + rectHeight); j++) { - for (j = destX; j < (destX + rectWidth); j++) + for (u32 i = destX; i < (destX + rectWidth); i++) { - u16 index = GetTileMapIndexFromCoords(j, i, screenSize, screenWidth, screenHeight); + u16 index = GetTileMapIndexFromCoords(i, j, screenSize, screenWidth, screenHeight); CopyTileMapEntry(srcPtr, sGpuBgConfigs2[bg].tilemap + (index * 2), palette1, tileOffset, palette2); srcPtr += 2; } @@ -983,11 +980,11 @@ void CopyRectToBgTilemapBufferRect(u32 bg, const void *src, u8 srcX, u8 srcY, u8 case BG_TYPE_AFFINE: srcPtr = src + ((srcY * srcWidth) + srcX); var = GetBgMetricAffineMode(bg, 0x1); - for (i = destY; i < (destY + rectHeight); i++) + for (u32 j = destY; j < (destY + rectHeight); j++) { - for (j = destX; j < (destX + rectWidth); j++) + for (u32 i = destX; i < (destX + rectWidth); i++) { - *(u8 *)(sGpuBgConfigs2[bg].tilemap + ((var * i) + j)) = *(u8 *)(srcPtr) + tileOffset; + *(u8 *)(sGpuBgConfigs2[bg].tilemap + ((var * j) + i)) = *(u8 *)(srcPtr) + tileOffset; srcPtr++; } srcPtr += (srcWidth - rectWidth); @@ -999,8 +996,6 @@ void CopyRectToBgTilemapBufferRect(u32 bg, const void *src, u8 srcX, u8 srcY, u8 void FillBgTilemapBufferRect_Palette0(u32 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height) { - u16 x16; - u16 y16; u16 mode; if (!IsInvalidBg(bg) && !IsTileMapOutsideWram(bg)) @@ -1008,21 +1003,21 @@ void FillBgTilemapBufferRect_Palette0(u32 bg, u16 tileNum, u8 x, u8 y, u8 width, switch (GetBgType(bg)) { case BG_TYPE_NORMAL: - for (y16 = y; y16 < (y + height); y16++) + for (u32 j = y; j < (y + height); j++) { - for (x16 = x; x16 < (x + width); x16++) + for (u32 i = x; i < (x + width); i++) { - ((u16 *)sGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum; + ((u16 *)sGpuBgConfigs2[bg].tilemap)[((j * 0x20) + i)] = tileNum; } } break; case BG_TYPE_AFFINE: mode = GetBgMetricAffineMode(bg, 0x1); - for (y16 = y; y16 < (y + height); y16++) + for (u32 j = y; j < (y + height); j++) { - for (x16 = x; x16 < (x + width); x16++) + for (u32 i = x; i < (x + width); i++) { - ((u8 *)sGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum; + ((u8 *)sGpuBgConfigs2[bg].tilemap)[((j * mode) + i)] = tileNum; } } break; @@ -1041,7 +1036,6 @@ void WriteSequenceToBgTilemapBuffer(u32 bg, u16 firstTileNum, u8 x, u8 y, u8 wid u16 mode2; u16 attribute; u16 mode3; - u16 x16, y16; if (!IsInvalidBg(bg) && !IsTileMapOutsideWram(bg)) { @@ -1051,22 +1045,22 @@ void WriteSequenceToBgTilemapBuffer(u32 bg, u16 firstTileNum, u8 x, u8 y, u8 wid switch (GetBgType(bg)) { case BG_TYPE_NORMAL: - for (y16 = y; y16 < (y + height); y16++) + for (u32 j = y; j < (y + height); j++) { - for (x16 = x; x16 < (x + width); x16++) + for (u32 i = x; i < (x + width); i++) { - CopyTileMapEntry(&firstTileNum, &((u16 *)sGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0); + CopyTileMapEntry(&firstTileNum, &((u16 *)sGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(i, j, attribute, mode, mode2)], paletteSlot, 0, 0); firstTileNum = (firstTileNum & 0xFC00) + ((firstTileNum + tileNumDelta) & 0x3FF); } } break; case BG_TYPE_AFFINE: mode3 = GetBgMetricAffineMode(bg, 0x1); - for (y16 = y; y16 < (y + height); y16++) + for (u32 j = y; j < (y + height); j++) { - for (x16 = x; x16 < (x + width); x16++) + for (u32 i = x; i < (x + width); i++) { - ((u8 *)sGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum; + ((u8 *)sGpuBgConfigs2[bg].tilemap)[(j * mode3) + i] = firstTileNum; firstTileNum = (firstTileNum & 0xFC00) + ((firstTileNum + tileNumDelta) & 0x3FF); } } diff --git a/src/bike.c b/src/bike.c index 50ed705da3..3f4181f129 100644 --- a/src/bike.c +++ b/src/bike.c @@ -5,6 +5,7 @@ #include "fieldmap.h" #include "field_specials.h" #include "metatile_behavior.h" +#include "oras_dowse.h" #include "overworld.h" #include "sound.h" #include "constants/songs.h" @@ -1003,6 +1004,7 @@ void GetOnOffBike(u8 transitionFlags) } else { + EndORASDowsing(); SetPlayerAvatarTransitionFlags(transitionFlags); Overworld_SetSavedMusic(MUS_CYCLING); Overworld_ChangeMusicTo(MUS_CYCLING); diff --git a/src/braille.c b/src/braille.c index 91872b88a0..310384ba32 100644 --- a/src/braille.c +++ b/src/braille.c @@ -1,18 +1,12 @@ #include "global.h" #include "main.h" -#include "window.h" #include "text.h" #include "sound.h" +#include "window.h" // This file handles the braille font. // For printing braille messages, see ScrCmd_braillemessage -ALIGNED(4) -static const u8 sScrollDistances[] = { - [OPTIONS_TEXT_SPEED_SLOW] = 1, - [OPTIONS_TEXT_SPEED_MID] = 2, - [OPTIONS_TEXT_SPEED_FAST] = 4, -}; static const u16 sFont_Braille[] = INCBIN_U16("graphics/fonts/braille.fwjpnfont"); static void DecompressGlyph_Braille(u16); @@ -22,6 +16,7 @@ u16 FontFunc_Braille(struct TextPrinter *textPrinter) u16 char_; struct TextPrinterSubStruct *subStruct; subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + u32 scrollSpeed = GetPlayerTextScrollSpeed(); switch (textPrinter->state) { @@ -164,15 +159,15 @@ u16 FontFunc_Braille(struct TextPrinter *textPrinter) case RENDER_STATE_SCROLL: if (textPrinter->scrollDistance) { - if (textPrinter->scrollDistance < sScrollDistances[gSaveBlock2Ptr->optionsTextSpeed]) + if (textPrinter->scrollDistance < scrollSpeed) { ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); textPrinter->scrollDistance = 0; } else { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, sScrollDistances[gSaveBlock2Ptr->optionsTextSpeed], PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance -= sScrollDistances[gSaveBlock2Ptr->optionsTextSpeed]; + ScrollWindow(textPrinter->printerTemplate.windowId, 0, scrollSpeed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance -= scrollSpeed; } CopyWindowToVram(textPrinter->printerTemplate.windowId, COPYWIN_GFX); } diff --git a/src/clock.c b/src/clock.c index 142e62ebf2..2440f5b5a6 100644 --- a/src/clock.c +++ b/src/clock.c @@ -13,6 +13,7 @@ #include "tv.h" #include "wallclock.h" #include "constants/form_change_types.h" +#include "apricorn_tree.h" static void UpdatePerDay(struct Time *localTime); static void UpdatePerMinute(struct Time *localTime); @@ -55,6 +56,7 @@ static void UpdatePerDay(struct Time *localTime) SetShoalItemFlag(daysSince); SetRandomLotteryNumber(daysSince); UpdateDaysPassedSinceFormChange(daysSince); + DailyResetApricornTrees(); *days = localTime->days; } } diff --git a/src/contest.c b/src/contest.c index 18738843ef..fcebf53aba 100644 --- a/src/contest.c +++ b/src/contest.c @@ -360,10 +360,32 @@ EWRAM_DATA u8 gCurContestWinnerSaveIdx = 0; // IWRAM common vars. COMMON_DATA rng_value_t gContestRngValue = {0}; -extern const u8 gText_LinkStandby4[]; +const u8 gText_LinkStandby4[] = COMPOUND_STRING("Link standby!"); extern const u8 gText_BDot[]; extern const u8 gText_CDot[]; -extern void (*const gContestEffectFuncs[])(void); + +//Text +const u8 gText_AppealNumWhichMoveWillBePlayed[] = COMPOUND_STRING("Appeal no. {STR_VAR_1}!\nWhich move will be played?"); +const u8 gText_AppealNumButItCantParticipate[] = COMPOUND_STRING("Appeal no. {STR_VAR_1}!\nBut it can't participate!"); +const u8 gText_MonAppealedWithMove[] = COMPOUND_STRING("{STR_VAR_1} appealed with\n{STR_VAR_2}!"); +const u8 gText_MonWasWatchingOthers[] = COMPOUND_STRING("{STR_VAR_1} was watching\nthe others.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_AllOutOfAppealTime[] = COMPOUND_STRING("We're all out of\nAppeal Time!{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_JudgeLookedAtMonExpectantly[] = COMPOUND_STRING("The JUDGE looked at\n{STR_VAR_1} expectantly.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_AppealComboWentOverWell[] = COMPOUND_STRING("The appeal combo went\nover well.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_AppealComboWentOverVeryWell[] = COMPOUND_STRING("The appeal combo went\nover very well.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_AppealComboWentOverExcellently[] = COMPOUND_STRING("The appeal combo went\nover excellently.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_MonWasTooNervousToMove[] = COMPOUND_STRING("{STR_VAR_1} was too\nnervous to move.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_CouldntImproveItsCondition[] = COMPOUND_STRING("But it couldn't improve\nits condition…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_BadConditionResultedInWeakAppeal[] = COMPOUND_STRING("Its bad condition\nresulted in a weak appeal.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_MonWasUnaffected[] = COMPOUND_STRING("{STR_VAR_1} was\nunaffected.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_RepeatedAppeal[] = COMPOUND_STRING("{STR_VAR_1} disappointed\nby repeating an appeal.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_MonsXWentOverGreat[] = COMPOUND_STRING("{STR_VAR_1}'s {STR_VAR_3}\nwent over great.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_MonsXDidntGoOverWell[] = COMPOUND_STRING("{STR_VAR_1}'s {STR_VAR_3}\ndidn't go over well here…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_MonsXGotTheCrowdGoing[] = COMPOUND_STRING("{STR_VAR_1}'s {STR_VAR_3}\ngot the crowd going.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_MonCantAppealNextTurn[] = COMPOUND_STRING("{STR_VAR_1} can't appeal\nnext turn…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_AttractedCrowdsAttention[] = COMPOUND_STRING("It attracted the crowd's\nattention.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_CrowdContinuesToWatchMon[] = COMPOUND_STRING("The crowd continues to\nwatch {STR_VAR_3}.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); +const u8 gText_MonsMoveIsIgnored[] = COMPOUND_STRING("{STR_VAR_1}'s\n{STR_VAR_2} is ignored.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"); static const u8 sSliderHeartYPositions[CONTESTANT_COUNT] = { @@ -688,84 +710,57 @@ static const u16 sText_Pal[] = INCBIN_U16("graphics/contest/text.gbapal"); #include "data/contest_text_tables.h" -const u8 *const gContestEffectDescriptionPointers[] = +const struct ContestCategory gContestCategoryInfo[CONTEST_CATEGORIES_COUNT + 1] = { - [CONTEST_EFFECT_HIGHLY_APPEALING] = COMPOUND_STRING("A highly appealing move."), - [CONTEST_EFFECT_USER_MORE_EASILY_STARTLED] = COMPOUND_STRING("After this move, the user is\nmore easily startled."), - [CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES] = COMPOUND_STRING("Makes a great appeal, but\nallows no more to the end."), - [CONTEST_EFFECT_REPETITION_NOT_BORING] = COMPOUND_STRING("Can be repeatedly used\nwithout boring the JUDGE."), - [CONTEST_EFFECT_AVOID_STARTLE_ONCE] = COMPOUND_STRING("Can avoid being startled\nby others once."), - [CONTEST_EFFECT_AVOID_STARTLE] = COMPOUND_STRING("Can avoid being startled\nby others."), - [CONTEST_EFFECT_AVOID_STARTLE_SLIGHTLY] = COMPOUND_STRING("Can avoid being startled\nby others a little."), - [CONTEST_EFFECT_USER_LESS_EASILY_STARTLED] = COMPOUND_STRING("After this move, the user is\nless likely to be startled."), - [CONTEST_EFFECT_STARTLE_FRONT_MON] = COMPOUND_STRING("Slightly startles the\nPOKéMON in front."), - [CONTEST_EFFECT_SLIGHTLY_STARTLE_PREV_MONS] = COMPOUND_STRING("Slightly startles those\nthat have made appeals."), - [CONTEST_EFFECT_STARTLE_PREV_MON] = COMPOUND_STRING("Startles the POKéMON that\nappealed before the user."), - [CONTEST_EFFECT_STARTLE_PREV_MONS] = COMPOUND_STRING("Startles all POKéMON that\nhave done their appeals."), - [CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON] = COMPOUND_STRING("Badly startles the\nPOKéMON in front."), - [CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS] = COMPOUND_STRING("Badly startles those that\nhave made appeals."), - [CONTEST_EFFECT_STARTLE_PREV_MON_2] = COMPOUND_STRING("Startles the POKéMON that\nappealed before the user."), - [CONTEST_EFFECT_STARTLE_PREV_MONS_2] = COMPOUND_STRING("Startles all POKéMON that\nhave done their appeals."), - [CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION] = COMPOUND_STRING("Shifts the JUDGE's\nattention from others."), - [CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION] = COMPOUND_STRING("Startles the POKéMON that\nhas the JUDGE's attention."), - [CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN] = COMPOUND_STRING("Jams the others, and misses\none turn of appeals."), - [CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL] = COMPOUND_STRING("Startles POKéMON that\nmade a same-type appeal."), - [CONTEST_EFFECT_STARTLE_MONS_COOL_APPEAL] = COMPOUND_STRING("Badly startles POKéMON\nthat made COOL appeals."), - [CONTEST_EFFECT_STARTLE_MONS_BEAUTY_APPEAL] = COMPOUND_STRING("Badly startles POKéMON\nthat made BEAUTY appeals."), - [CONTEST_EFFECT_STARTLE_MONS_CUTE_APPEAL] = COMPOUND_STRING("Badly startles POKéMON\nthat made CUTE appeals."), - [CONTEST_EFFECT_STARTLE_MONS_SMART_APPEAL] = COMPOUND_STRING("Badly startles POKéMON\nthat made SMART appeals."), - [CONTEST_EFFECT_STARTLE_MONS_TOUGH_APPEAL] = COMPOUND_STRING("Badly startles POKéMON\nthat made TOUGH appeals."), - [CONTEST_EFFECT_MAKE_FOLLOWING_MON_NERVOUS] = COMPOUND_STRING("Makes one POKéMON after\nthe user nervous."), - [CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS] = COMPOUND_STRING("Makes all POKéMON after\nthe user nervous."), - [CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS] = COMPOUND_STRING("Worsens the condition of\nthose that made appeals."), - [CONTEST_EFFECT_BADLY_STARTLES_MONS_IN_GOOD_CONDITION] = COMPOUND_STRING("Badly startles POKéMON in\ngood condition."), - [CONTEST_EFFECT_BETTER_IF_FIRST] = COMPOUND_STRING("The appeal works great if\nperformed first."), - [CONTEST_EFFECT_BETTER_IF_LAST] = COMPOUND_STRING("The appeal works great if\nperformed last."), - [CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES] = COMPOUND_STRING("Makes the appeal as good\nas those before it."), - [CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE] = COMPOUND_STRING("Makes the appeal as good\nas the one before it."), - [CONTEST_EFFECT_BETTER_WHEN_LATER] = COMPOUND_STRING("The appeal works better\nthe later it is performed."), - [CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING] = COMPOUND_STRING("The appeal's quality varies\ndepending on its timing."), - [CONTEST_EFFECT_BETTER_IF_SAME_TYPE] = COMPOUND_STRING("Works well if it's the same\ntype as the one before."), - [CONTEST_EFFECT_BETTER_IF_DIFF_TYPE] = COMPOUND_STRING("Works well if different in\ntype than the one before."), - [CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL] = COMPOUND_STRING("Affected by how well the\nappeal in front goes."), - [CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS] = COMPOUND_STRING("Ups the user's condition.\nHelps prevent nervousness."), - [CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION] = COMPOUND_STRING("The appeal works well if the\nuser's condition is good."), - [CONTEST_EFFECT_NEXT_APPEAL_EARLIER] = COMPOUND_STRING("The next appeal can be\nmade earlier next turn."), - [CONTEST_EFFECT_NEXT_APPEAL_LATER] = COMPOUND_STRING("The next appeal can be\nmade later next turn."), - [CONTEST_EFFECT_MAKE_SCRAMBLING_TURN_ORDER_EASIER] = COMPOUND_STRING("Makes the next turn's order\nmore easily scrambled."), - [CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER] = COMPOUND_STRING("Scrambles the order of\nappeals on the next turn."), - [CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST] = COMPOUND_STRING("An appeal that excites the\naudience in any CONTEST."), - [CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS] = COMPOUND_STRING("Badly startles all POKéMON\nthat made good appeals."), - [CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED] = COMPOUND_STRING("The appeal works best the\nmore the crowd is excited."), - [CONTEST_EFFECT_DONT_EXCITE_AUDIENCE] = COMPOUND_STRING("Temporarily stops the\ncrowd from growing excited."), -}; + [CONTEST_CATEGORY_COOL] = + { + .name = COMPOUND_STRING("COOL"), + .condition = COMPOUND_STRING("coolness"), + .generic = COMPOUND_STRING("COOL Move"), + .negativeTrait = COMPOUND_STRING("shyness"), + .palette = 13, + }, -const u8 *const gContestMoveTypeTextPointers[] = -{ - [CONTEST_CATEGORY_COOL] = COMPOUND_STRING("COOL"), - [CONTEST_CATEGORY_BEAUTY] = COMPOUND_STRING("BEAUTY"), - [CONTEST_CATEGORY_CUTE] = COMPOUND_STRING("CUTE"), - [CONTEST_CATEGORY_SMART] = COMPOUND_STRING("SMART"), - [CONTEST_CATEGORY_TOUGH] = COMPOUND_STRING("TOUGH"), -}; + [CONTEST_CATEGORY_BEAUTY] = + { + .name = COMPOUND_STRING("BEAUTY"), + .condition = COMPOUND_STRING("beauty"), + .generic = COMPOUND_STRING("BEAUTY Move"), + .negativeTrait = COMPOUND_STRING("anxiety"), + .palette = 14, + }, -static const u8 *const sContestConditions[] = -{ - [CONTEST_CATEGORY_COOL] = COMPOUND_STRING("coolness"), - [CONTEST_CATEGORY_BEAUTY] = COMPOUND_STRING("beauty"), - [CONTEST_CATEGORY_CUTE] = COMPOUND_STRING("cuteness"), - [CONTEST_CATEGORY_SMART] = COMPOUND_STRING("smartness"), - [CONTEST_CATEGORY_TOUGH] = COMPOUND_STRING("toughness"), -}; + [CONTEST_CATEGORY_CUTE] = + { + .name = COMPOUND_STRING("CUTE"), + .condition = COMPOUND_STRING("cuteness"), + .generic = COMPOUND_STRING("CUTE Move"), + .negativeTrait = COMPOUND_STRING("laziness"), + .palette = 14, + }, -static const u8 *const sInvalidContestMoveNames[] = -{ - [CONTEST_CATEGORY_COOL] = COMPOUND_STRING("COOL Move"), - [CONTEST_CATEGORY_BEAUTY] = COMPOUND_STRING("BEAUTY Move"), - [CONTEST_CATEGORY_CUTE] = COMPOUND_STRING("CUTE Move"), - [CONTEST_CATEGORY_SMART] = COMPOUND_STRING("SMART Move"), - [CONTEST_CATEGORY_TOUGH] = COMPOUND_STRING("TOUGH Move"), - [CONTEST_CATEGORIES_COUNT] = COMPOUND_STRING("???"), + [CONTEST_CATEGORY_SMART] = + { + .name = COMPOUND_STRING("SMART"), + .condition = COMPOUND_STRING("smartness"), + .generic = COMPOUND_STRING("SMART Move"), + .negativeTrait = COMPOUND_STRING("hesitancy"), + .palette = 15, + }, + + [CONTEST_CATEGORY_TOUGH] = + { + .name = COMPOUND_STRING("TOUGH"), + .condition = COMPOUND_STRING("toughness"), + .generic = COMPOUND_STRING("TOUGH Move"), + .negativeTrait = COMPOUND_STRING("fear"), + .palette = 13, + }, + + [CONTEST_CATEGORIES_COUNT] = + { + .generic = COMPOUND_STRING("???"), + }, }; // Takes the .attentionLevel of a contestant as an index. @@ -1914,7 +1909,7 @@ static void Task_DoAppeals(u8 taskId) if (eContestantStatus[contestant].currMove < MOVES_COUNT) StringCopy(gStringVar2, GetMoveName(eContestantStatus[contestant].currMove)); else - StringCopy(gStringVar2, sInvalidContestMoveNames[eContestantStatus[contestant].moveCategory]); + StringCopy(gStringVar2, gContestCategoryInfo[eContestantStatus[contestant].moveCategory].generic); StringExpandPlaceholders(gStringVar4, gText_MonAppealedWithMove); Contest_StartTextPrinter(gStringVar4, TRUE); gTasks[taskId].tState = APPEALSTATE_WAIT_USED_MOVE_MSG; @@ -2310,7 +2305,7 @@ static void Task_DoAppeals(u8 taskId) } else { - StringCopy(gStringVar3, sContestConditions[GetMoveContestCategory(eContestantStatus[contestant].currMove)]); + StringCopy(gStringVar3, gContestCategoryInfo[GetMoveContestCategory(eContestantStatus[contestant].currMove)].condition); } if (r3 > 0 && eContestantStatus[contestant].repeatedMove) @@ -3330,7 +3325,7 @@ static void PrintContestMoveDescription(u16 move) ContestBG_FillBoxWithTile(0, TILE_FILLED_JAM_HEART, 0x15, 0x20, numHearts, 0x01, 0x11); FillWindowPixelBuffer(WIN_MOVE_DESCRIPTION, PIXEL_FILL(0)); - Contest_PrintTextToBg0WindowStd(WIN_MOVE_DESCRIPTION, gContestEffectDescriptionPointers[GetMoveContestEffect(move)]); + Contest_PrintTextToBg0WindowStd(WIN_MOVE_DESCRIPTION, gContestEffects[GetMoveContestEffect(move)].description); Contest_PrintTextToBg0WindowStd(WIN_SLASH, gText_Slash); } @@ -4559,7 +4554,7 @@ static void CalculateAppealMoveImpact(u8 contestant) && !AreMovesContestCombo(eContestantStatus[contestant].prevMove, eContestantStatus[contestant].currMove)) eContestantStatus[contestant].hasJudgesAttention = FALSE; - gContestEffectFuncs[effect](); + gContestEffects[effect].function(); if (eContestantStatus[contestant].conditionMod == CONDITION_GAIN) eContestantStatus[contestant].appeal += eContestantStatus[contestant].condition - 10; @@ -4664,16 +4659,7 @@ static void PrintAppealMoveResultText(u8 contestant, u8 stringId) { StringCopy(gStringVar1, gContestMons[contestant].nickname); StringCopy(gStringVar2, GetMoveName(eContestantStatus[contestant].currMove)); - if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_COOL) - StringCopy(gStringVar3, gText_Contest_Shyness); - else if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_BEAUTY) - StringCopy(gStringVar3, gText_Contest_Anxiety); - else if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_CUTE) - StringCopy(gStringVar3, gText_Contest_Laziness); - else if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_SMART) - StringCopy(gStringVar3, gText_Contest_Hesitancy); - else - StringCopy(gStringVar3, gText_Contest_Fear); + StringCopy(gStringVar3, gContestCategoryInfo[GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove)].negativeTrait); StringExpandPlaceholders(gStringVar4, sAppealResultTexts[stringId]); ContestClearGeneralTextWindow(); Contest_StartTextPrinter(gStringVar4, TRUE); diff --git a/src/contest_ai.c b/src/contest_ai.c index 77f27fcc91..8d4a347280 100644 --- a/src/contest_ai.c +++ b/src/contest_ai.c @@ -1199,7 +1199,7 @@ static void ContestAICmd_if_condition_not_eq(void) static void ContestAICmd_get_used_combo_starter(void) { - u16 result = FALSE; + bool32 result = FALSE; u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]); if (IsContestantAllowedToCombo(contestant)) diff --git a/src/contest_effect.c b/src/contest_effect.c index 51416ba14a..3190e98443 100644 --- a/src/contest_effect.c +++ b/src/contest_effect.c @@ -133,7 +133,7 @@ static void ContestEffect_UserLessEasilyStartled(void) SetContestantEffectStringID(eContestAppealResults.contestant,CONTEST_STRING_STOPPED_CARING); } -// Slightly startles the POK�MON in front. +// Badly startles the Pokémon in front. static void ContestEffect_StartleFrontMon(void) { u8 idx = 0; @@ -611,6 +611,7 @@ static void ContestEffect_BetterWhenLater(void) } // The appeal's quality varies depending on its timing. +// Despite the name, it seems to be random and not based on timing static void ContestEffect_QualityDependsOnTiming(void) { u8 rval = Random() % 10; diff --git a/src/contest_painting.c b/src/contest_painting.c index e8f929ef4b..cbf6fd6297 100644 --- a/src/contest_painting.c +++ b/src/contest_painting.c @@ -42,32 +42,7 @@ static void PrintContestPaintingCaption(u8, u8); static void VBlankCB_ContestPainting(void); static void _InitContestMonPixels(u8 *spriteGfx, u16 *palette, u16 (*destPixels)[64][64]); -extern const u8 gContestHallPaintingCaption[]; -extern const u8 gContestCoolness[]; -extern const u8 gContestBeauty[]; -extern const u8 gContestCuteness[]; -extern const u8 gContestSmartness[]; -extern const u8 gContestToughness[]; -extern const u8 gContestRankNormal[]; -extern const u8 gContestRankSuper[]; -extern const u8 gContestRankHyper[]; -extern const u8 gContestRankMaster[]; -extern const u8 gContestLink[]; -extern const u8 gContestPaintingCool1[]; -extern const u8 gContestPaintingCool2[]; -extern const u8 gContestPaintingCool3[]; -extern const u8 gContestPaintingBeauty1[]; -extern const u8 gContestPaintingBeauty2[]; -extern const u8 gContestPaintingBeauty3[]; -extern const u8 gContestPaintingCute1[]; -extern const u8 gContestPaintingCute2[]; -extern const u8 gContestPaintingCute3[]; -extern const u8 gContestPaintingSmart1[]; -extern const u8 gContestPaintingSmart2[]; -extern const u8 gContestPaintingSmart3[]; -extern const u8 gContestPaintingTough1[]; -extern const u8 gContestPaintingTough2[]; -extern const u8 gContestPaintingTough3[]; +const u8 gContestHallPaintingCaption[] = COMPOUND_STRING("{STR_VAR_1}\n{STR_VAR_2}'s {STR_VAR_3}"); static const u16 sPictureFramePalettes[] = INCBIN_U16("graphics/picture_frame/bg.gbapal"); static const u32 sPictureFrameTiles_Cool[] = INCBIN_U32("graphics/picture_frame/cool.4bpp.smol"); @@ -85,20 +60,20 @@ static const u32 sPictureFrameTilemap_HallLobby[] = INCBIN_U32("graphics/picture static const u8 *const sContestCategoryNames_Unused[] = { - [CONTEST_CATEGORY_COOL] = gContestCoolness, - [CONTEST_CATEGORY_BEAUTY] = gContestBeauty, - [CONTEST_CATEGORY_CUTE] = gContestCuteness, - [CONTEST_CATEGORY_SMART] = gContestSmartness, - [CONTEST_CATEGORY_TOUGH] = gContestToughness, + [CONTEST_CATEGORY_COOL] = COMPOUND_STRING("COOLNESS"), + [CONTEST_CATEGORY_BEAUTY] = COMPOUND_STRING("BEAUTY"), + [CONTEST_CATEGORY_CUTE] = COMPOUND_STRING("CUTENESS"), + [CONTEST_CATEGORY_SMART] = COMPOUND_STRING("SMARTNESS"), + [CONTEST_CATEGORY_TOUGH] = COMPOUND_STRING("TOUGHNESS"), }; static const u8 *const sContestRankNames[] = { - [CONTEST_RANK_NORMAL] = gContestRankNormal, - [CONTEST_RANK_SUPER] = gContestRankSuper, - [CONTEST_RANK_HYPER] = gContestRankHyper, - [CONTEST_RANK_MASTER] = gContestRankMaster, - [CONTEST_RANK_LINK] = gContestLink, + [CONTEST_RANK_NORMAL] = COMPOUND_STRING("NORMAL RANK"), + [CONTEST_RANK_SUPER] = COMPOUND_STRING("SUPER RANK"), + [CONTEST_RANK_HYPER] = COMPOUND_STRING("HYPER RANK"), + [CONTEST_RANK_MASTER] = COMPOUND_STRING("MASTER RANK"), + [CONTEST_RANK_LINK] = COMPOUND_STRING("LINK"), }; static const struct BgTemplate sBgTemplates[] = @@ -127,21 +102,21 @@ static const struct WindowTemplate sWindowTemplate = static const u8 *const sMuseumCaptions[NUM_PAINTING_CAPTIONS * CONTEST_CATEGORIES_COUNT] = { - [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_COOL] = gContestPaintingCool1, - [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_COOL] = gContestPaintingCool2, - [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_COOL] = gContestPaintingCool3, - [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_BEAUTY] = gContestPaintingBeauty1, - [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_BEAUTY] = gContestPaintingBeauty2, - [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_BEAUTY] = gContestPaintingBeauty3, - [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_CUTE] = gContestPaintingCute1, - [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_CUTE] = gContestPaintingCute2, - [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_CUTE] = gContestPaintingCute3, - [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_SMART] = gContestPaintingSmart1, - [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_SMART] = gContestPaintingSmart2, - [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_SMART] = gContestPaintingSmart3, - [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_TOUGH] = gContestPaintingTough1, - [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_TOUGH] = gContestPaintingTough2, - [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_TOUGH] = gContestPaintingTough3, + [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_COOL] = COMPOUND_STRING("Nonstop supercool--\nthe inestimable {STR_VAR_1}"), + [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_COOL] = COMPOUND_STRING("Hey, there!\nThe good-looking POKéMON {STR_VAR_1}"), + [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_COOL] = COMPOUND_STRING("The marvelous, wonderful, and\nvery great {STR_VAR_1}"), + [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_BEAUTY] = COMPOUND_STRING("This century's last Venus--\nthe beautiful {STR_VAR_1}"), + [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_BEAUTY] = COMPOUND_STRING("{STR_VAR_1}'s dazzling,\nglittering smile"), + [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_BEAUTY] = COMPOUND_STRING("POKéMON CENTER's super idol--\nthe incomparable {STR_VAR_1}"), + [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_CUTE] = COMPOUND_STRING("The lovely and sweet {STR_VAR_1}"), + [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_CUTE] = COMPOUND_STRING("The pretty {STR_VAR_1}'s\nwinning portrait"), + [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_CUTE] = COMPOUND_STRING("Give us a wink!\nThe cutie POKéMON {STR_VAR_1}"), + [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_SMART] = COMPOUND_STRING("The smartness maestro--\nthe wise POKéMON {STR_VAR_1}"), + [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_SMART] = COMPOUND_STRING("{STR_VAR_1}--the one chosen\nabove all POKéMON"), + [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_SMART] = COMPOUND_STRING("The excellent {STR_VAR_1}'s\nmoment of elegance"), + [0 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_TOUGH] = COMPOUND_STRING("The powerfully muscular\nspeedster {STR_VAR_1}"), + [1 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_TOUGH] = COMPOUND_STRING("The strong, stronger, and\nstrongest {STR_VAR_1}"), + [2 + NUM_PAINTING_CAPTIONS * CONTEST_CATEGORY_TOUGH] = COMPOUND_STRING("The mighty tough\nhyper POKéMON {STR_VAR_1}"), }; static const struct OamData sContestPaintingMonOamData = diff --git a/src/contest_util.c b/src/contest_util.c index 3bd5e1ec5f..dd7070e9a3 100644 --- a/src/contest_util.c +++ b/src/contest_util.c @@ -1959,7 +1959,7 @@ void TryEnterContestMon(void) u16 HasMonWonThisContestBefore(void) { - u16 hasRankRibbon = FALSE; + bool32 hasRankRibbon = FALSE; struct Pokemon *mon = &gPlayerParty[gContestMonPartyIndex]; switch (gSpecialVar_ContestCategory) { diff --git a/src/data/abilities.h b/src/data/abilities.h index cfffb4e05d..39a0644c4f 100644 --- a/src/data/abilities.h +++ b/src/data/abilities.h @@ -1,4 +1,4 @@ -const struct Ability gAbilitiesInfo[ABILITIES_COUNT] = +const struct AbilityInfo gAbilitiesInfo[ABILITIES_COUNT] = { [ABILITY_NONE] = { diff --git a/src/data/apricorns.h b/src/data/apricorns.h new file mode 100644 index 0000000000..4f76f30648 --- /dev/null +++ b/src/data/apricorns.h @@ -0,0 +1,18 @@ +struct ApricornTree +{ + u8 minimum; + u8 maximum; + enum ApricornType apricornType; +}; + +const struct ApricornTree gApricornTrees[APRICORN_TREE_COUNT] = +{ + #if APRICORN_TREE_COUNT > 0 + [APRICORN_TREE_NONE] = + { + .minimum = 1, + .maximum = 1, + .apricornType = APRICORN_RED, + }, + #endif +}; diff --git a/src/data/battle_frontier/battle_pyramid_wild_requirements.h b/src/data/battle_frontier/battle_pyramid_wild_requirements.h index fd5695344a..6679905f58 100644 --- a/src/data/battle_frontier/battle_pyramid_wild_requirements.h +++ b/src/data/battle_frontier/battle_pyramid_wild_requirements.h @@ -5,9 +5,9 @@ struct BattlePyramidRequirement { const u16 *moves; /* use moves instead of effects so we don't need to find moves with said effect in our loop */ - u16 abilities[10]; + enum Ability abilities[10]; u8 nAbilities; - u8 type; + enum Type type; u8 nMoves; const u16 *evoItems; u8 nEvoItems; diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 121a753161..e206246b27 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -50,7 +50,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_MIRROR_MOVE] = { - .battleScript = BattleScript_EffectMirrorMove, + .battleScript = BattleScript_EffectHit, .battleTvScore = 1, }, @@ -399,7 +399,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_METRONOME] = { - .battleScript = BattleScript_EffectMetronome, + .battleScript = BattleScript_EffectHit, .battleTvScore = 1, }, @@ -503,7 +503,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_SLEEP_TALK] = { - .battleScript = BattleScript_EffectSleepTalk, + .battleScript = BattleScript_EffectHit, .battleTvScore = 3, .encourageEncore = TRUE, }, @@ -820,14 +820,14 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_FIRST_TURN_ONLY] = { - .battleScript = BattleScript_EffectFirstTurnOnly, + .battleScript = BattleScript_EffectHit, .battleTvScore = 4, .encourageEncore = TRUE, }, [EFFECT_UPROAR] = { - .battleScript = BattleScript_EffectUproar, + .battleScript = BattleScript_EffectHit, .battleTvScore = 4, }, @@ -852,9 +852,9 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .encourageEncore = TRUE, }, - [EFFECT_WORRY_SEED] = + [EFFECT_OVERWRITE_ABILITY] = { - .battleScript = BattleScript_EffectWorrySeed, + .battleScript = BattleScript_EffectOverwriteAbility, .battleTvScore = 0, // TODO: Assign points .encourageEncore = TRUE, }, @@ -912,7 +912,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_NATURE_POWER] = { - .battleScript = BattleScript_EffectNaturePower, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, @@ -957,7 +957,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_ASSIST] = { - .battleScript = BattleScript_EffectAssist, + .battleScript = BattleScript_EffectHit, .battleTvScore = 2, }, @@ -1393,13 +1393,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_SUCKER_PUNCH] = { - .battleScript = BattleScript_EffectSuckerPunch, - .battleTvScore = 0, // TODO: Assign points - }, - - [EFFECT_SIMPLE_BEAM] = - { - .battleScript = BattleScript_EffectSimpleBeam, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, @@ -1487,7 +1481,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_ME_FIRST] = { - .battleScript = BattleScript_EffectMeFirst, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, @@ -1532,7 +1526,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_LAST_RESORT] = { - .battleScript = BattleScript_EffectLastResort, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, @@ -1602,7 +1596,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_COPYCAT] = { - .battleScript = BattleScript_EffectCopycat, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, @@ -1722,7 +1716,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_MAT_BLOCK] = { - .battleScript = BattleScript_EffectMatBlock, + .battleScript = BattleScript_EffectProtect, .battleTvScore = 0, // TODO: Assign points .encourageEncore = TRUE, }, @@ -1775,7 +1769,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_FAIL_IF_NOT_ARG_TYPE] = { - .battleScript = BattleScript_FailIfNotArgType, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, @@ -1882,7 +1876,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_AURA_WHEEL] = { - .battleScript = BattleScript_EffectAuraWheel, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, @@ -1985,12 +1979,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_HIT_SET_TERRAIN] = - { - .battleScript = BattleScript_EffectHitSetTerrain, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_DARK_VOID] = { .battleScript = BattleScript_EffectDarkVoid, @@ -2134,7 +2122,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_UPPER_HAND] = { - .battleScript = BattleScript_EffectUpperHand, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points .encourageEncore = TRUE, }, @@ -2234,7 +2222,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_STEEL_ROLLER] = { - .battleScript = BattleScript_EffectSteelRoller, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, diff --git a/src/data/battle_pool_rules.h b/src/data/battle_pool_rules.h index b88db3c797..eefb101f55 100644 --- a/src/data/battle_pool_rules.h +++ b/src/data/battle_pool_rules.h @@ -12,6 +12,8 @@ const struct PoolRules defaultPoolRules = .excludeForms = B_POOL_RULE_EXCLUDE_FORMS, .itemClause = B_POOL_RULE_ITEM_CLAUSE, .itemClauseExclusions = B_POOL_RULES_USE_ITEM_EXCLUSIONS, + .megaStoneClause = B_POOL_RULE_MEGA_STONE_CLAUSE, + .zCrystalClause = B_POOL_RULE_Z_CRYSTAL_CLAUSE, }; const struct PoolRules gPoolRulesetsList[] = { @@ -20,6 +22,8 @@ const struct PoolRules gPoolRulesetsList[] = { .excludeForms = B_POOL_RULE_EXCLUDE_FORMS, .itemClause = B_POOL_RULE_ITEM_CLAUSE, .itemClauseExclusions = B_POOL_RULES_USE_ITEM_EXCLUSIONS, + .megaStoneClause = B_POOL_RULE_MEGA_STONE_CLAUSE, + .zCrystalClause = B_POOL_RULE_Z_CRYSTAL_CLAUSE, .tagMaxMembers[POOL_TAG_LEAD] = 1, .tagMaxMembers[POOL_TAG_ACE] = 1, }, @@ -28,6 +32,8 @@ const struct PoolRules gPoolRulesetsList[] = { .excludeForms = B_POOL_RULE_EXCLUDE_FORMS, .itemClause = B_POOL_RULE_ITEM_CLAUSE, .itemClauseExclusions = B_POOL_RULES_USE_ITEM_EXCLUSIONS, + .megaStoneClause = B_POOL_RULE_MEGA_STONE_CLAUSE, + .zCrystalClause = B_POOL_RULE_Z_CRYSTAL_CLAUSE, .tagMaxMembers[POOL_TAG_LEAD] = 2, .tagMaxMembers[POOL_TAG_ACE] = 2, }, @@ -36,6 +42,8 @@ const struct PoolRules gPoolRulesetsList[] = { .excludeForms = B_POOL_RULE_EXCLUDE_FORMS, .itemClause = B_POOL_RULE_ITEM_CLAUSE, .itemClauseExclusions = B_POOL_RULES_USE_ITEM_EXCLUSIONS, + .megaStoneClause = B_POOL_RULE_MEGA_STONE_CLAUSE, + .zCrystalClause = B_POOL_RULE_Z_CRYSTAL_CLAUSE, .tagMaxMembers[POOL_TAG_LEAD] = 1, .tagMaxMembers[POOL_TAG_ACE] = 1, .tagMaxMembers[POOL_TAG_WEATHER_SETTER] = 1, @@ -48,6 +56,8 @@ const struct PoolRules gPoolRulesetsList[] = { .excludeForms = B_POOL_RULE_EXCLUDE_FORMS, .itemClause = B_POOL_RULE_ITEM_CLAUSE, .itemClauseExclusions = B_POOL_RULES_USE_ITEM_EXCLUSIONS, + .megaStoneClause = B_POOL_RULE_MEGA_STONE_CLAUSE, + .zCrystalClause = B_POOL_RULE_Z_CRYSTAL_CLAUSE, .tagMaxMembers[POOL_TAG_LEAD] = 2, .tagMaxMembers[POOL_TAG_ACE] = 2, .tagMaxMembers[POOL_TAG_WEATHER_SETTER] = 1, @@ -60,6 +70,8 @@ const struct PoolRules gPoolRulesetsList[] = { .excludeForms = B_POOL_RULE_EXCLUDE_FORMS, .itemClause = B_POOL_RULE_ITEM_CLAUSE, .itemClauseExclusions = B_POOL_RULES_USE_ITEM_EXCLUSIONS, + .megaStoneClause = B_POOL_RULE_MEGA_STONE_CLAUSE, + .zCrystalClause = B_POOL_RULE_Z_CRYSTAL_CLAUSE, .tagMaxMembers[POOL_TAG_LEAD] = 2, .tagMaxMembers[POOL_TAG_ACE] = 2, .tagMaxMembers[POOL_TAG_SUPPORT] = 1, diff --git a/src/data/contest_moves.h b/src/data/contest_moves.h index ce88430bb6..39d6abbd52 100644 --- a/src/data/contest_moves.h +++ b/src/data/contest_moves.h @@ -2,342 +2,422 @@ const struct ContestEffect gContestEffects[] = { [CONTEST_EFFECT_HIGHLY_APPEALING] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Quite the appealing move."), + #else + .description = COMPOUND_STRING("A highly appealing move."), + #endif .effectType = CONTEST_EFFECT_TYPE_APPEAL, .appeal = 40, .jam = 0, + .function = ContestEffect_HighlyAppealing, }, [CONTEST_EFFECT_USER_MORE_EASILY_STARTLED] = { + .description = COMPOUND_STRING("After this move, the user is\nmore easily startled."), .effectType = CONTEST_EFFECT_TYPE_APPEAL, .appeal = 60, .jam = 0, + .function = ContestEffect_UserMoreEasilyStartled, }, [CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES] = { + .description = COMPOUND_STRING("Makes a great appeal, but\nallows no more to the end."), .effectType = CONTEST_EFFECT_TYPE_APPEAL, .appeal = 80, .jam = 0, + .function = ContestEffect_GreatAppealButNoMoreMoves, }, [CONTEST_EFFECT_REPETITION_NOT_BORING] = { + .description = COMPOUND_STRING("Can be repeatedly used\nwithout boring the JUDGE."), .effectType = CONTEST_EFFECT_TYPE_APPEAL, .appeal = 30, .jam = 0, + .function = ContestEffect_RepetitionNotBoring, }, [CONTEST_EFFECT_AVOID_STARTLE_ONCE] = { + .description = COMPOUND_STRING("Can avoid being startled\nby others once."), .effectType = CONTEST_EFFECT_TYPE_AVOID_STARTLE, .appeal = 20, .jam = 0, + .function = ContestEffect_AvoidStartleOnce, }, [CONTEST_EFFECT_AVOID_STARTLE] = { + .description = COMPOUND_STRING("Can avoid being startled\nby others."), .effectType = CONTEST_EFFECT_TYPE_AVOID_STARTLE, .appeal = 10, .jam = 0, + .function = ContestEffect_AvoidStartle, }, [CONTEST_EFFECT_AVOID_STARTLE_SLIGHTLY] = { + .description = COMPOUND_STRING("Can avoid being startled\nby others a little."), .effectType = CONTEST_EFFECT_TYPE_AVOID_STARTLE, .appeal = 30, .jam = 0, + .function = ContestEffect_AvoidStartleSlightly, }, [CONTEST_EFFECT_USER_LESS_EASILY_STARTLED] = { + .description = COMPOUND_STRING("After this move, the user is\nless likely to be startled."), .effectType = CONTEST_EFFECT_TYPE_AVOID_STARTLE, .appeal = 30, .jam = 0, + .function = ContestEffect_UserLessEasilyStartled, }, [CONTEST_EFFECT_STARTLE_FRONT_MON] = { + .description = COMPOUND_STRING("Slightly startles the\nPOKéMON in front."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MON, .appeal = 30, .jam = 20, + .function = ContestEffect_StartleFrontMon, }, [CONTEST_EFFECT_SLIGHTLY_STARTLE_PREV_MONS] = { + .description = COMPOUND_STRING("Slightly startles those\nthat have made appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 30, .jam = 10, + .function = ContestEffect_StartlePrevMons, }, [CONTEST_EFFECT_STARTLE_PREV_MON] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Startles the last Pokémon\nto act before the user."), + #else + .description = COMPOUND_STRING("Startles the POKéMON that\nappealed before the user."), + #endif .effectType = CONTEST_EFFECT_TYPE_STARTLE_MON, .appeal = 20, .jam = 30, + .function = ContestEffect_StartleFrontMon, }, [CONTEST_EFFECT_STARTLE_PREV_MONS] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Startles all of the Pokémon\nto act before the user."), + #else + .description = COMPOUND_STRING("Startles all POKéMON that\nhave done their appeals."), + #endif .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 20, + .function = ContestEffect_StartlePrevMons, }, [CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON] = { + .description = COMPOUND_STRING("Badly startles the\nPOKéMON in front."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MON, .appeal = 10, .jam = 40, + .function = ContestEffect_StartleFrontMon, }, [CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS] = { + .description = COMPOUND_STRING("Badly startles those that\nhave made appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 10, .jam = 30, + .function = ContestEffect_StartlePrevMons, }, [CONTEST_EFFECT_STARTLE_PREV_MON_2] = { + .description = COMPOUND_STRING("Startles the POKéMON that\nappealed before the user."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MON, .appeal = 30, .jam = 20, + .function = ContestEffect_StartlePrevMon2, }, [CONTEST_EFFECT_STARTLE_PREV_MONS_2] = { + .description = COMPOUND_STRING("Startles all POKéMON that\nhave done their appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 30, .jam = 10, + .function = ContestEffect_StartlePrevMons2, }, [CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Makes audience expect\nlittle of other contestants."), + #else + .description = COMPOUND_STRING("Shifts the JUDGE's\nattention from others."), + #endif .effectType = CONTEST_EFFECT_TYPE_WORSEN, .appeal = 30, .jam = 0, + .function = ContestEffect_ShiftJudgeAttention, }, [CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION] = { + .description = COMPOUND_STRING("Startles the POKéMON that\nhas the JUDGE's attention."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_StartleMonWithJudgesAttention, }, [CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN] = { + .description = COMPOUND_STRING("Jams the others, and misses\none turn of appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 40, .jam = 40, + .function = ContestEffect_JamsOthersButMissOneTurn, }, [CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL] = { + .description = COMPOUND_STRING("Startles POKéMON that\nmade a same-type appeal."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_StartleMonsSameTypeAppeal, }, [CONTEST_EFFECT_STARTLE_MONS_COOL_APPEAL] = { + .description = COMPOUND_STRING("Badly startles POKéMON\nthat made COOL appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_StartleMonsCoolAppeal, }, [CONTEST_EFFECT_STARTLE_MONS_BEAUTY_APPEAL] = { + .description = COMPOUND_STRING("Badly startles POKéMON\nthat made BEAUTY appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_StartleMonsBeautyAppeal, }, [CONTEST_EFFECT_STARTLE_MONS_CUTE_APPEAL] = { + .description = COMPOUND_STRING("Badly startles POKéMON\nthat made CUTE appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_StartleMonsCuteAppeal, }, [CONTEST_EFFECT_STARTLE_MONS_SMART_APPEAL] = { + .description = COMPOUND_STRING("Badly startles POKéMON\nthat made SMART appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_StartleMonsSmartAppeal, }, [CONTEST_EFFECT_STARTLE_MONS_TOUGH_APPEAL] = { + .description = COMPOUND_STRING("Badly startles POKéMON\nthat made TOUGH appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_StartleMonsToughAppeal, }, [CONTEST_EFFECT_MAKE_FOLLOWING_MON_NERVOUS] = { + .description = COMPOUND_STRING("Makes one POKéMON after\nthe user nervous."), .effectType = CONTEST_EFFECT_TYPE_WORSEN, .appeal = 20, .jam = 0, + .function = ContestEffect_MakeFollowingMonNervous, }, [CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Makes the remaining\nPokémon nervous."), + #else + .description = COMPOUND_STRING("Makes all POKéMON after\nthe user nervous."), + #endif .effectType = CONTEST_EFFECT_TYPE_WORSEN, .appeal = 20, .jam = 0, + .function = ContestEffect_MakeFollowingMonsNervous, }, [CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS] = { + .description = COMPOUND_STRING("Worsens the condition of\nthose that made appeals."), .effectType = CONTEST_EFFECT_TYPE_WORSEN, .appeal = 30, .jam = 0, + .function = ContestEffect_WorsenConditionOfPrevMons, }, [CONTEST_EFFECT_BADLY_STARTLES_MONS_IN_GOOD_CONDITION] = { + .description = COMPOUND_STRING("Badly startles POKéMON in\ngood condition."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 30, .jam = 10, + .function = ContestEffect_BadlyStartlesMonsInGoodCondition, }, [CONTEST_EFFECT_BETTER_IF_FIRST] = { + .description = COMPOUND_STRING("The appeal works great if\nperformed first."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 20, .jam = 0, + .function = ContestEffect_BetterIfFirst, }, [CONTEST_EFFECT_BETTER_IF_LAST] = { + .description = COMPOUND_STRING("The appeal works great if\nperformed last."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 20, .jam = 0, + .function = ContestEffect_BetterIfLast, }, [CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES] = { + .description = COMPOUND_STRING("Makes the appeal as good\nas those before it."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 10, .jam = 0, + .function = ContestEffect_AppealAsGoodAsPrevOnes, }, [CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE] = { + .description = COMPOUND_STRING("Makes the appeal as good\nas the one before it."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 10, .jam = 0, + .function = ContestEffect_AppealAsGoodAsPrevOne, }, [CONTEST_EFFECT_BETTER_WHEN_LATER] = { + .description = COMPOUND_STRING("The appeal works better\nthe later it is performed."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 10, .jam = 0, + .function = ContestEffect_BetterWhenLater, }, [CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Effectiveness varies\ndepending on when it is used."), + #else + .description = COMPOUND_STRING("The appeal's quality varies\ndepending on its timing."), + #endif .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 10, .jam = 0, + .function = ContestEffect_QualityDependsOnTiming, }, [CONTEST_EFFECT_BETTER_IF_SAME_TYPE] = { + .description = COMPOUND_STRING("Works well if it's the same\ntype as the one before."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 20, .jam = 0, + .function = ContestEffect_BetterIfSameType, }, [CONTEST_EFFECT_BETTER_IF_DIFF_TYPE] = { + .description = COMPOUND_STRING("Works well if different in\ntype than the one before."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 20, .jam = 0, + .function = ContestEffect_BetterIfDiffType, }, [CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Affected by how well the\nprevious Pokémon's move went."), + #else + .description = COMPOUND_STRING("Affected by how well the\nappeal in front goes."), + #endif .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 30, .jam = 0, + .function = ContestEffect_AffectedByPrevAppeal, }, [CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS] = { + .description = COMPOUND_STRING("Ups the user's condition.\nHelps prevent nervousness."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 10, .jam = 0, + .function = ContestEffect_ImproveConditionPreventNervousness, }, [CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION] = { + .description = COMPOUND_STRING("The appeal works well if the\nuser's condition is good."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 10, .jam = 0, + .function = ContestEffect_BetterWithGoodCondition, }, [CONTEST_EFFECT_NEXT_APPEAL_EARLIER] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Causes the user to move\nearlier on the next turn."), + #else + .description = COMPOUND_STRING("The next appeal can be\nmade earlier next turn."), + #endif .effectType = CONTEST_EFFECT_TYPE_TURN_ORDER, .appeal = 30, .jam = 0, + .function = ContestEffect_NextAppealEarlier, }, [CONTEST_EFFECT_NEXT_APPEAL_LATER] = { + #if C_UPDATED_MOVE_EFFECTS >= GEN_6 + .description = COMPOUND_STRING("Causes the user to move\nlater on the next turn."), + #else + .description = COMPOUND_STRING("The next appeal can be\nmade later next turn."), + #endif .effectType = CONTEST_EFFECT_TYPE_TURN_ORDER, .appeal = 30, .jam = 0, + .function = ContestEffect_NextAppealLater, }, [CONTEST_EFFECT_MAKE_SCRAMBLING_TURN_ORDER_EASIER] = { + .description = COMPOUND_STRING("Makes the next turn's order\nmore easily scrambled."), .effectType = CONTEST_EFFECT_TYPE_TURN_ORDER, .appeal = 30, .jam = 0, + .function = ContestEffect_MakeScramblingTurnOrderEasier, }, [CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER] = { + .description = COMPOUND_STRING("Scrambles the order of\nappeals on the next turn."), .effectType = CONTEST_EFFECT_TYPE_TURN_ORDER, .appeal = 30, .jam = 0, + .function = ContestEffect_ScrambleNextTurnOrder, }, [CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST] = { + .description = COMPOUND_STRING("An appeal that excites the\naudience in any CONTEST."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, - .appeal = 10, + .appeal = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? 20 : 10, .jam = 0, + .function = ContestEffect_ExciteAudienceInAnyContest, }, [CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS] = { + .description = COMPOUND_STRING("Badly startles all POKéMON\nthat made good appeals."), .effectType = CONTEST_EFFECT_TYPE_STARTLE_MONS, .appeal = 20, .jam = 10, + .function = ContestEffect_BadlyStartleMonsWithGoodAppeals, }, [CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED] = { + .description = COMPOUND_STRING("The appeal works best the\nmore the crowd is excited."), .effectType = CONTEST_EFFECT_TYPE_SPECIAL_APPEAL, .appeal = 10, .jam = 0, + .function = ContestEffect_BetterWhenAudienceExcited, }, [CONTEST_EFFECT_DONT_EXCITE_AUDIENCE] = { + .description = COMPOUND_STRING("Temporarily stops the\ncrowd from growing excited."), .effectType = CONTEST_EFFECT_TYPE_WORSEN, .appeal = 30, .jam = 0, + .function = ContestEffect_DontExciteAudience, }, }; - -void (*const gContestEffectFuncs[])(void) = -{ - ContestEffect_HighlyAppealing, - ContestEffect_UserMoreEasilyStartled, - ContestEffect_GreatAppealButNoMoreMoves, - ContestEffect_RepetitionNotBoring, - ContestEffect_AvoidStartleOnce, - ContestEffect_AvoidStartle, - ContestEffect_AvoidStartleSlightly, - ContestEffect_UserLessEasilyStartled, - ContestEffect_StartleFrontMon, - ContestEffect_StartlePrevMons, - ContestEffect_StartleFrontMon, - ContestEffect_StartlePrevMons, - ContestEffect_StartleFrontMon, - ContestEffect_StartlePrevMons, - ContestEffect_StartlePrevMon2, - ContestEffect_StartlePrevMons2, - ContestEffect_ShiftJudgeAttention, - ContestEffect_StartleMonWithJudgesAttention, - ContestEffect_JamsOthersButMissOneTurn, - ContestEffect_StartleMonsSameTypeAppeal, - ContestEffect_StartleMonsCoolAppeal, - ContestEffect_StartleMonsBeautyAppeal, - ContestEffect_StartleMonsCuteAppeal, - ContestEffect_StartleMonsSmartAppeal, - ContestEffect_StartleMonsToughAppeal, - ContestEffect_MakeFollowingMonNervous, - ContestEffect_MakeFollowingMonsNervous, - ContestEffect_WorsenConditionOfPrevMons, - ContestEffect_BadlyStartlesMonsInGoodCondition, - ContestEffect_BetterIfFirst, - ContestEffect_BetterIfLast, - ContestEffect_AppealAsGoodAsPrevOnes, - ContestEffect_AppealAsGoodAsPrevOne, - ContestEffect_BetterWhenLater, - ContestEffect_QualityDependsOnTiming, - ContestEffect_BetterIfSameType, - ContestEffect_BetterIfDiffType, - ContestEffect_AffectedByPrevAppeal, - ContestEffect_ImproveConditionPreventNervousness, - ContestEffect_BetterWithGoodCondition, - ContestEffect_NextAppealEarlier, - ContestEffect_NextAppealLater, - ContestEffect_MakeScramblingTurnOrderEasier, - ContestEffect_ScrambleNextTurnOrder, - ContestEffect_ExciteAudienceInAnyContest, - ContestEffect_BadlyStartleMonsWithGoodAppeals, - ContestEffect_BetterWhenAudienceExcited, - ContestEffect_DontExciteAudience, -}; diff --git a/src/data/contest_text_tables.h b/src/data/contest_text_tables.h index 3560b2af04..6de163b1b5 100644 --- a/src/data/contest_text_tables.h +++ b/src/data/contest_text_tables.h @@ -1,151 +1,73 @@ #include "global.h" // sAppealResultTexts -extern const u8 gText_BecameMoreConsciousOfOtherMons[]; -extern const u8 gText_MonCantMakeAnAppealAfterThis[]; -extern const u8 gText_SettledDownJustLittleBit[]; -extern const u8 gText_BecameObliviousToOtherMons[]; -extern const u8 gText_BecameLessAwareOfOtherMons[]; -extern const u8 gText_StoppedCaringAboutOtherMons[]; -extern const u8 gText_TriedToStartleOtherMons[]; -extern const u8 gText_TriedToDazzleOthers[]; -extern const u8 gText_JudgeLookedAwayFromMon[]; -extern const u8 gText_TriedToUnnerveNextMon[]; -extern const u8 gText_MonBecameNervous[]; -extern const u8 gText_AppealTriedToUnnerveWaitingMons[]; -extern const u8 gText_TauntedMonsDoingWell[]; -extern const u8 gText_MonRegainedItsForm[]; -extern const u8 gText_TriedToJamMonDoingWell[]; -extern const u8 gText_StandoutMonHustledEvenMore[]; -extern const u8 gText_LargelyUnnoticedMonWorkedHard[]; -extern const u8 gText_WorkedAsMuchAsMonBefore[]; -extern const u8 gText_WorkedAsMuchAsPrecedingMon[]; -extern const u8 gText_MonsAppealWasDud[]; -extern const u8 gText_MonsAppealDidNotGoWell[]; -extern const u8 gText_MonsAppealDidNotGoWell2[]; -extern const u8 gText_MonsAppealDidNotGoWell3[]; -extern const u8 gText_MonsAppealDidNotWorkVeryWell[]; -extern const u8 gText_MonsAppealWentSlightlyWell[]; -extern const u8 gText_MonsAppealWentSlightlyWell2[]; -extern const u8 gText_MonsAppealWentPrettyWell[]; -extern const u8 gText_MonsAppealWentPrettyWell2[]; -extern const u8 gText_MonsAppealWentVeryWell[]; -extern const u8 gText_MonsAppealWentExcellently[]; -extern const u8 gText_MonsAppealWentExcellently2[]; -extern const u8 gText_SameTypeAsOneBeforeGood[]; -extern const u8 gText_NotSameTypeAsOneBeforeGood[]; -extern const u8 gText_StoodOutMuchMoreThanMonBefore[]; -extern const u8 gText_DidntDoAsWellAsMonBefore[]; -extern const u8 gText_MonsConditionRoseAboveUsual[]; -extern const u8 gText_MonsHotStatusMadeGreatAppeal[]; -extern const u8 gText_MovedUpInLineForNextAppeal[]; -extern const u8 gText_MovedBackInLineForNextAppeal[]; -extern const u8 gText_ScrambledUpOrderForNextTurn[]; extern const u8 gText_JudgeLookedAtMonExpectantly[]; extern const u8 gText_AppealComboWentOverWell[]; extern const u8 gText_AppealComboWentOverVeryWell[]; extern const u8 gText_AppealComboWentOverExcellently[]; -extern const u8 gText_MonManagedToAvertGaze[]; -extern const u8 gText_MonManagedToAvoidSeeingIt[]; -extern const u8 gText_MonIsntFazedByThatSortOfThing[]; -extern const u8 gText_MonBecameALittleDistracted[]; -extern const u8 gText_TriedToStartleOtherPokemon[]; -extern const u8 gText_MonLookedDownOutOfDistraction[]; -extern const u8 gText_MonTurnedBackOutOfDistraction[]; -extern const u8 gText_MonCouldntHelpUtteringCry[]; -extern const u8 gText_MonCouldntHelpLeapingUp[]; -extern const u8 gText_MonTrippedOutOfDistraction[]; -extern const u8 gText_ButItMessedUp2[]; -extern const u8 gText_ButItFailedToMakeTargetNervous[]; -extern const u8 gText_ButItFailedToMakeAnyoneNervous[]; -extern const u8 gText_ButItWasIgnored[]; -extern const u8 gText_CouldntImproveItsCondition[]; -extern const u8 gText_BadConditionResultedInWeakAppeal[]; -extern const u8 gText_MonWasUnaffected[]; -extern const u8 gText_AttractedCrowdsAttention[]; - -// Misc, used directly -extern const u8 gText_MonAppealedWithMove[]; -extern const u8 gText_MonCantAppealNextTurn[]; -extern const u8 gText_RepeatedAppeal[]; -extern const u8 gText_MonsXDidntGoOverWell[]; -extern const u8 gText_MonsXWentOverGreat[]; -extern const u8 gText_MonsXGotTheCrowdGoing[]; -extern const u8 gText_CrowdContinuesToWatchMon[]; -extern const u8 gText_MonsMoveIsIgnored[]; -extern const u8 gText_MonWasTooNervousToMove[]; -extern const u8 gText_MonWasWatchingOthers[]; -extern const u8 gText_AllOutOfAppealTime[]; -extern const u8 gText_Contest_Shyness[]; -extern const u8 gText_Contest_Anxiety[]; -extern const u8 gText_Contest_Laziness[]; -extern const u8 gText_Contest_Hesitancy[]; -extern const u8 gText_Contest_Fear[]; -extern const u8 gText_AppealNumWhichMoveWillBePlayed[]; -extern const u8 gText_AppealNumButItCantParticipate[]; static const u8 *const sAppealResultTexts[] = { - [CONTEST_STRING_MORE_CONSCIOUS] = gText_BecameMoreConsciousOfOtherMons, - [CONTEST_STRING_NO_APPEAL] = gText_MonCantMakeAnAppealAfterThis, - [CONTEST_STRING_SETTLE_DOWN] = gText_SettledDownJustLittleBit, - [CONTEST_STRING_OBLIVIOUS_TO_OTHERS] = gText_BecameObliviousToOtherMons, - [CONTEST_STRING_LESS_AWARE] = gText_BecameLessAwareOfOtherMons, - [CONTEST_STRING_STOPPED_CARING] = gText_StoppedCaringAboutOtherMons, - [CONTEST_STRING_STARTLE_ATTEMPT] = gText_TriedToStartleOtherMons, - [CONTEST_STRING_DAZZLE_ATTEMPT] = gText_TriedToDazzleOthers, - [CONTEST_STRING_JUDGE_LOOK_AWAY2] = gText_JudgeLookedAwayFromMon, - [CONTEST_STRING_UNNERVE_ATTEMPT] = gText_TriedToUnnerveNextMon, - [CONTEST_STRING_NERVOUS] = gText_MonBecameNervous, - [CONTEST_STRING_UNNERVE_WAITING] = gText_AppealTriedToUnnerveWaitingMons, - [CONTEST_STRING_TAUNT_WELL] = gText_TauntedMonsDoingWell, - [CONTEST_STRING_REGAINED_FORM] = gText_MonRegainedItsForm, - [CONTEST_STRING_JAM_WELL] = gText_TriedToJamMonDoingWell, - [CONTEST_STRING_HUSTLE_STANDOUT] = gText_StandoutMonHustledEvenMore, - [CONTEST_STRING_WORK_HARD_UNNOTICED] = gText_LargelyUnnoticedMonWorkedHard, - [CONTEST_STRING_WORK_BEFORE] = gText_WorkedAsMuchAsMonBefore, - [CONTEST_STRING_APPEAL_NOT_WELL] = gText_MonsAppealDidNotGoWell, - [CONTEST_STRING_WORK_PRECEDING] = gText_WorkedAsMuchAsPrecedingMon, - [CONTEST_STRING_APPEAL_NOT_WELL2] = gText_MonsAppealDidNotGoWell2, - [CONTEST_STRING_APPEAL_NOT_SHOWN_WELL] = gText_MonsAppealDidNotGoWell3, - [CONTEST_STRING_APPEAL_SLIGHTLY_WELL] = gText_MonsAppealWentSlightlyWell, - [CONTEST_STRING_APPEAL_PRETTY_WELL] = gText_MonsAppealWentPrettyWell, - [CONTEST_STRING_APPEAL_EXCELLENTLY] = gText_MonsAppealWentExcellently, - [CONTEST_STRING_APPEAL_DUD] = gText_MonsAppealWasDud, - [CONTEST_STRING_APPEAL_NOT_VERY_WELL] = gText_MonsAppealDidNotWorkVeryWell, - [CONTEST_STRING_APPEAL_SLIGHTLY_WELL2] = gText_MonsAppealWentSlightlyWell2, - [CONTEST_STRING_APPEAL_PRETTY_WELL2] = gText_MonsAppealWentPrettyWell2, - [CONTEST_STRING_APPEAL_VERY_WELL] = gText_MonsAppealWentVeryWell, - [CONTEST_STRING_APPEAL_EXCELLENTLY2] = gText_MonsAppealWentExcellently2, - [CONTEST_STRING_SAME_TYPE_GOOD] = gText_SameTypeAsOneBeforeGood, - [CONTEST_STRING_DIFF_TYPE_GOOD] = gText_NotSameTypeAsOneBeforeGood, - [CONTEST_STRING_STOOD_OUT_AS_MUCH] = gText_StoodOutMuchMoreThanMonBefore, - [CONTEST_STRING_NOT_AS_WELL] = gText_DidntDoAsWellAsMonBefore, - [CONTEST_STRING_CONDITION_ROSE] = gText_MonsConditionRoseAboveUsual, - [CONTEST_STRING_HOT_STATUS] = gText_MonsHotStatusMadeGreatAppeal, - [CONTEST_STRING_MOVE_UP_LINE] = gText_MovedUpInLineForNextAppeal, - [CONTEST_STRING_MOVE_BACK_LINE] = gText_MovedBackInLineForNextAppeal, - [CONTEST_STRING_SCRAMBLE_ORDER] = gText_ScrambledUpOrderForNextTurn, + [CONTEST_STRING_MORE_CONSCIOUS] = COMPOUND_STRING("It became more conscious\nof the other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_NO_APPEAL] = COMPOUND_STRING("{STR_VAR_1} can't make an\nappeal after this.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_SETTLE_DOWN] = COMPOUND_STRING("It settled down just a\nlittle bit.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_OBLIVIOUS_TO_OTHERS] = COMPOUND_STRING("It became oblivious to\nthe other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_LESS_AWARE] = COMPOUND_STRING("It became less aware of\nthe other POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_STOPPED_CARING] = COMPOUND_STRING("It stopped caring about\nother POKéMON much.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_STARTLE_ATTEMPT] = COMPOUND_STRING("It tried to startle the\nother POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_DAZZLE_ATTEMPT] = COMPOUND_STRING("It tried to dazzle the\nothers.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_JUDGE_LOOK_AWAY2] = COMPOUND_STRING("The JUDGE looked away\nfrom {STR_VAR_1}.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_UNNERVE_ATTEMPT] = COMPOUND_STRING("It tried to unnerve the\nnext POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_NERVOUS] = COMPOUND_STRING("{STR_VAR_1} became\nnervous.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_UNNERVE_WAITING] = COMPOUND_STRING("The appeal tried to\nunnerve waiting POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_TAUNT_WELL] = COMPOUND_STRING("It taunted POKéMON\ndoing well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_REGAINED_FORM] = COMPOUND_STRING("{STR_VAR_1} regained its\nform.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_JAM_WELL] = COMPOUND_STRING("It tried to jam POKéMON\ndoing well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_HUSTLE_STANDOUT] = COMPOUND_STRING("The standout {STR_VAR_1}\nhustled even more.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_WORK_HARD_UNNOTICED] = COMPOUND_STRING("The largely unnoticed\n{STR_VAR_1} worked hard.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_WORK_BEFORE] = COMPOUND_STRING("It worked as much as\nPOKéMON before it.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_NOT_WELL] = COMPOUND_STRING("{STR_VAR_1}'s appeal did\nnot go well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_WORK_PRECEDING] = COMPOUND_STRING("It worked as much as the\npreceding POKéMON.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_NOT_WELL2] = COMPOUND_STRING("{STR_VAR_1}'s appeal did\nnot go well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_NOT_SHOWN_WELL] = COMPOUND_STRING("{STR_VAR_1}'s appeal did\nnot go well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_SLIGHTLY_WELL] = COMPOUND_STRING("{STR_VAR_1}'s appeal\nwent slightly well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_PRETTY_WELL] = COMPOUND_STRING("{STR_VAR_1}'s appeal\nwent pretty well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_EXCELLENTLY] = COMPOUND_STRING("{STR_VAR_1}'s appeal\nwent excellently.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_DUD] = COMPOUND_STRING("{STR_VAR_1}'s appeal was\na dud.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_NOT_VERY_WELL] = COMPOUND_STRING("{STR_VAR_1}'s appeal did\nnot work very well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_SLIGHTLY_WELL2] = COMPOUND_STRING("{STR_VAR_1}'s appeal\nwent slightly well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_PRETTY_WELL2] = COMPOUND_STRING("{STR_VAR_1}'s appeal\nwent pretty well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_VERY_WELL] = COMPOUND_STRING("{STR_VAR_1}'s appeal\nwent very well.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_APPEAL_EXCELLENTLY2] = COMPOUND_STRING("{STR_VAR_1}'s appeal\nwent excellently.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_SAME_TYPE_GOOD] = COMPOUND_STRING("It's the same type as the\nPOKéMON before--good!{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_DIFF_TYPE_GOOD] = COMPOUND_STRING("It's not the same type as\nthe one before--good!{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_STOOD_OUT_AS_MUCH] = COMPOUND_STRING("It stood out much more\nthan the POKéMON before.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_NOT_AS_WELL] = COMPOUND_STRING("It didn't do as well as the\nPOKéMON before.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_CONDITION_ROSE] = COMPOUND_STRING("{STR_VAR_1}'s condition\nrose above usual.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_HOT_STATUS] = COMPOUND_STRING("{STR_VAR_1}'s hot status\nmade it a great appeal!{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_MOVE_UP_LINE] = COMPOUND_STRING("It moved up in line for\nthe next appeal.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_MOVE_BACK_LINE] = COMPOUND_STRING("It moved back in line once\nfor the next appeal.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), + [CONTEST_STRING_SCRAMBLE_ORDER] = COMPOUND_STRING("It scrambled up the\norder for the next turn.{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}"), [CONTEST_STRING_JUDGE_EXPECTANTLY2] = gText_JudgeLookedAtMonExpectantly, [CONTEST_STRING_WENT_OVER_WELL] = gText_AppealComboWentOverWell, [CONTEST_STRING_WENT_OVER_VERY_WELL] = gText_AppealComboWentOverVeryWell, [CONTEST_STRING_APPEAL_COMBO_EXCELLENTLY] = gText_AppealComboWentOverExcellently, - [CONTEST_STRING_AVERT_GAZE] = gText_MonManagedToAvertGaze, - [CONTEST_STRING_AVOID_SEEING] = gText_MonManagedToAvoidSeeingIt, - [CONTEST_STRING_NOT_FAZED] = gText_MonIsntFazedByThatSortOfThing, - [CONTEST_STRING_LITTLE_DISTRACTED] = gText_MonBecameALittleDistracted, - [CONTEST_STRING_ATTEMPT_STARTLE] = gText_TriedToStartleOtherPokemon, - [CONTEST_STRING_LOOKED_DOWN] = gText_MonLookedDownOutOfDistraction, - [CONTEST_STRING_TURNED_BACK] = gText_MonTurnedBackOutOfDistraction, - [CONTEST_STRING_UTTER_CRY] = gText_MonCouldntHelpUtteringCry, - [CONTEST_STRING_LEAPT_UP] = gText_MonCouldntHelpLeapingUp, - [CONTEST_STRING_TRIPPED_OVER] = gText_MonTrippedOutOfDistraction, - [CONTEST_STRING_MESSED_UP2] = gText_ButItMessedUp2, - [CONTEST_STRING_FAILED_TARGET_NERVOUS] = gText_ButItFailedToMakeTargetNervous, - [CONTEST_STRING_FAILED_ANYONE_NERVOUS] = gText_ButItFailedToMakeAnyoneNervous, - [CONTEST_STRING_IGNORED] = gText_ButItWasIgnored, - [CONTEST_STRING_NO_CONDITION_IMPROVE] = gText_CouldntImproveItsCondition, - [CONTEST_STRING_BAD_CONDITION_WEAK_APPEAL] = gText_BadConditionResultedInWeakAppeal, - [CONTEST_STRING_UNAFFECTED] = gText_MonWasUnaffected, - [CONTEST_STRING_ATTRACTED_ATTENTION] = gText_AttractedCrowdsAttention + [CONTEST_STRING_AVERT_GAZE] = COMPOUND_STRING("{STR_VAR_1} managed to\navert its gaze.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_AVOID_SEEING] = COMPOUND_STRING("{STR_VAR_1} managed to\navoid seeing it.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_NOT_FAZED] = COMPOUND_STRING("{STR_VAR_1} isn't fazed\nby that sort of thing.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_LITTLE_DISTRACTED] = COMPOUND_STRING("{STR_VAR_1} became a\nlittle distracted.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_ATTEMPT_STARTLE] = COMPOUND_STRING("It tried to startle the\nother POKéMON.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_LOOKED_DOWN] = COMPOUND_STRING("{STR_VAR_1} looked down\nout of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_TURNED_BACK] = COMPOUND_STRING("{STR_VAR_1} turned back\nout of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_UTTER_CRY] = COMPOUND_STRING("{STR_VAR_1} couldn't help\nuttering a cry.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_LEAPT_UP] = COMPOUND_STRING("{STR_VAR_1} couldn't help\nleaping up.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_TRIPPED_OVER] = COMPOUND_STRING("{STR_VAR_1} tripped over\nout of distraction.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_MESSED_UP2] = COMPOUND_STRING("But it messed up.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_FAILED_TARGET_NERVOUS] = COMPOUND_STRING("But it failed to make\nthe target nervous.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_FAILED_ANYONE_NERVOUS] = COMPOUND_STRING("But it failed to make\nanyone nervous.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_IGNORED] = COMPOUND_STRING("But it was ignored…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_NO_CONDITION_IMPROVE] = COMPOUND_STRING("But it couldn't improve\nits condition…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_BAD_CONDITION_WEAK_APPEAL] = COMPOUND_STRING("Its bad condition\nresulted in a weak appeal.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_UNAFFECTED] = COMPOUND_STRING("{STR_VAR_1} was\nunaffected.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}"), + [CONTEST_STRING_ATTRACTED_ATTENTION] = COMPOUND_STRING("It attracted the crowd's\nattention.{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}") }; diff --git a/src/data/field_effects/field_effect_object_template_pointers.h b/src/data/field_effects/field_effect_object_template_pointers.h index 281c664f03..369b5821a9 100755 --- a/src/data/field_effects/field_effect_object_template_pointers.h +++ b/src/data/field_effects/field_effect_object_template_pointers.h @@ -42,6 +42,8 @@ extern const struct SpriteTemplate gFieldEffectObjectTemplate_SpotTracks; extern const struct SpriteTemplate gFieldEffectObjectTemplate_CaveDust; extern const struct SpriteTemplate gFieldEffectObjectTemplate_RockClimbBlob; extern const struct SpriteTemplate gFieldEffectObjectTemplate_RockClimbDust; +extern const struct SpriteTemplate gFieldEffectObjectTemplate_ORASDowsingBrendan; +extern const struct SpriteTemplate gFieldEffectObjectTemplate_ORASDowsingMay; const struct SpriteTemplate *const gFieldEffectObjectTemplatePointers[] = { [FLDEFFOBJ_SHADOW_S] = &gFieldEffectObjectTemplate_ShadowSmall, @@ -87,4 +89,6 @@ const struct SpriteTemplate *const gFieldEffectObjectTemplatePointers[] = { [FLDEFFOBJ_CAVE_DUST] = &gFieldEffectObjectTemplate_CaveDust, [FLDEFFOBJ_ROCK_CLIMB_BLOB] = &gFieldEffectObjectTemplate_RockClimbBlob, [FLDEFFOBJ_ROCK_CLIMB_DUST] = &gFieldEffectObjectTemplate_RockClimbDust, + [FLDEFFOBJ_ORAS_DOWSE_BRENDAN] = &gFieldEffectObjectTemplate_ORASDowsingBrendan, + [FLDEFFOBJ_ORAS_DOWSE_MAY] = &gFieldEffectObjectTemplate_ORASDowsingMay, }; diff --git a/src/data/heal_locations.json b/src/data/heal_locations.json index 3bfa468729..bd789dbdf5 100644 --- a/src/data/heal_locations.json +++ b/src/data/heal_locations.json @@ -6,9 +6,9 @@ "x": 4, "y": 2, "respawn_map": "MAP_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F", + "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM", "respawn_x": 2, - "respawn_y": 7, - "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM" + "respawn_y": 7 }, { "id": "HEAL_LOCATION_LITTLEROOT_TOWN_MAYS_HOUSE_2F", @@ -16,9 +16,9 @@ "x": 4, "y": 2, "respawn_map": "MAP_LITTLEROOT_TOWN_MAYS_HOUSE_1F", + "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM", "respawn_x": 8, - "respawn_y": 7, - "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM" + "respawn_y": 7 }, { "id": "HEAL_LOCATION_PETALBURG_CITY", @@ -98,9 +98,9 @@ "x": 5, "y": 9, "respawn_map": "MAP_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F", + "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM", "respawn_x": 2, - "respawn_y": 7, - "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM" + "respawn_y": 7 }, { "id": "HEAL_LOCATION_LITTLEROOT_TOWN_MAYS_HOUSE", @@ -108,9 +108,9 @@ "x": 14, "y": 9, "respawn_map": "MAP_LITTLEROOT_TOWN_MAYS_HOUSE_1F", + "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM", "respawn_x": 8, - "respawn_y": 7, - "respawn_npc": "LOCALID_PLAYERS_HOUSE_1F_MOM" + "respawn_y": 7 }, { "id": "HEAL_LOCATION_OLDALE_TOWN", @@ -166,9 +166,9 @@ "x": 18, "y": 6, "respawn_map": "MAP_EVER_GRANDE_CITY_POKEMON_LEAGUE_1F", + "respawn_npc": "LOCALID_LEAGUE_NURSE", "respawn_x": 3, - "respawn_y": 4, - "respawn_npc": "LOCALID_LEAGUE_NURSE" + "respawn_y": 4 }, { "id": "HEAL_LOCATION_SOUTHERN_ISLAND_EXTERIOR", diff --git a/src/data/hold_effects.h b/src/data/hold_effects.h new file mode 100644 index 0000000000..221c9e166f --- /dev/null +++ b/src/data/hold_effects.h @@ -0,0 +1,649 @@ +const struct HoldEffectInfo gHoldEffectsInfo[HOLD_EFFECT_COUNT] = +{ + [HOLD_EFFECT_NONE] = + { + }, + + [HOLD_EFFECT_RESTORE_HP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CURE_PAR] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_SLP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_PSN] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_BRN] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_FRZ] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_RESTORE_PP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_CURE_CONFUSION] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CURE_STATUS] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onStatusChange = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_SPICY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_DRY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_SWEET] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_BITTER] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CONFUSE_SOUR] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_ATTACK_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_DEFENSE_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_SPEED_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_SP_ATTACK_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_SP_DEFENSE_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CRITICAL_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_RANDOM_STAT_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_EVASION_UP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_WHITE_HERB] = + { + .whiteHerb = TRUE, + .whiteHerbFirstTurn = TRUE, + .whiteHerbEndTurn = TRUE, + .onFling = TRUE, + }, + + [HOLD_EFFECT_MACHO_BRACE] = + { + }, + + [HOLD_EFFECT_EXP_SHARE] = + { + }, + + [HOLD_EFFECT_QUICK_CLAW] = + { + }, + + [HOLD_EFFECT_FRIENDSHIP_UP] = + { + }, + + [HOLD_EFFECT_MENTAL_HERB] = + { + .onTargetAfterHit = TRUE, + .onAttackerAfterHit = TRUE, + .onFling = TRUE, + }, + + [HOLD_EFFECT_CHOICE_BAND] = + { + }, + + [HOLD_EFFECT_FLINCH] = + { + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_DOUBLE_PRIZE] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + }, + + [HOLD_EFFECT_REPEL] = + { + }, + + [HOLD_EFFECT_SOUL_DEW] = + { + }, + + [HOLD_EFFECT_DEEP_SEA_TOOTH] = + { + }, + + [HOLD_EFFECT_DEEP_SEA_SCALE] = + { + }, + + [HOLD_EFFECT_CAN_ALWAYS_RUN] = + { + }, + + [HOLD_EFFECT_PREVENT_EVOLVE] = + { + }, + + [HOLD_EFFECT_FOCUS_BAND] = + { + }, + + [HOLD_EFFECT_LUCKY_EGG] = + { + }, + + [HOLD_EFFECT_SCOPE_LENS] = + { + }, + + [HOLD_EFFECT_LEFTOVERS] = + { + .leftovers = TRUE, + }, + + [HOLD_EFFECT_DRAGON_SCALE] = + { + }, + + [HOLD_EFFECT_LIGHT_BALL] = + { + }, + + [HOLD_EFFECT_TYPE_POWER] = + { + }, + + [HOLD_EFFECT_UPGRADE] = + { + }, + + [HOLD_EFFECT_SHELL_BELL] = + { + .lifeOrbShellBell = TRUE, + }, + + [HOLD_EFFECT_LUCKY_PUNCH] = + { + }, + + [HOLD_EFFECT_METAL_POWDER] = + { + }, + + [HOLD_EFFECT_THICK_CLUB] = + { + }, + + [HOLD_EFFECT_LEEK] = + { + }, + + [HOLD_EFFECT_CHOICE_SCARF] = + { + }, + + [HOLD_EFFECT_CHOICE_SPECS] = + { + }, + + [HOLD_EFFECT_DAMP_ROCK] = + { + }, + + [HOLD_EFFECT_GRIP_CLAW] = + { + }, + + [HOLD_EFFECT_HEAT_ROCK] = + { + }, + + [HOLD_EFFECT_ICY_ROCK] = + { + }, + + [HOLD_EFFECT_LIGHT_CLAY] = + { + }, + + [HOLD_EFFECT_SMOOTH_ROCK] = + { + }, + + [HOLD_EFFECT_POWER_HERB] = + { + }, + + [HOLD_EFFECT_BIG_ROOT] = + { + }, + + [HOLD_EFFECT_EXPERT_BELT] = + { + }, + + [HOLD_EFFECT_LIFE_ORB] = + { + .lifeOrbShellBell = TRUE, + }, + + [HOLD_EFFECT_METRONOME] = + { + }, + + [HOLD_EFFECT_MUSCLE_BAND] = + { + }, + + [HOLD_EFFECT_WIDE_LENS] = + { + }, + + [HOLD_EFFECT_WISE_GLASSES] = + { + }, + + [HOLD_EFFECT_ZOOM_LENS] = + { + }, + + [HOLD_EFFECT_LAGGING_TAIL] = + { + }, + + [HOLD_EFFECT_FOCUS_SASH] = + { + }, + + [HOLD_EFFECT_FLAME_ORB] = + { + .orbs = TRUE, + }, + + [HOLD_EFFECT_TOXIC_ORB] = + { + .orbs = TRUE, + }, + + [HOLD_EFFECT_STICKY_BARB] = + { + .onTargetAfterHit = TRUE, + .orbs = TRUE, + }, + + [HOLD_EFFECT_IRON_BALL] = + { + }, + + [HOLD_EFFECT_BLACK_SLUDGE] = + { + .leftovers = TRUE, + }, + + [HOLD_EFFECT_DESTINY_KNOT] = + { + }, + + [HOLD_EFFECT_SHED_SHELL] = + { + }, + + [HOLD_EFFECT_QUICK_POWDER] = + { + }, + + [HOLD_EFFECT_ADAMANT_ORB] = + { + }, + + [HOLD_EFFECT_LUSTROUS_ORB] = + { + }, + + [HOLD_EFFECT_GRISEOUS_ORB] = + { + }, + + [HOLD_EFFECT_ENIGMA_BERRY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_RESIST_BERRY] = + { + }, + + [HOLD_EFFECT_POWER_ITEM] = + { + }, + + [HOLD_EFFECT_RESTORE_PCT_HP] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_MICLE_BERRY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onHpThreshold = TRUE, + }, + + [HOLD_EFFECT_CUSTAP_BERRY] = + { + }, + + [HOLD_EFFECT_JABOCA_BERRY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_ROWAP_BERRY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_KEE_BERRY] = + { + .keeMarangaBerry = TRUE, + }, + + [HOLD_EFFECT_MARANGA_BERRY] = + { + .keeMarangaBerry = TRUE, + }, + + [HOLD_EFFECT_PLATE] = + { + }, + + [HOLD_EFFECT_FLOAT_STONE] = + { + }, + + [HOLD_EFFECT_EVIOLITE] = + { + }, + + [HOLD_EFFECT_ASSAULT_VEST] = + { + }, + + [HOLD_EFFECT_DRIVE] = + { + }, + + [HOLD_EFFECT_GEMS] = + { + }, + + [HOLD_EFFECT_ROCKY_HELMET] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_AIR_BALLOON] = + { + .onTargetAfterHit = TRUE, + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + }, + + [HOLD_EFFECT_RED_CARD] = + { + }, + + [HOLD_EFFECT_RING_TARGET] = + { + }, + + [HOLD_EFFECT_BINDING_BAND] = + { + }, + + [HOLD_EFFECT_EJECT_BUTTON] = + { + }, + + [HOLD_EFFECT_ABSORB_BULB] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_CELL_BATTERY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_MEGA_STONE] = + { + }, + + [HOLD_EFFECT_SAFETY_GOGGLES] = + { + }, + + [HOLD_EFFECT_LUMINOUS_MOSS] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_SNOWBALL] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_WEAKNESS_POLICY] = + { + .onTargetAfterHit = TRUE, + }, + + [HOLD_EFFECT_PRIMAL_ORB] = + { + }, + + [HOLD_EFFECT_PROTECTIVE_PADS] = + { + }, + + [HOLD_EFFECT_TERRAIN_EXTENDER] = + { + }, + + [HOLD_EFFECT_TERRAIN_SEED] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onEffect = TRUE, + }, + + [HOLD_EFFECT_ADRENALINE_ORB] = + { + }, + + [HOLD_EFFECT_MEMORY] = + { + }, + + [HOLD_EFFECT_Z_CRYSTAL] = + { + }, + + [HOLD_EFFECT_UTILITY_UMBRELLA] = + { + }, + + [HOLD_EFFECT_EJECT_PACK] = + { + }, + + [HOLD_EFFECT_ROOM_SERVICE] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onEffect = TRUE, + }, + + [HOLD_EFFECT_BLUNDER_POLICY] = + { + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_HEAVY_DUTY_BOOTS] = + { + }, + + [HOLD_EFFECT_THROAT_SPRAY] = + { + .onAttackerAfterHit = TRUE, + }, + + [HOLD_EFFECT_ABILITY_SHIELD] = + { + }, + + [HOLD_EFFECT_CLEAR_AMULET] = + { + }, + + [HOLD_EFFECT_MIRROR_HERB] = + { + .mirrorHerb = TRUE, + .mirrorHerbFirstTurn = TRUE, + }, + + [HOLD_EFFECT_PUNCHING_GLOVE] = + { + }, + + [HOLD_EFFECT_COVERT_CLOAK] = + { + }, + + [HOLD_EFFECT_LOADED_DICE] = + { + }, + + [HOLD_EFFECT_BOOSTER_ENERGY] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + .onEffect = TRUE, + }, + + [HOLD_EFFECT_OGERPON_MASK] = + { + }, + + [HOLD_EFFECT_BERSERK_GENE] = + { + .onSwitchIn = TRUE, + .onSwitchInFirstTurn = TRUE, + }, +}; diff --git a/src/data/items.h b/src/data/items.h index 6f19ad6d0b..e39d84166d 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -6366,6 +6366,474 @@ const struct Item gItemsInfo[] = .iconPalette = gItemIconPalette_Diancite, }, + [ITEM_CLEFABLITE] = + { + .name = ITEM_NAME("Clefablite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Clefable to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Clefablite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Clefablite, + }, + + [ITEM_VICTREEBELITE] = + { + .name = ITEM_NAME("Victreebelite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Victreebel to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Victreebelite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Victreebelite, + }, + + [ITEM_STARMINITE] = + { + .name = ITEM_NAME("Starminite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Starmie to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Starminite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Starminite, + }, + + [ITEM_DRAGONINITE] = + { + .name = ITEM_NAME("Dragoninite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Dragonite to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Dragoninite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Dragoninite, + }, + + [ITEM_MEGANIUMITE] = + { + .name = ITEM_NAME("Meganiumite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Meganium to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Meganiumite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Meganiumite, + }, + + [ITEM_FERALIGITE] = + { + .name = ITEM_NAME("Feraligite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Feraligatr to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Feraligite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Feraligite, + }, + + [ITEM_SKARMORITE] = + { + .name = ITEM_NAME("Skarmorite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Skarmory to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Skarmorite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Skarmorite, + }, + + [ITEM_FROSLASSITE] = + { + .name = ITEM_NAME("Froslassite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Froslass to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Froslassite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Froslassite, + }, + + [ITEM_EMBOARITE] = + { + .name = ITEM_NAME("Emboarite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Emboar to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Emboarite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Emboarite, + }, + + [ITEM_EXCADRITE] = + { + .name = ITEM_NAME("Excadrite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Excadrill to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Excadrite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Excadrite, + }, + + [ITEM_SCOLIPITE] = + { + .name = ITEM_NAME("Scolipite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Scolipede to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Scolipite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Scolipite, + }, + + [ITEM_SCRAFTINITE] = + { + .name = ITEM_NAME("Scraftinite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Scrafty to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Scraftinite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Scraftinite, + }, + + [ITEM_EELEKTROSSITE] = + { + .name = ITEM_NAME("Eelektrossite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Eelektross to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Eelektrossite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Eelektrossite, + }, + + [ITEM_CHANDELURITE] = + { + .name = ITEM_NAME("Chandelurite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Chandelure to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Chandelurite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Chandelurite, + }, + + [ITEM_CHESNAUGHTITE] = + { + .name = ITEM_NAME("Chesnaughtite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Chesnaught to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Chesnaughtite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Chesnaughtite, + }, + + [ITEM_DELPHOXITE] = + { + .name = ITEM_NAME("Delphoxite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Delphox to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Delphoxite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Delphoxite, + }, + + [ITEM_GRENINJITE] = + { + .name = ITEM_NAME("Greninjite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Greninja to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Greninjite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Greninjite, + }, + + [ITEM_PYROARITE] = + { + .name = ITEM_NAME("Pyroarite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Pyroar to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Pyroarite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Pyroarite, + }, + + [ITEM_FLOETTITE] = + { + .name = ITEM_NAME("Floettite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Floette to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Floettite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Floettite, + }, + + [ITEM_MALAMARITE] = + { + .name = ITEM_NAME("Malamarite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Malamar to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Malamarite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Malamarite, + }, + + [ITEM_BARBARACITE] = + { + .name = ITEM_NAME("Barbaracite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Barbaracle to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Barbaracite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Barbaracite, + }, + + [ITEM_DRAGALGITE] = + { + .name = ITEM_NAME("Dragalgite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Dragalge to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Dragalgite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Dragalgite, + }, + + [ITEM_HAWLUCHANITE] = + { + .name = ITEM_NAME("Hawluchanite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Hawlucha to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Hawluchanite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Hawluchanite, + }, + + [ITEM_ZYGARDITE] = + { + .name = ITEM_NAME("Zygardite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Zygarde to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Zygardite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Zygardite, + }, + + [ITEM_DRAMPANITE] = + { + .name = ITEM_NAME("Drampanite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Drampa to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Drampanite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Drampanite, + }, + + [ITEM_FALINKSITE] = + { + .name = ITEM_NAME("Falinksite"), + .price = 0, + .holdEffect = HOLD_EFFECT_MEGA_STONE, + .description = COMPOUND_STRING( + "This stone enables\n" + "Falinks to Mega\n" + "Evolve in battle."), + .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_MEGA_STONE, + .type = ITEM_USE_BAG_MENU, + .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .flingPower = 80, + .iconPic = gItemIcon_QuestionMark, // gItemIcon_Falinksite, + .iconPalette = gItemIconPalette_QuestionMark, // gItemIconPalette_Falinksite, + }, + // Gems [ITEM_NORMAL_GEM] = @@ -8489,7 +8957,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Electric Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN, .description = COMPOUND_STRING( "Boosts Defense on\n" @@ -8508,7 +8976,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Psychic Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN, .description = COMPOUND_STRING( "Boosts Sp. Def. on\n" @@ -8527,7 +8995,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Misty Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_MISTY_TERRAIN, .description = COMPOUND_STRING( "Boosts Sp. Def. on\n" @@ -8546,7 +9014,7 @@ const struct Item gItemsInfo[] = { .name = ITEM_NAME("Grassy Seed"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, - .holdEffect = HOLD_EFFECT_SEEDS, + .holdEffect = HOLD_EFFECT_TERRAIN_SEED, .holdEffectParam = HOLD_EFFECT_PARAM_GRASSY_TERRAIN, .description = COMPOUND_STRING( "Boosts Defense on\n" @@ -14580,7 +15048,7 @@ const struct Item gItemsInfo[] = .price = 2000, .description = COMPOUND_STRING( "A wooden toy\n" - "resembling a Poké-.\n" + "resembling a Poké-\n" "mon. Can be sold."), .pocket = POCKET_ITEMS, .sortType = ITEM_TYPE_SELLABLE, diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 51f27ceec9..a4f0dc06bc 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -179,7 +179,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -202,8 +202,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_POUND}, .battleAnimScript = gBattleAnimMove_DoubleSlap, @@ -226,7 +226,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .punchingMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -249,7 +249,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .punchingMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_MIND_READER}, @@ -274,7 +274,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PAYDAY, }), - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST : CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -302,7 +302,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_FIRE_PUNCH, .contestComboMoves = {COMBO_STARTER_ICE_PUNCH, COMBO_STARTER_SUNNY_DAY, COMBO_STARTER_THUNDER_PUNCH}, .battleAnimScript = gBattleAnimMove_FirePunch, @@ -503,7 +503,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SWORDS_DANCE}, @@ -527,7 +527,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_4) || (B_UPDATED_MOVE_FLAGS < GEN_3), .damagesAirborneDoubleDamage = TRUE, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -549,7 +549,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -577,10 +577,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_STEALTH_ROCK, COMBO_STARTER_SPIKES, COMBO_STARTER_TOXIC_SPIKES}, .battleAnimScript = gBattleAnimMove_Whirlwind, .validApprenticeMove = TRUE, }, @@ -605,7 +605,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .assistBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNFLEWHIGH, .status = STATE_ON_AIR }, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -657,7 +657,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_POUND}, @@ -714,7 +714,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LEER}, @@ -738,7 +738,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -761,7 +761,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_MIND_READER}, @@ -819,7 +819,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -843,7 +843,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_EVSN_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_SAND_ATTACK, .contestComboMoves = {COMBO_STARTER_MUD_SLAP, COMBO_STARTER_SANDSTORM}, @@ -870,7 +870,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -915,7 +915,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HORN_ATTACK, COMBO_STARTER_PECK}, @@ -1073,7 +1073,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAGE}, @@ -1173,7 +1173,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1195,7 +1195,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1218,7 +1218,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_LEER, .contestComboMoves = {COMBO_STARTER_RAGE, COMBO_STARTER_SCARY_FACE}, @@ -1245,7 +1245,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LEER, COMBO_STARTER_SCARY_FACE}, @@ -1299,10 +1299,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .soundMove = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_STEALTH_ROCK, COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE, COMBO_STARTER_SPIKES, COMBO_STARTER_TOXIC_SPIKES}, .battleAnimScript = gBattleAnimMove_Roar, .validApprenticeMove = TRUE, }, @@ -1352,7 +1352,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1375,7 +1375,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .fixedDamage = 20 }, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1442,7 +1442,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = B_UPDATED_MOVE_DATA >= GEN_4 ? MOVE_EFFECT_SP_DEF_MINUS_1 : MOVE_EFFECT_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1468,7 +1468,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_Ember, @@ -1561,7 +1561,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -1589,7 +1589,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .damagesUnderwater = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_SURF, .contestComboMoves = {COMBO_STARTER_DIVE, COMBO_STARTER_RAIN_DANCE}, @@ -1621,7 +1621,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL}, @@ -1653,7 +1653,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL, COMBO_STARTER_POWDER_SNOW}, @@ -1679,7 +1679,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -1705,7 +1705,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -1730,7 +1730,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ATK_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL}, @@ -1799,7 +1799,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_PECK}, @@ -1846,7 +1846,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_LATER : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1874,10 +1874,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = B_UPDATED_MOVE_FLAGS >= GEN_2, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_TAUNT}, + .contestComboMoves = {COMBO_STARTER_TAUNT, COMBO_STARTER_ENCORE, COMBO_STARTER_TORMENT}, .battleAnimScript = gBattleAnimMove_Counter, .validApprenticeMove = TRUE, }, @@ -1898,10 +1898,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_FAKE_OUT}, + .contestComboMoves = {COMBO_STARTER_FAKE_OUT, COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE}, .battleAnimScript = gBattleAnimMove_SeismicToss, .validApprenticeMove = TRUE, }, @@ -1921,7 +1921,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -1946,7 +1946,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 50 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -1969,7 +1969,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .powerOverride = 120 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -1992,10 +1992,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_RESET_STATS }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_LEECH_SEED, - .contestComboMoves = {COMBO_STARTER_GROWTH, COMBO_STARTER_WORRY_SEED}, + .contestComboMoves = {COMBO_STARTER_GROWTH, COMBO_STARTER_WORRY_SEED, COMBO_STARTER_ROTOTILLER}, .battleAnimScript = gBattleAnimMove_LeechSeed, .validApprenticeMove = TRUE, }, @@ -2026,7 +2026,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_GROWTH, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_Growth, .validApprenticeMove = TRUE, }, @@ -2047,7 +2047,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -2072,7 +2072,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKSUNLIGHT, .status = B_WEATHER_SUN }, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH, COMBO_STARTER_SUNNY_DAY}, @@ -2100,7 +2100,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .powderMove = TRUE, .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_POISON_POWDER, .contestComboMoves = {COMBO_STARTER_SWEET_SCENT}, .battleAnimScript = gBattleAnimMove_PoisonPowder, .validApprenticeMove = TRUE, @@ -2152,7 +2152,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .powderMove = TRUE, .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_SLEEP_POWDER, .contestComboMoves = {COMBO_STARTER_SWEET_SCENT}, .battleAnimScript = gBattleAnimMove_SleepPowder, .validApprenticeMove = TRUE, @@ -2185,7 +2185,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -2232,7 +2232,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_4) || (B_UPDATED_MOVE_FLAGS < GEN_3), .argument = { .fixedDamage = 40 }, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DRAGON_RAGE, .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RUSH, COMBO_STARTER_DRAGON_TAIL}, @@ -2335,9 +2335,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_PARALYSIS }, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_COOL, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_THUNDER_WAVE, .contestComboMoves = {COMBO_STARTER_CHARGE}, .battleAnimScript = gBattleAnimMove_ThunderWave, .validApprenticeMove = TRUE, @@ -2364,7 +2364,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE, COMBO_STARTER_LOCK_ON, COMBO_STARTER_RAIN_DANCE}, @@ -2386,7 +2386,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_ROCK_THROW, .contestComboMoves = {0}, @@ -2410,7 +2410,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresKingsRock = B_UPDATED_MOVE_FLAGS < GEN_3, .damagesUnderground = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_EARTHQUAKE, .contestComboMoves = {0}, @@ -2462,8 +2462,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .assistBanned = TRUE, .skyBattleBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNDUGHOLE, .status = STATE_UNDERGROUND }, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Dig, @@ -2513,7 +2513,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_CONFUSION, .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_KINESIS, COMBO_STARTER_PSYCHIC}, @@ -2538,7 +2538,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_PSYCHIC, .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_CONFUSION, COMBO_STARTER_KINESIS}, @@ -2617,7 +2617,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, .contestCategory = CONTEST_CATEGORY_COOL, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_AGILITY, .contestComboMoves = {COMBO_STARTER_DOUBLE_TEAM}, .battleAnimScript = gBattleAnimMove_Agility, .validApprenticeMove = TRUE, @@ -2661,8 +2661,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS : CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_RAGE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Rage, @@ -2712,7 +2712,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2769,7 +2769,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2795,7 +2795,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DOUBLE_TEAM, .contestComboMoves = {0}, @@ -2828,7 +2828,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .healingMove = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2884,7 +2884,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2908,7 +2908,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_EVSN_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SMOG}, @@ -2932,7 +2932,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -2958,7 +2958,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -3036,7 +3036,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -3088,7 +3088,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -3115,7 +3115,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_FOCUS_ENERGY, .contestComboMoves = {0}, @@ -3141,7 +3141,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3171,7 +3171,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .encoreBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3228,7 +3228,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_MEAN_LOOK, COMBO_STARTER_BLOCK}, .battleAnimScript = gBattleAnimMove_SelfDestruct, .validApprenticeMove = TRUE, }, @@ -3249,7 +3249,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SOFT_BOILED}, .battleAnimScript = gBattleAnimMove_EggBomb, @@ -3275,8 +3275,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Lick, @@ -3301,7 +3301,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 40, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SMOG, .contestComboMoves = {0}, @@ -3326,7 +3326,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SLUDGE, .contestComboMoves = {COMBO_STARTER_SLUDGE_BOMB}, @@ -3351,7 +3351,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_BONE_CLUB, .contestComboMoves = {COMBO_STARTER_BONEMERANG, COMBO_STARTER_BONE_RUSH, COMBO_STARTER_SHADOW_BONE}, @@ -3376,7 +3376,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -3405,7 +3405,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 20, }), #endif - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -3486,7 +3486,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .onChargeTurnOnly = TRUE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3508,7 +3508,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3534,7 +3534,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3559,9 +3559,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_AMNESIA, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Amnesia, .validApprenticeMove = TRUE, @@ -3583,7 +3583,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_EVSN_UP_1 }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_KINESIS, .contestComboMoves = {COMBO_STARTER_CONFUSION, COMBO_STARTER_PSYCHIC}, @@ -3610,8 +3610,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_FIRST : CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_SOFT_BOILED, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SoftBoiled, @@ -3671,9 +3671,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_PARALYSIS }, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_GLARE, .contestComboMoves = {COMBO_STARTER_LEER}, .battleAnimScript = gBattleAnimMove_Glare, .validApprenticeMove = TRUE, @@ -3698,7 +3698,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_HYPNOSIS}, + .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_HYPNOSIS, COMBO_STARTER_LOVELY_KISS, COMBO_STARTER_SPORE, COMBO_STARTER_SING, COMBO_STARTER_YAWN, COMBO_STARTER_DARK_VOID, COMBO_STARTER_GRASS_WHISTLE, COMBO_STARTER_SLEEP_POWDER}, .battleAnimScript = gBattleAnimMove_DreamEater, .validApprenticeMove = TRUE, }, @@ -3730,9 +3730,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_POISON }, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_POISON_GAS, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PoisonGas, }, @@ -3752,8 +3752,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Barrage, @@ -3777,7 +3777,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -3801,9 +3801,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_SLEEP }, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_BEAUTY, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_LOVELY_KISS, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LovelyKiss, .validApprenticeMove = TRUE, @@ -3890,7 +3890,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -3917,8 +3917,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DizzyPunch, @@ -3945,7 +3945,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .powderMove = TRUE, .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_SPORE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Spore, .validApprenticeMove = TRUE, @@ -3989,7 +3989,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -4015,7 +4015,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .gravityBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4040,7 +4040,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4064,7 +4064,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE, COMBO_STARTER_SWORDS_DANCE}, @@ -4091,7 +4091,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_MEAN_LOOK, COMBO_STARTER_BLOCK}, .battleAnimScript = gBattleAnimMove_Explosion, .validApprenticeMove = TRUE, }, @@ -4111,7 +4111,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SCRATCH}, @@ -4133,7 +4133,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_BONEMERANG, .contestComboMoves = {COMBO_STARTER_BONE_CLUB, COMBO_STARTER_BONE_RUSH, COMBO_STARTER_SHADOW_BONE}, @@ -4160,7 +4160,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .healingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_REST, .contestComboMoves = {COMBO_STARTER_BELLY_DRUM, COMBO_STARTER_CHARM, COMBO_STARTER_YAWN}, @@ -4186,7 +4186,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ROCK_THROW}, @@ -4214,7 +4214,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4300,7 +4300,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_TRI_ATTACK, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LOCK_ON}, @@ -4350,7 +4350,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SCRATCH, COMBO_STARTER_SWORDS_DANCE}, @@ -4378,7 +4378,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Substitute, @@ -4422,6 +4422,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sketchBanned = TRUE, .battleAnimScript = gBattleAnimMove_Struggle, .validApprenticeMove = TRUE, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_TOUGH, }, [MOVE_SKETCH] = @@ -4474,7 +4476,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 3, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -4502,7 +4504,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE : CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4550,7 +4552,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_EARLIER : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_MIND_READER, .contestComboMoves = {0}, @@ -4577,7 +4579,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_LOVELY_KISS, COMBO_STARTER_SPORE, COMBO_STARTER_SING, COMBO_STARTER_YAWN, COMBO_STARTER_HYPNOSIS, COMBO_STARTER_DARK_VOID, COMBO_STARTER_GRASS_WHISTLE, COMBO_STARTER_SLEEP_POWDER}, .battleAnimScript = gBattleAnimMove_Nightmare, .validApprenticeMove = TRUE, }, @@ -4602,7 +4604,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -4630,7 +4632,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_REST}, @@ -4729,7 +4731,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST : .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -4781,7 +4783,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_LATER : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ENDURE}, @@ -4810,10 +4812,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_RECOVER_HP }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_CURSE}, + .contestComboMoves = {COMBO_STARTER_CURSE, COMBO_STARTER_ENCORE, COMBO_STARTER_TAUNT, COMBO_STARTER_TORMENT}, .battleAnimScript = gBattleAnimMove_Spite, .validApprenticeMove = TRUE, }, @@ -4864,7 +4866,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HARDEN}, @@ -4912,7 +4914,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SCARY_FACE, .contestComboMoves = {COMBO_STARTER_LEER, COMBO_STARTER_RAGE}, @@ -4985,7 +4987,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_BELLY_DRUM, .contestComboMoves = {0}, @@ -5038,7 +5040,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_MUD_SLAP, .contestComboMoves = {COMBO_STARTER_MUD_SPORT, COMBO_STARTER_SAND_ATTACK, COMBO_STARTER_SANDSTORM}, @@ -5065,7 +5067,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_LOCK_ON, COMBO_STARTER_RAIN_DANCE}, @@ -5095,7 +5097,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .skyBattleBanned = TRUE, .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_SPIKES, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Spikes, .validApprenticeMove = TRUE, @@ -5120,7 +5122,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE, COMBO_STARTER_LOCK_ON}, @@ -5145,7 +5147,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_BOOST_CRITS }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5174,10 +5176,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, + .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_CURSE, COMBO_STARTER_ENDURE, COMBO_STARTER_MEAN_LOOK}, + .contestComboMoves = {COMBO_STARTER_CURSE, COMBO_STARTER_ENDURE, COMBO_STARTER_MEAN_LOOK, COMBO_STARTER_ENCORE, COMBO_STARTER_TAUNT, COMBO_STARTER_TORMENT}, .battleAnimScript = gBattleAnimMove_DestinyBond, .validApprenticeMove = TRUE, }, @@ -5201,10 +5203,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .mirrorMoveBanned = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_MEAN_LOOK, COMBO_STARTER_SING}, + .contestComboMoves = {COMBO_STARTER_MEAN_LOOK, COMBO_STARTER_SING, COMBO_STARTER_BLOCK}, .battleAnimScript = gBattleAnimMove_PerishSong, .validApprenticeMove = TRUE, }, @@ -5255,7 +5257,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_TAUNT}, @@ -5277,7 +5279,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_BONE_RUSH, .contestComboMoves = {COMBO_STARTER_BONE_CLUB, COMBO_STARTER_BONEMERANG, COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_SHADOW_BONE}, @@ -5299,7 +5301,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_EARLIER : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_LOCK_ON, .contestComboMoves = {0}, @@ -5327,7 +5329,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5353,7 +5355,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SANDSTORM, .contestComboMoves = {0}, @@ -5378,7 +5380,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 50 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -5406,7 +5408,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_NEXT_APPEAL_LATER : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_ENDURE, .contestComboMoves = {0}, @@ -5430,7 +5432,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_CHARM, .contestComboMoves = {0}, @@ -5455,8 +5457,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .instructBanned = TRUE, .parentalBondBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_DEFENSE_CURL, COMBO_STARTER_HARDEN}, .battleAnimScript = gBattleAnimMove_Rollout, @@ -5476,7 +5478,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SWORDS_DANCE}, @@ -5500,7 +5502,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_RESET_STATS }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS : CONTEST_EFFECT_BETTER_IF_FIRST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5527,7 +5529,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_FIRST : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5554,7 +5556,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE}, @@ -5611,7 +5613,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5693,7 +5695,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mimicBanned = TRUE, .encoreBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_REST}, @@ -5721,7 +5723,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_HEAL_BELL, .contestComboMoves = {COMBO_STARTER_LUCKY_CHANT}, @@ -5744,7 +5746,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5770,7 +5772,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_CELEBRATE, COMBO_STARTER_COVET, COMBO_STARTER_HAPPY_HOUR, COMBO_STARTER_WISH}, .battleAnimScript = gBattleAnimMove_Present, .validApprenticeMove = TRUE, }, @@ -5790,7 +5792,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5816,7 +5818,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5839,7 +5841,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ENDURE}, @@ -5866,7 +5868,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -5940,7 +5942,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -5967,7 +5969,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DRAGON_BREATH, .contestComboMoves = {COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_RUSH, COMBO_STARTER_DRAGON_TAIL}, @@ -5992,10 +5994,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_RESET_STATS }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION : CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_AGILITY, COMBO_STARTER_AMNESIA, COMBO_STARTER_HONE_CLAWS, COMBO_STARTER_CALM_MIND, COMBO_STARTER_NASTY_PLOT, COMBO_STARTER_ROCK_POLISH}, .battleAnimScript = gBattleAnimMove_BatonPass, .validApprenticeMove = TRUE, }, @@ -6020,7 +6022,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = TRUE, .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_ENCORE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Encore, .validApprenticeMove = TRUE, @@ -6042,7 +6044,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6078,7 +6080,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = } #endif ), - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6107,7 +6109,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_SWEET_SCENT, .contestComboMoves = {0}, @@ -6134,7 +6136,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6185,10 +6187,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = -1, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_NEXT_APPEAL_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_FAKE_OUT}, + .contestComboMoves = {COMBO_STARTER_FAKE_OUT, COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE}, .battleAnimScript = gBattleAnimMove_VitalThrow, .validApprenticeMove = TRUE, }, @@ -6345,7 +6347,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6370,7 +6372,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_RAIN_DANCE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RainDance, @@ -6456,10 +6458,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .meFirstBanned = TRUE, .metronomeBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_TAUNT}, + .contestComboMoves = {COMBO_STARTER_TAUNT, COMBO_STARTER_ENCORE, COMBO_STARTER_TORMENT}, .battleAnimScript = gBattleAnimMove_MirrorCoat, .validApprenticeMove = TRUE, }, @@ -6561,7 +6563,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6591,7 +6593,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_SAME_TYPE : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND, COMBO_STARTER_CONFUSION, COMBO_STARTER_KINESIS, COMBO_STARTER_PSYCHIC}, @@ -6618,7 +6620,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6667,7 +6669,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6694,7 +6696,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_FAKE_OUT, .contestComboMoves = {0}, @@ -6728,7 +6730,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_UPROAR, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -6754,7 +6756,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_STOCKPILE, .contestComboMoves = {0}, @@ -6777,7 +6779,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_STOCKPILE}, @@ -6804,7 +6806,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_STOCKPILE}, @@ -6831,7 +6833,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -6863,7 +6865,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_HAIL, .contestComboMoves = {0}, @@ -6889,7 +6891,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_TOUGH, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_TORMENT, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Torment, .validApprenticeMove = TRUE, @@ -6936,9 +6938,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .nonVolatileStatus = MOVE_EFFECT_BURN }, .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_BEAUTY, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_WILL_O_WISP, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_WillOWisp, .validApprenticeMove = TRUE, @@ -6962,7 +6964,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_MEAN_LOOK, COMBO_STARTER_BLOCK}, .battleAnimScript = gBattleAnimMove_Memento, .validApprenticeMove = TRUE, }, @@ -7013,7 +7015,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_NEXT_APPEAL_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -7040,10 +7042,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_STATUS, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL : CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_FORCE_PALM, COMBO_STARTER_THUNDER_WAVE, COMBO_STARTER_GLARE}, .battleAnimScript = gBattleAnimMove_SmellingSalts, .validApprenticeMove = TRUE, }, @@ -7123,7 +7125,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_CHARGE, .contestComboMoves = {0}, @@ -7148,7 +7150,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .ignoresSubstitute = TRUE, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION : CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_TAUNT, .contestComboMoves = {0}, @@ -7177,7 +7179,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7203,7 +7205,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7256,9 +7258,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_WISH, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Wish, .validApprenticeMove = TRUE, @@ -7314,7 +7316,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7366,7 +7368,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPDEF_UP_2 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7392,7 +7394,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE : CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7413,7 +7415,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = -4, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_NEXT_APPEAL_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_REVENGE, .contestComboMoves = {COMBO_STARTER_PAYBACK}, @@ -7436,7 +7438,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -7484,7 +7486,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MON : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FAKE_OUT}, @@ -7530,7 +7532,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_EARTHQUAKE, COMBO_STARTER_ENDURE, COMBO_STARTER_SUNNY_DAY}, @@ -7582,7 +7584,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, .forcePressure = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_DONT_EXCITE_AUDIENCE : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7608,7 +7610,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SING, COMBO_STARTER_WATER_SPORT}, @@ -7634,10 +7636,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_CURSE}, + .contestComboMoves = {COMBO_STARTER_CURSE, COMBO_STARTER_ENCORE, COMBO_STARTER_TAUNT, COMBO_STARTER_TORMENT}, .battleAnimScript = gBattleAnimMove_Grudge, .validApprenticeMove = TRUE, }, @@ -7662,7 +7664,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7739,7 +7741,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FAKE_OUT, COMBO_STARTER_FOCUS_ENERGY}, @@ -7764,7 +7766,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -7820,7 +7822,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_STARTLE_PREV_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -7847,7 +7849,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CALM_MIND}, @@ -7925,10 +7927,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, + .contestComboMoves = {COMBO_STARTER_SUNNY_DAY, COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_BlazeKick, .validApprenticeMove = TRUE, }, @@ -7952,7 +7954,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_MUD_SPORT, .contestComboMoves = {COMBO_STARTER_MUD_SLAP, COMBO_STARTER_SANDSTORM, COMBO_STARTER_WATER_SPORT}, @@ -7981,7 +7983,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_HAIL}, + .contestComboMoves = {COMBO_STARTER_HAIL, COMBO_STARTER_DEFENSE_CURL}, .battleAnimScript = gBattleAnimMove_IceBall, }, @@ -8005,7 +8007,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8032,7 +8034,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8056,7 +8058,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .soundMove = TRUE, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8084,7 +8086,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_TOXIC, .chance = B_UPDATED_MOVE_DATA >= GEN_6 ? 50 : 30, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8191,7 +8193,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8220,7 +8222,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 30, }), .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Astonish, @@ -8243,8 +8245,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .zMove = { .powerOverride = 160 }, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL, COMBO_STARTER_RAIN_DANCE, COMBO_STARTER_SANDSTORM, COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_WeatherBall, @@ -8269,7 +8271,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE : CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8293,8 +8295,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUICKLY_GROW_BORED : + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FakeTears, @@ -8318,7 +8320,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .windMove = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8370,7 +8372,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .ignoresSubstitute = TRUE, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8396,7 +8398,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ROCK_THROW}, @@ -8477,9 +8479,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_AVOID_STARTLE_ONCE : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_GRASS_WHISTLE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GrassWhistle, .validApprenticeMove = TRUE, @@ -8528,7 +8530,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_CosmicPower, @@ -8549,7 +8551,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -8575,7 +8577,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8626,7 +8628,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL : CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8726,7 +8728,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_STARTLE_PREV_MONS : CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -8749,10 +8751,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_GROWTH}, + .contestComboMoves = {COMBO_STARTER_GROWTH, COMBO_STARTER_ROTOTILLER}, .battleAnimScript = gBattleAnimMove_BulletSeed, }, @@ -8794,7 +8796,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8846,7 +8848,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = TRUE, .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_BLOCK, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Block, .validApprenticeMove = TRUE, @@ -8871,7 +8873,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .soundMove = B_UPDATED_MOVE_FLAGS >= GEN_8, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BETTER_IF_LAST : CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -8894,7 +8896,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_RUSH, COMBO_STARTER_DRAGON_TAIL}, @@ -8948,7 +8950,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BulkUp, @@ -9005,7 +9007,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_HIGHLY_APPEALING : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SANDSTORM}, @@ -9035,7 +9037,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_PoisonTail, .validApprenticeMove = TRUE, }, @@ -9061,7 +9063,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .assistBanned = TRUE, .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_COVET, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Covet, .validApprenticeMove = TRUE, @@ -9097,7 +9099,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = #endif .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_COOL, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_CHARGE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_VoltTackle, .validApprenticeMove = TRUE, @@ -9144,7 +9146,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_WATER_SPORT, .contestComboMoves = {COMBO_STARTER_MUD_SPORT, COMBO_STARTER_RAIN_DANCE}, @@ -9170,7 +9172,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS : CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_CALM_MIND, .contestComboMoves = {0}, @@ -9195,7 +9197,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9245,7 +9247,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = B_UPDATED_MOVE_FLAGS >= GEN_6, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING : CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9293,7 +9295,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION : CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, @@ -9317,8 +9319,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST : + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DoomDesire, @@ -9370,8 +9372,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_BRAVE_BIRD}, .battleAnimScript = gBattleAnimMove_Roost, @@ -9395,8 +9397,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Gravity, @@ -9419,8 +9421,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .ignoresSubstitute = TRUE, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MiracleEye, @@ -9445,10 +9447,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_STATUS, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_LOVELY_KISS, COMBO_STARTER_SPORE, COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE, COMBO_STARTER_SING, COMBO_STARTER_YAWN, COMBO_STARTER_HYPNOSIS, COMBO_STARTER_DARK_VOID, COMBO_STARTER_GRASS_WHISTLE, COMBO_STARTER_SLEEP_POWDER}, .battleAnimScript = gBattleAnimMove_WakeUpSlap, }, @@ -9472,8 +9474,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_HammerArm, @@ -9495,8 +9497,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GyroBall, @@ -9519,7 +9521,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_GREAT_APPEAL_BUT_NO_MORE_MOVES, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HealingWish, @@ -9539,8 +9541,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_Brine, @@ -9560,8 +9562,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_NaturalGift, @@ -9587,8 +9589,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Feint, @@ -9610,7 +9612,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BUG_BITE, }), - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9641,7 +9643,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Tailwind, @@ -9665,8 +9667,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = B_UPDATED_MOVE_FLAGS < GEN_5, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Acupressure, @@ -9687,10 +9689,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .meFirstBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_METAL_SOUND}, + .contestComboMoves = {COMBO_STARTER_METAL_SOUND, COMBO_STARTER_ENCORE, COMBO_STARTER_TAUNT, COMBO_STARTER_TORMENT}, .battleAnimScript = gBattleAnimMove_MetalBurst, }, @@ -9707,7 +9709,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -9732,7 +9734,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY, COMBO_STARTER_MIND_READER}, .battleAnimScript = gBattleAnimMove_CloseCombat, @@ -9753,8 +9755,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_PAYBACK, .contestComboMoves = {COMBO_STARTER_REVENGE}, .battleAnimScript = gBattleAnimMove_Payback, @@ -9775,8 +9777,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_PAYBACK, COMBO_STARTER_REVENGE}, .battleAnimScript = gBattleAnimMove_Assurance, @@ -9798,8 +9800,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Embargo, @@ -9820,10 +9822,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .parentalBondBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_CELEBRATE, COMBO_STARTER_COVET, COMBO_STARTER_HAPPY_HOUR, COMBO_STARTER_WISH}, .battleAnimScript = gBattleAnimMove_Fling, }, @@ -9842,8 +9844,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_2 }, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PsychoShift, @@ -9887,8 +9889,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_2 }, .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HealBlock, @@ -9907,8 +9909,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WringOut, @@ -9932,8 +9934,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PowerTrick, @@ -9955,8 +9957,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GastroAcid, @@ -9980,7 +9982,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_LUCKY_CHANT, .contestComboMoves = {COMBO_STARTER_HEAL_BELL}, @@ -10013,7 +10015,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .assistBanned = TRUE, .mimicBanned = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MeFirst, @@ -10044,7 +10046,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .assistBanned = TRUE, .mimicBanned = TRUE, .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Copycat, @@ -10067,7 +10069,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .ignoresSubstitute = TRUE, .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PowerSwap, @@ -10089,8 +10091,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GuardSwap, @@ -10111,8 +10113,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Punishment, @@ -10133,7 +10135,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10146,7 +10148,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Plants a seed on the foe\n" "giving it Insomnia."), - .effect = EFFECT_WORRY_SEED, + .effect = EFFECT_OVERWRITE_ABILITY, .power = 0, .type = TYPE_GRASS, .accuracy = 100, @@ -10154,12 +10156,13 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, + .argument = { .overwriteAbility = ABILITY_INSOMNIA }, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .magicCoatAffected = TRUE, .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_WORRY_SEED, - .contestComboMoves = {COMBO_STARTER_LEECH_SEED}, + .contestComboMoves = {COMBO_STARTER_LEECH_SEED, COMBO_STARTER_ROTOTILLER}, .battleAnimScript = gBattleAnimMove_WorrySeed, }, @@ -10205,7 +10208,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .skyBattleBanned = TRUE, .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_TOXIC_SPIKES, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ToxicSpikes, }, @@ -10227,7 +10230,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_BOOST_CRITS }, .ignoresSubstitute = TRUE, .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HeartSwap, @@ -10251,7 +10254,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10277,8 +10280,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .gravityBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MagnetRise, @@ -10306,7 +10309,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, .battleAnimScript = gBattleAnimMove_FlareBlitz, @@ -10331,9 +10334,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_FORCE_PALM, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ForcePalm, }, @@ -10381,7 +10384,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, .contestCategory = CONTEST_CATEGORY_TOUGH, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_ROCK_POLISH, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RockPolish, }, @@ -10405,8 +10408,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PoisonJab, @@ -10431,7 +10434,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10456,9 +10459,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .slicingMove = TRUE, .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_NightSlash, }, @@ -10478,7 +10481,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_AquaTail, @@ -10500,9 +10503,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .ballisticMove = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_ROTOTILLER}, .battleAnimScript = gBattleAnimMove_SeedBomb, }, @@ -10525,7 +10528,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -10548,8 +10551,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SWORDS_DANCE}, .battleAnimScript = gBattleAnimMove_XScissor, @@ -10575,8 +10578,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTIFUL : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BugBuzz, @@ -10597,8 +10600,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .pulseMove = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DragonPulse, @@ -10624,8 +10627,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DRAGON_RUSH, .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_TAIL}, .battleAnimScript = gBattleAnimMove_DragonRush, @@ -10668,8 +10671,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .punchingMove = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_DrainPunch, @@ -10690,7 +10693,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 1, .category = DAMAGE_CATEGORY_SPECIAL, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_VacuumWave, @@ -10715,7 +10718,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, @@ -10741,7 +10744,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, @@ -10765,7 +10768,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_CUTE, .contestComboStarterId = COMBO_STARTER_BRAVE_BIRD, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BraveBird, @@ -10790,8 +10793,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_EarthPower, @@ -10815,8 +10818,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Switcheroo, @@ -10840,7 +10843,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GigaImpact, @@ -10865,8 +10868,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, + .contestComboStarterId = COMBO_STARTER_NASTY_PLOT, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_NastyPlot, }, @@ -10888,7 +10891,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .punchingMove = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BulletPunch, @@ -10907,8 +10910,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = -4, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Avalanche, @@ -10951,10 +10954,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_ShadowClaw, }, @@ -10983,7 +10986,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_THUNDER_FANG, .contestComboMoves = {COMBO_STARTER_CHARGE, COMBO_STARTER_FIRE_FANG, COMBO_STARTER_ICE_FANG}, .battleAnimScript = gBattleAnimMove_ThunderFang, @@ -11049,7 +11052,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_FIRE_FANG, .contestComboMoves = {COMBO_STARTER_ICE_FANG, COMBO_STARTER_THUNDER_FANG}, .battleAnimScript = gBattleAnimMove_FireFang, @@ -11096,8 +11099,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MudBomb, @@ -11119,7 +11122,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11145,8 +11148,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ZenHeadbutt, @@ -11170,8 +11173,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MirrorShot, @@ -11195,8 +11198,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlashCannon, @@ -11221,7 +11224,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11245,8 +11248,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, //.ignoresSubstitute = TRUE, In Gen5+, the evasion drop will no longer bypass Substitute. However, this is tricky to code .magicCoatAffected = B_UPDATED_MOVE_FLAGS >= GEN_5, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Defog, @@ -11268,8 +11271,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, .ignoresProtect = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_SMART : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_TrickRoom, @@ -11294,7 +11297,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DracoMeteor, @@ -11318,8 +11321,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE}, .battleAnimScript = gBattleAnimMove_Discharge, @@ -11341,7 +11344,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SUNNY_DAY}, @@ -11367,7 +11370,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LeafStorm, @@ -11388,8 +11391,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_GROWTH}, .battleAnimScript = gBattleAnimMove_PowerWhip, @@ -11440,7 +11443,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11465,8 +11468,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_TOUGH : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GunkShot, @@ -11491,7 +11494,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -11538,7 +11541,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_StoneEdge, }, @@ -11558,8 +11561,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_2 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARM}, .battleAnimScript = gBattleAnimMove_Captivate, @@ -11587,7 +11590,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_STEALTH_ROCK}, .battleAnimScript = gBattleAnimMove_StealthRock, }, @@ -11607,8 +11610,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .makesContact = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GrassKnot, @@ -11647,8 +11650,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 31, #endif }), - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Chatter, @@ -11669,8 +11672,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .holdEffect = HOLD_EFFECT_PLATE }, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Judgment, @@ -11692,8 +11695,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BUG_BITE, }), - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_CUTE : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BugBite, @@ -11718,7 +11721,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 70, }), - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_CHARGE}, @@ -11764,7 +11767,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_AquaJet, @@ -11785,7 +11788,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_ATTACK_ORDER, .contestComboMoves = {COMBO_STARTER_DEFEND_ORDER, COMBO_STARTER_HEAL_ORDER}, @@ -11810,7 +11813,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_DEFEND_ORDER, .contestComboMoves = {COMBO_STARTER_ATTACK_ORDER, COMBO_STARTER_HEAL_ORDER}, @@ -11882,8 +11885,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DoubleHit, @@ -11908,7 +11911,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, }), .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RoarOfTime, @@ -11929,8 +11932,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SpacialRend, @@ -11973,7 +11976,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12023,9 +12026,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_RESET_STATS }, .magicCoatAffected = TRUE, .sketchBanned = (B_SKETCH_BANS >= GEN_9), - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_DARK_VOID, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DarkVoid, }, @@ -12048,8 +12051,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_2, .chance = 40, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SeedFlare, @@ -12076,7 +12079,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .chance = 10, }), .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_BEAUTY : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_OminousWind, @@ -12104,8 +12107,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestCategory = C_UPDATED_MOVE_CATEGORIES >= GEN_6 ? CONTEST_CATEGORY_COOL : CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ShadowForce, @@ -12130,8 +12133,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_COOL, - .contestComboStarterId = 0, + .contestCategory = CONTEST_CATEGORY_CUTE, + .contestComboStarterId = COMBO_STARTER_HONE_CLAWS, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HoneClaws, }, @@ -12179,7 +12182,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12225,8 +12228,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .ignoresProtect = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WonderRoom, @@ -12244,8 +12247,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Psyshock, @@ -12267,9 +12270,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .status = STATUS1_PSN_ANY }, .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_TOXIC}, + .contestComboMoves = {COMBO_STARTER_TOXIC, COMBO_STARTER_POISON_GAS, COMBO_STARTER_POISON_POWDER, COMBO_STARTER_TOXIC_SPIKES}, .battleAnimScript = gBattleAnimMove_Venoshock, }, @@ -12291,8 +12294,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Autotomize, @@ -12320,7 +12323,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .assistBanned = TRUE, .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RagePowder, @@ -12343,7 +12346,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, .gravityBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12366,7 +12369,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .ignoresProtect = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12389,10 +12392,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .damagesAirborne = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE}, .battleAnimScript = gBattleAnimMove_SmackDown, }, @@ -12410,10 +12413,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .alwaysCriticalHit = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE}, .battleAnimScript = gBattleAnimMove_StormThrow, }, @@ -12435,7 +12438,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLAME_BURST, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12460,7 +12463,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_POISON, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12487,7 +12490,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_QuiverDance, @@ -12508,7 +12511,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .minimizeDoubleDamage = B_UPDATED_MOVE_FLAGS >= GEN_7, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12529,7 +12532,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_FOES_AND_ALLY, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12551,10 +12554,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .ballisticMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_AGILITY, COMBO_STARTER_CHARGE, COMBO_STARTER_ROCK_POLISH}, .battleAnimScript = gBattleAnimMove_ElectroBall, }, @@ -12575,10 +12578,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_WATER }, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_Soak, }, @@ -12602,8 +12605,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlameCharge, @@ -12628,7 +12631,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Coil, @@ -12653,8 +12656,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LowSweep, @@ -12679,8 +12682,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_DEF_MINUS_2, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_AcidSpray, @@ -12701,8 +12704,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FoulPlay, @@ -12714,7 +12717,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "A beam that changes the\n" "foe's Ability to Simple."), - .effect = EFFECT_SIMPLE_BEAM, + .effect = EFFECT_OVERWRITE_ABILITY, .power = 0, .type = TYPE_NORMAL, .accuracy = 100, @@ -12722,9 +12725,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, + .argument = { .overwriteAbility = ABILITY_SIMPLE }, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12747,9 +12751,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_ENTRAINMENT, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Entrainment, }, @@ -12799,8 +12803,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_ROUND, }), - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Round, @@ -12823,7 +12827,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_EchoedVoice, @@ -12843,7 +12847,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .ignoresTargetDefenseEvasionStages = TRUE, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12867,7 +12871,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_CLEAR_SMOG, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -12888,10 +12892,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_AMNESIA, COMBO_STARTER_HONE_CLAWS, COMBO_STARTER_CALM_MIND, COMBO_STARTER_NASTY_PLOT}, .battleAnimScript = gBattleAnimMove_StoredPower, }, @@ -12915,8 +12919,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_QuickGuard, @@ -12965,7 +12969,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_SCALD, .contestComboMoves = {0}, @@ -12990,7 +12994,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13016,8 +13020,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .healingMove = TRUE, .pulseMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HealPulse, @@ -13039,10 +13043,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .zMove = { .powerOverride = 160 }, .argument = { .status = STATUS1_ANY }, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_TOXIC}, + .contestComboMoves = {COMBO_STARTER_TOXIC, COMBO_STARTER_FORCE_PALM, COMBO_STARTER_THUNDER_WAVE, COMBO_STARTER_INFERNO, COMBO_STARTER_WILL_O_WISP, COMBO_STARTER_LOVELY_KISS, COMBO_STARTER_SPORE, COMBO_STARTER_SING, COMBO_STARTER_YAWN, COMBO_STARTER_HYPNOSIS, COMBO_STARTER_DARK_VOID, COMBO_STARTER_GRASS_WHISTLE, COMBO_STARTER_SLEEP_POWDER, COMBO_STARTER_POISON_GAS, COMBO_STARTER_POISON_POWDER, COMBO_STARTER_TOXIC_SPIKES, COMBO_STARTER_GLARE}, .battleAnimScript = gBattleAnimMove_Hex, }, @@ -13066,10 +13070,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .assistBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKTARGETHIGH, .status = STATE_ON_AIR }, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE}, .battleAnimScript = gBattleAnimMove_SkyDrop, }, @@ -13093,7 +13097,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_SMART, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_SHIFT_GEAR, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ShiftGear, }, @@ -13113,10 +13117,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_ENTRAINMENT, COMBO_STARTER_PLAY_NICE}, .battleAnimScript = gBattleAnimMove_CircleThrow, }, @@ -13137,8 +13141,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_INCINERATE, }), - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_SHIFT_JUDGE_ATTENTION, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Incinerate, @@ -13160,8 +13164,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPD_UP_1 }, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Quash, @@ -13182,7 +13186,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13206,7 +13210,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13228,8 +13232,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Retaliate, @@ -13278,10 +13282,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .metronomeBanned = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_CELEBRATE, COMBO_STARTER_COVET, COMBO_STARTER_HAPPY_HOUR, COMBO_STARTER_WISH}, .battleAnimScript = gBattleAnimMove_Bestow, }, @@ -13303,9 +13307,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_BEAUTY, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_INFERNO, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Inferno, }, @@ -13325,8 +13329,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WaterPledge, @@ -13347,7 +13351,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13369,8 +13373,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GrassPledge, @@ -13388,9 +13392,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_COOL, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_CHARGE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_VoltSwitch, }, @@ -13413,8 +13417,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_StruggleBug, @@ -13439,7 +13443,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13459,7 +13463,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .alwaysCriticalHit = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13481,10 +13485,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .copycatBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_LATER, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_DRAGON_TAIL, - .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_RUSH}, + .contestComboMoves = {COMBO_STARTER_DRAGON_BREATH, COMBO_STARTER_DRAGON_DANCE, COMBO_STARTER_DRAGON_RAGE, COMBO_STARTER_DRAGON_RUSH, COMBO_STARTER_STEALTH_ROCK, COMBO_STARTER_SPIKES, COMBO_STARTER_TOXIC_SPIKES}, .battleAnimScript = gBattleAnimMove_DragonTail, }, @@ -13506,8 +13510,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WorkUp, @@ -13531,10 +13535,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_STRING_SHOT}, .battleAnimScript = gBattleAnimMove_Electroweb, }, @@ -13555,7 +13559,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .recoilPercentage = 25 }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WildCharge, @@ -13580,7 +13584,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_FOCUS_ENERGY}, .battleAnimScript = gBattleAnimMove_DrillRun, }, @@ -13600,7 +13604,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13626,7 +13630,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13648,8 +13652,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 50 }, .makesContact = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONE, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HornLeech, @@ -13670,8 +13674,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .ignoresTargetDefenseEvasionStages = TRUE, .slicingMove = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SacredSword, @@ -13697,8 +13701,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RazorShell, @@ -13718,8 +13722,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .minimizeDoubleDamage = B_UPDATED_MOVE_FLAGS >= GEN_6, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HeatCrash, @@ -13743,8 +13747,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LeafTornado, @@ -13770,7 +13774,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13796,7 +13800,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_CottonGuard, @@ -13820,7 +13824,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ACC_MINUS_1, .chance = 40, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13839,8 +13843,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Psystrike, @@ -13861,7 +13865,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -13890,10 +13894,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_CONFUSION, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_RAIN_DANCE}, .battleAnimScript = gBattleAnimMove_Hurricane, }, @@ -13937,10 +13941,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .powerOverride = 180 }, .makesContact = TRUE, .strikeCount = 2, - .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_SHIFT_GEAR}, .battleAnimScript = gBattleAnimMove_GearGrind, }, @@ -13961,8 +13965,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SearingShot, @@ -13984,7 +13988,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .holdEffect = HOLD_EFFECT_DRIVE }, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14013,8 +14017,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SLEEP, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RelicSong, @@ -14036,8 +14040,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .slicingMove = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SecretSword, @@ -14061,10 +14065,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_HAIL}, .battleAnimScript = gBattleAnimMove_Glaciate, }, @@ -14087,8 +14091,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_BoltStrike, @@ -14112,7 +14116,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 20, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14139,7 +14143,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14168,7 +14172,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14225,8 +14229,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Snarl, @@ -14250,10 +14254,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_HAIL}, .battleAnimScript = gBattleAnimMove_IcicleCrash, }, @@ -14300,7 +14304,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .thawsUser = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14321,7 +14325,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14348,8 +14352,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .minimizeDoubleDamage = TRUE, .gravityBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlyingPress, @@ -14378,7 +14382,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .assistBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14407,8 +14411,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Belch, @@ -14434,7 +14438,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .skyBattleBanned = TRUE, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_TOUGH, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_ROTOTILLER, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Rototiller, }, @@ -14458,10 +14462,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .magicCoatAffected = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_STRING_SHOT}, .battleAnimScript = gBattleAnimMove_StickyWeb, }, @@ -14480,8 +14484,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FellStinger, @@ -14509,8 +14513,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PhantomForce, @@ -14533,8 +14537,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_GHOST }, .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_TrickOrTreat, @@ -14558,8 +14562,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .magicCoatAffected = TRUE, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_NobleRoar, @@ -14582,7 +14586,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14605,10 +14609,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .absorbPercentage = 50 }, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, - .contestCategory = CONTEST_CATEGORY_BEAUTY, - .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, + .contestCategory = CONTEST_CATEGORY_SMART, + .contestComboStarterId = COMBO_STARTER_PARABOLIC_CHARGE, + .contestComboMoves = {COMBO_STARTER_CHARGE}, .battleAnimScript = gBattleAnimMove_ParabolicCharge, }, @@ -14629,7 +14633,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_GRASS }, .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14651,7 +14655,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .windMove = TRUE, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14681,7 +14685,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14729,8 +14733,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = TRUE, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PartingShot, @@ -14752,8 +14756,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ATK_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_TopsyTurvy, @@ -14774,7 +14778,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .absorbPercentage = 75 }, .makesContact = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14800,7 +14804,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -14825,7 +14829,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FlowerShield, @@ -14849,8 +14853,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_GRASSY_TERRAIN, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_GrassyTerrain, @@ -14874,8 +14878,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_MISTY_TERRAIN, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MistyTerrain, @@ -14896,10 +14900,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPATK_UP_1 }, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_PARABOLIC_CHARGE}, .battleAnimScript = gBattleAnimMove_Electrify, }, @@ -14922,8 +14926,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ATK_MINUS_1, .chance = 10, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PlayRough, @@ -14945,7 +14949,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .windMove = TRUE, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FairyWind, @@ -14969,8 +14973,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Moonblast, @@ -14992,8 +14996,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Boomburst, @@ -15016,8 +15020,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, - .contestEffect = CONTEST_EFFECT_MAKE_FOLLOWING_MONS_NERVOUS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_FairyLock, @@ -15046,7 +15050,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .instructBanned = TRUE, .assistBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_KingsShield, @@ -15070,9 +15074,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_PLAY_NICE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PlayNice, }, @@ -15096,8 +15100,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .magicCoatAffected = TRUE, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Confide, @@ -15123,7 +15127,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 50, }), - .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15150,8 +15154,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_BURN, .chance = 30, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_SCALD}, .battleAnimScript = gBattleAnimMove_SteamEruption, @@ -15175,7 +15179,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_HYPERSPACE_HOLE, .contestComboMoves = {COMBO_STARTER_HYPERSPACE_FURY}, @@ -15196,8 +15200,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 1, .category = B_UPDATED_MOVE_DATA >= GEN_7 ? DAMAGE_CATEGORY_SPECIAL : DAMAGE_CATEGORY_PHYSICAL, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WaterShuriken, @@ -15221,7 +15225,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SP_ATK_MINUS_1, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_REPETITION_NOT_BORING, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15250,7 +15254,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .copycatBanned = TRUE, .assistBanned = TRUE, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SpikyShield, @@ -15274,8 +15278,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_AromaticMist, @@ -15297,8 +15301,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, - .contestCategory = CONTEST_CATEGORY_COOL, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_EerieImpulse, @@ -15323,7 +15327,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, - .contestComboMoves = {COMBO_STARTER_TOXIC}, + .contestComboMoves = {COMBO_STARTER_TOXIC, COMBO_STARTER_POISON_GAS, COMBO_STARTER_POISON_POWDER, COMBO_STARTER_TOXIC_SPIKES}, .battleAnimScript = gBattleAnimMove_VenomDrench, }, @@ -15344,7 +15348,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_SPDEF_UP_2 }, .powderMove = TRUE, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, + .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, //CONTEST_EFFECT_QUICKLY_GROW_BORED .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15371,7 +15375,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .skyBattleBanned = TRUE, .argument.twoTurnAttack = { .stringId = STRINGID_PKNMABSORBINGPOWER }, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Geomancy, @@ -15396,8 +15400,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .ignoresSubstitute = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_MagneticFlux, @@ -15420,9 +15424,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_COOL, - .contestComboStarterId = 0, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, + .contestCategory = CONTEST_CATEGORY_CUTE, + .contestComboStarterId = COMBO_STARTER_HAPPY_HOUR, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HappyHour, }, @@ -15445,8 +15449,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, - .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestEffect = CONTEST_EFFECT_BETTER_WHEN_AUDIENCE_EXCITED, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST + .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = COMBO_STARTER_ELECTRIC_TERRAIN, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ElectricTerrain, @@ -15466,8 +15470,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_DazzlingGleam, @@ -15496,9 +15500,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, - .contestComboStarterId = 0, + .contestComboStarterId = COMBO_STARTER_CELEBRATE, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Celebrate, }, @@ -15575,10 +15579,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, - .contestComboMoves = {0}, + .contestComboMoves = {COMBO_STARTER_CHARGE}, .battleAnimScript = gBattleAnimMove_Nuzzle, }, @@ -15595,8 +15599,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, //CONTEST_EFFECT_QUICKLY_GROW_BORED + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HoldBack, @@ -15622,7 +15626,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .multistring.wrapped = B_MSG_WRAPPED_INFESTATION, }), .contestEffect = CONTEST_EFFECT_DONT_EXCITE_AUDIENCE, - .contestCategory = CONTEST_CATEGORY_SMART, + .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Infestation, @@ -15649,7 +15653,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 100, }), - .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15670,7 +15674,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .absorbPercentage = 75 }, .healingMove = B_HEAL_BLOCKING >= GEN_6, - .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, + .contestEffect = CONTEST_EFFECT_APPEAL_AS_GOOD_AS_PREV_ONES, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15695,8 +15699,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoreTypeIfFlyingAndUngrounded = TRUE, .metronomeBanned = TRUE, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_STARTLE_MONS_SAME_TYPE_APPEAL, + .contestCategory = CONTEST_CATEGORY_BEAUTIFUL, .contestComboStarterId = COMBO_STARTER_THOUSAND_ARROWS, .contestComboMoves = {COMBO_STARTER_THOUSAND_WAVES}, .battleAnimScript = gBattleAnimMove_ThousandArrows, @@ -15721,7 +15725,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PREVENT_ESCAPE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_THOUSAND_WAVES, .contestComboMoves = {COMBO_STARTER_THOUSAND_ARROWS}, @@ -15743,8 +15747,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .skyBattleBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, - .contestCategory = CONTEST_CATEGORY_TOUGH, + .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LandsWrath, @@ -15766,6 +15770,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .recoilPercentage = 50 }, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_LightOfRuin, }, @@ -15785,7 +15793,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .pulseMove = TRUE, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -15807,8 +15815,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, - .contestCategory = CONTEST_CATEGORY_CUTE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_LAST + .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_PrecipiceBlades, @@ -15860,7 +15868,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, //CONTEST_EFFECT_EXCITES_AUDIENCE_MORE_IF_FIRST .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = COMBO_STARTER_HYPERSPACE_FURY, .contestComboMoves = {COMBO_STARTER_HYPERSPACE_HOLE}, @@ -16040,7 +16048,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_SPD_MINUS_1, .self = TRUE, }), - .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_HAIL}, @@ -16066,7 +16074,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .mirrorMoveBanned = TRUE, .healingMove = TRUE, .magicCoatAffected = TRUE, - .contestEffect = CONTEST_EFFECT_QUALITY_DEPENDS_ON_TIMING, + .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -16432,7 +16440,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -17700,7 +17708,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .type = TYPE_PSYCHIC }, .magicCoatAffected = TRUE, .powderMove = TRUE, - .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, + .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -18609,7 +18617,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .pulseMove = TRUE, - .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_REPETITION_NOT_BORING : CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, .contestComboMoves = {COMBO_STARTER_ELECTRIC_TERRAIN, COMBO_STARTER_MISTY_TERRAIN, COMBO_STARTER_GRASSY_TERRAIN, COMBO_STARTER_PSYCHIC_TERRAIN}, @@ -18969,7 +18977,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .metronomeBanned = TRUE, - .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, @@ -19282,6 +19290,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_THRASH, .self = TRUE, }), + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_USER_MORE_EASILY_STARTLED : CONTEST_EFFECT_JAMS_OTHERS_BUT_MISS_ONE_TURN, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_RagingFury, }, @@ -19302,6 +19313,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .argument = { .recoilPercentage = 33 }, .makesContact = TRUE, .skyBattleBanned = B_EXTRAPOLATED_MOVE_FLAGS, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_WaveCrash, }, @@ -19361,6 +19375,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .snatchAffected = TRUE, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, + .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_VictoryDance, }, @@ -19384,6 +19401,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_SPDEF_DOWN, .self = TRUE, }), + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_HeadlongRush, }, @@ -19798,6 +19818,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .punchingMove = TRUE, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_JetPunch, }, @@ -20174,6 +20197,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_SPECIAL, .argument = { .damagePercentage = 50 }, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Ruination, }, @@ -20308,6 +20334,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .metronomeBanned = TRUE, + .contestEffect = C_UPDATED_MOVE_EFFECTS >= GEN_6 ? CONTEST_EFFECT_BADLY_STARTLE_MONS_WITH_GOOD_APPEALS : CONTEST_EFFECT_BADLY_STARTLE_PREV_MONS, + .contestCategory = CONTEST_CATEGORY_BEAUTY, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = (B_PREFERRED_ICE_WEATHER == B_ICE_WEATHER_HAIL) ? gBattleAnimMove_Hail : gBattleAnimMove_Snowscape, }, @@ -20355,6 +20385,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .self = TRUE, .chance = 100, }), + .contestEffect = CONTEST_EFFECT_BETTER_WITH_GOOD_CONDITION, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Trailblaze, }, @@ -20377,6 +20410,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_ATK_MINUS_1, .chance = 100, }), + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ChillingWater, }, @@ -20458,6 +20494,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .moveEffect = MOVE_EFFECT_DEF_SPDEF_DOWN, .self = TRUE, }), + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_ArmorCannon, }, @@ -20541,6 +20580,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .makesContact = TRUE, .meFirstBanned = TRUE, .metronomeBanned = TRUE, + .contestEffect = CONTEST_EFFECT_BETTER_IF_LAST, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Comeuppance, }, @@ -20928,6 +20970,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 1, .category = DAMAGE_CATEGORY_SPECIAL, + .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_Thunderclap, }, @@ -21060,6 +21105,9 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .minimizeDoubleDamage = TRUE, + .contestEffect = CONTEST_EFFECT_USER_MORE_EASILY_STARTLED, + .contestComboStarterId = 0, + .contestComboMoves = {0}, .battleAnimScript = gBattleAnimMove_SupercellSlam, }, @@ -21510,7 +21558,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Mew attacks with full force.\n" "Psychically charges terrain."), - .effect = EFFECT_HIT_SET_TERRAIN, + .effect = EFFECT_HIT, .power = 185, .type = TYPE_PSYCHIC, .accuracy = 0, @@ -21518,8 +21566,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = { .moveProperty = STATUS_FIELD_PSYCHIC_TERRAIN }, .battleAnimScript = gBattleAnimMove_GenesisSupernova, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_PSYCHIC_TERRAIN, + .chance = 100, + }), }, [MOVE_SINISTER_ARROW_RAID] = { diff --git a/src/data/object_events/object_event_graphics.h b/src/data/object_events/object_event_graphics.h index e3d2c674ad..424d4224f3 100755 --- a/src/data/object_events/object_event_graphics.h +++ b/src/data/object_events/object_event_graphics.h @@ -465,3 +465,5 @@ const u16 gObjectEventPal_StrangeBall[] = INCBIN_U16("graphics/object_events/pic const u32 gFieldEffectObjectPic_CaveDust[] = INCBIN_U32("graphics/field_effects/pics/cave_dust.4bpp"); const u16 gFieldEffectObjectPalette_CaveDust[] = INCBIN_U16("graphics/field_effects/palettes/cave_dust.gbapal"); + +const u32 gObjectEventPic_ApricornTree[] = INCBIN_U32("graphics/object_events/pics/misc/apricorn_tree.4bpp"); diff --git a/src/data/object_events/object_event_graphics_info.h b/src/data/object_events/object_event_graphics_info.h index 91b3ab2c9d..5b1c891eb4 100755 --- a/src/data/object_events/object_event_graphics_info.h +++ b/src/data/object_events/object_event_graphics_info.h @@ -4690,3 +4690,22 @@ const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_BallLight = { .images = gFieldEffectObjectPicTable_BallLight, .affineAnims = gDummySpriteAffineAnimTable, }; + +const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_ApricornTree = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_NPC_3, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 128, + .width = 16, + .height = 16, + .paletteSlot = PALSLOT_NPC_3, + .shadowSize = SHADOW_SIZE_S, + .inanimate = TRUE, + .compressed = FALSE, + .tracks = TRACKS_NONE, + .oam = &gObjectEventBaseOam_16x16, + .subspriteTables = sOamTables_16x16, + .anims = sAnimTable_Inanimate, + .images = sPicTable_ApricornTree, + .affineAnims = gDummySpriteAffineAnimTable, +}; diff --git a/src/data/object_events/object_event_graphics_info_pointers.h b/src/data/object_events/object_event_graphics_info_pointers.h index 117187739b..a239bce993 100755 --- a/src/data/object_events/object_event_graphics_info_pointers.h +++ b/src/data/object_events/object_event_graphics_info_pointers.h @@ -248,6 +248,7 @@ extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Storyteller extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Giddy; extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_UnusedMauvilleOldMan1; extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_UnusedMauvilleOldMan2; +extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_ApricornTree; const struct ObjectEventGraphicsInfo *const gObjectEventGraphicsInfoPointers[NUM_OBJ_EVENT_GFX] = { [OBJ_EVENT_GFX_BRENDAN_NORMAL] = &gObjectEventGraphicsInfo_BrendanNormal, @@ -492,6 +493,7 @@ const struct ObjectEventGraphicsInfo *const gObjectEventGraphicsInfoPointers[NUM [OBJ_EVENT_GFX_POKE_BALL] = &gObjectEventGraphicsInfo_PokeBall, [OBJ_EVENT_GFX_OW_MON] = &gObjectEventGraphicsInfo_Follower, [OBJ_EVENT_GFX_LIGHT_SPRITE] = &gObjectEventGraphicsInfo_BallLight, + [OBJ_EVENT_GFX_APRICORN_TREE] = &gObjectEventGraphicsInfo_ApricornTree, }; const struct ObjectEventGraphicsInfo *const gMauvilleOldManGraphicsInfoPointers[] = { diff --git a/src/data/object_events/object_event_pic_tables.h b/src/data/object_events/object_event_pic_tables.h index c1f8fd6f1c..06d353b44d 100755 --- a/src/data/object_events/object_event_pic_tables.h +++ b/src/data/object_events/object_event_pic_tables.h @@ -1356,3 +1356,7 @@ static const struct SpriteFrameImage sPicTable_KirliaOld[] = { static const struct SpriteFrameImage sPicTable_RubySapphireMay[] = { overworld_ascending_frames(gObjectEventPic_RubySapphireMayNormal, 2, 4), }; + +static const struct SpriteFrameImage sPicTable_ApricornTree[] = { + overworld_frame(gObjectEventPic_ApricornTree, 2, 2, 0), +}; diff --git a/src/data/party_menu.h b/src/data/party_menu.h index 655264f02d..cce9c7036c 100644 --- a/src/data/party_menu.h +++ b/src/data/party_menu.h @@ -118,6 +118,7 @@ static const u8 sFontColorTable[][3] = {TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}, // Selection actions {TEXT_COLOR_WHITE, TEXT_COLOR_BLUE, TEXT_COLOR_LIGHT_BLUE}, // Field moves {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY}, // Unused + {TEXT_COLOR_WHITE, TEXT_COLOR_RED, TEXT_COLOR_LIGHT_RED}, // Move relearner }; static const struct WindowTemplate sSinglePartyMenuWindowTemplate[] = @@ -717,6 +718,11 @@ struct [MENU_TRADE1] = {sText_Trade4, CursorCb_Trade1}, [MENU_TRADE2] = {sText_Trade4, CursorCb_Trade2}, [MENU_TOSS] = {gMenuText_Toss, CursorCb_Toss}, + [MENU_LEVEL_UP_MOVES] = {COMPOUND_STRING("LEVEL MOVES"), CursorCb_ChangeLevelUpMoves}, + [MENU_EGG_MOVES] = {COMPOUND_STRING("EGG MOVES"), CursorCb_ChangeEggMoves}, + [MENU_TM_MOVES] = {COMPOUND_STRING("TM MOVES"), CursorCb_ChangeTMMoves}, + [MENU_TUTOR_MOVES] = {COMPOUND_STRING("TUTOR MOVES"), CursorCb_ChangeTutorMoves}, + [MENU_SUB_MOVES] = {COMPOUND_STRING("LEARN MOVES"), CursorCb_LearnMovesSubMenu}, [MENU_CATALOG_BULB] = {COMPOUND_STRING("Light bulb"), CursorCb_CatalogBulb}, [MENU_CATALOG_OVEN] = {COMPOUND_STRING("Microwave oven"), CursorCb_CatalogOven}, [MENU_CATALOG_WASHING] = {COMPOUND_STRING("Washing machine"), CursorCb_CatalogWashing}, diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index fd443458c7..54584c5796 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -73,6 +73,15 @@ static const struct FormChange sPikachuFormChangeTable[] = }; #endif //P_FAMILY_PIKACHU +#if P_FAMILY_CLEFAIRY +static const struct FormChange sClefableFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_CLEFABLE_MEGA, ITEM_CLEFABLITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_CLEFAIRY + #if P_FAMILY_MEOWTH static const struct FormChange sMeowthFormChangeTable[] = { @@ -102,6 +111,15 @@ static const struct FormChange sMachampFormChangeTable[] = }; #endif //P_FAMILY_MACHOP +#if P_FAMILY_BELLSPROUT +static const struct FormChange sVictreebelFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_VICTREEBEL_MEGA, ITEM_VICTREEBELITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_BELLSPROUT + #if P_FAMILY_SLOWPOKE static const struct FormChange sSlowbroFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -153,6 +171,15 @@ static const struct FormChange sKangaskhanFormChangeTable[] = { }; #endif //P_FAMILY_KANGASKHAN +#if P_FAMILY_STARYU +static const struct FormChange sStarmieFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_STARMIE_MEGA, ITEM_STARMINITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_STARYU + #if P_FAMILY_SCYTHER #if P_GEN_2_CROSS_EVOS static const struct FormChange sScizorFormChangeTable[] = { @@ -218,6 +245,15 @@ static const struct FormChange sSnorlaxFormChangeTable[] = { }; #endif //P_FAMILY_SNORLAX +#if P_FAMILY_DRATINI +static const struct FormChange sDragoniteFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DRAGONITE_MEGA, ITEM_DRAGONINITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_DRATINI + #if P_FAMILY_MEWTWO static const struct FormChange sMewtwoFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -228,6 +264,24 @@ static const struct FormChange sMewtwoFormChangeTable[] = { }; #endif //P_FAMILY_MEWTWO +#if P_FAMILY_CHIKORITA +static const struct FormChange sMeganiumFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_MEGANIUM_MEGA, ITEM_MEGANIUMITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_CHIKORITA + +#if P_FAMILY_TOTODILE +static const struct FormChange sFeraligatrFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FERALIGATR_MEGA, ITEM_FERALIGITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_TOTODILE + #if P_FAMILY_MAREEP static const struct FormChange sAmpharosFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -246,6 +300,15 @@ static const struct FormChange sHeracrossFormChangeTable[] = { }; #endif //P_FAMILY_HERACROSS +#if P_FAMILY_SKARMORY +static const struct FormChange sSkarmoryFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_SKARMORY_MEGA, ITEM_SKARMORITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_SKARMORY + #if P_FAMILY_HOUNDOUR static const struct FormChange sHoundoomFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -406,6 +469,13 @@ static const struct FormChange sGlalieFormChangeTable[] = { #endif {FORM_CHANGE_TERMINATOR}, }; + +static const struct FormChange sFroslassFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FROSLASS_MEGA, ITEM_FROSLASSITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; #endif //P_FAMILY_SNORUNT #if P_FAMILY_CASTFORM @@ -690,6 +760,24 @@ static const struct FormChange sArceusFormChangeTable[] = { }; #endif //P_FAMILY_ARCEUS +#if P_FAMILY_TEPIG +static const struct FormChange sEmboarFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_EMBOAR_MEGA, ITEM_EMBOARITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_TEPIG + +#if P_FAMILY_DRILBUR +static const struct FormChange sExcadrillFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_EXCADRILL_MEGA, ITEM_EXCADRITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_DRILBUR + #if P_FAMILY_AUDINO static const struct FormChange sAudinoFormChangeTable[] = { #if P_MEGA_EVOLUTIONS @@ -699,6 +787,15 @@ static const struct FormChange sAudinoFormChangeTable[] = { }; #endif //P_FAMILY_AUDINO +#if P_FAMILY_VENIPEDE +static const struct FormChange sScolipedeFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_SCOLIPEDE_MEGA, ITEM_SCOLIPITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_VENIPEDE + #if P_FAMILY_DARUMAKA static const struct FormChange sDarmanitanFormChangeTable[] = { {FORM_CHANGE_BATTLE_HP_PERCENT, SPECIES_DARMANITAN_STANDARD, ABILITY_ZEN_MODE, HP_HIGHER_THAN, 50}, @@ -719,6 +816,15 @@ static const struct FormChange sDarmanitanGalarFormChangeTable[] = { #endif //P_GALARIAN_FORMS #endif //P_FAMILY_DARUMAKA +#if P_FAMILY_SCRAGGY +static const struct FormChange sScraftyFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_SCRAFTY_MEGA, ITEM_SCRAFTINITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_SCRAGGY + #if P_FAMILY_TRUBBISH static const struct FormChange sGarbodorFormChangeTable[] = { @@ -729,6 +835,24 @@ static const struct FormChange sGarbodorFormChangeTable[] = }; #endif //P_FAMILY_TRUBBISH +#if P_FAMILY_TYNAMO +static const struct FormChange sEelektrossFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_EELEKTROSS_MEGA, ITEM_EELEKTROSSITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_TYNAMO + +#if P_FAMILY_LITWICK +static const struct FormChange sChandelureFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_CHANDELURE_MEGA, ITEM_CHANDELURITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_LITWICK + #if P_FAMILY_TORNADUS static const struct FormChange sTornadusFormChangeTable[] = { {FORM_CHANGE_ITEM_USE, SPECIES_TORNADUS_THERIAN, ITEM_REVEAL_GLASS}, @@ -790,7 +914,32 @@ static const struct FormChange sGenesectFormChangeTable[] = { }; #endif //P_FAMILY_GENESECT +#if P_FAMILY_CHESPIN +static const struct FormChange sChesnaughtFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_CHESNAUGHT_MEGA, ITEM_CHESNAUGHTITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_CHESPIN + +#if P_FAMILY_FENNEKIN +static const struct FormChange sDelphoxFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DELPHOX_MEGA, ITEM_DELPHOXITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_FENNEKIN + #if P_FAMILY_FROAKIE +static const struct FormChange sGreninjaFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_GRENINJA_MEGA, ITEM_GRENINJITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; + static const struct FormChange sGreninjaBattleBondFormChangeTable[] = { {FORM_CHANGE_FAINT, SPECIES_GRENINJA_BATTLE_BOND}, {FORM_CHANGE_END_BATTLE, SPECIES_GRENINJA_BATTLE_BOND}, @@ -798,6 +947,24 @@ static const struct FormChange sGreninjaBattleBondFormChangeTable[] = { }; #endif //P_FAMILY_FROAKIE +#if P_FAMILY_LITLEO +static const struct FormChange sPyroarFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_PYROAR_MEGA, ITEM_PYROARITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_LITLEO + +#if P_FAMILY_FLABEBE +static const struct FormChange sFloetteEternalFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FLOETTE_MEGA, ITEM_FLOETTITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_FLABEBE + #if P_FAMILY_FURFROU static const struct FormChange sFurfrouFormChangeTable[] = { {FORM_CHANGE_WITHDRAW, SPECIES_FURFROU_NATURAL}, @@ -818,6 +985,42 @@ static const struct FormChange sAegislashFormChangeTable[] = { }; #endif //P_FAMILY_HONEDGE +#if P_FAMILY_INKAY +static const struct FormChange sMalamarFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_MALAMAR_MEGA, ITEM_MALAMARITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_INKAY + +#if P_FAMILY_BINACLE +static const struct FormChange sBarbaracleFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_BARBARACLE_MEGA, ITEM_BARBARACITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_BINACLE + +#if P_FAMILY_SKRELP +static const struct FormChange sDragalgeFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DRAGALGE_MEGA, ITEM_DRAGALGITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_SKRELP + +#if P_FAMILY_HAWLUCHA +static const struct FormChange sHawluchaFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_HAWLUCHA_MEGA, ITEM_HAWLUCHANITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_HAWLUCHA + #if P_FAMILY_XERNEAS static const struct FormChange sXerneasFormChangeTable[] = { {FORM_CHANGE_BEGIN_BATTLE, SPECIES_XERNEAS_ACTIVE}, @@ -856,6 +1059,9 @@ static const struct FormChange sZygarde10PowerConstructFormChangeTable[] = { static const struct FormChange sZygardeCompleteFormChangeTable[] = { {FORM_CHANGE_FAINT}, {FORM_CHANGE_END_BATTLE}, +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_ZYGARDE_MEGA, ITEM_ZYGARDITE}, +#endif {FORM_CHANGE_TERMINATOR}, }; #endif //P_FAMILY_ZYGARDE @@ -1003,6 +1209,15 @@ static const struct FormChange sMimikyuTotemFormChangeTable[] = { }; #endif //P_FAMILY_MIMIKYU +#if P_FAMILY_DRAMPA +static const struct FormChange sDrampaFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_DRAMPA_MEGA, ITEM_DRAMPANITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_DRAMPA + #if P_FAMILY_NECROZMA static const struct Fusion sNecrozmaFusionTable[] = { {1, ITEM_N_SOLARIZER, SPECIES_NECROZMA, SPECIES_SOLGALEO, SPECIES_NECROZMA_DUSK_MANE, MOVE_SUNSTEEL_STRIKE, FORGET_EXTRA_MOVES}, @@ -1202,8 +1417,18 @@ static const struct FormChange sAlcremieFormChangeTable[] = }; #endif //P_FAMILY_MILCERY +#if P_FAMILY_FALINKS +static const struct FormChange sFalinksFormChangeTable[] = { +#if P_GEN_9_MEGA_EVOLUTIONS + {FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM, SPECIES_FALINKS_MEGA, ITEM_FALINKSITE}, +#endif + {FORM_CHANGE_TERMINATOR}, +}; +#endif //P_FAMILY_FALINKS + #if P_FAMILY_EISCUE static const struct FormChange sEiscueFormChangeTable[] = { + {FORM_CHANGE_BATTLE_WEATHER, SPECIES_EISCUE_ICE, B_WEATHER_HAIL | B_WEATHER_SNOW, ABILITY_ICE_FACE}, {FORM_CHANGE_FAINT, SPECIES_EISCUE_ICE}, {FORM_CHANGE_END_BATTLE, SPECIES_EISCUE_ICE}, {FORM_CHANGE_TERMINATOR}, diff --git a/src/data/pokemon/form_species_tables.h b/src/data/pokemon/form_species_tables.h index 53ee47f933..ab703bc2d0 100644 --- a/src/data/pokemon/form_species_tables.h +++ b/src/data/pokemon/form_species_tables.h @@ -150,6 +150,16 @@ static const u16 sSandslashFormSpeciesIdTable[] = { }; #endif //P_FAMILY_SANDSHREW +#if P_FAMILY_CLEFAIRY +static const u16 sClefableFormSpeciesIdTable[] = { + SPECIES_CLEFABLE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_CLEFABLE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_CLEFAIRY + #if P_FAMILY_VULPIX static const u16 sVulpixFormSpeciesIdTable[] = { SPECIES_VULPIX, @@ -248,6 +258,16 @@ static const u16 sMachampFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MACHOP +#if P_FAMILY_BELLSPROUT +static const u16 sVictreebelFormSpeciesIdTable[] = { + SPECIES_VICTREEBEL, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_VICTREEBEL_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_BELLSPROUT + #if P_FAMILY_GEODUDE static const u16 sGeodudeFormSpeciesIdTable[] = { SPECIES_GEODUDE, @@ -445,6 +465,16 @@ static const u16 sKangaskhanFormSpeciesIdTable[] = { }; #endif //P_FAMILY_KANGASKHAN +#if P_FAMILY_STARYU +static const u16 sStarmieFormSpeciesIdTable[] = { + SPECIES_STARMIE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_STARMIE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_STARYU + #if P_FAMILY_MR_MIME static const u16 sMrMimeFormSpeciesIdTable[] = { SPECIES_MR_MIME, @@ -570,6 +600,16 @@ static const u16 sMoltresFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MOLTRES +#if P_FAMILY_DRATINI +static const u16 sDragoniteFormSpeciesIdTable[] = { + SPECIES_DRAGONITE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DRAGONITE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_DRATINI + #if P_FAMILY_MEWTWO static const u16 sMewtwoFormSpeciesIdTable[] = { SPECIES_MEWTWO, @@ -581,6 +621,16 @@ static const u16 sMewtwoFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MEWTWO +#if P_FAMILY_CHIKORITA +static const u16 sMeganiumFormSpeciesIdTable[] = { + SPECIES_MEGANIUM, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_MEGANIUM_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_CHIKORITA + #if P_FAMILY_CYNDAQUIL static const u16 sTyphlosionFormSpeciesIdTable[] = { SPECIES_TYPHLOSION, @@ -591,6 +641,16 @@ static const u16 sTyphlosionFormSpeciesIdTable[] = { }; #endif //P_FAMILY_CYNDAQUIL +#if P_FAMILY_TOTODILE +static const u16 sFeraligatrFormSpeciesIdTable[] = { + SPECIES_FERALIGATR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FERALIGATR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_TOTODILE + #if P_FAMILY_MAREEP static const u16 sAmpharosFormSpeciesIdTable[] = { SPECIES_AMPHAROS, @@ -701,6 +761,16 @@ static const u16 sCorsolaFormSpeciesIdTable[] = { }; #endif //P_FAMILY_CORSOLA +#if P_FAMILY_SKARMORY +static const u16 sSkarmoryFormSpeciesIdTable[] = { + SPECIES_SKARMORY, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_SKARMORY_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_SKARMORY + #if P_FAMILY_HOUNDOUR static const u16 sHoundoomFormSpeciesIdTable[] = { SPECIES_HOUNDOOM, @@ -907,6 +977,14 @@ static const u16 sGlalieFormSpeciesIdTable[] = { #endif FORM_SPECIES_END, }; + +static const u16 sFroslassFormSpeciesIdTable[] = { + SPECIES_FROSLASS, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FROSLASS_MEGA, +#endif + FORM_SPECIES_END, +}; #endif //P_FAMILY_SNORUNT #if P_FAMILY_BAGON @@ -1142,6 +1220,16 @@ static const u16 sArceusFormSpeciesIdTable[] = { }; #endif //P_FAMILY_ARCEUS +#if P_FAMILY_TEPIG +static const u16 sEmboarFormSpeciesIdTable[] = { + SPECIES_EMBOAR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_EMBOAR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_TEPIG + #if P_FAMILY_OSHAWOTT static const u16 sSamurottFormSpeciesIdTable[] = { SPECIES_SAMUROTT, @@ -1152,6 +1240,16 @@ static const u16 sSamurottFormSpeciesIdTable[] = { }; #endif //P_FAMILY_OSHAWOTT +#if P_FAMILY_DRILBUR +static const u16 sExcadrillFormSpeciesIdTable[] = { + SPECIES_EXCADRILL, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_EXCADRILL_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_DRILBUR + #if P_FAMILY_AUDINO static const u16 sAudinoFormSpeciesIdTable[] = { SPECIES_AUDINO, @@ -1162,6 +1260,16 @@ static const u16 sAudinoFormSpeciesIdTable[] = { }; #endif //P_FAMILY_AUDINO +#if P_FAMILY_VENIPEDE +static const u16 sScolipedeFormSpeciesIdTable[] = { + SPECIES_SCOLIPEDE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_SCOLIPEDE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_VENIPEDE + #if P_FAMILY_PETILIL static const u16 sLilligantFormSpeciesIdTable[] = { SPECIES_LILLIGANT, @@ -1207,6 +1315,16 @@ static const u16 sDarmanitanFormSpeciesIdTable[] = { }; #endif //P_FAMILY_DARUMAKA +#if P_FAMILY_SCRAGGY +static const u16 sScraftyFormSpeciesIdTable[] = { + SPECIES_SCRAFTY, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_SCRAFTY_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_SCRAGGY + #if P_FAMILY_YAMASK static const u16 sYamaskFormSpeciesIdTable[] = { SPECIES_YAMASK, @@ -1263,6 +1381,26 @@ static const u16 sSawsbuckFormSpeciesIdTable[] = { }; #endif //P_FAMILY_DEERLING +#if P_FAMILY_TYNAMO +static const u16 sEelektrossFormSpeciesIdTable[] = { + SPECIES_EELEKTROSS, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_EELEKTROSS_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_TYNAMO + +#if P_FAMILY_LITWICK +static const u16 sChandelureFormSpeciesIdTable[] = { + SPECIES_CHANDELURE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_CHANDELURE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_LITWICK + #if P_FAMILY_STUNFISK static const u16 sStunfiskFormSpeciesIdTable[] = { SPECIES_STUNFISK, @@ -1343,11 +1481,34 @@ static const u16 sGenesectFormSpeciesIdTable[] = { }; #endif //P_FAMILY_GENESECT +#if P_FAMILY_CHESPIN +static const u16 sChesnaughtFormSpeciesIdTable[] = { + SPECIES_CHESNAUGHT, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_CHESNAUGHT_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_CHESPIN + +#if P_FAMILY_FENNEKIN +static const u16 sDelphoxFormSpeciesIdTable[] = { + SPECIES_DELPHOX, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DELPHOX_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_FENNEKIN + #if P_FAMILY_FROAKIE static const u16 sGreninjaFormSpeciesIdTable[] = { SPECIES_GRENINJA, SPECIES_GRENINJA_BATTLE_BOND, SPECIES_GRENINJA_ASH, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_GRENINJA_MEGA, +#endif FORM_SPECIES_END, }; #endif //P_FAMILY_FROAKIE @@ -1426,6 +1587,16 @@ static const u16 sVivillonFormSpeciesIdTable[] = { }; #endif //P_FAMILY_SCATTERBUG +#if P_FAMILY_LITLEO +static const u16 sPyroarFormSpeciesIdTable[] = { + SPECIES_PYROAR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_PYROAR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_LITLEO + #if P_FAMILY_FLABEBE static const u16 sFlabebeFormSpeciesIdTable[] = { SPECIES_FLABEBE_RED, @@ -1443,6 +1614,9 @@ static const u16 sFloetteFormSpeciesIdTable[] = { SPECIES_FLOETTE_BLUE, SPECIES_FLOETTE_WHITE, SPECIES_FLOETTE_ETERNAL, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FLOETTE_MEGA, +#endif FORM_SPECIES_END, }; @@ -1488,6 +1662,46 @@ static const u16 sAegislashFormSpeciesIdTable[] = { }; #endif //P_FAMILY_HONEDGE +#if P_FAMILY_INKAY +static const u16 sMalamarFormSpeciesIdTable[] = { + SPECIES_MALAMAR, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_MALAMAR_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_INKAY + +#if P_FAMILY_BINACLE +static const u16 sBarbaracleFormSpeciesIdTable[] = { + SPECIES_BARBARACLE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_BARBARACLE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_BINACLE + +#if P_FAMILY_SKRELP +static const u16 sDragalgeFormSpeciesIdTable[] = { + SPECIES_DRAGALGE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DRAGALGE_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_SKRELP + +#if P_FAMILY_HAWLUCHA +static const u16 sHawluchaFormSpeciesIdTable[] = { + SPECIES_HAWLUCHA, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_HAWLUCHA_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_HAWLUCHA + #if P_FAMILY_GOOMY static const u16 sSliggooFormSpeciesIdTable[] = { SPECIES_SLIGGOO, @@ -1549,6 +1763,9 @@ static const u16 sZygardeFormSpeciesIdTable[] = { SPECIES_ZYGARDE_10_POWER_CONSTRUCT, SPECIES_ZYGARDE_50_POWER_CONSTRUCT, SPECIES_ZYGARDE_COMPLETE, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_ZYGARDE_MEGA, +#endif FORM_SPECIES_END, }; #endif //P_FAMILY_ZYGARDE @@ -1724,6 +1941,16 @@ static const u16 sMimikyuFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MIMIKYU +#if P_FAMILY_DRAMPA +static const u16 sDrampaFormSpeciesIdTable[] = { + SPECIES_DRAMPA, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_DRAMPA_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_DRAMPA + #if P_FAMILY_JANGMO_O static const u16 sKommoOFormSpeciesIdTable[] = { SPECIES_KOMMO_O, @@ -1999,6 +2226,16 @@ static const u16 sAlcremieFormSpeciesIdTable[] = { }; #endif //P_FAMILY_MILCERY +#if P_FAMILY_FALINKS +static const u16 sFalinksFormSpeciesIdTable[] = { + SPECIES_FALINKS, +#if P_GEN_9_MEGA_EVOLUTIONS + SPECIES_FALINKS_MEGA, +#endif + FORM_SPECIES_END, +}; +#endif //P_FAMILY_FALINKS + #if P_FAMILY_EISCUE static const u16 sEiscueFormSpeciesIdTable[] = { SPECIES_EISCUE_ICE, diff --git a/src/data/pokemon/species_info/gen_1_families.h b/src/data/pokemon/species_info/gen_1_families.h index ce9cdce188..aab42559cb 100644 --- a/src/data/pokemon/species_info/gen_1_families.h +++ b/src/data/pokemon/species_info/gen_1_families.h @@ -2949,8 +2949,8 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .teachableLearnset = sPikachuTeachableLearnset, .formSpeciesIdTable = sPikachuFormSpeciesIdTable, .formChangeTable = sPikachuFormChangeTable, - .evolutions = EVOLUTION({EVO_ITEM, ITEM_THUNDER_STONE, SPECIES_RAICHU}, - {EVO_NONE, 0, SPECIES_RAICHU_ALOLA}), + .evolutions = EVOLUTION({EVO_ITEM, ITEM_THUNDER_STONE, SPECIES_RAICHU, CONDITIONS({IF_NOT_REGION, REGION_ALOLA})}, + {EVO_ITEM, ITEM_THUNDER_STONE, SPECIES_RAICHU_ALOLA, CONDITIONS({IF_REGION, REGION_ALOLA})}), }, #if P_COSPLAY_PIKACHU_FORMS @@ -5001,7 +5001,96 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = ) .levelUpLearnset = sClefableLevelUpLearnset, .teachableLearnset = sClefableTeachableLearnset, + .formSpeciesIdTable = sClefableFormSpeciesIdTable, + .formChangeTable = sClefableFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_CLEFABLE_MEGA] = + { + .baseHP = 95, + .baseAttack = 80, + .baseDefense = 93, + .baseSpeed = 70, + .baseSpAttack = 135, + .baseSpDefense = 110, + .types = MON_TYPES(TYPE_FAIRY, TYPE_FLYING), + .catchRate = 25, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 242, + #elif P_UPDATED_EXP_YIELDS >= GEN_7 + .expYield = 217, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 213, + #else + .expYield = 129, + #endif + .evYield_HP = 3, + .itemRare = ITEM_MOON_STONE, + .genderRatio = PERCENT_FEMALE(75), + .eggCycles = 10, + .friendship = 140, + .growthRate = GROWTH_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FAIRY), + #if P_UPDATED_ABILITIES >= GEN_4 + .abilities = { ABILITY_CUTE_CHARM, ABILITY_MAGIC_GUARD, ABILITY_UNAWARE }, + #else + .abilities = { ABILITY_CUTE_CHARM, ABILITY_NONE, ABILITY_UNAWARE }, + #endif + .bodyColor = BODY_COLOR_PINK, + .speciesName = _("Clefable"), + .cryId = CRY_CLEFABLE, // CRY_CLEFABLE_MEGA, + .natDexNum = NATIONAL_DEX_CLEFABLE, + .categoryName = _("Fairy"), + .height = 17, + .weight = 423, + .description = COMPOUND_STRING( + "It flies by using the power of\n" + "moonlight to control gravity within\n" + "a radius of over 32 feet around it."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sClefableLevelUpLearnset, + .teachableLearnset = sClefableTeachableLearnset, + .formSpeciesIdTable = sClefableFormSpeciesIdTable, + .formChangeTable = sClefableFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_CLEFAIRY #if P_FAMILY_VULPIX @@ -9121,7 +9210,92 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = ) .levelUpLearnset = sVictreebelLevelUpLearnset, .teachableLearnset = sVictreebelTeachableLearnset, + .formSpeciesIdTable = sVictreebelFormSpeciesIdTable, + .formChangeTable = sVictreebelFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_VICTREEBEL_MEGA] = + { + .baseHP = 80, + .baseAttack = 125, + .baseDefense = 85, + .baseSpeed = 70, + .baseSpAttack = 135, + .baseSpDefense = 95, + .types = MON_TYPES(TYPE_GRASS, TYPE_POISON), + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 245, + #elif P_UPDATED_EXP_YIELDS >= GEN_7 + .expYield = 221, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 216, + #else + .expYield = 191, + #endif + .evYield_Attack = 3, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_GRASS), + .abilities = { ABILITY_CHLOROPHYLL, ABILITY_NONE, ABILITY_GLUTTONY }, + .bodyColor = BODY_COLOR_GREEN, + .speciesName = _("Victreebel"), + .cryId = CRY_VICTREEBEL, // CRY_VICTREEBEL_MEGA, + .natDexNum = NATIONAL_DEX_VICTREEBEL, + .categoryName = _("Flycatcher"), + .height = 45, + .weight = 1255, + .description = COMPOUND_STRING( + "The volume of this Pokémon's acid\n" + "has increased due to Mega Evolution,\n" + "filling its mouth. If not careful,\n" + "the acid will overflow and spill out."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sVictreebelLevelUpLearnset, + .teachableLearnset = sVictreebelTeachableLearnset, + .formSpeciesIdTable = sVictreebelFormSpeciesIdTable, + .formChangeTable = sVictreebelFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_BELLSPROUT #if P_FAMILY_TENTACOOL @@ -13022,8 +13196,8 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .levelUpLearnset = sExeggcuteLevelUpLearnset, .teachableLearnset = sExeggcuteTeachableLearnset, .eggMoveLearnset = sExeggcuteEggMoveLearnset, - .evolutions = EVOLUTION({EVO_ITEM, ITEM_LEAF_STONE, SPECIES_EXEGGUTOR}, - {EVO_NONE, 0, SPECIES_EXEGGUTOR_ALOLA}), + .evolutions = EVOLUTION({EVO_ITEM, ITEM_LEAF_STONE, SPECIES_EXEGGUTOR, CONDITIONS({IF_NOT_REGION, REGION_ALOLA})}, + {EVO_ITEM, ITEM_LEAF_STONE, SPECIES_EXEGGUTOR_ALOLA, CONDITIONS({IF_REGION, REGION_ALOLA})}), }, #if P_UPDATED_EXP_YIELDS >= GEN_7 @@ -13249,8 +13423,8 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .levelUpLearnset = sCuboneLevelUpLearnset, .teachableLearnset = sCuboneTeachableLearnset, .eggMoveLearnset = sCuboneEggMoveLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 28, SPECIES_MAROWAK}, - {EVO_NONE, 0, SPECIES_MAROWAK_ALOLA}, + .evolutions = EVOLUTION({EVO_LEVEL, 28, SPECIES_MAROWAK, CONDITIONS({IF_NOT_REGION, REGION_ALOLA})}, + {EVO_LEVEL, 28, SPECIES_MAROWAK_ALOLA, CONDITIONS({IF_REGION, REGION_ALOLA}, {IF_TIME, TIME_NIGHT})}, {EVO_NONE, 0, SPECIES_MAROWAK_ALOLA_TOTEM}), }, @@ -13982,8 +14156,8 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .levelUpLearnset = sKoffingLevelUpLearnset, .teachableLearnset = sKoffingTeachableLearnset, .eggMoveLearnset = sKoffingEggMoveLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 35, SPECIES_WEEZING}, - {EVO_NONE, 0, SPECIES_WEEZING_GALAR}), + .evolutions = EVOLUTION({EVO_LEVEL, 35, SPECIES_WEEZING, CONDITIONS({IF_NOT_REGION, REGION_GALAR})}, + {EVO_LEVEL, 35, SPECIES_WEEZING_GALAR, CONDITIONS({IF_REGION, REGION_GALAR})}), }, [SPECIES_WEEZING] = @@ -15473,7 +15647,86 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = ) .levelUpLearnset = sStarmieLevelUpLearnset, .teachableLearnset = sStarmieTeachableLearnset, + .formSpeciesIdTable = sStarmieFormSpeciesIdTable, + .formChangeTable = sStarmieFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_STARMIE_MEGA] = + { + .baseHP = 60, + .baseAttack = 140, + .baseDefense = 105, + .baseSpeed = 120, + .baseSpAttack = 130, + .baseSpDefense = 105, + .types = MON_TYPES(TYPE_WATER, TYPE_PSYCHIC), + .catchRate = 60, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_5) ? 182 : 207, + .evYield_Speed = 2, + .itemCommon = ITEM_STARDUST, + .itemRare = ITEM_STAR_PIECE, + .genderRatio = MON_GENDERLESS, + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_3), + .abilities = { ABILITY_ILLUMINATE, ABILITY_NATURAL_CURE, ABILITY_ANALYTIC }, + .bodyColor = BODY_COLOR_PURPLE, + .speciesName = _("Starmie"), + .cryId = CRY_STARMIE, // CRY_STARMIE_MEGA, + .natDexNum = NATIONAL_DEX_STARMIE, + .categoryName = _("Mysterious"), + .height = 23, + .weight = 800, + .description = COMPOUND_STRING( + "Its movements have become more\n" + "humanlike. Whether it's simply\n" + "trying to communicate or wants to\n" + "supplant humanity is unclear."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sStarmieLevelUpLearnset, + .teachableLearnset = sStarmieTeachableLearnset, + .formSpeciesIdTable = sStarmieFormSpeciesIdTable, + .formChangeTable = sStarmieFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_STARYU #if P_FAMILY_MR_MIME @@ -15555,8 +15808,8 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .levelUpLearnset = sMimeJrLevelUpLearnset, .teachableLearnset = sMimeJrTeachableLearnset, .eggMoveLearnset = sMimeJrEggMoveLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 0, SPECIES_MR_MIME, CONDITIONS({IF_KNOWS_MOVE, MOVE_MIMIC})}, - {EVO_NONE, 0, SPECIES_MR_MIME_GALAR}), + .evolutions = EVOLUTION({EVO_LEVEL, 0, SPECIES_MR_MIME, CONDITIONS({IF_KNOWS_MOVE, MOVE_MIMIC}, {IF_NOT_REGION, REGION_GALAR})}, + {EVO_LEVEL, 0, SPECIES_MR_MIME_GALAR, CONDITIONS({IF_KNOWS_MOVE, MOVE_MIMIC}, {IF_REGION, REGION_GALAR})}), }, #endif //P_GEN_4_CROSS_EVOS @@ -19936,7 +20189,91 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = ) .levelUpLearnset = sDragoniteLevelUpLearnset, .teachableLearnset = sDragoniteTeachableLearnset, + .formSpeciesIdTable = sDragoniteFormSpeciesIdTable, + .formChangeTable = sDragoniteFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_DRAGONITE_MEGA] = + { + .baseHP = 91, + .baseAttack = 124, + .baseDefense = 115, + .baseSpeed = 100, + .baseSpAttack = 145, + .baseSpDefense = 125, + .types = MON_TYPES(TYPE_DRAGON, TYPE_FLYING), + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 300, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 270, + #else + .expYield = 218, + #endif + .evYield_Attack = 3, + .itemRare = ITEM_DRAGON_SCALE, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 40, + .friendship = 35, + .growthRate = GROWTH_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_1, EGG_GROUP_DRAGON), + .abilities = { ABILITY_INNER_FOCUS, ABILITY_NONE, ABILITY_MULTISCALE }, + .bodyColor = BODY_COLOR_BROWN, + .speciesName = _("Dragonite"), + .cryId = CRY_DRAGONITE, // CRY_DRAGONITE_MEGA, + .natDexNum = NATIONAL_DEX_DRAGONITE, + .categoryName = _("Dragon"), + .height = 22, + .weight = 2900, + .description = COMPOUND_STRING( + "Mega Evolution has excessively\n" + "powered up this Pokémon's feelings\n" + "of kindness. It finishes off its\n" + "opponents with mercy in its heart."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sDragoniteLevelUpLearnset, + .teachableLearnset = sDragoniteTeachableLearnset, + .formSpeciesIdTable = sDragoniteFormSpeciesIdTable, + .formChangeTable = sDragoniteFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_DRATINI #if P_FAMILY_MEWTWO diff --git a/src/data/pokemon/species_info/gen_2_families.h b/src/data/pokemon/species_info/gen_2_families.h index 702b907451..3849ab760d 100644 --- a/src/data/pokemon/species_info/gen_2_families.h +++ b/src/data/pokemon/species_info/gen_2_families.h @@ -225,7 +225,91 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = ) .levelUpLearnset = sMeganiumLevelUpLearnset, .teachableLearnset = sMeganiumTeachableLearnset, + .formSpeciesIdTable = sMeganiumFormSpeciesIdTable, + .formChangeTable = sMeganiumFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_MEGANIUM_MEGA] = + { + .baseHP = 80, + .baseAttack = 92, + .baseDefense = 115, + .baseSpeed = 80, + .baseSpAttack = 143, + .baseSpDefense = 115, + .types = MON_TYPES(TYPE_GRASS, TYPE_FAIRY), + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 263, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 236, + #else + .expYield = 208, + #endif + .evYield_Defense = 1, + .evYield_SpDefense = 2, + .genderRatio = PERCENT_FEMALE(12.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MONSTER, EGG_GROUP_GRASS), + .abilities = { ABILITY_OVERGROW, ABILITY_NONE, ABILITY_LEAF_GUARD }, + .bodyColor = BODY_COLOR_GREEN, + .speciesName = _("Meganium"), + .cryId = CRY_MEGANIUM, // CRY_MEGANIUM_MEGA, + .natDexNum = NATIONAL_DEX_MEGANIUM, + .categoryName = _("Herb"), + .height = 24, + .weight = 2010, + .description = COMPOUND_STRING( + "This Pokémon can fire a tremendously\n" + "powerful Solar Beam from its four\n" + "flowers. Another name for this is\n" + "Mega Sol Cannon."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sMeganiumLevelUpLearnset, + .teachableLearnset = sMeganiumTeachableLearnset, + .formSpeciesIdTable = sMeganiumFormSpeciesIdTable, + .formChangeTable = sMeganiumFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_CHIKORITA #if P_FAMILY_CYNDAQUIL @@ -364,8 +448,8 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = ) .levelUpLearnset = sQuilavaLevelUpLearnset, .teachableLearnset = sQuilavaTeachableLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 36, SPECIES_TYPHLOSION}, - {EVO_NONE, 0, SPECIES_TYPHLOSION_HISUI}), + .evolutions = EVOLUTION({EVO_LEVEL, 36, SPECIES_TYPHLOSION, CONDITIONS({IF_NOT_REGION, REGION_HISUI})}, + {EVO_LEVEL, 36, SPECIES_TYPHLOSION_HISUI, CONDITIONS({IF_REGION, REGION_HISUI})}), }, #if P_UPDATED_EXP_YIELDS >= GEN_8 @@ -728,7 +812,91 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = ) .levelUpLearnset = sFeraligatrLevelUpLearnset, .teachableLearnset = sFeraligatrTeachableLearnset, + .formSpeciesIdTable = sFeraligatrFormSpeciesIdTable, + .formChangeTable = sFeraligatrFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_FERALIGATR_MEGA] = + { + .baseHP = 85, + .baseAttack = 160, + .baseDefense = 125, + .baseSpeed = 78, + .baseSpAttack = 89, + .baseSpDefense = 93, + .types = MON_TYPES(TYPE_WATER, TYPE_DRAGON), + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 265, + #elif P_UPDATED_EXP_YIELDS >= GEN_5 + .expYield = 239, + #else + .expYield = 210, + #endif + .evYield_Attack = 2, + .evYield_Defense = 1, + .genderRatio = PERCENT_FEMALE(12.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MONSTER, EGG_GROUP_WATER_1), + .abilities = { ABILITY_TORRENT, ABILITY_NONE, ABILITY_SHEER_FORCE }, + .bodyColor = BODY_COLOR_BLUE, + .speciesName = _("Feraligatr"), + .cryId = CRY_FERALIGATR, // CRY_FERALIGATR_MEGA, + .natDexNum = NATIONAL_DEX_FERALIGATR, + .categoryName = _("Double Jaw"), + .height = 23, + .weight = 1088, + .description = COMPOUND_STRING( + "With its arms and hoodlike fin, this\n" + "Pokémon forms a gigantic set of jaws\n" + "with a bite 10 times as powerful\n" + "as Mega Feraligatr's actual jaws."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sFeraligatrLevelUpLearnset, + .teachableLearnset = sFeraligatrTeachableLearnset, + .formSpeciesIdTable = sFeraligatrFormSpeciesIdTable, + .formChangeTable = sFeraligatrFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_TOTODILE #if P_FAMILY_SENTRET @@ -5916,7 +6084,7 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = .levelUpLearnset = sUrsaringLevelUpLearnset, .teachableLearnset = sUrsaringTeachableLearnset, #if P_GEN_8_CROSS_EVOS - .evolutions = EVOLUTION({EVO_ITEM, ITEM_PEAT_BLOCK, SPECIES_URSALUNA, CONDITIONS({IF_TIME, TIME_NIGHT})}, + .evolutions = EVOLUTION({EVO_ITEM, ITEM_PEAT_BLOCK, SPECIES_URSALUNA, CONDITIONS({IF_REGION, REGION_HISUI}, {IF_TIME, TIME_NIGHT})}, {EVO_NONE, 0, SPECIES_URSALUNA_BLOODMOON}), #endif }, @@ -7107,7 +7275,85 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = .levelUpLearnset = sSkarmoryLevelUpLearnset, .teachableLearnset = sSkarmoryTeachableLearnset, .eggMoveLearnset = sSkarmoryEggMoveLearnset, + .formSpeciesIdTable = sSkarmoryFormSpeciesIdTable, + .formChangeTable = sSkarmoryFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_SKARMORY_MEGA] = + { + .baseHP = 65, + .baseAttack = 140, + .baseDefense = 110, + .baseSpeed = 110, + .baseSpAttack = 40, + .baseSpDefense = 100, + .types = MON_TYPES(TYPE_STEEL, TYPE_FLYING), + .catchRate = 25, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_5) ? 163 : 168, + .evYield_Defense = 2, + .itemRare = ITEM_METAL_COAT, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 25, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), + .abilities = { ABILITY_KEEN_EYE, ABILITY_STURDY, ABILITY_WEAK_ARMOR }, + .bodyColor = BODY_COLOR_GRAY, + .speciesName = _("Skarmory"), + .cryId = CRY_SKARMORY, // CRY_SKARMORY_MEGA, + .natDexNum = NATIONAL_DEX_SKARMORY, + .categoryName = _("Armor Bird"), + .height = 17, + .weight = 404, + .description = COMPOUND_STRING( + "Due to the effects of Mega Evolution,\n" + "its pincers have taken a more\n" + "diabolical form, ripping anything\n" + "they pierce to shreds."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sSkarmoryLevelUpLearnset, + .teachableLearnset = sSkarmoryTeachableLearnset, + .formSpeciesIdTable = sSkarmoryFormSpeciesIdTable, + .formChangeTable = sSkarmoryFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_SKARMORY #if P_FAMILY_HOUNDOUR diff --git a/src/data/pokemon/species_info/gen_3_families.h b/src/data/pokemon/species_info/gen_3_families.h index 566f79b404..fb29550820 100644 --- a/src/data/pokemon/species_info/gen_3_families.h +++ b/src/data/pokemon/species_info/gen_3_families.h @@ -10688,7 +10688,84 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = ) .levelUpLearnset = sFroslassLevelUpLearnset, .teachableLearnset = sFroslassTeachableLearnset, + .formSpeciesIdTable = sFroslassFormSpeciesIdTable, + .formChangeTable = sFroslassFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_FROSLASS_MEGA] = + { + .baseHP = 70, + .baseAttack = 80, + .baseDefense = 70, + .baseSpeed = 120, + .baseSpAttack = 140, + .baseSpDefense = 100, + .types = MON_TYPES(TYPE_ICE, TYPE_GHOST), + .catchRate = 75, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_5) ? 168 : 187, + .evYield_Speed = 2, + .genderRatio = MON_FEMALE, + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FAIRY, EGG_GROUP_MINERAL), + .abilities = { ABILITY_SNOW_CLOAK, ABILITY_NONE, ABILITY_CURSED_BODY }, + .bodyColor = BODY_COLOR_WHITE, + .speciesName = _("Froslass"), + .cryId = CRY_FROSLASS, // CRY_FROSLASS_MEGA, + .natDexNum = NATIONAL_DEX_FROSLASS, + .categoryName = _("Snow Land"), + .height = 26, + .weight = 296, + .description = COMPOUND_STRING( + "This Pokémon can use eerie cold\n" + "air imbued with ghost energy to\n" + "freeze even insubstantial things,\n" + "such as flames or the wind."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sFroslassLevelUpLearnset, + .teachableLearnset = sFroslassTeachableLearnset, + .formSpeciesIdTable = sFroslassFormSpeciesIdTable, + .formChangeTable = sFroslassFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_GEN_4_CROSS_EVOS #endif //P_FAMILY_SNORUNT diff --git a/src/data/pokemon/species_info/gen_5_families.h b/src/data/pokemon/species_info/gen_5_families.h index 6b46006a58..0acaeb8ec7 100644 --- a/src/data/pokemon/species_info/gen_5_families.h +++ b/src/data/pokemon/species_info/gen_5_families.h @@ -512,7 +512,85 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sEmboarLevelUpLearnset, .teachableLearnset = sEmboarTeachableLearnset, + .formSpeciesIdTable = sEmboarFormSpeciesIdTable, + .formChangeTable = sEmboarFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_EMBOAR_MEGA] = + { + .baseHP = 110, + .baseAttack = 148, + .baseDefense = 75, + .baseSpeed = 75, + .baseSpAttack = 110, + .baseSpDefense = 110, + .types = MON_TYPES(TYPE_FIRE, TYPE_FIGHTING), + .catchRate = 45, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_8) ? 264 : 238, + .evYield_Attack = 3, + .genderRatio = PERCENT_FEMALE(12.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD), + .abilities = { ABILITY_BLAZE, ABILITY_NONE, ABILITY_RECKLESS }, + .bodyColor = BODY_COLOR_RED, + .noFlip = TRUE, + .speciesName = _("Emboar"), + .cryId = CRY_EMBOAR, // CRY_EMBOAR_MEGA, + .natDexNum = NATIONAL_DEX_EMBOAR, + .categoryName = _("Fire Pig"), + .height = 18, + .weight = 1803, + .description = COMPOUND_STRING( + "Brandishing a blazing flame\n" + "shaped like a serpentine spear,\n" + "it rushes in to save its\n" + "imperiled allies."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sEmboarLevelUpLearnset, + .teachableLearnset = sEmboarTeachableLearnset, + .formSpeciesIdTable = sEmboarFormSpeciesIdTable, + .formChangeTable = sEmboarFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_TEPIG #if P_FAMILY_OSHAWOTT @@ -656,8 +734,8 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sDewottLevelUpLearnset, .teachableLearnset = sDewottTeachableLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 36, SPECIES_SAMUROTT}, - {EVO_NONE, 0, SPECIES_SAMUROTT_HISUI}), + .evolutions = EVOLUTION({EVO_LEVEL, 36, SPECIES_SAMUROTT, CONDITIONS({IF_NOT_REGION, REGION_HISUI})}, + {EVO_LEVEL, 36, SPECIES_SAMUROTT_HISUI, CONDITIONS({IF_REGION, REGION_HISUI})}), }, [SPECIES_SAMUROTT] = @@ -2766,7 +2844,85 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sExcadrillLevelUpLearnset, .teachableLearnset = sExcadrillTeachableLearnset, + .formSpeciesIdTable = sExcadrillFormSpeciesIdTable, + .formChangeTable = sExcadrillFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_EXCADRILL_MEGA] = + { + .baseHP = 110, + .baseAttack = 165, + .baseDefense = 100, + .baseSpeed = 103, + .baseSpAttack = 65, + .baseSpDefense = 65, + .types = MON_TYPES(TYPE_GROUND, TYPE_STEEL), + .catchRate = 60, + .expYield = 178, + .evYield_Attack = 2, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD), + .abilities = { ABILITY_SAND_RUSH, ABILITY_SAND_FORCE, ABILITY_MOLD_BREAKER }, + .bodyColor = BODY_COLOR_GRAY, + .noFlip = TRUE, + .speciesName = _("Excadrill"), + .cryId = CRY_EXCADRILL, // CRY_EXCADRILL_MEGA, + .natDexNum = NATIONAL_DEX_EXCADRILL, + .categoryName = _("Subterrene"), + .height = 9, + .weight = 600, + .description = COMPOUND_STRING( + "If this Pokémon brings its arms and\n" + "head together to form a streamlined\n" + "shape and spins at high speeds,\n" + "it can destroy anything."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sExcadrillLevelUpLearnset, + .teachableLearnset = sExcadrillTeachableLearnset, + .formSpeciesIdTable = sExcadrillFormSpeciesIdTable, + .formChangeTable = sExcadrillFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_DRILBUR #if P_FAMILY_AUDINO @@ -3932,7 +4088,90 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sScolipedeLevelUpLearnset, .teachableLearnset = sScolipedeTeachableLearnset, + .formSpeciesIdTable = sScolipedeFormSpeciesIdTable, + .formChangeTable = sScolipedeFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_SCOLIPEDE_MEGA] = + { + .baseHP = 60, + .baseAttack = 140, + .baseDefense = 149, + .baseSpeed = 62, + .baseSpAttack = 75, + .baseSpDefense = 99, + .types = MON_TYPES(TYPE_BUG, TYPE_POISON), + .catchRate = 45, + #if P_UPDATED_EXP_YIELDS >= GEN_8 + .expYield = 243, + #elif P_UPDATED_EXP_YIELDS >= GEN_7 + .expYield = 218, + #else + .expYield = 214, + #endif + .evYield_Speed = 3, + .itemRare = ITEM_POISON_BARB, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_BUG), + .abilities = { ABILITY_POISON_POINT, ABILITY_SWARM, ABILITY_SPEED_BOOST }, + .bodyColor = BODY_COLOR_RED, + .speciesName = _("Scolipede"), + .cryId = CRY_SCOLIPEDE, // CRY_SCOLIPEDE_MEGA, + .natDexNum = NATIONAL_DEX_SCOLIPEDE, + .categoryName = _("Megapede"), + .height = 32, + .weight = 2305, + .description = COMPOUND_STRING( + "Its deadly venom gives off a faint\n" + "glow. The venom affects Scolipede's\n" + "mind, honing its viciousness."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sScolipedeLevelUpLearnset, + .teachableLearnset = sScolipedeTeachableLearnset, + .formSpeciesIdTable = sScolipedeFormSpeciesIdTable, + .formChangeTable = sScolipedeFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_VENIPEDE #if P_FAMILY_COTTONEE @@ -4158,8 +4397,8 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = .levelUpLearnset = sPetililLevelUpLearnset, .teachableLearnset = sPetililTeachableLearnset, .eggMoveLearnset = sPetililEggMoveLearnset, - .evolutions = EVOLUTION({EVO_ITEM, ITEM_SUN_STONE, SPECIES_LILLIGANT}, - {EVO_NONE, 0, SPECIES_LILLIGANT_HISUI}), + .evolutions = EVOLUTION({EVO_ITEM, ITEM_SUN_STONE, SPECIES_LILLIGANT, CONDITIONS({IF_NOT_REGION, REGION_HISUI})}, + {EVO_ITEM, ITEM_SUN_STONE, SPECIES_LILLIGANT_HISUI, CONDITIONS({IF_REGION, REGION_HISUI})}), }, [SPECIES_LILLIGANT] = @@ -5609,7 +5848,86 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sScraftyLevelUpLearnset, .teachableLearnset = sScraftyTeachableLearnset, + .formSpeciesIdTable = sScraftyFormSpeciesIdTable, + .formChangeTable = sScraftyFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_SCRAFTY_MEGA] = + { + .baseHP = 65, + .baseAttack = 130, + .baseDefense = 135, + .baseSpeed = 68, + .baseSpAttack = 55, + .baseSpDefense = 135, + .types = MON_TYPES(TYPE_DARK, TYPE_FIGHTING), + .catchRate = 90, + .expYield = 171, + .evYield_Defense = 1, + .evYield_SpDefense = 1, + .itemRare = ITEM_SHED_SHELL, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 15, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD, EGG_GROUP_DRAGON), + .abilities = { ABILITY_SHED_SKIN, ABILITY_MOXIE, ABILITY_INTIMIDATE }, + .bodyColor = BODY_COLOR_RED, + .speciesName = _("Scrafty"), + .cryId = CRY_SCRAFTY, + .natDexNum = NATIONAL_DEX_SCRAFTY, + .categoryName = _("Hoodlum"), + .height = 11, + .weight = 310, + .description = COMPOUND_STRING( + "Mega Evolution has caused Scrafty's\n" + "shed skin to turn white, growing\n" + "tough and supple. Of course, this\n" + "Pokémon is still as feisty as ever."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sScraftyLevelUpLearnset, + .teachableLearnset = sScraftyTeachableLearnset, + .formSpeciesIdTable = sScraftyFormSpeciesIdTable, + .formChangeTable = sScraftyFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_SCRAGGY #if P_FAMILY_SIGILYPH @@ -9540,7 +9858,84 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sEelektrossLevelUpLearnset, .teachableLearnset = sEelektrossTeachableLearnset, + .formSpeciesIdTable = sEelektrossFormSpeciesIdTable, + .formChangeTable = sEelektrossFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_EELEKTROSS_MEGA] = + { + .baseHP = 85, + .baseAttack = 145, + .baseDefense = 80, + .baseSpeed = 80, + .baseSpAttack = 135, + .baseSpDefense = 90, + .types = MON_TYPES(TYPE_ELECTRIC), + .catchRate = 30, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_8) ? 258 : 232, + .evYield_Attack = 3, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_AMORPHOUS), + .abilities = { ABILITY_LEVITATE, ABILITY_NONE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_BLUE, + .speciesName = _("Eelektross"), + .cryId = CRY_EELEKTROSS, // CRY_EELEKTROSS_MEGA, + .natDexNum = NATIONAL_DEX_EELEKTROSS, + .categoryName = _("EleFish"), + .height = 30, + .weight = 1800, + .description = COMPOUND_STRING( + "It now generates 10 times the\n" + "electricity it did before Mega\n" + "Evolving. It discharges this energy\n" + "from its false Eelektrik made of mucus."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sEelektrossLevelUpLearnset, + .teachableLearnset = sEelektrossTeachableLearnset, + .formSpeciesIdTable = sEelektrossFormSpeciesIdTable, + .formChangeTable = sEelektrossFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_TYNAMO #if P_FAMILY_ELGYEM @@ -9905,7 +10300,84 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sChandelureLevelUpLearnset, .teachableLearnset = sChandelureTeachableLearnset, + .formSpeciesIdTable = sChandelureFormSpeciesIdTable, + .formChangeTable = sChandelureFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_CHANDELURE_MEGA] = + { + .baseHP = 60, + .baseAttack = 75, + .baseDefense = 110, + .baseSpeed = 90, + .baseSpAttack = 175, + .baseSpDefense = 110, + .types = MON_TYPES(TYPE_GHOST, TYPE_FIRE), + .catchRate = 45, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_8) ? 260 : 234, + .evYield_SpAttack = 3, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_AMORPHOUS), + .abilities = { ABILITY_FLASH_FIRE, ABILITY_FLAME_BODY, ABILITY_INFILTRATOR }, + .bodyColor = BODY_COLOR_BLACK, + .speciesName = _("Chandelure"), + .cryId = CRY_CHANDELURE, // CRY_CHANDELURE_MEGA, + .natDexNum = NATIONAL_DEX_CHANDELURE, + .categoryName = _("Luring"), + .height = 25, + .weight = 696, + .description = COMPOUND_STRING( + "One of its eyes is a window linking\n" + "our world with the afterlife.\n" + "This Pokémon draws in hatred and\n" + "converts it into power."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sChandelureLevelUpLearnset, + .teachableLearnset = sChandelureTeachableLearnset, + .formSpeciesIdTable = sChandelureFormSpeciesIdTable, + .formChangeTable = sChandelureFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_LITWICK #if P_FAMILY_AXEW @@ -11316,8 +11788,8 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sRuffletLevelUpLearnset, .teachableLearnset = sRuffletTeachableLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 54, SPECIES_BRAVIARY}, - {EVO_NONE, 0, SPECIES_BRAVIARY_HISUI}), + .evolutions = EVOLUTION({EVO_LEVEL, 54, SPECIES_BRAVIARY, CONDITIONS({IF_NOT_REGION, REGION_HISUI})}, + {EVO_LEVEL, 54, SPECIES_BRAVIARY_HISUI, CONDITIONS({IF_REGION, REGION_HISUI})}), }, [SPECIES_BRAVIARY] = diff --git a/src/data/pokemon/species_info/gen_6_families.h b/src/data/pokemon/species_info/gen_6_families.h index 411ef400f6..4290c47ca6 100644 --- a/src/data/pokemon/species_info/gen_6_families.h +++ b/src/data/pokemon/species_info/gen_6_families.h @@ -210,7 +210,83 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = ) .levelUpLearnset = sChesnaughtLevelUpLearnset, .teachableLearnset = sChesnaughtTeachableLearnset, + .formSpeciesIdTable = sChesnaughtFormSpeciesIdTable, + .formChangeTable = sChesnaughtFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_CHESNAUGHT_MEGA] = + { + .baseHP = 88, + .baseAttack = 137, + .baseDefense = 172, + .baseSpeed = 44, + .baseSpAttack = 74, + .baseSpDefense = 115, + .types = MON_TYPES(TYPE_GRASS, TYPE_FIGHTING), + .catchRate = 45, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_8) ? 265 : 239, + .evYield_Defense = 3, + .genderRatio = PERCENT_FEMALE(12.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD), + .abilities = { ABILITY_OVERGROW, ABILITY_NONE, ABILITY_BULLETPROOF }, + .bodyColor = BODY_COLOR_GREEN, + .speciesName = _("Chesnaught"), + .cryId = CRY_CHESNAUGHT, + .natDexNum = NATIONAL_DEX_CHESNAUGHT, + .categoryName = _("Spiny Armor"), + .height = 16, + .weight = 900, + .description = COMPOUND_STRING( + "It has fortified armor and a\n" + "will to defend at all costs.\n" + "Both are absurdly strong."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sChesnaughtLevelUpLearnset, + .teachableLearnset = sChesnaughtTeachableLearnset, + .formSpeciesIdTable = sChesnaughtFormSpeciesIdTable, + .formChangeTable = sChesnaughtFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_CHESPIN #if P_FAMILY_FENNEKIN @@ -424,7 +500,84 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = ) .levelUpLearnset = sDelphoxLevelUpLearnset, .teachableLearnset = sDelphoxTeachableLearnset, + .formSpeciesIdTable = sDelphoxFormSpeciesIdTable, + .formChangeTable = sDelphoxFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_DELPHOX_MEGA] = + { + .baseHP = 75, + .baseAttack = 69, + .baseDefense = 72, + .baseSpeed = 134, + .baseSpAttack = 159, + .baseSpDefense = 125, + .types = MON_TYPES(TYPE_FIRE, TYPE_PSYCHIC), + .catchRate = 45, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_8) ? 267 : 240, + .evYield_SpAttack = 3, + .genderRatio = PERCENT_FEMALE(12.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD), + .abilities = { ABILITY_BLAZE, ABILITY_NONE, ABILITY_MAGICIAN }, + .bodyColor = BODY_COLOR_RED, + .speciesName = _("Delphox"), + .cryId = CRY_DELPHOX, // CRY_DELPHOX_MEGA, + .natDexNum = NATIONAL_DEX_DELPHOX, + .categoryName = _("Fox"), + .height = 15, + .weight = 390, + .description = COMPOUND_STRING( + "It wields flaming branches to\n" + "dazzle its opponents before\n" + "incinerating them with a\n" + "huge fireball."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sDelphoxLevelUpLearnset, + .teachableLearnset = sDelphoxTeachableLearnset, + .formSpeciesIdTable = sDelphoxFormSpeciesIdTable, + .formChangeTable = sDelphoxFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_FENNEKIN #if P_FAMILY_FROAKIE @@ -627,6 +780,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .levelUpLearnset = sGreninjaLevelUpLearnset, .teachableLearnset = sGreninjaTeachableLearnset, .formSpeciesIdTable = sGreninjaFormSpeciesIdTable, + .formChangeTable = sGreninjaFormChangeTable, }, [SPECIES_GRENINJA_BATTLE_BOND] = @@ -760,6 +914,82 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .formSpeciesIdTable = sGreninjaFormSpeciesIdTable, .formChangeTable = sGreninjaBattleBondFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_GRENINJA_MEGA] = + { + .baseHP = 72, + .baseAttack = 125, + .baseDefense = 77, + .baseSpeed = 142, + .baseSpAttack = 133, + .baseSpDefense = 81, + .types = MON_TYPES(TYPE_WATER, TYPE_DARK), + .catchRate = 45, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_8) ? 265 : 239, + .evYield_Speed = 3, + .genderRatio = PERCENT_FEMALE(12.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_1), + .abilities = { ABILITY_TORRENT, ABILITY_NONE, ABILITY_PROTEAN }, + .bodyColor = BODY_COLOR_BLUE, + .noFlip = TRUE, + .speciesName = _("Greninja"), + .cryId = CRY_GRENINJA, // CRY_GRENINJA_MEGA, + .natDexNum = NATIONAL_DEX_GRENINJA, + .categoryName = _("Ninja"), + .height = 15, + .weight = 400, + .description = COMPOUND_STRING( + "This Pokémon spins a giant\n" + "shuriken at high speed to make it\n" + "float, then clings to it upside\n" + "down to catch opponents unawares."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sGreninjaLevelUpLearnset, + .teachableLearnset = sGreninjaTeachableLearnset, + .formSpeciesIdTable = sGreninjaFormSpeciesIdTable, + .formChangeTable = sGreninjaFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_FROAKIE #if P_FAMILY_BUNNELBY @@ -1672,7 +1902,84 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = ) .levelUpLearnset = sPyroarLevelUpLearnset, .teachableLearnset = sPyroarTeachableLearnset, + .formSpeciesIdTable = sPyroarFormSpeciesIdTable, + .formChangeTable = sPyroarFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_PYROAR_MEGA] = + { + .baseHP = 86, + .baseAttack = 88, + .baseDefense = 92, + .baseSpeed = 126, + .baseSpAttack = 129, + .baseSpDefense = 86, + .types = MON_TYPES(TYPE_FIRE, TYPE_NORMAL), + .catchRate = 65, + .expYield = 177, + .evYield_SpAttack = 2, + .genderRatio = PERCENT_FEMALE(87.5), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD), + .abilities = { ABILITY_RIVALRY, ABILITY_UNNERVE, ABILITY_MOXIE }, + .bodyColor = BODY_COLOR_BROWN, + .speciesName = _("Pyroar"), + .cryId = CRY_PYROAR, // CRY_PYROAR_MEGA, + .natDexNum = NATIONAL_DEX_PYROAR, + .categoryName = _("Royal"), + .height = 15, + .weight = 933, + .description = COMPOUND_STRING( + "This Pokémon spews flames hotter\n" + "than 18,000 degrees Fahrenheit.\n" + "It swings around its grand, blazing\n" + "mane as it protects its allies."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sPyroarLevelUpLearnset, + .teachableLearnset = sPyroarTeachableLearnset, + .formSpeciesIdTable = sPyroarFormSpeciesIdTable, + .formChangeTable = sPyroarFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_LITLEO #if P_FAMILY_FLABEBE @@ -2018,6 +2325,81 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = "decorated with flowering plants of\n" "many different colors."), }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_FLOETTE_MEGA] = + { + .baseHP = 74, + .baseAttack = 85, + .baseDefense = 87, + .baseSpeed = 102, + .baseSpAttack = 155, + .baseSpDefense = 148, + .types = MON_TYPES(TYPE_FAIRY), + .catchRate = 120, + .expYield = 1, + .evYield_SpDefense = 2, + .genderRatio = MON_FEMALE, + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), + .abilities = { ABILITY_FLOWER_VEIL, ABILITY_NONE, ABILITY_SYMBIOSIS }, + .bodyColor = BODY_COLOR_WHITE, + .speciesName = _("Floette"), + .cryId = CRY_FLOETTE_ETERNAL, // CRY_FLOETTE_MEGA, + .natDexNum = NATIONAL_DEX_FLOETTE, + .categoryName = _("Single Bloom"), + // height + // weight + .description = COMPOUND_STRING( + "The Eternal Flower has absorbed\n" + "all the energy from Mega\n" + "Evolution. The flower now attacks\n" + "enemies on its own."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sFloetteEternalLevelUpLearnset, + .teachableLearnset = sFloetteEternalTeachableLearnset, + .formSpeciesIdTable = sFloetteFormSpeciesIdTable, + .formChangeTable = sFloetteEternalFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_FLABEBE #if P_FAMILY_SKIDDO @@ -3295,7 +3677,84 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = ) .levelUpLearnset = sMalamarLevelUpLearnset, .teachableLearnset = sMalamarTeachableLearnset, + .formSpeciesIdTable = sMalamarFormSpeciesIdTable, + .formChangeTable = sMalamarFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_MALAMAR_MEGA] = + { + .baseHP = 86, + .baseAttack = 102, + .baseDefense = 88, + .baseSpeed = 88, + .baseSpAttack = 98, + .baseSpDefense = 120, + .types = MON_TYPES(TYPE_DARK, TYPE_PSYCHIC), + .catchRate = 80, + .expYield = 169, + .evYield_Attack = 2, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_1, EGG_GROUP_WATER_2), + .abilities = { ABILITY_CONTRARY, ABILITY_SUCTION_CUPS, ABILITY_INFILTRATOR }, + .bodyColor = BODY_COLOR_BLUE, + .speciesName = _("Malamar"), + .cryId = CRY_MALAMAR, // CRY_MALAMAR_MEGA, + .natDexNum = NATIONAL_DEX_MALAMAR, + .categoryName = _("Overturning"), + .height = 29, + .weight = 698, + .description = COMPOUND_STRING( + "It uses its colorful lights to\n" + "overwrite the personality and\n" + "memories of others-and to\n" + "control them."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sMalamarLevelUpLearnset, + .teachableLearnset = sMalamarTeachableLearnset, + .formSpeciesIdTable = sMalamarFormSpeciesIdTable, + .formChangeTable = sMalamarFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_INKAY #if P_FAMILY_BINACLE @@ -3436,7 +3895,84 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = ) .levelUpLearnset = sBarbaracleLevelUpLearnset, .teachableLearnset = sBarbaracleTeachableLearnset, + .formSpeciesIdTable = sBarbaracleFormSpeciesIdTable, + .formChangeTable = sBarbaracleFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_BARBARACLE_MEGA] = + { + .baseHP = 72, + .baseAttack = 140, + .baseDefense = 130, + .baseSpeed = 88, + .baseSpAttack = 64, + .baseSpDefense = 106, + .types = MON_TYPES(TYPE_ROCK, TYPE_FIGHTING), + .catchRate = 45, + .expYield = 175, + .evYield_Attack = 2, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_3), + .abilities = { ABILITY_TOUGH_CLAWS, ABILITY_SNIPER, ABILITY_PICKPOCKET }, + .bodyColor = BODY_COLOR_BROWN, + .noFlip = TRUE, + .speciesName = _("Barbaracle"), + .cryId = CRY_BARBARACLE, // CRY_BARBARACLE_MEGA, + .natDexNum = NATIONAL_DEX_BARBARACLE, + .categoryName = _("Collective"), + .height = 22, + .weight = 1000, + .description = COMPOUND_STRING( + "It uses its many arms to toy\n" + "with its opponents. This\n" + "keeps the head extremely busy."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sBarbaracleLevelUpLearnset, + .teachableLearnset = sBarbaracleTeachableLearnset, + .formSpeciesIdTable = sBarbaracleFormSpeciesIdTable, + .formChangeTable = sBarbaracleFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_BINACLE #if P_FAMILY_SKRELP @@ -3580,7 +4116,84 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = ) .levelUpLearnset = sDragalgeLevelUpLearnset, .teachableLearnset = sDragalgeTeachableLearnset, + .formSpeciesIdTable = sDragalgeFormSpeciesIdTable, + .formChangeTable = sDragalgeFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_DRAGALGE_MEGA] = + { + .baseHP = 65, + .baseAttack = 85, + .baseDefense = 105, + .baseSpeed = 44, + .baseSpAttack = 132, + .baseSpDefense = 163, + .types = MON_TYPES(TYPE_POISON, TYPE_DRAGON), + .catchRate = 55, + .expYield = 173, + .evYield_SpDefense = 2, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_1, EGG_GROUP_DRAGON), + .abilities = { ABILITY_POISON_POINT, ABILITY_POISON_TOUCH, ABILITY_ADAPTABILITY }, + .bodyColor = BODY_COLOR_BROWN, + .speciesName = _("Dragalge"), + .cryId = CRY_DRAGALGE, // CRY_DRAGALGE_MEGA, + .natDexNum = NATIONAL_DEX_DRAGALGE, + .categoryName = _("Mock Kelp"), + .height = 21, + .weight = 1003, + .description = COMPOUND_STRING( + "It spits a liquid that causes the\n" + "regenerative power of cells to run\n" + "wild. The liquid is deadly poison\n" + "to everything other than itself."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sDragalgeLevelUpLearnset, + .teachableLearnset = sDragalgeTeachableLearnset, + .formSpeciesIdTable = sDragalgeFormSpeciesIdTable, + .formChangeTable = sDragalgeFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_SKRELP #if P_FAMILY_CLAUNCHER @@ -4223,7 +4836,84 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .levelUpLearnset = sHawluchaLevelUpLearnset, .teachableLearnset = sHawluchaTeachableLearnset, .eggMoveLearnset = sHawluchaEggMoveLearnset, + .formSpeciesIdTable = sHawluchaFormSpeciesIdTable, + .formChangeTable = sHawluchaFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_HAWLUCHA_MEGA] = + { + .baseHP = 78, + .baseAttack = 137, + .baseDefense = 100, + .baseSpeed = 118, + .baseSpAttack = 74, + .baseSpDefense = 93, + .types = MON_TYPES(TYPE_FIGHTING, TYPE_FLYING), + .catchRate = 100, + .expYield = 175, + .evYield_Attack = 2, + .itemRare = ITEM_KINGS_ROCK, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING, EGG_GROUP_HUMAN_LIKE), + .abilities = { ABILITY_LIMBER, ABILITY_UNBURDEN, ABILITY_MOLD_BREAKER }, + .bodyColor = BODY_COLOR_GREEN, + .speciesName = _("Hawlucha"), + .cryId = CRY_HAWLUCHA, // CRY_HAWLUCHA_MEGA, + .natDexNum = NATIONAL_DEX_HAWLUCHA, + .categoryName = _("Wrestling"), + .height = 10, + .weight = 250, + .description = COMPOUND_STRING( + "Mega Evolution has pumped up all\n" + "its muscles. Hawlucha flexes to\n" + "show off its strength."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sHawluchaLevelUpLearnset, + .teachableLearnset = sHawluchaTeachableLearnset, + .formSpeciesIdTable = sHawluchaFormSpeciesIdTable, + .formChangeTable = sHawluchaFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_HAWLUCHA #if P_FAMILY_DEDENNE @@ -4441,8 +5131,8 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .levelUpLearnset = sGoomyLevelUpLearnset, .teachableLearnset = sGoomyTeachableLearnset, .eggMoveLearnset = sGoomyEggMoveLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 40, SPECIES_SLIGGOO}, - {EVO_NONE, 0, SPECIES_SLIGGOO_HISUI}), + .evolutions = EVOLUTION({EVO_LEVEL, 40, SPECIES_SLIGGOO, CONDITIONS({IF_NOT_REGION, REGION_HISUI})}, + {EVO_LEVEL, 40, SPECIES_SLIGGOO_HISUI, CONDITIONS({IF_REGION, REGION_HISUI})}), }, [SPECIES_SLIGGOO] = @@ -5546,8 +6236,8 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .levelUpLearnset = sBergmiteLevelUpLearnset, .teachableLearnset = sBergmiteTeachableLearnset, .eggMoveLearnset = sBergmiteEggMoveLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 37, SPECIES_AVALUGG}, - {EVO_NONE, 0, SPECIES_AVALUGG_HISUI}), + .evolutions = EVOLUTION({EVO_LEVEL, 37, SPECIES_AVALUGG, CONDITIONS({IF_NOT_REGION, REGION_HISUI})}, + {EVO_LEVEL, 37, SPECIES_AVALUGG_HISUI, CONDITIONS({IF_REGION, REGION_HISUI})}), }, [SPECIES_AVALUGG] = @@ -6372,6 +7062,82 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .formSpeciesIdTable = sZygardeFormSpeciesIdTable, .formChangeTable = sZygardeCompleteFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_ZYGARDE_MEGA] = + { + .baseHP = 216, + .baseAttack = 70, + .baseDefense = 91, + .baseSpeed = 100, + .baseSpAttack = 216, + .baseSpDefense = 85, + .types = MON_TYPES(TYPE_DRAGON, TYPE_GROUND), + .catchRate = 3, + .expYield = (P_UPDATED_EXP_YIELDS >= GEN_8) ? 354 : 319, + .evYield_HP = 3, + .genderRatio = MON_GENDERLESS, + .eggCycles = 120, + .friendship = 0, + .growthRate = GROWTH_SLOW, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), + .abilities = { ABILITY_AURA_BREAK, ABILITY_NONE, ABILITY_NONE }, + .bodyColor = BODY_COLOR_BLACK, + .noFlip = TRUE, + .speciesName = _("Zygarde"), + .cryId = CRY_ZYGARDE_COMPLETE, // CRY_ZYGARDE_MEGA, + .natDexNum = NATIONAL_DEX_ZYGARDE, + .categoryName = _("Order"), + .height = 77, + .weight = 6100, + .description = COMPOUND_STRING( + "In response to people's emotions\n" + "during an unprecedented crisis,\n" + "Zygarde Mega Evolves and calms the\n" + "situation with its unmatched power."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sZygardeLevelUpLearnset, + .teachableLearnset = sZygardeTeachableLearnset, + .formSpeciesIdTable = sZygardeFormSpeciesIdTable, + .formChangeTable = sZygardeCompleteFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_ZYGARDE #if P_FAMILY_DIANCIE diff --git a/src/data/pokemon/species_info/gen_7_families.h b/src/data/pokemon/species_info/gen_7_families.h index d264f830ad..3b982f2c22 100644 --- a/src/data/pokemon/species_info/gen_7_families.h +++ b/src/data/pokemon/species_info/gen_7_families.h @@ -137,8 +137,8 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = ) .levelUpLearnset = sDartrixLevelUpLearnset, .teachableLearnset = sDartrixTeachableLearnset, - .evolutions = EVOLUTION({EVO_LEVEL, 34, SPECIES_DECIDUEYE}, - {EVO_NONE, 0, SPECIES_DECIDUEYE_HISUI}), + .evolutions = EVOLUTION({EVO_LEVEL, 34, SPECIES_DECIDUEYE, CONDITIONS({IF_NOT_REGION, REGION_HISUI})}, + {EVO_LEVEL, 36, SPECIES_DECIDUEYE_HISUI, CONDITIONS({IF_REGION, REGION_HISUI})}), }, [SPECIES_DECIDUEYE] = @@ -5203,7 +5203,85 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .levelUpLearnset = sDrampaLevelUpLearnset, .teachableLearnset = sDrampaTeachableLearnset, .eggMoveLearnset = sDrampaEggMoveLearnset, + .formSpeciesIdTable = sDrampaFormSpeciesIdTable, + .formChangeTable = sDrampaFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_DRAMPA_MEGA] = + { + .baseHP = 78, + .baseAttack = 85, + .baseDefense = 110, + .baseSpeed = 36, + .baseSpAttack = 160, + .baseSpDefense = 116, + .types = MON_TYPES(TYPE_NORMAL, TYPE_DRAGON), + .catchRate = 70, + .expYield = 170, + .evYield_SpAttack = 2, + .itemRare = ITEM_PERSIM_BERRY, + .genderRatio = PERCENT_FEMALE(50), + .eggCycles = 20, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MONSTER, EGG_GROUP_DRAGON), + .abilities = { ABILITY_BERSERK, ABILITY_SAP_SIPPER, ABILITY_CLOUD_NINE }, + .bodyColor = BODY_COLOR_WHITE, + .speciesName = _("Drampa"), + .cryId = CRY_DRAMPA, // CRY_DRAMPA_MEGA, + .natDexNum = NATIONAL_DEX_DRAMPA, + .categoryName = _("Imposing"), + .height = 3, + .weight = 2405, + .description = COMPOUND_STRING( + "Drampa's cells have been\n" + "invigorated, allowing it to regain\n" + "its youth. It manipulates the\n" + "atmosphere to summon storms."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sDrampaLevelUpLearnset, + .teachableLearnset = sDrampaTeachableLearnset, + .formSpeciesIdTable = sDrampaFormSpeciesIdTable, + .formChangeTable = sDrampaFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_DRAMPA #if P_FAMILY_DHELMISE diff --git a/src/data/pokemon/species_info/gen_8_families.h b/src/data/pokemon/species_info/gen_8_families.h index 6ba7fed676..04dc82f493 100644 --- a/src/data/pokemon/species_info/gen_8_families.h +++ b/src/data/pokemon/species_info/gen_8_families.h @@ -5241,7 +5241,85 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = ) .levelUpLearnset = sFalinksLevelUpLearnset, .teachableLearnset = sFalinksTeachableLearnset, + .formSpeciesIdTable = sFalinksFormSpeciesIdTable, + .formChangeTable = sFalinksFormChangeTable, }, + +#if P_GEN_9_MEGA_EVOLUTIONS + [SPECIES_FALINKS_MEGA] = + { + .baseHP = 65, + .baseAttack = 135, + .baseDefense = 135, + .baseSpeed = 100, + .baseSpAttack = 70, + .baseSpDefense = 65, + .types = MON_TYPES(TYPE_FIGHTING), + .catchRate = 45, + .expYield = 165, + .evYield_Attack = 2, + .evYield_SpDefense = 1, + .genderRatio = MON_GENDERLESS, + .eggCycles = 25, + .friendship = STANDARD_FRIENDSHIP, + .growthRate = GROWTH_MEDIUM_FAST, + .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FAIRY, EGG_GROUP_MINERAL), + .abilities = { ABILITY_BATTLE_ARMOR, ABILITY_NONE, ABILITY_DEFIANT }, + .bodyColor = BODY_COLOR_YELLOW, + .speciesName = _("Falinks"), + .cryId = CRY_FALINKS, + .natDexNum = NATIONAL_DEX_FALINKS, + .categoryName = _("Formation"), + .height = 16, + .weight = 990, + .description = COMPOUND_STRING( + "Mega Falinks has taken on the\n" + "ultimate battle formation, which\n" + "can be achieved only if the troopers\n" + "and brass have the strongest of bonds."), + .frontPic = gMonFrontPic_CircledQuestionMark, + .frontPicSize = MON_COORDS_SIZE(40, 40), + .frontPicYOffset = 12, + .frontAnimFrames = sAnims_TwoFramePlaceHolder, + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .backPic = gMonBackPic_CircledQuestionMark, + .backPicSize = MON_COORDS_SIZE(40, 40), + .backPicYOffset = 12, + .backAnimId = BACK_ANIM_NONE, + .palette = gMonPalette_CircledQuestionMark, + .shinyPalette = gMonShinyPalette_CircledQuestionMark, + .iconSprite = gMonIcon_QuestionMark, + .iconPalIndex = 0, + .pokemonJumpType = PKMN_JUMP_TYPE_NONE, + FOOTPRINT(QuestionMark) + SHADOW(-1, 0, SHADOW_SIZE_M) + #if OW_BATTLE_ONLY_FORMS + .overworldData = { + .tileTag = TAG_NONE, + .paletteTag = OBJ_EVENT_PAL_TAG_SUBSTITUTE, + .reflectionPaletteTag = OBJ_EVENT_PAL_TAG_NONE, + .size = 512, + .width = 32, + .height = 32, + .paletteSlot = PALSLOT_NPC_1, + .shadowSize = SHADOW_SIZE_M, + .inanimate = FALSE, + .compressed = COMP, + .tracks = TRACKS_FOOT, + .oam = &gObjectEventBaseOam_32x32, + .subspriteTables = sOamTables_32x32, + .anims = sAnimTable_Following, + .images = sPicTable_Substitute, + .affineAnims = gDummySpriteAffineAnimTable, + }, + #endif //OW_BATTLE_ONLY_FORMS + .isMegaEvolution = TRUE, + .levelUpLearnset = sFalinksLevelUpLearnset, + .teachableLearnset = sFalinksTeachableLearnset, + .formSpeciesIdTable = sFalinksFormSpeciesIdTable, + .formChangeTable = sFalinksFormChangeTable, + }, +#endif //P_GEN_9_MEGA_EVOLUTIONS #endif //P_FAMILY_FALINKS #if P_FAMILY_PINCURCHIN diff --git a/src/data/pokemon/teachable_learnsets.h b/src/data/pokemon/teachable_learnsets.h index 8b400f5675..970cde222a 100644 --- a/src/data/pokemon/teachable_learnsets.h +++ b/src/data/pokemon/teachable_learnsets.h @@ -909,8 +909,10 @@ static const u16 sArbokTeachableLearnset[] = { static const u16 sPichuTeachableLearnset[] = { MOVE_ATTRACT, MOVE_BODY_SLAM, + MOVE_BRICK_BREAK, MOVE_COUNTER, MOVE_DEFENSE_CURL, + MOVE_DIG, MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, MOVE_ENDURE, @@ -1501,6 +1503,7 @@ static const u16 sNidokingTeachableLearnset[] = { #if P_GEN_2_CROSS_EVOS static const u16 sCleffaTeachableLearnset[] = { MOVE_ATTRACT, + MOVE_BLIZZARD, MOVE_BODY_SLAM, MOVE_CALM_MIND, MOVE_COUNTER, @@ -1514,6 +1517,7 @@ static const u16 sCleffaTeachableLearnset[] = { MOVE_FIRE_BLAST, MOVE_FLAMETHROWER, MOVE_FLASH, + MOVE_ICE_BEAM, MOVE_ICY_WIND, MOVE_IRON_TAIL, MOVE_LIGHT_SCREEN, @@ -1539,6 +1543,8 @@ static const u16 sCleffaTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SWAGGER, MOVE_SWIFT, + MOVE_THUNDER, + MOVE_THUNDERBOLT, MOVE_THUNDER_WAVE, MOVE_TOXIC, MOVE_WATER_PULSE, @@ -4113,6 +4119,7 @@ static const u16 sSlowbroGalarTeachableLearnset[] = { MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_BLAST, + MOVE_FIRE_PUNCH, MOVE_FLAMETHROWER, MOVE_HAIL, MOVE_HYPER_BEAM, @@ -4139,6 +4146,7 @@ static const u16 sSlowbroGalarTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SURF, MOVE_SWIFT, + MOVE_THUNDER_PUNCH, MOVE_THUNDER_WAVE, MOVE_TOXIC, MOVE_WATERFALL, @@ -6401,6 +6409,7 @@ static const u16 sStaryuTeachableLearnset[] = { MOVE_REFLECT, MOVE_REST, MOVE_ROLLOUT, + MOVE_SAFEGUARD, MOVE_SLEEP_TALK, MOVE_SNORE, MOVE_SURF, @@ -6418,6 +6427,7 @@ static const u16 sStaryuTeachableLearnset[] = { static const u16 sStarmieTeachableLearnset[] = { MOVE_ATTRACT, MOVE_BLIZZARD, + MOVE_BULK_UP, MOVE_DIVE, MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, @@ -6437,6 +6447,7 @@ static const u16 sStarmieTeachableLearnset[] = { MOVE_REFLECT, MOVE_REST, MOVE_ROLLOUT, + MOVE_SAFEGUARD, MOVE_SKILL_SWAP, MOVE_SLEEP_TALK, MOVE_SNORE, @@ -7073,6 +7084,7 @@ static const u16 sMagmortarTeachableLearnset[] = { #if P_FAMILY_PINSIR static const u16 sPinsirTeachableLearnset[] = { + MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_BODY_SLAM, MOVE_BRICK_BREAK, @@ -7373,6 +7385,7 @@ static const u16 sVaporeonTeachableLearnset[] = { MOVE_SURF, MOVE_SWAGGER, MOVE_SWIFT, + MOVE_TAUNT, MOVE_TOXIC, MOVE_WATERFALL, MOVE_WATER_PULSE, @@ -7442,6 +7455,8 @@ static const u16 sFlareonTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SWAGGER, MOVE_SWIFT, + MOVE_SWORDS_DANCE, + MOVE_TAUNT, MOVE_TOXIC, MOVE_UNAVAILABLE, }; @@ -7471,6 +7486,7 @@ static const u16 sEspeonTeachableLearnset[] = { MOVE_REST, MOVE_ROAR, MOVE_ROCK_SMASH, + MOVE_SAFEGUARD, MOVE_SHADOW_BALL, MOVE_SKILL_SWAP, MOVE_SLEEP_TALK, @@ -7556,6 +7572,7 @@ static const u16 sLeafeonTeachableLearnset[] = { MOVE_SWAGGER, MOVE_SWIFT, MOVE_SWORDS_DANCE, + MOVE_TAUNT, MOVE_TOXIC, MOVE_UNAVAILABLE, }; @@ -7588,6 +7605,7 @@ static const u16 sGlaceonTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SWAGGER, MOVE_SWIFT, + MOVE_TAUNT, MOVE_TOXIC, MOVE_WATER_PULSE, MOVE_UNAVAILABLE, @@ -7626,6 +7644,7 @@ static const u16 sSylveonTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SWAGGER, MOVE_SWIFT, + MOVE_TAUNT, MOVE_TOXIC, MOVE_UNAVAILABLE, }; @@ -14445,6 +14464,7 @@ static const u16 sSableyeTeachableLearnset[] = { MOVE_REST, MOVE_ROCK_SMASH, MOVE_ROCK_TOMB, + MOVE_SAFEGUARD, MOVE_SEISMIC_TOSS, MOVE_SHADOW_BALL, MOVE_SHOCK_WAVE, @@ -14974,6 +14994,7 @@ static const u16 sIllumiseTeachableLearnset[] = { #if P_GEN_4_CROSS_EVOS static const u16 sBudewTeachableLearnset[] = { MOVE_ATTRACT, + MOVE_BODY_SLAM, MOVE_BULLET_SEED, MOVE_CUT, MOVE_DOUBLE_TEAM, @@ -16512,6 +16533,7 @@ static const u16 sShuppetTeachableLearnset[] = { MOVE_SNORE, MOVE_SUNNY_DAY, MOVE_SWAGGER, + MOVE_SWORDS_DANCE, MOVE_TAUNT, MOVE_THIEF, MOVE_THUNDER, @@ -19381,6 +19403,7 @@ static const u16 sBunearyTeachableLearnset[] = { MOVE_DIG, MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, + MOVE_DYNAMIC_PUNCH, MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_PUNCH, @@ -19419,6 +19442,7 @@ static const u16 sLopunnyTeachableLearnset[] = { MOVE_DIG, MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, + MOVE_DYNAMIC_PUNCH, MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_PUNCH, @@ -19444,6 +19468,7 @@ static const u16 sLopunnyTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SWAGGER, MOVE_SWIFT, + MOVE_SWORDS_DANCE, MOVE_THUNDER, MOVE_THUNDERBOLT, MOVE_THUNDER_PUNCH, @@ -19778,6 +19803,7 @@ static const u16 sGabiteTeachableLearnset[] = { MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_BODY_SLAM, + MOVE_BRICK_BREAK, MOVE_CUT, MOVE_DIG, MOVE_DOUBLE_EDGE, @@ -21372,6 +21398,7 @@ static const u16 sPatratTeachableLearnset[] = { MOVE_CUT, MOVE_DIG, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_IRON_TAIL, MOVE_PROTECT, @@ -21394,8 +21421,10 @@ static const u16 sWatchogTeachableLearnset[] = { MOVE_BULLET_SEED, MOVE_CUT, MOVE_DIG, + MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, MOVE_DREAM_EATER, + MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_PUNCH, MOVE_FLAMETHROWER, @@ -21417,6 +21446,7 @@ static const u16 sWatchogTeachableLearnset[] = { MOVE_STRENGTH, MOVE_SUNNY_DAY, MOVE_SWAGGER, + MOVE_SWIFT, MOVE_SWORDS_DANCE, MOVE_THUNDER, MOVE_THUNDERBOLT, @@ -21576,10 +21606,12 @@ static const u16 sLiepardTeachableLearnset[] = { #if P_FAMILY_PANSAGE static const u16 sPansageTeachableLearnset[] = { MOVE_ATTRACT, + MOVE_BRICK_BREAK, MOVE_BULLET_SEED, MOVE_CUT, MOVE_DIG, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_FLASH, MOVE_FOCUS_PUNCH, @@ -21587,6 +21619,7 @@ static const u16 sPansageTeachableLearnset[] = { MOVE_IRON_TAIL, MOVE_PROTECT, MOVE_REST, + MOVE_ROCK_SLIDE, MOVE_ROCK_SMASH, MOVE_ROCK_TOMB, MOVE_SLEEP_TALK, @@ -21594,6 +21627,7 @@ static const u16 sPansageTeachableLearnset[] = { MOVE_SOLAR_BEAM, MOVE_SUNNY_DAY, MOVE_SWAGGER, + MOVE_SWIFT, MOVE_TAUNT, MOVE_THIEF, MOVE_TORMENT, @@ -21608,6 +21642,7 @@ static const u16 sSimisageTeachableLearnset[] = { MOVE_CUT, MOVE_DIG, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_FLASH, MOVE_FOCUS_PUNCH, @@ -21624,6 +21659,7 @@ static const u16 sSimisageTeachableLearnset[] = { MOVE_SOLAR_BEAM, MOVE_SUNNY_DAY, MOVE_SWAGGER, + MOVE_SWIFT, MOVE_TAUNT, MOVE_THIEF, MOVE_TORMENT, @@ -21635,9 +21671,11 @@ static const u16 sSimisageTeachableLearnset[] = { #if P_FAMILY_PANSEAR static const u16 sPansearTeachableLearnset[] = { MOVE_ATTRACT, + MOVE_BRICK_BREAK, MOVE_CUT, MOVE_DIG, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_BLAST, MOVE_FIRE_PUNCH, @@ -21647,6 +21685,7 @@ static const u16 sPansearTeachableLearnset[] = { MOVE_OVERHEAT, MOVE_PROTECT, MOVE_REST, + MOVE_ROCK_SLIDE, MOVE_ROCK_SMASH, MOVE_ROCK_TOMB, MOVE_SLEEP_TALK, @@ -21654,6 +21693,7 @@ static const u16 sPansearTeachableLearnset[] = { MOVE_SOLAR_BEAM, MOVE_SUNNY_DAY, MOVE_SWAGGER, + MOVE_SWIFT, MOVE_TAUNT, MOVE_THIEF, MOVE_TORMENT, @@ -21667,6 +21707,7 @@ static const u16 sSimisearTeachableLearnset[] = { MOVE_CUT, MOVE_DIG, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_BLAST, MOVE_FIRE_PUNCH, @@ -21685,6 +21726,7 @@ static const u16 sSimisearTeachableLearnset[] = { MOVE_SOLAR_BEAM, MOVE_SUNNY_DAY, MOVE_SWAGGER, + MOVE_SWIFT, MOVE_TAUNT, MOVE_THIEF, MOVE_TORMENT, @@ -21697,10 +21739,12 @@ static const u16 sSimisearTeachableLearnset[] = { static const u16 sPanpourTeachableLearnset[] = { MOVE_ATTRACT, MOVE_BLIZZARD, + MOVE_BRICK_BREAK, MOVE_CUT, MOVE_DIG, MOVE_DIVE, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_FOCUS_PUNCH, MOVE_HAIL, @@ -21711,12 +21755,14 @@ static const u16 sPanpourTeachableLearnset[] = { MOVE_PROTECT, MOVE_RAIN_DANCE, MOVE_REST, + MOVE_ROCK_SLIDE, MOVE_ROCK_SMASH, MOVE_ROCK_TOMB, MOVE_SLEEP_TALK, MOVE_SNORE, MOVE_SURF, MOVE_SWAGGER, + MOVE_SWIFT, MOVE_TAUNT, MOVE_THIEF, MOVE_TORMENT, @@ -21734,6 +21780,7 @@ static const u16 sSimipourTeachableLearnset[] = { MOVE_DIG, MOVE_DIVE, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_FOCUS_PUNCH, MOVE_HAIL, @@ -21752,6 +21799,7 @@ static const u16 sSimipourTeachableLearnset[] = { MOVE_SNORE, MOVE_SURF, MOVE_SWAGGER, + MOVE_SWIFT, MOVE_TAUNT, MOVE_THIEF, MOVE_TORMENT, @@ -22558,6 +22606,7 @@ static const u16 sVenipedeTeachableLearnset[] = { MOVE_PROTECT, MOVE_REST, MOVE_ROCK_SMASH, + MOVE_ROCK_TOMB, MOVE_ROLLOUT, MOVE_SLEEP_TALK, MOVE_SLUDGE_BOMB, @@ -22580,6 +22629,7 @@ static const u16 sWhirlipedeTeachableLearnset[] = { MOVE_PROTECT, MOVE_REST, MOVE_ROCK_SMASH, + MOVE_ROCK_TOMB, MOVE_ROLLOUT, MOVE_SLEEP_TALK, MOVE_SLUDGE_BOMB, @@ -22823,6 +22873,7 @@ static const u16 sBasculegionTeachableLearnset[] = { #if P_FAMILY_SANDILE static const u16 sSandileTeachableLearnset[] = { + MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_BODY_SLAM, MOVE_BRICK_BREAK, @@ -22831,6 +22882,7 @@ static const u16 sSandileTeachableLearnset[] = { MOVE_DIG, MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, + MOVE_DRAGON_CLAW, MOVE_EARTHQUAKE, MOVE_ENDURE, MOVE_FACADE, @@ -23166,6 +23218,7 @@ static const u16 sScraggyTeachableLearnset[] = { MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, MOVE_DRAGON_CLAW, + MOVE_DYNAMIC_PUNCH, MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_PUNCH, @@ -23206,6 +23259,7 @@ static const u16 sScraftyTeachableLearnset[] = { MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, MOVE_DRAGON_CLAW, + MOVE_DYNAMIC_PUNCH, MOVE_ENDURE, MOVE_FACADE, MOVE_FIRE_PUNCH, @@ -23513,6 +23567,7 @@ static const u16 sArcheopsTeachableLearnset[] = { #if P_FAMILY_TRUBBISH static const u16 sTrubbishTeachableLearnset[] = { MOVE_ATTRACT, + MOVE_BULLET_SEED, MOVE_DOUBLE_TEAM, MOVE_ENDURE, MOVE_EXPLOSION, @@ -23535,6 +23590,7 @@ static const u16 sTrubbishTeachableLearnset[] = { static const u16 sGarbodorTeachableLearnset[] = { MOVE_ATTRACT, MOVE_BODY_SLAM, + MOVE_BULLET_SEED, MOVE_DOUBLE_TEAM, MOVE_ENDURE, MOVE_EXPLOSION, @@ -24568,6 +24624,7 @@ static const u16 sKlinklangTeachableLearnset[] = { #if P_FAMILY_TYNAMO static const u16 sTynamoTeachableLearnset[] = { + MOVE_PROTECT, MOVE_THUNDER_WAVE, MOVE_UNAVAILABLE, }; @@ -24633,6 +24690,7 @@ static const u16 sEelektrossTeachableLearnset[] = { MOVE_THUNDER_PUNCH, MOVE_THUNDER_WAVE, MOVE_TOXIC, + MOVE_WATERFALL, MOVE_UNAVAILABLE, }; #endif //P_FAMILY_TYNAMO @@ -25106,6 +25164,7 @@ static const u16 sStunfiskGalarTeachableLearnset[] = { MOVE_SNORE, MOVE_SURF, MOVE_THUNDER_WAVE, + MOVE_TOXIC, MOVE_UNAVAILABLE, }; #endif //P_GALARIAN_FORMS @@ -26523,6 +26582,7 @@ static const u16 sFrogadierTeachableLearnset[] = { MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_BLIZZARD, + MOVE_BRICK_BREAK, MOVE_COUNTER, MOVE_CUT, MOVE_DIG, @@ -26762,6 +26822,7 @@ static const u16 sTalonflameTeachableLearnset[] = { #if P_FAMILY_SCATTERBUG static const u16 sScatterbugTeachableLearnset[] = { + MOVE_PROTECT, MOVE_UNAVAILABLE, }; @@ -26926,6 +26987,7 @@ static const u16 sFloetteEternalTeachableLearnset[] = { MOVE_FACADE, MOVE_FLASH, MOVE_GIGA_DRAIN, + MOVE_HYPER_BEAM, MOVE_LIGHT_SCREEN, MOVE_METRONOME, MOVE_PROTECT, @@ -27099,6 +27161,7 @@ static const u16 sPangoroTeachableLearnset[] = { MOVE_FACADE, MOVE_FIRE_PUNCH, MOVE_FOCUS_PUNCH, + MOVE_GIGA_DRAIN, MOVE_HYPER_BEAM, MOVE_ICE_PUNCH, MOVE_MEGA_KICK, @@ -27133,9 +27196,12 @@ static const u16 sPangoroTeachableLearnset[] = { static const u16 sFurfrouTeachableLearnset[] = { MOVE_ATTRACT, MOVE_DIG, + MOVE_DOUBLE_EDGE, MOVE_DOUBLE_TEAM, + MOVE_ENDURE, MOVE_FACADE, MOVE_FLASH, + MOVE_HYPER_BEAM, MOVE_IRON_TAIL, MOVE_PROTECT, MOVE_RAIN_DANCE, @@ -27217,6 +27283,7 @@ static const u16 sMeowsticMTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SWAGGER, MOVE_SWIFT, + MOVE_TAUNT, MOVE_THUNDERBOLT, MOVE_THUNDER_WAVE, MOVE_TORMENT, @@ -27257,6 +27324,7 @@ static const u16 sMeowsticFTeachableLearnset[] = { MOVE_THUNDER_WAVE, MOVE_TORMENT, MOVE_TOXIC, + MOVE_WATER_PULSE, MOVE_UNAVAILABLE, }; #endif //P_FAMILY_ESPURR @@ -27417,6 +27485,7 @@ static const u16 sSwirlixTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SURF, MOVE_SWAGGER, + MOVE_SWORDS_DANCE, MOVE_THIEF, MOVE_THUNDERBOLT, MOVE_TOXIC, @@ -27446,6 +27515,7 @@ static const u16 sSlurpuffTeachableLearnset[] = { MOVE_SUNNY_DAY, MOVE_SURF, MOVE_SWAGGER, + MOVE_SWORDS_DANCE, MOVE_THIEF, MOVE_THUNDER, MOVE_THUNDERBOLT, @@ -27491,6 +27561,7 @@ static const u16 sInkayTeachableLearnset[] = { static const u16 sMalamarTeachableLearnset[] = { MOVE_AERIAL_ACE, MOVE_ATTRACT, + MOVE_BULK_UP, MOVE_CALM_MIND, MOVE_CUT, MOVE_DOUBLE_TEAM, @@ -27558,6 +27629,7 @@ static const u16 sBinacleTeachableLearnset[] = { MOVE_THIEF, MOVE_TORMENT, MOVE_TOXIC, + MOVE_WATERFALL, MOVE_WATER_PULSE, MOVE_UNAVAILABLE, }; @@ -27600,6 +27672,7 @@ static const u16 sBarbaracleTeachableLearnset[] = { MOVE_THIEF, MOVE_TORMENT, MOVE_TOXIC, + MOVE_WATERFALL, MOVE_WATER_PULSE, MOVE_UNAVAILABLE, }; @@ -28061,6 +28134,7 @@ static const u16 sGoomyTeachableLearnset[] = { MOVE_SLUDGE_BOMB, MOVE_SNORE, MOVE_SUNNY_DAY, + MOVE_SURF, MOVE_SWAGGER, MOVE_THUNDERBOLT, MOVE_TOXIC, @@ -28087,6 +28161,7 @@ static const u16 sSliggooTeachableLearnset[] = { MOVE_SLUDGE_BOMB, MOVE_SNORE, MOVE_SUNNY_DAY, + MOVE_SURF, MOVE_SWAGGER, MOVE_THUNDER, MOVE_THUNDERBOLT, @@ -28109,6 +28184,7 @@ static const u16 sGoodraTeachableLearnset[] = { MOVE_FIRE_PUNCH, MOVE_FLAMETHROWER, MOVE_FOCUS_PUNCH, + MOVE_GIGA_DRAIN, MOVE_HAIL, MOVE_HYPER_BEAM, MOVE_ICE_BEAM, @@ -28154,8 +28230,10 @@ static const u16 sSliggooHisuiTeachableLearnset[] = { MOVE_SLEEP_TALK, MOVE_SLUDGE_BOMB, MOVE_SUNNY_DAY, + MOVE_SURF, MOVE_THUNDER, MOVE_THUNDERBOLT, + MOVE_TOXIC, MOVE_WATER_PULSE, MOVE_UNAVAILABLE, }; @@ -28188,6 +28266,7 @@ static const u16 sGoodraHisuiTeachableLearnset[] = { MOVE_THUNDER, MOVE_THUNDERBOLT, MOVE_THUNDER_PUNCH, + MOVE_TOXIC, MOVE_WATER_PULSE, MOVE_UNAVAILABLE, }; @@ -28441,6 +28520,7 @@ static const u16 sAvaluggHisuiTeachableLearnset[] = { MOVE_ROCK_TOMB, MOVE_SANDSTORM, MOVE_SLEEP_TALK, + MOVE_SURF, MOVE_WATER_PULSE, MOVE_UNAVAILABLE, }; @@ -30524,6 +30604,7 @@ static const u16 sBruxishTeachableLearnset[] = { static const u16 sDrampaTeachableLearnset[] = { MOVE_ATTRACT, MOVE_BLIZZARD, + MOVE_BODY_SLAM, MOVE_CALM_MIND, MOVE_DOUBLE_TEAM, MOVE_DRAGON_CLAW, diff --git a/src/data/region_map/region_map_sections.json b/src/data/region_map/region_map_sections.json index 49426128b8..5fc041e8ea 100644 --- a/src/data/region_map/region_map_sections.json +++ b/src/data/region_map/region_map_sections.json @@ -531,7 +531,6 @@ { "id": "MAPSEC_AQUA_HIDEOUT_OLD", "name": "{AQUA} HIDEOUT", - "name_clone": true, "x": 19, "y": 3, "width": 1, @@ -690,8 +689,7 @@ "name": "SECRET BASE" }, { - "id": "MAPSEC_DYNAMIC", - "name": "" + "id": "MAPSEC_DYNAMIC" }, { "id": "MAPSEC_PALLET_TOWN", @@ -739,13 +737,11 @@ }, { "id": "MAPSEC_ROUTE_4_POKECENTER", - "name": "ROUTE 4", - "name_clone": true + "name": "ROUTE 4" }, { "id": "MAPSEC_ROUTE_10_POKECENTER", - "name": "ROUTE 10", - "name_clone": true + "name": "ROUTE 10" }, { "id": "MAPSEC_ROUTE_1", @@ -865,8 +861,7 @@ }, { "id": "MAPSEC_UNDERGROUND_PATH_2", - "name": "UNDERGROUND PATH", - "name_clone": true + "name": "UNDERGROUND PATH" }, { "id": "MAPSEC_DIGLETTS_CAVE", @@ -874,8 +869,7 @@ }, { "id": "MAPSEC_KANTO_VICTORY_ROAD", - "name": "VICTORY ROAD", - "name_clone": true + "name": "VICTORY ROAD" }, { "id": "MAPSEC_ROCKET_HIDEOUT", @@ -891,8 +885,7 @@ }, { "id": "MAPSEC_KANTO_SAFARI_ZONE", - "name": "SAFARI ZONE", - "name_clone": true + "name": "SAFARI ZONE" }, { "id": "MAPSEC_POKEMON_LEAGUE", @@ -1064,8 +1057,7 @@ }, { "id": "MAPSEC_TRAINER_TOWER_2", - "name": "TRAINER TOWER", - "name_clone": true + "name": "TRAINER TOWER" }, { "id": "MAPSEC_DOTTED_HOLE", diff --git a/src/data/region_map/region_map_sections.json.txt b/src/data/region_map/region_map_sections.json.txt index 0da2d31794..5c532a050a 100644 --- a/src/data/region_map/region_map_sections.json.txt +++ b/src/data/region_map/region_map_sections.json.txt @@ -2,21 +2,6 @@ #ifndef GUARD_DATA_REGION_MAP_REGION_MAP_ENTRIES_H #define GUARD_DATA_REGION_MAP_REGION_MAP_ENTRIES_H -## for map_section in map_sections -{% if existsIn(map_section, "name") and isEmptyString(getVar(map_section.name)) and not existsIn(map_section, "name_clone") %}{{ setVar(map_section.name, map_section.id) }}{% endif %} -## endfor - -## for map_section in map_sections -{% if existsIn(map_section, "name") %} -{% if getVar(map_section.name) == map_section.id %} -static const u8 sMapName_{{ cleanString(map_section.name) }}[] = _("{{ map_section.name }}"); -{% endif %} -{% if existsIn(map_section, "name_clone") %} -static const u8 sMapName_{{ cleanString(map_section.name) }}_Clone[] = _("{{ map_section.name }}"); -{% endif %} -{% endif %} -## endfor - const struct RegionMapLocation gRegionMapEntries[] = { ## for map_section in map_sections [{{ map_section.id }}] = { @@ -41,7 +26,7 @@ const struct RegionMapLocation gRegionMapEntries[] = { .height = 1, {% endif %} {% if existsIn(map_section, "name") %} - .name = sMapName_{{ cleanString(map_section.name) }}{% if existsIn(map_section, "name_clone") %}_Clone{% endif %}, + .name = COMPOUND_STRING("{{ map_section.name }}"), {% else %} .name = (const u8[])_(""), {% endif %} diff --git a/src/data/speaker_names.h b/src/data/speaker_names.h new file mode 100644 index 0000000000..7f0ca56ca7 --- /dev/null +++ b/src/data/speaker_names.h @@ -0,0 +1,5 @@ +const u8 *const gSpeakerNamesTable[SP_NAME_COUNT] = +{ + [SP_NAME_MOM] = COMPOUND_STRING("MOM"), + [SP_NAME_PLAYER] = COMPOUND_STRING("{PLAYER}"), +}; diff --git a/src/data/wild_encounters.json b/src/data/wild_encounters.json index 0b30c0f65b..053c4c095f 100755 --- a/src/data/wild_encounters.json +++ b/src/data/wild_encounters.json @@ -7,30 +7,71 @@ { "type": "land_mons", "encounter_rates": [ - 20, 20, 10, 10, 10, 10, 5, 5, 4, 4, 1, 1 + 20, + 20, + 10, + 10, + 10, + 10, + 5, + 5, + 4, + 4, + 1, + 1 ] }, { "type": "water_mons", "encounter_rates": [ - 60, 30, 5, 4, 1 + 60, + 30, + 5, + 4, + 1 ] }, { "type": "rock_smash_mons", "encounter_rates": [ - 60, 30, 5, 4, 1 + 60, + 30, + 5, + 4, + 1 ] }, { "type": "fishing_mons", "encounter_rates": [ - 70, 30, 60, 20, 20, 40, 40, 15, 4, 1 + 70, + 30, + 60, + 20, + 20, + 40, + 40, + 15, + 4, + 1 ], "groups": { - "old_rod": [0, 1], - "good_rod": [2, 3, 4], - "super_rod": [5, 6, 7, 8, 9] + "old_rod": [ + 0, + 1 + ], + "good_rod": [ + 2, + 3, + 4 + ], + "super_rod": [ + 5, + 6, + 7, + 8, + 9 + ] } } ], diff --git a/src/daycare.c b/src/daycare.c index 2dec8a81f1..439c0db3d6 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -24,7 +24,6 @@ #include "regions.h" #include "constants/form_change_types.h" #include "constants/items.h" -#include "constants/hold_effects.h" #include "constants/moves.h" #include "constants/region_map_sections.h" @@ -505,6 +504,8 @@ static u16 GetEggSpecies(u16 species) found = FALSE; for (j = 1; j < NUM_SPECIES; j++) { + if (!IsSpeciesEnabled(j)) + continue; const struct Evolution *evolutions = GetSpeciesEvolutions(j); if (evolutions == NULL) continue; @@ -741,10 +742,10 @@ static void InheritPokeball(struct Pokemon *egg, struct BoxPokemon *father, stru static void InheritAbility(struct Pokemon *egg, struct BoxPokemon *father, struct BoxPokemon *mother) { - u16 fatherAbility = GetBoxMonData(father, MON_DATA_ABILITY_NUM); - u16 motherAbility = GetBoxMonData(mother, MON_DATA_ABILITY_NUM); + enum Ability fatherAbility = GetBoxMonData(father, MON_DATA_ABILITY_NUM); + enum Ability motherAbility = GetBoxMonData(mother, MON_DATA_ABILITY_NUM); u16 motherSpecies = GetBoxMonData(mother, MON_DATA_SPECIES); - u16 inheritAbility = motherAbility; + enum Ability inheritAbility = motherAbility; if (motherSpecies == SPECIES_DITTO) { diff --git a/src/debug.c b/src/debug.c index 6fbfb3777f..4d3e5cd39f 100644 --- a/src/debug.c +++ b/src/debug.c @@ -29,6 +29,7 @@ #include "international_string_util.h" #include "item.h" #include "item_icon.h" +#include "item_use.h" #include "list_menu.h" #include "m4a.h" #include "main.h" @@ -106,8 +107,8 @@ enum FlagsVarsDebugMenu DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_COLLISION, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_ENCOUNTER, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_TRAINER_SEE, - DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BAG_USE, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_CATCHING, + DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BAG_USE, }; enum DebugBattleType @@ -237,6 +238,8 @@ static void Debug_DestroyMenu(u8 taskId); static void DebugAction_Cancel(u8 taskId); static void DebugAction_DestroyExtraWindow(u8 taskId); static void Debug_RefreshListMenu(u8 taskId); +static u8 DebugNativeStep_CreateDebugWindow(void); +static void DebugNativeStep_CloseDebugWindow(u8 taskId); static void DebugAction_OpenSubMenu(u8 taskId, const struct DebugMenuOption *items); static void DebugAction_OpenSubMenuFlagsVars(u8 taskId, const struct DebugMenuOption *items); @@ -342,12 +345,15 @@ static void DebugAction_Player_Id(u8 taskId); extern const u8 Debug_FlagsNotSetOverworldConfigMessage[]; extern const u8 Debug_FlagsNotSetBattleConfigMessage[]; +extern const u8 Debug_VarsNotSetBattleConfigMessage[]; extern const u8 Debug_FlagsAndVarNotSetBattleConfigMessage[]; extern const u8 Debug_EventScript_FontTest[]; extern const u8 Debug_EventScript_CheckEVs[]; extern const u8 Debug_EventScript_CheckIVs[]; extern const u8 Debug_EventScript_InflictStatus1[]; extern const u8 Debug_EventScript_SetHiddenNature[]; +extern const u8 Debug_EventScript_SetAbility[]; +extern const u8 Debug_EventScript_SetFriendship[]; extern const u8 Debug_EventScript_Script_1[]; extern const u8 Debug_EventScript_Script_2[]; extern const u8 Debug_EventScript_Script_3[]; @@ -380,7 +386,7 @@ extern const u8 Debug_EventScript_FakeRTCNotEnabled[]; extern const u8 Debug_BerryPestsDisabled[]; extern const u8 Debug_BerryWeedsDisabled[]; -extern const u8 FallarborTown_MoveRelearnersHouse_EventScript_ChooseMon[]; +extern const u8 Common_EventScript_MoveRelearner[]; #include "data/map_group_count.h" @@ -571,11 +577,13 @@ static const struct DebugMenuOption sDebugMenu_Actions_PCBag[] = static const struct DebugMenuOption sDebugMenu_Actions_Party[] = { - { COMPOUND_STRING("Move Reminder"), DebugAction_ExecuteScript, FallarborTown_MoveRelearnersHouse_EventScript_ChooseMon }, + { COMPOUND_STRING("Move Relearner"), DebugAction_ExecuteScript, Common_EventScript_MoveRelearner }, { COMPOUND_STRING("Hatch an Egg"), DebugAction_ExecuteScript, Debug_HatchAnEgg }, { COMPOUND_STRING("Heal party"), DebugAction_Party_HealParty }, { COMPOUND_STRING("Inflict Status1"), DebugAction_ExecuteScript, Debug_EventScript_InflictStatus1 }, { COMPOUND_STRING("Set Hidden Nature"), DebugAction_ExecuteScript, Debug_EventScript_SetHiddenNature }, + { COMPOUND_STRING("Set Friendship"), DebugAction_ExecuteScript, Debug_EventScript_SetFriendship }, + { COMPOUND_STRING("Set Ability"), DebugAction_ExecuteScript, Debug_EventScript_SetAbility }, { COMPOUND_STRING("Check EVs"), DebugAction_ExecuteScript, Debug_EventScript_CheckEVs }, { COMPOUND_STRING("Check IVs"), DebugAction_ExecuteScript, Debug_EventScript_CheckIVs }, { COMPOUND_STRING("Clear Party"), DebugAction_Party_ClearParty }, @@ -651,11 +659,18 @@ static const struct DebugMenuOption sDebugMenu_Actions_Flags[] = [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_COLLISION] = { COMPOUND_STRING("Toggle {STR_VAR_1}Collision OFF"), DebugAction_ToggleFlag, DebugAction_FlagsVars_CollisionOnOff }, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_ENCOUNTER] = { COMPOUND_STRING("Toggle {STR_VAR_1}Encounter OFF"), DebugAction_ToggleFlag, DebugAction_FlagsVars_EncounterOnOff }, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_TRAINER_SEE] = { COMPOUND_STRING("Toggle {STR_VAR_1}Trainer See OFF"), DebugAction_ToggleFlag, DebugAction_FlagsVars_TrainerSeeOnOff }, - [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BAG_USE] = { COMPOUND_STRING("Toggle {STR_VAR_1}Bag Use OFF"), DebugAction_ToggleFlag, DebugAction_FlagsVars_BagUseOnOff }, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_CATCHING] = { COMPOUND_STRING("Toggle {STR_VAR_1}Catching OFF"), DebugAction_ToggleFlag, DebugAction_FlagsVars_CatchingOnOff }, + [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BAG_USE] = { COMPOUND_STRING("Toggle {STR_VAR_1}Bag Use OFF"), DebugAction_ToggleFlag, DebugAction_FlagsVars_BagUseOnOff }, { NULL } }; +static const u8 *const sDebugMenu_Actions_BagUse_Options[] = +{ + COMPOUND_STRING("No Bag: {STR_VAR_1}Inactive"), + COMPOUND_STRING("No Bag: {STR_VAR_1}VS Trainers"), + COMPOUND_STRING("No Bag: {STR_VAR_1}Active"), +}; + static const struct DebugMenuOption sDebugMenu_Actions_Main[] = { { COMPOUND_STRING("Utilities…"), DebugAction_OpenSubMenu, sDebugMenu_Actions_Utilities, }, @@ -932,6 +947,30 @@ static void DebugAction_DestroyExtraWindow(u8 taskId) UnfreezeObjectEvents(); } +static u8 DebugNativeStep_CreateDebugWindow(void) +{ + u8 windowId; + + LockPlayerFieldControls(); + FreezeObjectEvents(); + HideMapNamePopUpWindow(); + LoadMessageBoxAndBorderGfx(); + windowId = AddWindow(&sDebugMenuWindowTemplateExtra); + DrawStdWindowFrame(windowId, FALSE); + CopyWindowToVram(windowId, COPYWIN_FULL); + + return windowId; +} + +static void DebugNativeStep_CloseDebugWindow(u8 taskId) +{ + ClearStdWindowAndFrame(gTasks[taskId].tSubWindowId, TRUE); + RemoveWindow(gTasks[taskId].tSubWindowId); + DestroyTask(taskId); + UnfreezeObjectEvents(); + UnlockPlayerFieldControls(); +} + static const u16 sLocationFlags[] = { FLAG_VISITED_LITTLEROOT_TOWN, @@ -956,7 +995,7 @@ static const u16 sLocationFlags[] = static u8 Debug_CheckToggleFlags(u8 id) { - u8 result = FALSE; + bool32 result = FALSE; switch (id) { @@ -1018,16 +1057,14 @@ static u8 Debug_CheckToggleFlags(u8 id) result = FlagGet(OW_FLAG_NO_TRAINER_SEE); break; #endif - #if B_FLAG_NO_BAG_USE != 0 - case DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BAG_USE: - result = FlagGet(B_FLAG_NO_BAG_USE); - break; - #endif #if B_FLAG_NO_CATCHING != 0 case DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_CATCHING: result = FlagGet(B_FLAG_NO_CATCHING); break; #endif + case DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BAG_USE: + result = VarGet(B_VAR_NO_BAG_USE); + break; default: result = 0xFF; break; @@ -1054,7 +1091,10 @@ static u8 Debug_GenerateListMenuNames(void) if (sDebugMenuListData->listId == 1) { flagResult = Debug_CheckToggleFlags(i); - name = sDebugMenu_Actions_Flags[i].text; + if (i == DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BAG_USE) + name = sDebugMenu_Actions_BagUse_Options[flagResult]; + else + name = sDebugMenu_Actions_Flags[i].text; } if (flagResult == 0xFF) @@ -2006,14 +2046,11 @@ static void DebugAction_FlagsVars_TrainerSeeOnOff(u8 taskId) static void DebugAction_FlagsVars_BagUseOnOff(u8 taskId) { -#if B_FLAG_NO_BAG_USE == 0 - Debug_DestroyMenu_Full_Script(taskId, Debug_FlagsNotSetBattleConfigMessage); +#if B_VAR_NO_BAG_USE < VARS_START || B_VAR_NO_BAG_USE > VARS_END + Debug_DestroyMenu_Full_Script(taskId, Debug_VarsNotSetBattleConfigMessage); #else - if (FlagGet(B_FLAG_NO_BAG_USE)) - PlaySE(SE_PC_OFF); - else - PlaySE(SE_PC_LOGIN); - FlagToggle(B_FLAG_NO_BAG_USE); + PlaySE(SE_SELECT); + VarSet(B_VAR_NO_BAG_USE, (VarGet(B_VAR_NO_BAG_USE) + 1) % 3); #endif } @@ -2040,6 +2077,17 @@ static void Debug_Display_ItemInfo(u32 itemId, u32 digit, u8 windowId) { StringCopy(gStringVar2, gText_DigitIndicator[digit]); u8* end = CopyItemName(itemId, gStringVar1); + u16 moveId = ItemIdToBattleMoveId(itemId); + if (moveId != MOVE_NONE) + { + end = StringCopy(end, gText_Space); + end = StringCopy(end, GetMoveName(moveId)); + } + else if (CheckIfItemIsTMHMOrEvolutionStone(itemId) == 1) + { + end = StringCopy(end, COMPOUND_STRING(" None")); + } + WrapFontIdToFit(gStringVar1, end, DEBUG_MENU_FONT, WindowWidthPx(windowId)); StringCopyPadded(gStringVar1, gStringVar1, CHAR_SPACE, 15); ConvertIntToDecimalStringN(gStringVar3, itemId, STR_CONV_MODE_LEADING_ZEROS, DEBUG_NUMBER_DIGITS_ITEMS); @@ -2386,7 +2434,7 @@ static void DebugAction_Give_Pokemon_SelectShiny(u8 taskId) } } -static void Debug_Display_Ability(u32 abilityId, u32 digit, u8 windowId)//(u32 natureId, u32 digit, u8 windowId) +static void Debug_Display_Ability(enum Ability abilityId, u32 digit, u8 windowId)//(u32 natureId, u32 digit, u8 windowId) { StringCopy(gStringVar2, gText_DigitIndicator[digit]); ConvertIntToDecimalStringN(gStringVar3, abilityId, STR_CONV_MODE_LEADING_ZEROS, 2); @@ -2425,7 +2473,7 @@ static void DebugAction_Give_Pokemon_SelectNature(u8 taskId) gTasks[taskId].tInput = 0; gTasks[taskId].tDigit = 0; - u32 abilityId = GetAbilityBySpecies(sDebugMonData->species, 0); + enum Ability abilityId = GetAbilityBySpecies(sDebugMonData->species, 0); Debug_Display_Ability(abilityId, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId); gTasks[taskId].func = DebugAction_Give_Pokemon_SelectAbility; @@ -2474,7 +2522,7 @@ static void DebugAction_Give_Pokemon_SelectAbility(u8 taskId) { i++; } - u32 abilityId = GetAbilityBySpecies(sDebugMonData->species, gTasks[taskId].tInput - i); + enum Ability abilityId = GetAbilityBySpecies(sDebugMonData->species, gTasks[taskId].tInput - i); Debug_Display_Ability(abilityId, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId); } @@ -3005,6 +3053,9 @@ static void DebugAction_Give_MaxMoney(u8 taskId) static void DebugAction_Give_MaxCoins(u8 taskId) { SetCoins(MAX_COINS); + + if (!CheckBagHasItem(ITEM_COIN_CASE, 1)) + AddBagItem(ITEM_COIN_CASE, 1); } static void DebugAction_Give_MaxBattlePoints(u8 taskId) @@ -3387,11 +3438,6 @@ static void DebugAction_DestroyFollowerNPC(u8 taskId) #undef tCurrentSong -#undef tMenuTaskId -#undef tWindowId -#undef tSubWindowId -#undef tInput -#undef tDigit #define SOUND_LIST_BGM \ X(MUS_LITTLEROOT_TEST) \ @@ -4015,6 +4061,81 @@ static void DebugAction_Party_HealParty(u8 taskId) Debug_DestroyMenu_Full(taskId); } +void DebugNative_GetAbilityNames(void) +{ + u32 species = GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPECIES); + StringCopy(gStringVar1, gAbilitiesInfo[GetAbilityBySpecies(species, 0)].name); + StringCopy(gStringVar2, gAbilitiesInfo[GetAbilityBySpecies(species, 1)].name); + StringCopy(gStringVar3, gAbilitiesInfo[GetAbilityBySpecies(species, 2)].name); +} + +#define tPartyId data[5] +#define tFriendship data[6] + +static void Debug_Display_FriendshipInfo(s32 oldFriendship, s32 newFriendship, u32 digit, u8 windowId) +{ + ConvertIntToDecimalStringN(gStringVar1, oldFriendship, STR_CONV_MODE_LEADING_ZEROS, 3); + ConvertIntToDecimalStringN(gStringVar2, newFriendship, STR_CONV_MODE_LEADING_ZEROS, 3); + StringCopy(gStringVar3, gText_DigitIndicator[digit]); + StringExpandPlaceholders(gStringVar4, COMPOUND_STRING("Friendship:\n{STR_VAR_1} {RIGHT_ARROW} {STR_VAR_2}\n\n{STR_VAR_3}")); + AddTextPrinterParameterized(windowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); +} + +static void DebugNativeStep_Party_SetFriendshipSelect(u8 taskId) +{ + if (JOY_NEW(A_BUTTON)) + { + PlaySE(SE_SELECT); + gTasks[taskId].tFriendship = gTasks[taskId].tInput; + SetMonData(&gPlayerParty[gTasks[taskId].tPartyId], MON_DATA_FRIENDSHIP, &gTasks[taskId].tInput); + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + DebugNativeStep_CloseDebugWindow(taskId); + return; + } + + Debug_HandleInput_Numeric(taskId, 0, 255, 3); + + if (JOY_NEW(DPAD_ANY) || JOY_NEW(A_BUTTON)) + Debug_Display_FriendshipInfo(gTasks[taskId].tFriendship, gTasks[taskId].tInput, gTasks[taskId].tDigit, gTasks[taskId].tSubWindowId); +} + +static void DebugNativeStep_Party_SetFriendshipMain(u8 taskId) +{ + u8 windowId = DebugNativeStep_CreateDebugWindow(); + u32 friendship = GetMonData(&gPlayerParty[gTasks[taskId].tPartyId], MON_DATA_FRIENDSHIP); + + // Display initial flag + Debug_Display_FriendshipInfo(friendship, friendship, 0, windowId); + + gTasks[taskId].func = DebugNativeStep_Party_SetFriendshipSelect; + gTasks[taskId].tSubWindowId = windowId; + gTasks[taskId].tFriendship = friendship; + gTasks[taskId].tInput = friendship; + gTasks[taskId].tDigit = 0; + gTasks[taskId].tPartyId = 0; +} + +void DebugNative_Party_SetFriendship(void) +{ + if (gSpecialVar_0x8004 < PARTY_SIZE) + { + u32 taskId = CreateTask(DebugNativeStep_Party_SetFriendshipMain, 1); + gTasks[taskId].tPartyId = gSpecialVar_0x8004; + } +} + +#undef tPartyId +#undef tFriendship + +#undef tMenuTaskId +#undef tWindowId +#undef tSubWindowId +#undef tInput +#undef tDigit + static void DebugAction_Party_ClearParty(u8 taskId) { ZeroPlayerPartyMons(); diff --git a/src/dexnav.c b/src/dexnav.c index 0efcf110aa..3244d07a6f 100644 --- a/src/dexnav.c +++ b/src/dexnav.c @@ -2123,7 +2123,7 @@ static void PrintCurrentSpeciesInfo(void) { u16 species = DexNavGetSpecies(); enum NationalDexOrder dexNum = SpeciesToNationalPokedexNum(species); - u8 type1, type2; + enum Type type1, type2; if (!GetSetPokedexFlag(dexNum, FLAG_GET_SEEN)) species = SPECIES_NONE; diff --git a/src/egg_hatch.c b/src/egg_hatch.c index 6f858c8f8d..2c632ee578 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -931,7 +931,7 @@ u8 GetEggCyclesToSubtract(void) { if (!GetMonData(&gPlayerParty[i], MON_DATA_SANITY_IS_EGG)) { - u16 ability = GetMonAbility(&gPlayerParty[i]); + enum Ability ability = GetMonAbility(&gPlayerParty[i]); if (ability == ABILITY_MAGMA_ARMOR || ability == ABILITY_FLAME_BODY || ability == ABILITY_STEAM_ENGINE) diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 8fdd7057b4..848289aec7 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -5502,7 +5502,7 @@ static bool32 TryStartFollowerTransformEffect(struct ObjectEvent *objectEvent, s { u32 multi; struct Pokemon *mon; - u32 ability; + enum Ability ability; if (DoesSpeciesHaveFormChangeMethod(OW_SPECIES(objectEvent), FORM_CHANGE_OVERWORLD_WEATHER) && OW_SPECIES(objectEvent) != (multi = GetOverworldWeatherSpecies(OW_SPECIES(objectEvent)))) { @@ -11536,3 +11536,8 @@ bool8 MovementAction_SurfStillRight_Step1(struct ObjectEvent *objectEvent, struc } return FALSE; } + +u8 GetObjectEventApricornTreeId(u8 objectEventId) +{ + return gObjectEvents[objectEventId].trainerRange_berryTreeId; +} diff --git a/src/field_effect.c b/src/field_effect.c index 45b4d61d17..174c071ae4 100644 --- a/src/field_effect.c +++ b/src/field_effect.c @@ -19,6 +19,7 @@ #include "mirage_tower.h" #include "menu.h" #include "metatile_behavior.h" +#include "oras_dowse.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" @@ -1679,6 +1680,7 @@ void StartEscalatorWarp(u8 metatileBehavior, u8 priority) { gTasks[taskId].tGoingUp = TRUE; } + EndORASDowsing(); } static void Task_EscalatorWarpOut(u8 taskId) @@ -2065,6 +2067,7 @@ static bool8 DiveFieldEffect_TryWarp(struct Task *task) void StartLavaridgeGymB1FWarp(u8 priority) { + EndORASDowsing(); CreateTask(Task_LavaridgeGymB1FWarp, priority); } @@ -2273,6 +2276,7 @@ void SpriteCB_AshLaunch(struct Sprite *sprite) void StartLavaridgeGym1FWarp(u8 priority) { + EndORASDowsing(); CreateTask(Task_LavaridgeGym1FWarp, priority); } @@ -2395,6 +2399,7 @@ void StartEscapeRopeFieldEffect(void) LockPlayerFieldControls(); FreezeObjectEvents(); HideFollowerForFieldEffect(); // hide follower before warping + EndORASDowsing(); CreateTask(Task_EscapeRopeWarpOut, 80); } @@ -2589,6 +2594,7 @@ static void TeleportWarpOutFieldEffect_Init(struct Task *task) LockPlayerFieldControls(); FreezeObjectEvents(); CameraObjectFreeze(); + EndORASDowsing(); task->data[15] = GetPlayerFacingDirection(); task->tState++; } diff --git a/src/field_effect_helpers.c b/src/field_effect_helpers.c index 66767882cd..f5f62a2367 100755 --- a/src/field_effect_helpers.c +++ b/src/field_effect_helpers.c @@ -1903,4 +1903,3 @@ static void UpdateGrassFieldEffectSubpriority(struct Sprite *sprite, u8 elevatio } } } - diff --git a/src/field_message_box.c b/src/field_message_box.c index a87745f76c..6cac521853 100755 --- a/src/field_message_box.c +++ b/src/field_message_box.c @@ -7,6 +7,7 @@ #include "field_message_box.h" #include "text_window.h" #include "script.h" +#include "field_name_box.h" static EWRAM_DATA u8 sFieldMessageBoxMode = 0; EWRAM_DATA u8 gWalkAwayFromSignpostTimer = 0; @@ -39,9 +40,14 @@ static void Task_DrawFieldMessage(u8 taskId) task->tState++; break; case 1: + { + u32 nameboxWinId = GetNameboxWindowId(); DrawDialogueFrame(0, TRUE); + if (nameboxWinId != WINDOW_NONE) + DrawNamebox(nameboxWinId, NAME_BOX_BASE_TILE_NUM - NAME_BOX_BASE_TILES_TOTAL, TRUE); task->tState++; break; + } case 2: if (RunTextPrintersAndIsPrinter0Active() != TRUE) { @@ -123,6 +129,7 @@ bool8 ShowFieldMessageFromBuffer(void) static void ExpandStringAndStartDrawFieldMessage(const u8 *str, bool32 allowSkippingDelayWithButtonPress) { + TrySpawnNamebox(NAME_BOX_BASE_TILE_NUM); StringExpandPlaceholders(gStringVar4, str); AddTextPrinterForMessage(allowSkippingDelayWithButtonPress); CreateTask_DrawFieldMessage(); @@ -138,6 +145,7 @@ void HideFieldMessageBox(void) { DestroyTask_DrawFieldMessage(); ClearDialogWindowAndFrame(0, TRUE); + DestroyNamebox(); sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN; } diff --git a/src/field_name_box.c b/src/field_name_box.c new file mode 100644 index 0000000000..4c51f89d85 --- /dev/null +++ b/src/field_name_box.c @@ -0,0 +1,201 @@ +#include "global.h" +#include "main.h" +#include "menu.h" +#include "bg.h" +#include "window.h" +#include "text.h" +#include "string_util.h" +#include "international_string_util.h" +#include "script_menu.h" +#include "field_message_box.h" +#include "graphics.h" +#include "script.h" +#include "field_name_box.h" +#include "event_data.h" +#include "match_call.h" +#include "malloc.h" +#include "constants/speaker_names.h" +#include "data/speaker_names.h" + +static EWRAM_INIT u8 sNameboxWindowId = WINDOW_NONE; +EWRAM_DATA const u8 *gSpeakerName = NULL; + +static const u32 sNameBoxDefaultGfx[] = INCBIN_U32("graphics/text_window/name_box.4bpp"); +static const u32 sNameBoxPokenavGfx[] = INCBIN_U32("graphics/pokenav/name_box.4bpp"); + +static void WindowFunc_DrawNamebox(u32, u32, u32, u32, u32, u32, u32); +static void WindowFunc_ClearNamebox(u8, u8, u8, u8, u8, u8); + +void TrySpawnNamebox(u32 tileNum) +{ + u8 *strbuf = AllocZeroed(32 * sizeof(u8)); + if ((OW_FLAG_SUPPRESS_NAME_BOX != 0 && FlagGet(OW_FLAG_SUPPRESS_NAME_BOX)) || gSpeakerName == NULL || !strbuf) + { + // Re-check again in case anything but !strbuf is TRUE. + if (strbuf) + Free(strbuf); + + DestroyNamebox(); + return; + } + + StringExpandPlaceholders(strbuf, gSpeakerName); + + u32 fontId = FONT_SMALL; + u32 winWidth = OW_NAME_BOX_DEFAULT_WIDTH; + + if (OW_NAME_BOX_USE_DYNAMIC_WIDTH) + { + winWidth = ConvertPixelWidthToTileWidth(GetStringWidth(fontId, strbuf, -1)); + if (winWidth > OW_NAME_BOX_DEFAULT_WIDTH) + winWidth = OW_NAME_BOX_DEFAULT_WIDTH; + } + + if (sNameboxWindowId != WINDOW_NONE) + { + DestroyNamebox(); + RedrawDialogueFrame(); + } + + bool32 matchCall = IsMatchCallTaskActive(); + + struct WindowTemplate template = + { + .bg = 0, + .tilemapLeft = 2, + .tilemapTop = 13, + .width = winWidth, + .height = OW_NAME_BOX_DEFAULT_HEIGHT, + .paletteNum = matchCall ? 14 : DLG_WINDOW_PALETTE_NUM, + .baseBlock = tileNum, + }; + + sNameboxWindowId = AddWindow(&template); + FillNamebox(); + + u8 colors[3] = {TEXT_COLOR_TRANSPARENT, OW_NAME_BOX_FOREGROUND_COLOR, OW_NAME_BOX_SHADOW_COLOR}; + u8 bakColors[3]; + int strX = GetStringCenterAlignXOffset(fontId, strbuf, (winWidth * 8)); + if (matchCall) + { + colors[1] = 1; + colors[2] = 0; + } + + SaveTextColors(&bakColors[0], &bakColors[1], &bakColors[2]); + AddTextPrinterParameterized3(sNameboxWindowId, fontId, strX, 0, colors, 0, strbuf); + RestoreTextColors(&bakColors[0], &bakColors[1], &bakColors[2]); + PutWindowTilemap(sNameboxWindowId); + Free(strbuf); +} + +u32 GetNameboxWindowId(void) +{ + return sNameboxWindowId; +} + +void ResetNameboxData(void) +{ + sNameboxWindowId = WINDOW_NONE; + gSpeakerName = NULL; +} + +void DestroyNamebox(void) +{ + if (sNameboxWindowId == WINDOW_NONE) + return; + + ClearNamebox(sNameboxWindowId, TRUE); + ClearWindowTilemap(sNameboxWindowId); + RemoveWindow(sNameboxWindowId); + sNameboxWindowId = WINDOW_NONE; + gSpeakerName = NULL; +} + +u32 GetNameboxWidth(void) +{ + return gWindows[sNameboxWindowId].window.width; +} + +static const u32 *GetNameboxGraphics(void) +{ + if (IsMatchCallTaskActive()) + return sNameBoxPokenavGfx; + else + return sNameBoxDefaultGfx; +} + +void FillNamebox(void) +{ + u32 winSize = GetNameboxWidth(); + const u32 *gfx = GetNameboxGraphics(); + + for (u32 i = 0; i < winSize; i++) + { + #define TILE(x) (8 * x) + CopyToWindowPixelBuffer(sNameboxWindowId, &gfx[TILE(1)], TILE_SIZE_4BPP, i); + CopyToWindowPixelBuffer(sNameboxWindowId, &gfx[TILE(4)], TILE_SIZE_4BPP, i + winSize); + #undef TILE + } +} + +void DrawNamebox(u32 windowId, u32 tileNum, bool32 copyToVram) +{ + // manual instead of using CallWindowFunction for extra tileNum param + struct WindowTemplate *w = &gWindows[windowId].window; + u32 size = TILE_OFFSET_4BPP(NAME_BOX_BASE_TILES_TOTAL); + + LoadBgTiles(GetWindowAttribute(sNameboxWindowId, WINDOW_BG), GetNameboxGraphics(), size, tileNum); + WindowFunc_DrawNamebox(w->bg, w->tilemapLeft, w->tilemapTop, w->width, w->height, w->paletteNum, tileNum); + PutWindowTilemap(windowId); + if (copyToVram == TRUE) + CopyWindowToVram(windowId, COPYWIN_FULL); +} + +void ClearNamebox(u32 windowId, bool32 copyToVram) +{ + CallWindowFunction(windowId, WindowFunc_ClearNamebox); + ClearWindowTilemap(windowId); + if (copyToVram == TRUE) + CopyWindowToVram(windowId, COPYWIN_FULL); +} + +static void WindowFunc_DrawNamebox(u32 bg, u32 L, u32 T, u32 w, u32 h, u32 p, u32 tileNum) +{ + // left-most + FillBgTilemapBufferRect(bg, tileNum, L - 1, T, 1, 1, p); + FillBgTilemapBufferRect(bg, tileNum + 3, L - 1, T + 1, 1, 1, p); + + // right-most + FillBgTilemapBufferRect(bg, tileNum + 2, L + w, T, 1, 1, p); + FillBgTilemapBufferRect(bg, tileNum + 5, L + w, T + 1, 1, 1, p); +} + +static void WindowFunc_ClearNamebox(u8 bg, u8 L, u8 T, u8 w, u8 h, u8 p) +{ + FillBgTilemapBufferRect(bg, 0, L - 1, T, w + 2, h, 0); // palette doesn't matter +} + +void SetSpeaker(struct ScriptContext *ctx) +{ + u32 arg = ScriptReadWord(ctx); + const u8 *speaker = NULL; + + if (arg < SP_NAME_COUNT) + speaker = gSpeakerNamesTable[arg]; + else if (arg >= ROM_START && arg < ROM_END) + speaker = (const u8 *)arg; + + gSpeakerName = speaker; +} + +// useful for other context e.g. match call +void TrySpawnAndShowNamebox(const u8 *speaker, u32 tileNum) +{ + gSpeakerName = speaker; + TrySpawnNamebox(tileNum); + if (sNameboxWindowId != WINDOW_NONE) + DrawNamebox(sNameboxWindowId, tileNum - NAME_BOX_BASE_TILES_TOTAL, TRUE); + else // either NULL or SP_NAME_NONE + RedrawDialogueFrame(); +} diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index aaf28a6dea..a46f292517 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -12,6 +12,7 @@ #include "follower_npc.h" #include "menu.h" #include "metatile_behavior.h" +#include "oras_dowse.h" #include "overworld.h" #include "party_menu.h" #include "random.h" @@ -146,40 +147,6 @@ static void CreateStopSurfingTask(u8); static void Task_StopSurfingInit(u8); static void Task_WaitStopSurfing(u8); -static void Task_Fishing(u8); -static bool32 Fishing_Init(struct Task *); -static bool32 Fishing_GetRodOut(struct Task *); -static bool32 Fishing_WaitBeforeDots(struct Task *); -static bool32 Fishing_InitDots(struct Task *); -static bool32 Fishing_ShowDots(struct Task *); -static bool32 Fishing_CheckForBite(struct Task *); -static bool32 Fishing_GotBite(struct Task *); -static bool32 Fishing_ChangeMinigame(struct Task *); -static bool32 Fishing_WaitForA(struct Task *); -static bool32 Fishing_APressNoMinigame(struct Task *); -static bool32 Fishing_CheckMoreDots(struct Task *); -static bool32 Fishing_MonOnHook(struct Task *); -static bool32 Fishing_StartEncounter(struct Task *); -static bool32 Fishing_NotEvenNibble(struct Task *); -static bool32 Fishing_GotAway(struct Task *); -static bool32 Fishing_NoMon(struct Task *); -static bool32 Fishing_PutRodAway(struct Task *); -static bool32 Fishing_EndNoMon(struct Task *); -static void AlignFishingAnimationFrames(void); -static bool32 DoesFishingMinigameAllowCancel(void); -static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void); -static bool32 Fishing_RollForBite(u32, bool32); -static u32 CalculateFishingBiteOdds(u32, bool32); -static u32 CalculateFishingFollowerBoost(void); -static u32 CalculateFishingProximityBoost(u32 odds); -static void GetCoordinatesAroundBobber(s16[], s16[][AXIS_COUNT], u32); -static u32 CountQualifyingTiles(s16[][AXIS_COUNT], s16 player[], u8 facingDirection, struct ObjectEvent *objectEvent, bool32 isTileLand[]); -static bool32 CheckTileQualification(s16 tile[], s16 player[], u32 facingDirection, struct ObjectEvent* objectEvent, bool32 isTileLand[], u32 direction); -static u32 CountLandTiles(bool32 isTileLand[]); -static bool32 IsPlayerHere(s16, s16, s16, s16); -static bool32 IsMetatileBlocking(s16, s16, u32); -static bool32 IsMetatileLand(s16, s16, u32); - static u8 TrySpinPlayerForWarp(struct ObjectEvent *, s16 *); static bool8 (*const sForcedMovementTestFuncs[NUM_FORCED_MOVEMENTS])(u8) = @@ -382,7 +349,7 @@ void PlayerStep(u8 direction, u16 newKeys, u16 heldKeys) DoPlayerAvatarTransition(); if (TryDoMetatileBehaviorForcedMovement() == 0) { - if (GetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT) != FALSE) + if (GetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT) != FNPC_FORCED_NONE) { gPlayerAvatar.preventStep = TRUE; CreateTask(Task_MoveNPCFollowerAfterForcedMovement, 1); @@ -397,6 +364,8 @@ void PlayerStep(u8 direction, u16 newKeys, u16 heldKeys) } } +#define sCounter data[3] + static bool8 TryInterruptObjectEventSpecialAnim(struct ObjectEvent *playerObjEvent, u8 direction) { if (ObjectEventIsMovementOverridden(playerObjEvent) @@ -405,6 +374,8 @@ static bool8 TryInterruptObjectEventSpecialAnim(struct ObjectEvent *playerObjEve u8 heldMovementActionId = ObjectEventGetHeldMovementActionId(playerObjEvent); if (heldMovementActionId > MOVEMENT_ACTION_WALK_FAST_RIGHT && heldMovementActionId < MOVEMENT_ACTION_WALK_IN_PLACE_NORMAL_DOWN) { + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + if (direction == DIR_NONE) { return TRUE; @@ -412,12 +383,21 @@ static bool8 TryInterruptObjectEventSpecialAnim(struct ObjectEvent *playerObjEve if (playerObjEvent->movementDirection != direction) { + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + gSprites[playerObj->fieldEffectSpriteId].sCounter = 0; + ObjectEventClearHeldMovement(playerObjEvent); return FALSE; } if (CheckForPlayerAvatarStaticCollision(direction) == COLLISION_NONE) { + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + { + gSprites[playerObj->fieldEffectSpriteId].sCounter = 0; + gSprites[playerObj->fieldEffectSpriteId].y2 = 0; + } + ObjectEventClearHeldMovement(playerObjEvent); return FALSE; } @@ -429,6 +409,8 @@ static bool8 TryInterruptObjectEventSpecialAnim(struct ObjectEvent *playerObjEve return FALSE; } +#undef sCounter + static void npc_clear_strange_bits(struct ObjectEvent *objEvent) { objEvent->inanimate = FALSE; @@ -519,7 +501,7 @@ static bool8 DoForcedMovement(u8 direction, void (*moveFunc)(u8)) { if (collision == COLLISION_LEDGE_JUMP) { - SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FALSE); + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FNPC_FORCED_NONE); PlayerJumpLedge(direction); } @@ -530,8 +512,8 @@ static bool8 DoForcedMovement(u8 direction, void (*moveFunc)(u8)) } else { - if (PlayerHasFollowerNPC()) - SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, TRUE); + if (PlayerHasFollowerNPC() && GetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT) != FNPC_FORCED_STAY) + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FNPC_FORCED_FOLLOW); playerAvatar->runningState = MOVING; moveFunc(direction); @@ -858,8 +840,12 @@ static void PlayerNotOnBikeMoving(u8 direction, u16 heldKeys) return; } - if (!(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_UNDERWATER) && (heldKeys & B_BUTTON) && FlagGet(FLAG_SYS_B_DASH) - && IsRunningDisallowed(gObjectEvents[gPlayerAvatar.objectEventId].currentMetatileBehavior) == 0 && !FollowerNPCComingThroughDoor()) + if (!(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_UNDERWATER) + && (heldKeys & B_BUTTON) + && FlagGet(FLAG_SYS_B_DASH) + && IsRunningDisallowed(gObjectEvents[gPlayerAvatar.objectEventId].currentMetatileBehavior) == 0 + && !FollowerNPCComingThroughDoor() + && (I_ORAS_DOWSING_FLAG == 0 || (I_ORAS_DOWSING_FLAG != 0 && !FlagGet(I_ORAS_DOWSING_FLAG)))) { if (ObjectMovingOnRockStairs(&gObjectEvents[gPlayerAvatar.objectEventId], direction)) PlayerRunSlow(direction); @@ -1660,12 +1646,14 @@ void SetPlayerInvisibility(bool8 invisible) void SetPlayerAvatarFieldMove(void) { + EndORASDowsing(); ObjectEventSetGraphicsId(&gObjectEvents[gPlayerAvatar.objectEventId], GetPlayerAvatarGraphicsIdByStateId(PLAYER_AVATAR_STATE_FIELD_MOVE)); StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], ANIM_FIELD_MOVE); } -static void SetPlayerAvatarFishing(u8 direction) +void SetPlayerAvatarFishing(u8 direction) { + EndORASDowsing(); ObjectEventSetGraphicsId(&gObjectEvents[gPlayerAvatar.objectEventId], GetPlayerAvatarGraphicsIdByStateId(PLAYER_AVATAR_STATE_FISHING)); StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingDirectionAnimNum(direction)); } @@ -1679,6 +1667,7 @@ void PlayerUseAcroBikeOnBumpySlope(u8 direction) void SetPlayerAvatarWatering(u8 direction) { + EndORASDowsing(); ObjectEventSetGraphicsId(&gObjectEvents[gPlayerAvatar.objectEventId], GetPlayerAvatarGraphicsIdByStateId(PLAYER_AVATAR_STATE_WATERING)); StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFaceDirectionAnimNum(direction)); } @@ -1934,644 +1923,6 @@ static void Task_WaitStopSurfing(u8 taskId) } } -#define tStep data[0] -#define tFrameCounter data[1] -#define tNumDots data[2] -#define tDotsRequired data[3] -#define tRoundsPlayed data[12] -#define tMinRoundsRequired data[13] -#define tPlayerGfxId data[14] -#define tFishingRod data[15] - -#define FISHING_PROXIMITY_BOOST 4 -#define FISHING_STICKY_BOOST 36 - -#if I_FISHING_BITE_ODDS >= GEN_4 - #define FISHING_OLD_ROD_ODDS 75 - #define FISHING_GOOD_ROD_ODDS 50 - #define FISHING_SUPER_ROD_ODDS 25 -#elif I_FISHING_BITE_ODDS >= GEN_3 - #define FISHING_OLD_ROD_ODDS 50 - #define FISHING_GOOD_ROD_ODDS 50 - #define FISHING_SUPER_ROD_ODDS 50 -#else - #define FISHING_OLD_ROD_ODDS 0 - #define FISHING_GOOD_ROD_ODDS 33 - #define FISHING_SUPER_ROD_ODDS 50 -#endif - -enum -{ - FISHING_INIT, - FISHING_GET_ROD_OUT, - FISHING_WAIT_BEFORE_DOTS, - FISHING_INIT_DOTS, - FISHING_SHOW_DOTS, - FISHING_CHECK_FOR_BITE, - FISHING_GOT_BITE, - FISHING_CHANGE_MINIGAME, - FISHING_WAIT_FOR_A, - FISHING_A_PRESS_NO_MINIGAME, - FISHING_CHECK_MORE_DOTS, - FISHING_MON_ON_HOOK, - FISHING_START_ENCOUNTER, - FISHING_NOT_EVEN_NIBBLE, - FISHING_GOT_AWAY, - FISHING_NO_MON, - FISHING_PUT_ROD_AWAY, - FISHING_END_NO_MON, -}; - -static bool32 (*const sFishingStateFuncs[])(struct Task *) = -{ - [FISHING_INIT] = Fishing_Init, - [FISHING_GET_ROD_OUT] = Fishing_GetRodOut, - [FISHING_WAIT_BEFORE_DOTS] = Fishing_WaitBeforeDots, - [FISHING_INIT_DOTS] = Fishing_InitDots, - [FISHING_SHOW_DOTS] = Fishing_ShowDots, - [FISHING_CHECK_FOR_BITE] = Fishing_CheckForBite, - [FISHING_GOT_BITE] = Fishing_GotBite, - [FISHING_CHANGE_MINIGAME] = Fishing_ChangeMinigame, - [FISHING_WAIT_FOR_A] = Fishing_WaitForA, - [FISHING_A_PRESS_NO_MINIGAME] = Fishing_APressNoMinigame, - [FISHING_CHECK_MORE_DOTS] = Fishing_CheckMoreDots, - [FISHING_MON_ON_HOOK] = Fishing_MonOnHook, - [FISHING_START_ENCOUNTER] = Fishing_StartEncounter, - [FISHING_NOT_EVEN_NIBBLE] = Fishing_NotEvenNibble, - [FISHING_GOT_AWAY] = Fishing_GotAway, - [FISHING_NO_MON] = Fishing_NoMon, - [FISHING_PUT_ROD_AWAY] = Fishing_PutRodAway, - [FISHING_END_NO_MON] = Fishing_EndNoMon, -}; - -void StartFishing(u8 rod) -{ - u8 taskId = CreateTask(Task_Fishing, 0xFF); - - gTasks[taskId].tFishingRod = rod; - Task_Fishing(taskId); -} - -static void Task_Fishing(u8 taskId) -{ - while (sFishingStateFuncs[gTasks[taskId].tStep](&gTasks[taskId])) - ; -} - -static bool32 Fishing_Init(struct Task *task) -{ - LockPlayerFieldControls(); - gPlayerAvatar.preventStep = TRUE; - task->tStep = FISHING_GET_ROD_OUT; - return FALSE; -} - -static bool32 Fishing_GetRodOut(struct Task *task) -{ - struct ObjectEvent *playerObjEvent; - const s16 minRounds1[] = { - [OLD_ROD] = 1, - [GOOD_ROD] = 1, - [SUPER_ROD] = 1 - }; - const s16 minRounds2[] = { - [OLD_ROD] = 1, - [GOOD_ROD] = 3, - [SUPER_ROD] = 6 - }; - - task->tRoundsPlayed = 0; - task->tMinRoundsRequired = minRounds1[task->tFishingRod] + (Random() % minRounds2[task->tFishingRod]); - task->tPlayerGfxId = gObjectEvents[gPlayerAvatar.objectEventId].graphicsId; - playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - ObjectEventClearHeldMovementIfActive(playerObjEvent); - playerObjEvent->enableAnim = TRUE; - SetPlayerAvatarFishing(playerObjEvent->facingDirection); - task->tStep = FISHING_WAIT_BEFORE_DOTS; - return FALSE; -} - -static bool32 Fishing_WaitBeforeDots(struct Task *task) -{ - AlignFishingAnimationFrames(); - - // Wait one second - task->tFrameCounter++; - if (task->tFrameCounter >= 60) - task->tStep = FISHING_INIT_DOTS; - return FALSE; -} - -static bool32 Fishing_InitDots(struct Task *task) -{ - u32 randVal; - - LoadMessageBoxAndFrameGfx(0, TRUE); - task->tStep = FISHING_SHOW_DOTS; - task->tFrameCounter = 0; - task->tNumDots = 0; - randVal = Random(); - randVal %= 10; - task->tDotsRequired = randVal + 1; - if (task->tRoundsPlayed == 0) - task->tDotsRequired = randVal + 4; - if (task->tDotsRequired >= 10) - task->tDotsRequired = 10; - return TRUE; -} - -static bool32 Fishing_ShowDots(struct Task *task) -{ - const u8 dot[] = _("·"); - - AlignFishingAnimationFrames(); - task->tFrameCounter++; - if (JOY_NEW(A_BUTTON)) - { - if (!DoesFishingMinigameAllowCancel()) - return FALSE; - - task->tStep = FISHING_NOT_EVEN_NIBBLE; - if (task->tRoundsPlayed != 0) - task->tStep = FISHING_GOT_AWAY; - return TRUE; - } - else - { - if (task->tFrameCounter >= 20) - { - task->tFrameCounter = 0; - if (task->tNumDots >= task->tDotsRequired) - { - task->tStep = FISHING_CHECK_FOR_BITE; - if (task->tRoundsPlayed != 0) - task->tStep = FISHING_GOT_BITE; - task->tRoundsPlayed++; - } - else - { - AddTextPrinterParameterized(0, FONT_NORMAL, dot, task->tNumDots * 8, 1, 0, NULL); - task->tNumDots++; - } - } - return FALSE; - } -} - -static bool32 Fishing_CheckForBite(struct Task *task) -{ - bool32 bite, firstMonHasSuctionOrSticky; - - AlignFishingAnimationFrames(); - task->tStep = FISHING_GOT_BITE; - bite = FALSE; - - if (!DoesCurrentMapHaveFishingMons()) - { - task->tStep = FISHING_NOT_EVEN_NIBBLE; - return TRUE; - } - - firstMonHasSuctionOrSticky = Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(); - - if(firstMonHasSuctionOrSticky) - bite = Fishing_RollForBite(task->tFishingRod, firstMonHasSuctionOrSticky); - - if (!bite) - bite = Fishing_RollForBite(task->tFishingRod, FALSE); - - if (!bite) - task->tStep = FISHING_NOT_EVEN_NIBBLE; - - if (bite) - StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingBiteDirectionAnimNum(GetPlayerFacingDirection())); - - return TRUE; -} - -static bool32 Fishing_GotBite(struct Task *task) -{ - AlignFishingAnimationFrames(); - AddTextPrinterParameterized(0, FONT_NORMAL, gText_OhABite, 0, 17, 0, NULL); - task->tStep = FISHING_CHANGE_MINIGAME; - task->tFrameCounter = 0; - return FALSE; -} - -static bool32 Fishing_ChangeMinigame(struct Task *task) -{ - switch (I_FISHING_MINIGAME) - { - case GEN_1: - case GEN_2: - task->tStep = FISHING_A_PRESS_NO_MINIGAME; - break; - case GEN_3: - default: - task->tStep = FISHING_WAIT_FOR_A; - break; - } - return TRUE; -} - -// We have a bite. Now, wait for the player to press A, or the timer to expire. -static bool32 Fishing_WaitForA(struct Task *task) -{ - const s16 reelTimeouts[3] = { - [OLD_ROD] = 36, - [GOOD_ROD] = 33, - [SUPER_ROD] = 30 - }; - - AlignFishingAnimationFrames(); - task->tFrameCounter++; - if (task->tFrameCounter >= reelTimeouts[task->tFishingRod]) - task->tStep = FISHING_GOT_AWAY; - else if (JOY_NEW(A_BUTTON)) - task->tStep = FISHING_CHECK_MORE_DOTS; - return FALSE; -} - -static bool32 Fishing_APressNoMinigame(struct Task *task) -{ - AlignFishingAnimationFrames(); - if (JOY_NEW(A_BUTTON)) - task->tStep = FISHING_MON_ON_HOOK; - return FALSE; -} - -// Determine if we're going to play the dot game again -static bool32 Fishing_CheckMoreDots(struct Task *task) -{ - const s16 moreDotsChance[][2] = - { - [OLD_ROD] = {0, 0}, - [GOOD_ROD] = {40, 10}, - [SUPER_ROD] = {70, 30} - }; - - AlignFishingAnimationFrames(); - task->tStep = FISHING_MON_ON_HOOK; - if (task->tRoundsPlayed < task->tMinRoundsRequired) - { - task->tStep = FISHING_INIT_DOTS; - } - else if (task->tRoundsPlayed < 2) - { - // probability of having to play another round - s16 probability = Random() % 100; - - if (moreDotsChance[task->tFishingRod][task->tRoundsPlayed] > probability) - task->tStep = FISHING_INIT_DOTS; - } - return FALSE; -} - -static bool32 Fishing_MonOnHook(struct Task *task) -{ - AlignFishingAnimationFrames(); - FillWindowPixelBuffer(0, PIXEL_FILL(1)); - AddTextPrinterParameterized2(0, FONT_NORMAL, gText_PokemonOnHook, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); - task->tStep = FISHING_START_ENCOUNTER; - task->tFrameCounter = 0; - return FALSE; -} - -static bool32 Fishing_StartEncounter(struct Task *task) -{ - if (task->tFrameCounter == 0) - AlignFishingAnimationFrames(); - - RunTextPrinters(); - - if (task->tFrameCounter == 0) - { - if (!IsTextPrinterActive(0)) - { - struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - - ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); - ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); - if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) - SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, FALSE, 0); - gSprites[gPlayerAvatar.spriteId].x2 = 0; - gSprites[gPlayerAvatar.spriteId].y2 = 0; - ClearDialogWindowAndFrame(0, TRUE); - task->tFrameCounter++; - return FALSE; - } - } - - if (task->tFrameCounter != 0) - { - gPlayerAvatar.preventStep = FALSE; - UnlockPlayerFieldControls(); - FishingWildEncounter(task->tFishingRod); - RecordFishingAttemptForTV(TRUE); - DestroyTask(FindTaskIdByFunc(Task_Fishing)); - } - return FALSE; -} - -static bool32 Fishing_NotEvenNibble(struct Task *task) -{ - gChainFishingDexNavStreak = 0; - AlignFishingAnimationFrames(); - StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); - FillWindowPixelBuffer(0, PIXEL_FILL(1)); - AddTextPrinterParameterized2(0, FONT_NORMAL, gText_NotEvenANibble, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); - task->tStep = FISHING_NO_MON; - return TRUE; -} - -static bool32 Fishing_GotAway(struct Task *task) -{ - gChainFishingDexNavStreak = 0; - AlignFishingAnimationFrames(); - StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); - FillWindowPixelBuffer(0, PIXEL_FILL(1)); - AddTextPrinterParameterized2(0, FONT_NORMAL, gText_ItGotAway, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); - task->tStep = FISHING_NO_MON; - return TRUE; -} - -static bool32 Fishing_NoMon(struct Task *task) -{ - AlignFishingAnimationFrames(); - task->tStep = FISHING_PUT_ROD_AWAY; - return FALSE; -} - -static bool32 Fishing_PutRodAway(struct Task *task) -{ - AlignFishingAnimationFrames(); - if (gSprites[gPlayerAvatar.spriteId].animEnded) - { - struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - - ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); - ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); - if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) - SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, FALSE, 0); - gSprites[gPlayerAvatar.spriteId].x2 = 0; - gSprites[gPlayerAvatar.spriteId].y2 = 0; - task->tStep = FISHING_END_NO_MON; - } - return FALSE; -} - -static bool32 Fishing_EndNoMon(struct Task *task) -{ - RunTextPrinters(); - if (!IsTextPrinterActive(0)) - { - gPlayerAvatar.preventStep = FALSE; - UnlockPlayerFieldControls(); - UnfreezeObjectEvents(); - ClearDialogWindowAndFrame(0, TRUE); - RecordFishingAttemptForTV(FALSE); - DestroyTask(FindTaskIdByFunc(Task_Fishing)); - } - return FALSE; -} - -static bool32 DoesFishingMinigameAllowCancel(void) -{ - switch(I_FISHING_MINIGAME) - { - case GEN_1: - case GEN_2: - return FALSE; - case GEN_3: - default: - return TRUE; - } -} - -static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void) -{ - u32 ability; - - if (GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) - return FALSE; - - ability = GetMonAbility(&gPlayerParty[0]); - - return (ability == ABILITY_SUCTION_CUPS || ability == ABILITY_STICKY_HOLD); -} - -static bool32 Fishing_RollForBite(u32 rod, bool32 isStickyHold) -{ - return ((Random() % 100) > CalculateFishingBiteOdds(rod, isStickyHold)); -} - -static u32 CalculateFishingBiteOdds(u32 rod, bool32 isStickyHold) -{ - u32 odds; - - if (rod == OLD_ROD) - odds = FISHING_OLD_ROD_ODDS; - if (rod == GOOD_ROD) - odds = FISHING_GOOD_ROD_ODDS; - if (rod == SUPER_ROD) - odds = FISHING_SUPER_ROD_ODDS; - - odds -= CalculateFishingFollowerBoost(); - - if (isStickyHold) - { - if (I_FISHING_STICKY_BOOST >= GEN_4) - odds -= (100 - odds); - else - odds -= FISHING_STICKY_BOOST; - } - - odds -= CalculateFishingProximityBoost(odds); - - return odds; -} - -static u32 CalculateFishingFollowerBoost() -{ - u32 friendship; - struct Pokemon *mon = GetFirstLiveMon(); - - if (!I_FISHING_FOLLOWER_BOOST || !mon) - return 0; - - friendship = GetMonData(mon, MON_DATA_FRIENDSHIP); - if (friendship >= 250) - return 50; - else if (friendship >= 200) - return 40; - else if (friendship >= 150) - return 30; - else if (friendship >= 100) - return 20; - else - return 0; -} - -static u32 CalculateFishingProximityBoost(u32 odds) -{ - s16 player[AXIS_COUNT], bobber[AXIS_COUNT]; - s16 surroundingTile[CARDINAL_DIRECTION_COUNT][AXIS_COUNT] = {{0, 0}}; - bool32 isTileLand[CARDINAL_DIRECTION_COUNT] = {FALSE}; - u32 facingDirection, numQualifyingTile = 0; - struct ObjectEvent *objectEvent; - - if (!I_FISHING_PROXIMITY) - return 0; - - objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; - - player[AXIS_X] = objectEvent->currentCoords.x; - player[AXIS_Y] = objectEvent->currentCoords.y; - bobber[AXIS_X] = objectEvent->currentCoords.x; - bobber[AXIS_Y] = objectEvent->currentCoords.y; - - facingDirection = GetPlayerFacingDirection(); - MoveCoords(facingDirection, &bobber[AXIS_X], &bobber[AXIS_Y]); - - GetCoordinatesAroundBobber(bobber, surroundingTile, facingDirection); - numQualifyingTile = CountQualifyingTiles(surroundingTile, player, facingDirection, objectEvent, isTileLand); - - numQualifyingTile += CountLandTiles(isTileLand); - - return (numQualifyingTile == 3) ? odds : (numQualifyingTile * FISHING_PROXIMITY_BOOST); -} - -static void GetCoordinatesAroundBobber(s16 bobber[], s16 surroundingTile[][AXIS_COUNT], u32 facingDirection) -{ - u32 direction; - - for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) - { - surroundingTile[direction][AXIS_X] = bobber[AXIS_X]; - surroundingTile[direction][AXIS_Y] = bobber[AXIS_Y]; - MoveCoords(direction, &surroundingTile[direction][AXIS_X], &surroundingTile[direction][AXIS_Y]); - } -} - -static u32 CountQualifyingTiles(s16 surroundingTile[][AXIS_COUNT], s16 player[], u8 facingDirection, struct ObjectEvent *objectEvent, bool32 isTileLand[]) -{ - u32 numQualifyingTile = 0; - s16 tile[AXIS_COUNT]; - u8 direction = DIR_SOUTH; - - for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) - { - tile[AXIS_X] = surroundingTile[direction][AXIS_X]; - tile[AXIS_Y] = surroundingTile[direction][AXIS_Y]; - - if (!CheckTileQualification(tile, player, facingDirection, objectEvent, isTileLand, direction)) - continue; - - numQualifyingTile++; - } - return numQualifyingTile; -} - -static bool32 CheckTileQualification(s16 tile[], s16 player[], u32 facingDirection, struct ObjectEvent* objectEvent, bool32 isTileLand[], u32 direction) -{ - u32 collison = GetCollisionAtCoords(objectEvent, tile[AXIS_X], tile[AXIS_Y], facingDirection); - - if (IsPlayerHere(tile[AXIS_X], tile[AXIS_Y], player[AXIS_X], player[AXIS_Y])) - return FALSE; - else if (IsMetatileBlocking(tile[AXIS_X], tile[AXIS_Y], collison)) - return TRUE; - else if (MetatileBehavior_IsSurfableFishableWater(MapGridGetMetatileBehaviorAt(tile[AXIS_X], tile[AXIS_Y]))) - return FALSE; - else if (IsMetatileLand(tile[AXIS_X], tile[AXIS_Y], collison)) - isTileLand[direction] = TRUE; - - return FALSE; -} - -static u32 CountLandTiles(bool32 isTileLand[]) -{ - u32 direction, numQualifyingTile = 0; - - for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) - if (isTileLand[direction]) - numQualifyingTile++; - - return (numQualifyingTile < 2) ? 0 : numQualifyingTile; -} - -static bool32 IsPlayerHere(s16 x, s16 y, s16 playerX, s16 playerY) -{ - return ((x == playerX) && (y == playerY)); -} - -static bool32 IsMetatileBlocking(s16 x, s16 y, u32 collison) -{ - switch(collison) - { - case COLLISION_NONE: - case COLLISION_STOP_SURFING: - case COLLISION_ELEVATION_MISMATCH: - return FALSE; - default: - return TRUE; - case COLLISION_OBJECT_EVENT: - return (gObjectEvents[GetObjectEventIdByXY(x,y)].inanimate); - } - return TRUE; -} - -static bool32 IsMetatileLand(s16 x, s16 y, u32 collison) -{ - switch(collison) - { - case COLLISION_NONE: - case COLLISION_STOP_SURFING: - case COLLISION_ELEVATION_MISMATCH: - return TRUE; - default: - return FALSE; - } -} - -#undef tStep -#undef tFrameCounter -#undef tFishingRod - -static void AlignFishingAnimationFrames(void) -{ - struct Sprite *playerSprite = &gSprites[gPlayerAvatar.spriteId]; - u8 animCmdIndex; - u8 animType; - - AnimateSprite(playerSprite); - playerSprite->x2 = 0; - playerSprite->y2 = 0; - animCmdIndex = playerSprite->animCmdIndex; - if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) - { - animCmdIndex--; - } - else - { - playerSprite->animDelayCounter++; - if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) - animCmdIndex--; - } - animType = playerSprite->anims[playerSprite->animNum][animCmdIndex].type; - if (animType == 1 || animType == 2 || animType == 3) - { - playerSprite->x2 = 8; - if (GetPlayerFacingDirection() == 3) - playerSprite->x2 = -8; - } - if (animType == 5) - playerSprite->y2 = -8; - if (animType == 10 || animType == 11) - playerSprite->y2 = 8; - if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) - SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, TRUE, playerSprite->y2); -} - void SetSpinStartFacingDir(u8 direction) { sSpinStartFacingDir = direction; diff --git a/src/field_screen_effect.c b/src/field_screen_effect.c index 74d2008ac9..2a3a5993d8 100644 --- a/src/field_screen_effect.c +++ b/src/field_screen_effect.c @@ -24,6 +24,7 @@ #include "mirage_tower.h" #include "metatile_behavior.h" #include "palette.h" +#include "oras_dowse.h" #include "overworld.h" #include "scanline_effect.h" #include "script.h" @@ -684,6 +685,7 @@ void Task_WarpAndLoadMap(u8 taskId) case 0: FreezeObjectEvents(); LockPlayerFieldControls(); + EndORASDowsing(); task->tState++; break; case 1: @@ -745,6 +747,7 @@ void Task_DoDoorWarp(u8 taskId) ObjectEventSetHeldMovement(followerObject, MOVEMENT_ACTION_ENTER_POKEBALL); } task->tDoorTask = FieldAnimateDoorOpen(*x, *y - 1); + EndORASDowsing(); task->tState = DOORWARP_START_WALK_UP; break; case DOORWARP_START_WALK_UP: diff --git a/src/field_special_scene.c b/src/field_special_scene.c index ccb15f02b4..6c66b50f8b 100644 --- a/src/field_special_scene.c +++ b/src/field_special_scene.c @@ -34,7 +34,7 @@ #define BOX3_Y_OFFSET 0 // porthole states -enum +enum PortholeState { INIT_PORTHOLE, IDLE_CHECK, @@ -300,7 +300,7 @@ void Task_HandlePorthole(u8 taskId) u16 *cruiseState = GetVarPointer(VAR_SS_TIDAL_STATE); struct WarpData *location = &gSaveBlock1Ptr->location; - switch (data[0]) + switch ((enum PortholeState)data[0]) { case INIT_PORTHOLE: // finish fading before making porthole finish. if (!gPaletteFade.active) diff --git a/src/field_specials.c b/src/field_specials.c index 9fc560916d..511f3282b5 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -123,14 +123,14 @@ static void Task_MoveElevator(u8); static void MoveElevatorWindowLights(u16, bool8); static void Task_MoveElevatorWindowLights(u8); static void Task_ShowScrollableMultichoice(u8); -static void FillFrontierExchangeCornerWindowAndItemIcon(u16, u16); -static void ShowBattleFrontierTutorWindow(u8, u16); +static void FillFrontierExchangeCornerWindowAndItemIcon(enum ScrollMulti, u16); +static void ShowBattleFrontierTutorWindow(enum ScrollMulti, u16); static void InitScrollableMultichoice(void); static void ScrollableMultichoice_ProcessInput(u8); static void ScrollableMultichoice_UpdateScrollArrows(u8); static void ScrollableMultichoice_MoveCursor(s32, bool8, struct ListMenu *); -static void HideFrontierExchangeCornerItemIcon(u16, u16); -static void ShowBattleFrontierTutorMoveDescription(u8, u16); +static void HideFrontierExchangeCornerItemIcon(enum ScrollMulti, u16); +static void ShowBattleFrontierTutorMoveDescription(enum ScrollMulti, u16); static void CloseScrollableMultichoice(u8); static void ScrollableMultichoice_RemoveScrollArrows(u8); static void Task_ScrollableMultichoice_WaitReturnToList(u8); @@ -315,10 +315,11 @@ bool32 CountSSTidalStep(u16 delta) return TRUE; } -u8 GetSSTidalLocation(s8 *mapGroup, s8 *mapNum, s16 *x, s16 *y) +enum SSTidalLocation GetSSTidalLocation(s8 *mapGroup, s8 *mapNum, s16 *x, s16 *y) { u16 *varCruiseStepCount = GetVarPointer(VAR_CRUISE_STEP_COUNT); - switch (*GetVarPointer(VAR_SS_TIDAL_STATE)) + + switch ((enum SSTidalState)(*GetVarPointer(VAR_SS_TIDAL_STATE))) { case SS_TIDAL_BOARD_SLATEPORT: case SS_TIDAL_LAND_SLATEPORT: @@ -1782,7 +1783,7 @@ static const u16 sElevatorWindowTiles_Descending[ELEVATOR_WINDOW_HEIGHT][ELEVATO void SetDeptStoreFloor(void) { - u8 deptStoreFloor; + enum DeptStoreFloorNumber deptStoreFloor; switch (gSaveBlock1Ptr->dynamicWarp.mapNum) { case MAP_NUM(MAP_LILYCOVE_CITY_DEPARTMENT_STORE_1F): @@ -2295,7 +2296,7 @@ void ShowScrollableMultichoice(void) struct Task *task = &gTasks[taskId]; task->tScrollMultiId = gSpecialVar_0x8004; - switch (gSpecialVar_0x8004) + switch ((enum ScrollMulti)gSpecialVar_0x8004) { case SCROLL_MULTI_NONE: task->tMaxItemsOnScreen = 1; @@ -2990,7 +2991,7 @@ void CloseFrontierExchangeCornerItemIconWindow(void) RemoveWindow(sFrontierExchangeCorner_ItemIconWindowId); } -static void FillFrontierExchangeCornerWindowAndItemIcon(u16 menu, u16 selection) +static void FillFrontierExchangeCornerWindowAndItemIcon(enum ScrollMulti menu, u16 selection) { #include "data/battle_frontier/battle_frontier_exchange_corner.h" @@ -3033,6 +3034,8 @@ static void FillFrontierExchangeCornerWindowAndItemIcon(u16 menu, u16 selection) AddTextPrinterParameterized2(0, FONT_NORMAL, sFrontierExchangeCorner_HoldItemsDescriptions[selection], 0, NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); ShowFrontierExchangeCornerItemIcon(sFrontierExchangeCorner_HoldItems[selection]); break; + default: + break; } } } @@ -3051,7 +3054,7 @@ static void ShowFrontierExchangeCornerItemIcon(u16 item) } } -static void HideFrontierExchangeCornerItemIcon(u16 menu, u16 unused) +static void HideFrontierExchangeCornerItemIcon(enum ScrollMulti menu, u16 unused) { if (sScrollableMultichoice_ItemSpriteId != MAX_SPRITES) { @@ -3064,6 +3067,8 @@ static void HideFrontierExchangeCornerItemIcon(u16 menu, u16 unused) // This makes sure deleting the icon will not clear palettes in use by object events FieldEffectFreeGraphicsResources(&gSprites[sScrollableMultichoice_ItemSpriteId]); break; + default: + break; } sScrollableMultichoice_ItemSpriteId = MAX_SPRITES; } @@ -3074,7 +3079,7 @@ void BufferBattleFrontierTutorMoveName(void) StringCopy(gStringVar1, GetMoveName(gSpecialVar_0x8005)); } -static void ShowBattleFrontierTutorWindow(u8 menu, u16 selection) +static void ShowBattleFrontierTutorWindow(enum ScrollMulti menu, u16 selection) { static const struct WindowTemplate sBattleFrontierTutor_WindowTemplate = { @@ -3098,7 +3103,7 @@ static void ShowBattleFrontierTutorWindow(u8 menu, u16 selection) } } -static void ShowBattleFrontierTutorMoveDescription(u8 menu, u16 selection) +static void ShowBattleFrontierTutorMoveDescription(enum ScrollMulti menu, u16 selection) { static const u8 *const sBattleFrontier_TutorMoveDescriptions1[] = { @@ -4369,3 +4374,9 @@ void SetHiddenNature(void) SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_HIDDEN_NATURE, &hiddenNature); CalculateMonStats(&gPlayerParty[gSpecialVar_0x8004]); } + +void SetAbility(void) +{ + u32 ability = gSpecialVar_Result; + SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_ABILITY_NUM, &ability); +} diff --git a/src/fishing.c b/src/fishing.c new file mode 100644 index 0000000000..7730351abb --- /dev/null +++ b/src/fishing.c @@ -0,0 +1,650 @@ +#include "global.h" +#include "main.h" +#include "event_object_movement.h" +#include "fieldmap.h" +#include "field_effect_helpers.h" +#include "field_player_avatar.h" +#include "menu.h" +#include "metatile_behavior.h" +#include "random.h" +#include "script.h" +#include "strings.h" +#include "task.h" +#include "text.h" +#include "tv.h" +#include "wild_encounter.h" +#include "config/fishing.h" + +static void Task_Fishing(u8); +static bool32 Fishing_Init(struct Task *); +static bool32 Fishing_GetRodOut(struct Task *); +static bool32 Fishing_WaitBeforeDots(struct Task *); +static bool32 Fishing_InitDots(struct Task *); +static bool32 Fishing_ShowDots(struct Task *); +static bool32 Fishing_CheckForBite(struct Task *); +static bool32 Fishing_GotBite(struct Task *); +static bool32 Fishing_ChangeMinigame(struct Task *); +static bool32 Fishing_WaitForA(struct Task *); +static bool32 Fishing_APressNoMinigame(struct Task *); +static bool32 Fishing_CheckMoreDots(struct Task *); +static bool32 Fishing_MonOnHook(struct Task *); +static bool32 Fishing_StartEncounter(struct Task *); +static bool32 Fishing_NotEvenNibble(struct Task *); +static bool32 Fishing_GotAway(struct Task *); +static bool32 Fishing_NoMon(struct Task *); +static bool32 Fishing_PutRodAway(struct Task *); +static bool32 Fishing_EndNoMon(struct Task *); +static void AlignFishingAnimationFrames(void); +static bool32 DoesFishingMinigameAllowCancel(void); +static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void); +static bool32 Fishing_RollForBite(u32, bool32); +static u32 CalculateFishingBiteOdds(u32, bool32); +static u32 CalculateFishingFollowerBoost(void); +static u32 CalculateFishingProximityBoost(void); +static u32 CalculateFishingTimeOfDayBoost(void); + +#define FISHING_PROXIMITY_BOOST 20 //Active if config I_FISHING_PROXIMITY is TRUE +#define FISHING_TIME_OF_DAY_BOOST 20 //Active if config I_FISHING_TIME_OF_DAY_BOOST is TRUE +#define FISHING_GEN3_STICKY_CHANCE 85 //Active if config I_FISHING_STICKY_BOOST is set to GEN_3 or lower + +#if I_FISHING_BITE_ODDS >= GEN_4 + #define FISHING_OLD_ROD_ODDS 25 + #define FISHING_GOOD_ROD_ODDS 50 + #define FISHING_SUPER_ROD_ODDS 75 +#elif I_FISHING_BITE_ODDS >= GEN_3 + #define FISHING_OLD_ROD_ODDS 50 + #define FISHING_GOOD_ROD_ODDS 50 + #define FISHING_SUPER_ROD_ODDS 50 +#else + #define FISHING_OLD_ROD_ODDS 100 + #define FISHING_GOOD_ROD_ODDS 33 + #define FISHING_SUPER_ROD_ODDS 50 +#endif + +struct FriendshipHookChanceBoost +{ + u8 threshold; + u8 bonus; +}; + +//Needs to be defined in descending order and end with the 0 friendship boost +//Active if config I_FISHING_FOLLOWER_BOOST is TRUE +static const struct FriendshipHookChanceBoost sFriendshipHookChanceBoostArray[] = +{ + {.threshold = 250, .bonus = 50}, + {.threshold = 200, .bonus = 40}, + {.threshold = 150, .bonus = 30}, + {.threshold = 100, .bonus = 20}, + {.threshold = 0, .bonus = 0}, +}; + +#define FISHING_CHAIN_SHINY_STREAK_MAX 20 + +enum +{ + FISHING_INIT, + FISHING_GET_ROD_OUT, + FISHING_WAIT_BEFORE_DOTS, + FISHING_INIT_DOTS, + FISHING_SHOW_DOTS, + FISHING_CHECK_FOR_BITE, + FISHING_GOT_BITE, + FISHING_CHANGE_MINIGAME, + FISHING_WAIT_FOR_A, + FISHING_A_PRESS_NO_MINIGAME, + FISHING_CHECK_MORE_DOTS, + FISHING_MON_ON_HOOK, + FISHING_START_ENCOUNTER, + FISHING_NOT_EVEN_NIBBLE, + FISHING_GOT_AWAY, + FISHING_NO_MON, + FISHING_PUT_ROD_AWAY, + FISHING_END_NO_MON, +}; + +static bool32 (*const sFishingStateFuncs[])(struct Task *) = +{ + [FISHING_INIT] = Fishing_Init, + [FISHING_GET_ROD_OUT] = Fishing_GetRodOut, + [FISHING_WAIT_BEFORE_DOTS] = Fishing_WaitBeforeDots, + [FISHING_INIT_DOTS] = Fishing_InitDots, + [FISHING_SHOW_DOTS] = Fishing_ShowDots, + [FISHING_CHECK_FOR_BITE] = Fishing_CheckForBite, + [FISHING_GOT_BITE] = Fishing_GotBite, + [FISHING_CHANGE_MINIGAME] = Fishing_ChangeMinigame, + [FISHING_WAIT_FOR_A] = Fishing_WaitForA, + [FISHING_A_PRESS_NO_MINIGAME] = Fishing_APressNoMinigame, + [FISHING_CHECK_MORE_DOTS] = Fishing_CheckMoreDots, + [FISHING_MON_ON_HOOK] = Fishing_MonOnHook, + [FISHING_START_ENCOUNTER] = Fishing_StartEncounter, + [FISHING_NOT_EVEN_NIBBLE] = Fishing_NotEvenNibble, + [FISHING_GOT_AWAY] = Fishing_GotAway, + [FISHING_NO_MON] = Fishing_NoMon, + [FISHING_PUT_ROD_AWAY] = Fishing_PutRodAway, + [FISHING_END_NO_MON] = Fishing_EndNoMon, +}; + +#define tStep data[0] +#define tFrameCounter data[1] +#define tNumDots data[2] +#define tDotsRequired data[3] +#define tRoundsPlayed data[12] +#define tMinRoundsRequired data[13] +#define tPlayerGfxId data[14] +#define tFishingRod data[15] + +void StartFishing(u8 rod) +{ + u8 taskId = CreateTask(Task_Fishing, 0xFF); + + gTasks[taskId].tFishingRod = rod; + Task_Fishing(taskId); +} + +static void Task_Fishing(u8 taskId) +{ + while (sFishingStateFuncs[gTasks[taskId].tStep](&gTasks[taskId])) + ; +} + +static bool32 Fishing_Init(struct Task *task) +{ + LockPlayerFieldControls(); + gPlayerAvatar.preventStep = TRUE; + task->tStep = FISHING_GET_ROD_OUT; + return FALSE; +} + +static bool32 Fishing_GetRodOut(struct Task *task) +{ + struct ObjectEvent *playerObjEvent; + const s16 minRounds1[] = { + [OLD_ROD] = 1, + [GOOD_ROD] = 1, + [SUPER_ROD] = 1 + }; + const s16 minRounds2[] = { + [OLD_ROD] = 1, + [GOOD_ROD] = 3, + [SUPER_ROD] = 6 + }; + + task->tRoundsPlayed = 0; + task->tMinRoundsRequired = minRounds1[task->tFishingRod] + (Random() % minRounds2[task->tFishingRod]); + task->tPlayerGfxId = gObjectEvents[gPlayerAvatar.objectEventId].graphicsId; + playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + ObjectEventClearHeldMovementIfActive(playerObjEvent); + playerObjEvent->enableAnim = TRUE; + SetPlayerAvatarFishing(playerObjEvent->facingDirection); + task->tStep = FISHING_WAIT_BEFORE_DOTS; + return FALSE; +} + +static bool32 Fishing_WaitBeforeDots(struct Task *task) +{ + AlignFishingAnimationFrames(); + + // Wait one second + task->tFrameCounter++; + if (task->tFrameCounter >= 60) + task->tStep = FISHING_INIT_DOTS; + return FALSE; +} + +static bool32 Fishing_InitDots(struct Task *task) +{ + u32 randVal; + + LoadMessageBoxAndFrameGfx(0, TRUE); + task->tStep = FISHING_SHOW_DOTS; + task->tFrameCounter = 0; + task->tNumDots = 0; + randVal = Random(); + randVal %= 10; + task->tDotsRequired = randVal + 1; + if (task->tRoundsPlayed == 0) + task->tDotsRequired = randVal + 4; + if (task->tDotsRequired >= 10) + task->tDotsRequired = 10; + return TRUE; +} + +static bool32 Fishing_ShowDots(struct Task *task) +{ + const u8 dot[] = _("·"); + + AlignFishingAnimationFrames(); + task->tFrameCounter++; + if (JOY_NEW(A_BUTTON)) + { + if (!DoesFishingMinigameAllowCancel()) + return FALSE; + + task->tStep = FISHING_NOT_EVEN_NIBBLE; + if (task->tRoundsPlayed != 0) + task->tStep = FISHING_GOT_AWAY; + return TRUE; + } + else + { + if (task->tFrameCounter >= 20) + { + task->tFrameCounter = 0; + if (task->tNumDots >= task->tDotsRequired) + { + task->tStep = FISHING_CHECK_FOR_BITE; + if (task->tRoundsPlayed != 0) + task->tStep = FISHING_GOT_BITE; + task->tRoundsPlayed++; + } + else + { + AddTextPrinterParameterized(0, FONT_NORMAL, dot, task->tNumDots * 8, 1, 0, NULL); + task->tNumDots++; + } + } + return FALSE; + } +} + +static bool32 Fishing_CheckForBite(struct Task *task) +{ + bool32 bite, firstMonHasSuctionOrSticky; + + AlignFishingAnimationFrames(); + task->tStep = FISHING_GOT_BITE; + bite = FALSE; + + if (!DoesCurrentMapHaveFishingMons()) + { + task->tStep = FISHING_NOT_EVEN_NIBBLE; + return TRUE; + } + + firstMonHasSuctionOrSticky = Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(); + + if(firstMonHasSuctionOrSticky && I_FISHING_STICKY_BOOST < GEN_4) + bite = RandomPercentage(RNG_FISHING_GEN3_STICKY, FISHING_GEN3_STICKY_CHANCE); + + if (!bite) + bite = Fishing_RollForBite(task->tFishingRod, firstMonHasSuctionOrSticky); + + if (!bite) + task->tStep = FISHING_NOT_EVEN_NIBBLE; + + if (bite) + StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingBiteDirectionAnimNum(GetPlayerFacingDirection())); + + return TRUE; +} + +static bool32 Fishing_GotBite(struct Task *task) +{ + AlignFishingAnimationFrames(); + AddTextPrinterParameterized(0, FONT_NORMAL, gText_OhABite, 0, 17, 0, NULL); + task->tStep = FISHING_CHANGE_MINIGAME; + task->tFrameCounter = 0; + return FALSE; +} + +static bool32 Fishing_ChangeMinigame(struct Task *task) +{ + switch (I_FISHING_MINIGAME) + { + case GEN_1: + case GEN_2: + task->tStep = FISHING_A_PRESS_NO_MINIGAME; + break; + case GEN_3: + default: + task->tStep = FISHING_WAIT_FOR_A; + break; + } + return TRUE; +} + +// We have a bite. Now, wait for the player to press A, or the timer to expire. +static bool32 Fishing_WaitForA(struct Task *task) +{ + const s16 reelTimeouts[3] = { + [OLD_ROD] = 36, + [GOOD_ROD] = 33, + [SUPER_ROD] = 30 + }; + + AlignFishingAnimationFrames(); + task->tFrameCounter++; + if (task->tFrameCounter >= reelTimeouts[task->tFishingRod]) + task->tStep = FISHING_GOT_AWAY; + else if (JOY_NEW(A_BUTTON)) + task->tStep = FISHING_CHECK_MORE_DOTS; + return FALSE; +} + +static bool32 Fishing_APressNoMinigame(struct Task *task) +{ + AlignFishingAnimationFrames(); + if (JOY_NEW(A_BUTTON)) + task->tStep = FISHING_MON_ON_HOOK; + return FALSE; +} + +// Determine if we're going to play the dot game again +static bool32 Fishing_CheckMoreDots(struct Task *task) +{ + const s16 moreDotsChance[][2] = + { + [OLD_ROD] = {0, 0}, + [GOOD_ROD] = {40, 10}, + [SUPER_ROD] = {70, 30} + }; + + AlignFishingAnimationFrames(); + task->tStep = FISHING_MON_ON_HOOK; + if (task->tRoundsPlayed < task->tMinRoundsRequired) + { + task->tStep = FISHING_INIT_DOTS; + } + else if (task->tRoundsPlayed < 2) + { + // probability of having to play another round + s16 probability = Random() % 100; + + if (moreDotsChance[task->tFishingRod][task->tRoundsPlayed] > probability) + task->tStep = FISHING_INIT_DOTS; + } + return FALSE; +} + +static bool32 Fishing_MonOnHook(struct Task *task) +{ + AlignFishingAnimationFrames(); + FillWindowPixelBuffer(0, PIXEL_FILL(1)); + AddTextPrinterParameterized2(0, FONT_NORMAL, gText_PokemonOnHook, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); + task->tStep = FISHING_START_ENCOUNTER; + task->tFrameCounter = 0; + return FALSE; +} + +static bool32 Fishing_StartEncounter(struct Task *task) +{ + if (task->tFrameCounter == 0) + AlignFishingAnimationFrames(); + + RunTextPrinters(); + + if (task->tFrameCounter == 0) + { + if (!IsTextPrinterActive(0)) + { + struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + + ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); + ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) + SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, FALSE, 0); + gSprites[gPlayerAvatar.spriteId].x2 = 0; + gSprites[gPlayerAvatar.spriteId].y2 = 0; + ClearDialogWindowAndFrame(0, TRUE); + task->tFrameCounter++; + return FALSE; + } + } + + if (task->tFrameCounter != 0) + { + gPlayerAvatar.preventStep = FALSE; + UnlockPlayerFieldControls(); + FishingWildEncounter(task->tFishingRod); + RecordFishingAttemptForTV(TRUE); + DestroyTask(FindTaskIdByFunc(Task_Fishing)); + } + return FALSE; +} + +static bool32 Fishing_NotEvenNibble(struct Task *task) +{ + gChainFishingDexNavStreak = 0; + AlignFishingAnimationFrames(); + StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); + FillWindowPixelBuffer(0, PIXEL_FILL(1)); + AddTextPrinterParameterized2(0, FONT_NORMAL, gText_NotEvenANibble, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); + task->tStep = FISHING_NO_MON; + return TRUE; +} + +static bool32 Fishing_GotAway(struct Task *task) +{ + gChainFishingDexNavStreak = 0; + AlignFishingAnimationFrames(); + StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFishingNoCatchDirectionAnimNum(GetPlayerFacingDirection())); + FillWindowPixelBuffer(0, PIXEL_FILL(1)); + AddTextPrinterParameterized2(0, FONT_NORMAL, gText_ItGotAway, 1, 0, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); + task->tStep = FISHING_NO_MON; + return TRUE; +} + +static bool32 Fishing_NoMon(struct Task *task) +{ + AlignFishingAnimationFrames(); + task->tStep = FISHING_PUT_ROD_AWAY; + return FALSE; +} + +static bool32 Fishing_PutRodAway(struct Task *task) +{ + AlignFishingAnimationFrames(); + if (gSprites[gPlayerAvatar.spriteId].animEnded) + { + struct ObjectEvent *playerObjEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + + ObjectEventSetGraphicsId(playerObjEvent, task->tPlayerGfxId); + ObjectEventTurn(playerObjEvent, playerObjEvent->movementDirection); + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) + SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, FALSE, 0); + gSprites[gPlayerAvatar.spriteId].x2 = 0; + gSprites[gPlayerAvatar.spriteId].y2 = 0; + task->tStep = FISHING_END_NO_MON; + } + return FALSE; +} + +static bool32 Fishing_EndNoMon(struct Task *task) +{ + RunTextPrinters(); + if (!IsTextPrinterActive(0)) + { + gPlayerAvatar.preventStep = FALSE; + UnlockPlayerFieldControls(); + UnfreezeObjectEvents(); + ClearDialogWindowAndFrame(0, TRUE); + RecordFishingAttemptForTV(FALSE); + DestroyTask(FindTaskIdByFunc(Task_Fishing)); + } + return FALSE; +} + +static bool32 DoesFishingMinigameAllowCancel(void) +{ + switch(I_FISHING_MINIGAME) + { + case GEN_1: + case GEN_2: + return FALSE; + case GEN_3: + default: + return TRUE; + } +} + +static bool32 Fishing_DoesFirstMonInPartyHaveSuctionCupsOrStickyHold(void) +{ + enum Ability ability; + + if (GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) + return FALSE; + + ability = GetMonAbility(&gPlayerParty[0]); + + return (ability == ABILITY_SUCTION_CUPS || ability == ABILITY_STICKY_HOLD); +} + +static bool32 Fishing_RollForBite(u32 rod, bool32 isStickyHold) +{ + return ((RandomUniform(RNG_FISHING_BITE, 1, 100)) <= CalculateFishingBiteOdds(rod, isStickyHold)); +} + +static u32 CalculateFishingBiteOdds(u32 rod, bool32 isStickyHold) +{ + u32 odds; + + if (rod == OLD_ROD) + odds = FISHING_OLD_ROD_ODDS; + if (rod == GOOD_ROD) + odds = FISHING_GOOD_ROD_ODDS; + if (rod == SUPER_ROD) + odds = FISHING_SUPER_ROD_ODDS; + + odds += CalculateFishingFollowerBoost(); + odds += CalculateFishingProximityBoost(); + odds += CalculateFishingTimeOfDayBoost(); + + if (isStickyHold && I_FISHING_STICKY_BOOST >= GEN_4) + odds *= 2; + + odds = min(100, odds); + DebugPrintf("Fishing odds: %d", odds); + return odds; +} + +static u32 CalculateFishingFollowerBoost() +{ + u32 friendship; + struct Pokemon *mon = GetFirstLiveMon(); + + if (!I_FISHING_FOLLOWER_BOOST || !mon) + return 0; + + friendship = GetMonData(mon, MON_DATA_FRIENDSHIP); + for (u32 i = 0;; i++) + { + if (friendship >= sFriendshipHookChanceBoostArray[i].threshold) + return sFriendshipHookChanceBoostArray[i].bonus; + } +} + +static u32 CalculateFishingProximityBoost() +{ + s16 bobber_x, bobber_y, tile_x, tile_y; + u32 direction, facingDirection, numQualifyingTile = 0; + struct ObjectEvent *objectEvent; + + if (!I_FISHING_PROXIMITY) + return 0; + + objectEvent = &gObjectEvents[gPlayerAvatar.objectEventId]; + + bobber_x = objectEvent->currentCoords.x; + bobber_y = objectEvent->currentCoords.y; + + facingDirection = GetPlayerFacingDirection(); + MoveCoords(facingDirection, &bobber_x, &bobber_y); + + numQualifyingTile = 0; + for (direction = DIR_SOUTH; direction < CARDINAL_DIRECTION_COUNT; direction++) + { + tile_x = bobber_x; + tile_y = bobber_y; + MoveCoords(direction, &tile_x, &tile_y); + if (tile_x == objectEvent->currentCoords.x && tile_y == objectEvent->currentCoords.y) + continue; + if (!MetatileBehavior_IsSurfableFishableWater(MapGridGetMetatileBehaviorAt(tile_x, tile_y))) + numQualifyingTile++; + else if (MapGridGetCollisionAt(tile_x, tile_y)) + numQualifyingTile++; + else if (GetMapBorderIdAt(tile_x, tile_y) == -1) + numQualifyingTile++; + } + + return (numQualifyingTile * FISHING_PROXIMITY_BOOST); +} + +static u32 CalculateFishingTimeOfDayBoost() +{ + if (!I_FISHING_TIME_OF_DAY_BOOST) + return 0; + + enum TimeOfDay timeOfDay = GetTimeOfDay(); + if (timeOfDay == TIME_MORNING || timeOfDay == TIME_EVENING) + return FISHING_TIME_OF_DAY_BOOST; + return 0; +} + +#undef tStep +#undef tFrameCounter +#undef tNumDots +#undef tDotsRequired +#undef tRoundsPlayed +#undef tMinRoundsRequired +#undef tPlayerGfxId +#undef tFishingRod + +static void AlignFishingAnimationFrames(void) +{ + struct Sprite *playerSprite = &gSprites[gPlayerAvatar.spriteId]; + u8 animCmdIndex; + u8 animType; + + AnimateSprite(playerSprite); + playerSprite->x2 = 0; + playerSprite->y2 = 0; + animCmdIndex = playerSprite->animCmdIndex; + if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) + { + animCmdIndex--; + } + else + { + playerSprite->animDelayCounter++; + if (playerSprite->anims[playerSprite->animNum][animCmdIndex].type == -1) + animCmdIndex--; + } + animType = playerSprite->anims[playerSprite->animNum][animCmdIndex].type; + if (animType == 1 || animType == 2 || animType == 3) + { + playerSprite->x2 = 8; + if (GetPlayerFacingDirection() == 3) + playerSprite->x2 = -8; + } + if (animType == 5) + playerSprite->y2 = -8; + if (animType == 10 || animType == 11) + playerSprite->y2 = 8; + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) + SetSurfBlob_PlayerOffset(gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId, TRUE, playerSprite->y2); +} + +void UpdateChainFishingStreak() +{ + if (!I_FISHING_CHAIN) + return; + + if (gChainFishingDexNavStreak == MAX_u8) + return; + + gChainFishingDexNavStreak++; +} + +u32 CalculateChainFishingShinyRolls(void) +{ + if (!I_FISHING_CHAIN || !gIsFishingEncounter) + return 0; + u32 a = 2 * min(gChainFishingDexNavStreak, FISHING_CHAIN_SHINY_STREAK_MAX); + DebugPrintf("Total Shiny Rolls %d", a); + return a; +} + +bool32 ShouldUseFishingEnvironmentInBattle() +{ + return (I_FISHING_ENVIRONMENT >= GEN_4 && gIsFishingEncounter); +} \ No newline at end of file diff --git a/src/fldeff_cut.c b/src/fldeff_cut.c index 4344186a54..a5f45ab29e 100644 --- a/src/fldeff_cut.c +++ b/src/fldeff_cut.c @@ -140,7 +140,7 @@ bool32 SetUpFieldMove_Cut(void) s16 x, y; u8 i, j; u8 tileBehavior; - u16 userAbility; + enum Ability userAbility; bool8 cutTiles[CUT_NORMAL_AREA]; bool8 ret; diff --git a/src/follower_npc.c b/src/follower_npc.c index 1833d555ab..2cca3186b3 100644 --- a/src/follower_npc.c +++ b/src/follower_npc.c @@ -4,6 +4,7 @@ #include "battle.h" #include "battle_setup.h" #include "battle_tower.h" +#include "bike.h" #include "event_data.h" #include "event_object_movement.h" #include "event_scripts.h" @@ -52,6 +53,8 @@ static void TurnNPCIntoFollower(u32 localId, u32 followerFlags, u32 setScript, c static u32 GetFollowerNPCSprite(void); static bool32 FollowerNPCHasRunningFrames(void); static bool32 IsStateMovement(u32 state); +static u32 GetNewPlayerMovementDirection(u32 state); +static bool32 IsPlayerForcedOntoSameTile(u8 metatileBehavior, u8 direction); static u32 GetPlayerFaceToDoorDirection(struct ObjectEvent *player, struct ObjectEvent *follower); static u32 ReturnFollowerNPCDelayedState(u32 direction); static void TryUpdateFollowerNPCSpriteUnderwater(void); @@ -351,6 +354,115 @@ static bool32 IsStateMovement(u32 state) return TRUE; } +// Because we want the NPC follower's movements to happen simultaneously with the player's, +// we need to set the follower's movement before the player object's movementDirection parameter gets set. +// This function allows us to determine the player's new movement direction before it gets set. +static u32 GetNewPlayerMovementDirection(u32 state) +{ + switch (state) + { + case MOVEMENT_ACTION_WALK_SLOW_DOWN: + case MOVEMENT_ACTION_WALK_NORMAL_DOWN: + case MOVEMENT_ACTION_WALK_FAST_DOWN: + case MOVEMENT_ACTION_WALK_FASTER_DOWN: + case MOVEMENT_ACTION_PLAYER_RUN_DOWN: + case MOVEMENT_ACTION_ACRO_WHEELIE_HOP_DOWN: + case MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_DOWN: + case MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_DOWN: + case MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_DOWN: + case MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_DOWN: + case MOVEMENT_ACTION_RIDE_WATER_CURRENT_DOWN: + case MOVEMENT_ACTION_JUMP_DOWN: + return DIR_SOUTH; + case MOVEMENT_ACTION_WALK_SLOW_UP: + case MOVEMENT_ACTION_WALK_NORMAL_UP: + case MOVEMENT_ACTION_WALK_FAST_UP: + case MOVEMENT_ACTION_WALK_FASTER_UP: + case MOVEMENT_ACTION_PLAYER_RUN_UP: + case MOVEMENT_ACTION_ACRO_WHEELIE_HOP_UP: + case MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_UP: + case MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_UP: + case MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_UP: + case MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_UP: + case MOVEMENT_ACTION_RIDE_WATER_CURRENT_UP: + case MOVEMENT_ACTION_JUMP_UP: + return DIR_NORTH; + case MOVEMENT_ACTION_WALK_SLOW_LEFT: + case MOVEMENT_ACTION_WALK_NORMAL_LEFT: + case MOVEMENT_ACTION_WALK_FAST_LEFT: + case MOVEMENT_ACTION_WALK_FASTER_LEFT: + case MOVEMENT_ACTION_PLAYER_RUN_LEFT: + case MOVEMENT_ACTION_ACRO_WHEELIE_HOP_LEFT: + case MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_LEFT: + case MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_LEFT: + case MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_LEFT: + case MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_LEFT: + case MOVEMENT_ACTION_RIDE_WATER_CURRENT_LEFT: + case MOVEMENT_ACTION_JUMP_LEFT: + return DIR_WEST; + case MOVEMENT_ACTION_WALK_SLOW_RIGHT: + case MOVEMENT_ACTION_WALK_NORMAL_RIGHT: + case MOVEMENT_ACTION_WALK_FAST_RIGHT: + case MOVEMENT_ACTION_WALK_FASTER_RIGHT: + case MOVEMENT_ACTION_PLAYER_RUN_RIGHT: + case MOVEMENT_ACTION_ACRO_WHEELIE_HOP_RIGHT: + case MOVEMENT_ACTION_ACRO_WHEELIE_JUMP_RIGHT: + case MOVEMENT_ACTION_ACRO_POP_WHEELIE_MOVE_RIGHT: + case MOVEMENT_ACTION_ACRO_WHEELIE_MOVE_RIGHT: + case MOVEMENT_ACTION_ACRO_END_WHEELIE_MOVE_RIGHT: + case MOVEMENT_ACTION_RIDE_WATER_CURRENT_RIGHT: + case MOVEMENT_ACTION_JUMP_RIGHT: + return DIR_EAST; + default: + return DIR_NONE; + } +} + +static bool32 IsPlayerForcedOntoSameTile(u8 metatileBehavior, u8 direction) +{ + u8 oppositeDirection = DIR_NONE; + + switch (metatileBehavior) + { + case MB_WALK_EAST: + case MB_SLIDE_EAST: + case MB_EASTWARD_CURRENT: + oppositeDirection = DIR_WEST; + break; + case MB_WALK_WEST: + case MB_SLIDE_WEST: + case MB_WESTWARD_CURRENT: + oppositeDirection = DIR_EAST; + break; + case MB_WALK_NORTH: + case MB_SLIDE_NORTH: + case MB_NORTHWARD_CURRENT: + oppositeDirection = DIR_SOUTH; + break; + case MB_WALK_SOUTH: + case MB_SLIDE_SOUTH: + case MB_SOUTHWARD_CURRENT: + case MB_MUDDY_SLOPE: + case MB_WATERFALL: + oppositeDirection = DIR_NORTH; + break; + default: + return FALSE; + } + + if (oppositeDirection == direction) + return TRUE; + + return FALSE; +} + +void GetXYCoordsPlayerMovementDest(u32 direction, s16 *x, s16 *y) +{ + *x = gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.x; + *y = gObjectEvents[gPlayerAvatar.objectEventId].currentCoords.y; + MoveCoords(direction, x, y); +} + static u32 GetPlayerFaceToDoorDirection(struct ObjectEvent *player, struct ObjectEvent *follower) { s32 delta_x = player->currentCoords.x - follower->currentCoords.x; @@ -760,6 +872,9 @@ u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direc u32 nextBehavior; u32 noSpecialAnimFrames = (GetFollowerNPCSprite() == GetFollowerNPCData(FNPC_DATA_GFX_ID)); u32 delayedState = GetFollowerNPCData(FNPC_DATA_DELAYED_STATE); + s16 playerDestX, playerDestY; + u32 playerMoveDirection = GetNewPlayerMovementDirection(state); + u32 newPlayerMB; MoveCoords(direction, &followerX, &followerY); nextBehavior = MapGridGetMetatileBehaviorAt(followerX, followerY); @@ -769,6 +884,24 @@ u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direc if (!IsStateMovement(state) && delayedState) return MOVEMENT_ACTION_NONE; + // Follower won't move if player is forced back onto the same tile. + if (GetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT) == FNPC_FORCED_STAY) + return MOVEMENT_ACTION_NONE; + + GetXYCoordsPlayerMovementDest(playerMoveDirection, &playerDestX, &playerDestY); + newPlayerMB = MapGridGetMetatileBehaviorAt(playerDestX, playerDestY); + + if (IsPlayerForcedOntoSameTile(newPlayerMB, playerMoveDirection) + && !(gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_MACH_BIKE && playerMoveDirection == DIR_NORTH && newPlayerMB == MB_MUDDY_SLOPE && GetPlayerSpeed() >= PLAYER_SPEED_FAST)) + { + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FNPC_FORCED_STAY); + SetFollowerNPCData(FNPC_DATA_DELAYED_STATE, 0); + if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_ON_FOOT) + ObjectEventSetHeldMovement(follower, GetFaceDirectionAnimNum(follower->facingDirection)); + + return MOVEMENT_INVALID; + } + if (IsStateMovement(state) && delayedState) { // Lock face direction for Acro side jump. @@ -1592,25 +1725,40 @@ void Task_MoveNPCFollowerAfterForcedMovement(u8 taskId) struct ObjectEvent *follower = &gObjectEvents[GetFollowerNPCObjectId()]; struct ObjectEvent *player = &gObjectEvents[gPlayerAvatar.objectEventId]; - // The NPC will take an extra step and be on the same tile as the player. - if (gTasks[taskId].tState == NPC_INTO_PLAYER && ObjectEventClearHeldMovementIfFinished(player) != 0 && ObjectEventClearHeldMovementIfFinished(follower) != 0) + // If follower moved during player's forced momvements. + if (GetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT) == FNPC_FORCED_FOLLOW) { - if (follower->currentMetatileBehavior == MB_MUDDY_SLOPE) - follower->facingDirectionLocked = TRUE; + // The NPC will take an extra step and be on the same tile as the player. + if (gTasks[taskId].tState == NPC_INTO_PLAYER && ObjectEventClearHeldMovementIfFinished(player) != 0 && ObjectEventClearHeldMovementIfFinished(follower) != 0) + { + if (follower->currentMetatileBehavior == MB_MUDDY_SLOPE) + follower->facingDirectionLocked = TRUE; - ObjectEventSetHeldMovement(follower, GetWalkFastMovementAction(DetermineFollowerNPCDirection(player, follower))); - gTasks[taskId].tState = ENABLE_PLAYER_STEP; - return; + ObjectEventSetHeldMovement(follower, GetWalkFastMovementAction(DetermineFollowerNPCDirection(player, follower))); + gTasks[taskId].tState = ENABLE_PLAYER_STEP; + return; + } + // Hide the NPC until the player takes a step. Reallow player input. + else if (gTasks[taskId].tState == ENABLE_PLAYER_STEP && ObjectEventClearHeldMovementIfFinished(follower) != 0) + { + follower->facingDirectionLocked = FALSE; + HideNPCFollower(); + SetFollowerNPCData(FNPC_DATA_WARP_END, FNPC_WARP_REAPPEAR); + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FNPC_FORCED_NONE); + gPlayerAvatar.preventStep = FALSE; + DestroyTask(taskId); + } } - // Hide the NPC until the player takes a step. Reallow player input. - else if (gTasks[taskId].tState == ENABLE_PLAYER_STEP && ObjectEventClearHeldMovementIfFinished(follower) != 0) + // If player was forced back onto the same tile. + else if (GetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT) == FNPC_FORCED_STAY) { - follower->facingDirectionLocked = FALSE; - HideNPCFollower(); - SetFollowerNPCData(FNPC_DATA_WARP_END, FNPC_WARP_REAPPEAR); - SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FALSE); - gPlayerAvatar.preventStep = FALSE; - DestroyTask(taskId); + if (ObjectEventClearHeldMovementIfFinished(player) != 0) + { + SetFollowerNPCData(FNPC_DATA_FORCED_MOVEMENT, FNPC_FORCED_NONE); + SetFollowerNPCData(FNPC_DATA_DELAYED_STATE, 0); + gPlayerAvatar.preventStep = FALSE; + DestroyTask(taskId); + } } } diff --git a/src/frontier_util.c b/src/frontier_util.c index 8fcf1221f3..50f0c67167 100644 --- a/src/frontier_util.c +++ b/src/frontier_util.c @@ -38,6 +38,7 @@ #include "constants/items.h" #include "constants/event_objects.h" #include "party_menu.h" +#include "list_menu.h" struct FrontierBrainMon { @@ -93,6 +94,9 @@ static void ShowArenaResultsWindow(void); static void ShowPyramidResultsWindow(void); static void ShowLinkContestResultsWindow(void); static void CopyFrontierBrainText(bool8 playerWonText); +static u16 *MakeCaughtBannesSpeciesList(u32 totalBannedSpecies); +static void PrintBannedSpeciesName(u8 windowId, u32 itemId, u8 y); +static void Task_BannedSpeciesWindowInput(u8 taskId); // battledBit: Flags to change the conversation when the Frontier Brain is encountered for a battle // First bit is has battled them before and not won yet, second bit is has battled them and won (obtained a Symbol) @@ -784,6 +788,58 @@ static const u8 *const sHallFacilityToRecordsText[] = [RANKING_HALL_TOWER_LINK] = gText_FrontierFacilityWinStreak, }; + +#define BANNED_SPECIES_SHOWN 6 + +static const struct ListMenuTemplate sCaughtBannedSpeciesListTemplate = +{ + .items = NULL, + .isDynamic = TRUE, + .moveCursorFunc = ListMenuDefaultCursorMoveFunc, + .itemPrintFunc = PrintBannedSpeciesName, + .maxShowed = BANNED_SPECIES_SHOWN, + .header_X = 0, + .item_X = 8, + .cursor_X = 0, + .upText_Y = 1, + .cursorPal = 2, + .fillValue = 1, + .cursorShadowPal = 3, + .lettersSpacing = 1, + .itemVerticalPadding = 0, + .scrollMultiple = LIST_NO_MULTIPLE_SCROLL, + .fontId = FONT_NORMAL, + .cursorKind = 0 +}; + +static const struct WindowTemplate sBannedSpeciesWindowTemplateMain = +{ + .bg = 0, + .tilemapLeft = 1, + .tilemapTop = 1, + .width = 12, + .height = 2 * BANNED_SPECIES_SHOWN, + .paletteNum = 15, + .baseBlock = 1, +}; + +#define TAG_LIST_ARROWS 5425 + +static const struct ScrollArrowsTemplate sCaughtBannedSpeciesScrollArrowsTemplate = +{ + .firstArrowType = SCROLL_ARROW_UP, + .firstX = 56, + .firstY = 8, + .secondArrowType = SCROLL_ARROW_DOWN, + .secondX = 56, + .secondY = 104, + .fullyUpThreshold = 0, + .fullyDownThreshold = 0, + .tileTag = TAG_LIST_ARROWS, + .palTag = TAG_LIST_ARROWS, + .palNum = 0, +}; + // code void CallFrontierUtilFunc(void) { @@ -1943,21 +1999,18 @@ static void CheckBattleTypeFlag(void) gSpecialVar_Result = FALSE; } -#define SPECIES_PER_LINE 3 - static void AppendCaughtBannedMonSpeciesName(u16 species, u8 count, s32 numBannedMonsCaught) { - if (numBannedMonsCaught == count) + if (count == 1) + ; + else if (numBannedMonsCaught == count) StringAppend(gStringVar1, gText_SpaceAndSpace); else if (numBannedMonsCaught > count) StringAppend(gStringVar1, gText_CommaSpace); - if ((count % SPECIES_PER_LINE) == 0) - { - if (count == SPECIES_PER_LINE) - StringAppend(gStringVar1, gText_NewLine); - else - StringAppend(gStringVar1, gText_LineBreak); - } + if (count == 3) + StringAppend(gStringVar1, gText_NewLine2); + else if (count == 6) + StringAppend(gStringVar1, gText_LineBreak); StringAppend(gStringVar1, GetSpeciesName(species)); } @@ -2053,46 +2106,60 @@ static void CheckPartyIneligibility(void) if (numEligibleMons < toChoose) { - u32 i; + u32 i, j; u32 baseSpecies = 0; u32 totalCaughtBanned = 0; - u32 caughtBanned[100] = {0}; + u32 totalPartyBanned = 0; + u32 partyBanned[PARTY_SIZE] = {0}; for (i = 0; i < NUM_SPECIES; i++) { - if (totalCaughtBanned >= ARRAY_COUNT(caughtBanned)) - break; baseSpecies = GET_BASE_SPECIES_ID(i); - if (baseSpecies == i) + if (baseSpecies == i && gSpeciesInfo[baseSpecies].isFrontierBanned) { - if (gSpeciesInfo[baseSpecies].isFrontierBanned) + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(baseSpecies), FLAG_GET_CAUGHT)) + totalCaughtBanned++; + } + } + + for (i = 0; i < PARTY_SIZE; i++) + { + u16 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG); + if (species == SPECIES_EGG || species == SPECIES_NONE) + continue; + if (gSpeciesInfo[GET_BASE_SPECIES_ID(species)].isFrontierBanned) + { + bool32 addToList = TRUE; + for (j = 0; j < totalPartyBanned; j++) + if (partyBanned[j] == species) + addToList = FALSE; + if (addToList) { - if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(baseSpecies), FLAG_GET_CAUGHT)) - { - caughtBanned[totalCaughtBanned] = baseSpecies; - totalCaughtBanned++; - } + partyBanned[totalPartyBanned] = species; + totalPartyBanned++; } } } + gStringVar1[0] = EOS; gSpecialVar_0x8004 = TRUE; - for (i = 0; i < totalCaughtBanned; i++) - AppendCaughtBannedMonSpeciesName(caughtBanned[i], i+1, totalCaughtBanned); - if (totalCaughtBanned == 0) { - StringAppend(gStringVar1, gText_Space2); - StringAppend(gStringVar1, gText_Are); + StringAppend(gStringVar1, gText_FrontierFacilityAreInelegible); } else { - if (totalCaughtBanned % SPECIES_PER_LINE == SPECIES_PER_LINE - 1) - StringAppend(gStringVar1, gText_LineBreak); - else - StringAppend(gStringVar1, gText_Space2); - StringAppend(gStringVar1, gText_Are2); + ConvertIntToDecimalStringN(gStringVar2, totalCaughtBanned, STR_CONV_MODE_LEFT_ALIGN, 3); + StringExpandPlaceholders(gStringVar4, gText_FrontierFacilityTotalCaughtSpeciesBanned); + StringAppend(gStringVar1, gStringVar4); } + if (totalPartyBanned > 0) + { + StringAppend(gStringVar1, gText_FrontierFacilityIncluding); + for (i = 0; i < totalPartyBanned; i++) + AppendCaughtBannedMonSpeciesName(partyBanned[i], i+1, totalPartyBanned); + } + gSpecialVar_0x8005 = totalCaughtBanned; } else { @@ -2102,8 +2169,6 @@ static void CheckPartyIneligibility(void) #undef numEligibleMons } -#undef SPECIES_PER_LINE - static void ValidateVisitingTrainer(void) { ValidateEReaderTrainer(); @@ -2649,3 +2714,98 @@ void ClearEnemyPartyAfterChallenge() ZeroEnemyPartyMons(); } } + +#define tWindowId data[0] +#define tMenuTaskId data[1] +#define tArrowTaskId data[2] +#define tScrollOffset data[3] +#define tListPointerElemId 4 + +static u16 *MakeCaughtBannesSpeciesList(u32 totalBannedSpecies) +{ + u32 count = 0; + u16 *list = AllocZeroed(sizeof(u16) * totalBannedSpecies); + for (u32 i = 0; i < NUM_SPECIES; i++) + { + u32 baseSpecies = GET_BASE_SPECIES_ID(i); + if (baseSpecies == i && gSpeciesInfo[baseSpecies].isFrontierBanned) + { + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(baseSpecies), FLAG_GET_CAUGHT)) + { + list[count] = i; + count++; + } + } + } + return list; +} + +static void PrintBannedSpeciesName(u8 windowId, u32 itemId, u8 y) +{ + u8 colors[3] = { + sCaughtBannedSpeciesListTemplate.fillValue, + sCaughtBannedSpeciesListTemplate.cursorPal, + sCaughtBannedSpeciesListTemplate.cursorShadowPal + }; + u16 *list = (u16 *) GetWordTaskArg(gSpecialVar_0x8006, tListPointerElemId); + AddTextPrinterParameterized4(windowId, + sCaughtBannedSpeciesListTemplate.fontId, + sCaughtBannedSpeciesListTemplate.item_X, y, + sCaughtBannedSpeciesListTemplate.lettersSpacing, 0, colors, TEXT_SKIP_DRAW, + GetSpeciesName(list[itemId])); +} + +void ShowBattleFrontierCaughtBannedSpecies(void) +{ + u8 windowId; + struct ListMenuTemplate listTemplate = sCaughtBannedSpeciesListTemplate; + u32 totalCaughtBanned = gSpecialVar_0x8005; + listTemplate.totalItems = totalCaughtBanned; + + // create window + LoadMessageBoxAndBorderGfx(); + windowId = AddWindow(&sBannedSpeciesWindowTemplateMain); + DrawStdWindowFrame(windowId, FALSE); + listTemplate.windowId = windowId; + + u16 *listItems = MakeCaughtBannesSpeciesList(totalCaughtBanned); + u32 inputTaskId = CreateTask(Task_BannedSpeciesWindowInput, 3); + gTasks[inputTaskId].tWindowId = windowId; + gSpecialVar_0x8006 = inputTaskId; + SetWordTaskArg(inputTaskId, tListPointerElemId, (u32)listItems); + u32 menuTaskId = ListMenuInit(&listTemplate, 0, 0); + gTasks[inputTaskId].tMenuTaskId = menuTaskId; + gTasks[inputTaskId].tArrowTaskId = TASK_NONE; + if (listTemplate.totalItems > listTemplate.maxShowed) + { + gTempScrollArrowTemplate = sCaughtBannedSpeciesScrollArrowsTemplate; + gTempScrollArrowTemplate.fullyDownThreshold = listTemplate.totalItems - listTemplate.maxShowed; + gTasks[inputTaskId].tArrowTaskId = AddScrollIndicatorArrowPair(&gTempScrollArrowTemplate, (u16 *)&gTasks[inputTaskId].tScrollOffset); + } + + // draw everything + CopyWindowToVram(windowId, COPYWIN_FULL); +} + +static void Task_BannedSpeciesWindowInput(u8 taskId) +{ + ListMenu_ProcessInput(gTasks[taskId].tMenuTaskId); + ListMenuGetScrollAndRow(gTasks[taskId].tMenuTaskId, (u16 *)&gTasks[taskId].tScrollOffset, NULL); + if (JOY_NEW(B_BUTTON)) + { + ScriptContext_Enable(); + if (gTasks[taskId].tArrowTaskId < TASK_NONE) + RemoveScrollIndicatorArrowPair(gTasks[taskId].tArrowTaskId); + Free((struct ListItem *)(GetWordTaskArg(taskId, tListPointerElemId))); + DestroyListMenuTask(gTasks[taskId].tMenuTaskId, NULL, NULL); + ClearStdWindowAndFrame(gTasks[taskId].tWindowId, TRUE); + RemoveWindow(gTasks[taskId].tWindowId); + DestroyTask(taskId); + } +} + +#undef tWindowId +#undef tMenuTaskId +#undef tArrowTaskId +#undef tScrollOffset +#undef tListPointerElemId diff --git a/src/international_string_util.c b/src/international_string_util.c index feba03c97f..b5a904c773 100644 --- a/src/international_string_util.c +++ b/src/international_string_util.c @@ -220,7 +220,7 @@ void FillWindowTilesByRow(int windowId, int columnStart, int rowStart, int numFi fillSize = numFillTiles * TILE_SIZE_4BPP; windowRowSize = window->window.width * TILE_SIZE_4BPP; - windowTileData = window->tileData + (rowStart * windowRowSize) + (columnStart * TILE_SIZE_4BPP); + windowTileData = (u8 *)window->tileData + (rowStart * windowRowSize) + (columnStart * TILE_SIZE_4BPP); if (numRows > 0) { for (i = numRows; i != 0; i--) diff --git a/src/item.c b/src/item.c index 5bfc59c68f..c3e4f23a83 100644 --- a/src/item.c +++ b/src/item.c @@ -88,6 +88,19 @@ static inline void NONNULL BagPocket_SetSlotDataPC(struct BagPocket *pocket, u32 pocket->itemSlots[pocketPos].quantity = newSlot.quantity; } +enum TMHMItemId GetTMHMItemIdFromMoveId(u16 move) +{ + if (move == MOVE_NONE) + return 0; + + for (u16 i = 0; i < NUM_ALL_MACHINES; i++) + { + if (GetTMHMMoveId(i + 1) == move) + return GetTMHMItemId(i + 1); + } + return 0; +} + struct ItemSlot NONNULL BagPocket_GetSlotData(struct BagPocket *pocket, u32 pocketPos) { switch (pocket->id) @@ -819,7 +832,7 @@ const u8 *GetItemEffect(u32 itemId) return gItemsInfo[SanitizeItemId(itemId)].effect; } -u32 GetItemHoldEffect(u32 itemId) +enum HoldEffect GetItemHoldEffect(u32 itemId) { return gItemsInfo[SanitizeItemId(itemId)].holdEffect; } @@ -942,7 +955,7 @@ u32 GetItemSellPrice(u32 itemId) return GetItemPrice(itemId) / ITEM_SELL_FACTOR; } -bool32 IsHoldEffectChoice(enum ItemHoldEffect holdEffect) +bool32 IsHoldEffectChoice(enum HoldEffect holdEffect) { return holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF diff --git a/src/item_use.c b/src/item_use.c index 460eb8a883..ff8ff9d588 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -18,6 +18,7 @@ #include "field_player_avatar.h" #include "field_screen_effect.h" #include "field_weather.h" +#include "fishing.h" #include "fldeff.h" #include "follower_npc.h" #include "item.h" @@ -28,6 +29,7 @@ #include "menu.h" #include "menu_helpers.h" #include "metatile_behavior.h" +#include "oras_dowse.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" @@ -54,8 +56,6 @@ static void Task_UseItemfinder(u8); static void Task_CloseItemfinderMessage(u8); static void Task_HiddenItemNearby(u8); static void Task_StandingOnHiddenItem(u8); -static bool8 ItemfinderCheckForHiddenItems(const struct MapEvents *, u8); -static u8 GetDirectionToHiddenItem(s16, s16); static void PlayerFaceHiddenItem(u8); static void CheckForHiddenItemsInMapConnection(u8); static void Task_OpenRegisteredPokeblockCase(u8); @@ -367,10 +367,20 @@ void ItemUseOutOfBattle_Itemfinder(u8 var) static void ItemUseOnFieldCB_Itemfinder(u8 taskId) { - if (ItemfinderCheckForHiddenItems(gMapHeader.events, taskId) == TRUE) - gTasks[taskId].func = Task_UseItemfinder; + if (I_ORAS_DOWSING_FLAG != 0) + { + if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING) && !TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_UNDERWATER)) + gTasks[taskId].func = Task_UseORASDowsingMachine; + else + DisplayItemMessageOnField(taskId, gText_DadsAdvice, Task_CloseItemfinderMessage); + } else - DisplayItemMessageOnField(taskId, sText_ItemFinderNothing, Task_CloseItemfinderMessage); + { + if (ItemfinderCheckForHiddenItems(gMapHeader.events, taskId) == TRUE) + gTasks[taskId].func = Task_UseItemfinder; + else + DisplayItemMessageOnField(taskId, sText_ItemFinderNothing, Task_CloseItemfinderMessage); + } } // Define itemfinder task data @@ -426,12 +436,15 @@ static void Task_CloseItemfinderMessage(u8 taskId) DestroyTask(taskId); } -static bool8 ItemfinderCheckForHiddenItems(const struct MapEvents *events, u8 taskId) +bool8 ItemfinderCheckForHiddenItems(const struct MapEvents *events, u8 taskId) { int itemX, itemY; s16 playerX, playerY, i, distanceX, distanceY; PlayerGetDestCoords(&playerX, &playerY); - gTasks[taskId].tItemFound = FALSE; + if (I_ORAS_DOWSING_FLAG != 0) + gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId].tItemFound = FALSE; + else + gTasks[taskId].tItemFound = FALSE; for (i = 0; i < events->bgEventCount; i++) { @@ -451,7 +464,7 @@ static bool8 ItemfinderCheckForHiddenItems(const struct MapEvents *events, u8 ta } CheckForHiddenItemsInMapConnection(taskId); - if (gTasks[taskId].tItemFound == TRUE) + if (gTasks[taskId].tItemFound == TRUE || gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId].tItemFound) return TRUE; else return FALSE; @@ -550,6 +563,8 @@ static void SetDistanceOfClosestHiddenItem(u8 taskId, s16 itemDistanceX, s16 ite { s16 *data = gTasks[taskId].data; s16 oldItemAbsX, oldItemAbsY, newItemAbsX, newItemAbsY; + if (I_ORAS_DOWSING_FLAG != 0) + data = gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId].data; if (tItemFound == FALSE) { @@ -606,7 +621,7 @@ static void SetDistanceOfClosestHiddenItem(u8 taskId, s16 itemDistanceX, s16 ite } } -static u8 GetDirectionToHiddenItem(s16 itemDistanceX, s16 itemDistanceY) +u8 GetDirectionToHiddenItem(s16 itemDistanceX, s16 itemDistanceY) { s16 absX, absY; @@ -1133,7 +1148,7 @@ static u32 GetBallThrowableState(void) return BALL_THROW_UNABLE_NO_ROOM; else if (B_SEMI_INVULNERABLE_CATCH >= GEN_4 && IsSemiInvulnerable(GetCatchingBattler(), CHECK_ALL)) return BALL_THROW_UNABLE_SEMI_INVULNERABLE; - else if (FlagGet(B_FLAG_NO_CATCHING)) + else if (FlagGet(B_FLAG_NO_CATCHING) || !IsAllowedToUseBag()) return BALL_THROW_UNABLE_DISABLED_FLAG; return BALL_THROW_ABLE; diff --git a/src/landmark.c b/src/landmark.c index a8cf6c1233..c26e61f45f 100644 --- a/src/landmark.c +++ b/src/landmark.c @@ -15,90 +15,49 @@ struct LandmarkList const struct Landmark *const *landmarks; }; -static const u8 LandmarkName_FlowerShop[] = _("FLOWER SHOP"); -static const u8 LandmarkName_PetalburgWoods[] = _("PETALBURG WOODS"); -static const u8 LandmarkName_MrBrineysCottage[] = _("MR. BRINEY'S COTTAGE"); -static const u8 LandmarkName_AbandonedShip[] = _("ABANDONED SHIP"); -static const u8 LandmarkName_SeashoreHouse[] = _("SEASHORE HOUSE"); -static const u8 LandmarkName_SlateportBeach[] = _("SLATEPORT BEACH"); -static const u8 LandmarkName_CyclingRoad[] = _("CYCLING ROAD"); -static const u8 LandmarkName_NewMauville[] = _("NEW MAUVILLE"); -static const u8 LandmarkName_TrickHouse[] = _("TRICK HOUSE"); -static const u8 LandmarkName_OldLadysRestShop[] = _("OLD LADY'S REST STOP"); -static const u8 LandmarkName_Desert[] = _("DESERT"); -static const u8 LandmarkName_WinstrateFamily[] = _("THE WINSTRATE FAMILY"); -static const u8 LandmarkName_CableCar[] = _("CABLE CAR"); -static const u8 LandmarkName_GlassWorkshop[] = _("GLASS WORKSHOP"); -static const u8 LandmarkName_WeatherInstitute[] = _("WEATHER INSTITUTE"); -static const u8 LandmarkName_MeteorFalls[] = _("METEOR FALLS"); -static const u8 LandmarkName_TunnelersRestHouse[] = _("TUNNELER'S RESTHOUSE"); -static const u8 LandmarkName_RusturfTunnel[] = _("RUSTURF TUNNEL"); -static const u8 LandmarkName_PokemonDayCare[] = _("POKéMON DAY CARE"); -static const u8 LandmarkName_SafariZoneEntrance[] = _("SAFARI ZONE ENTRANCE"); -static const u8 LandmarkName_MtPyre[] = _("MT. PYRE"); -static const u8 LandmarkName_ShoalCave[] = _("SHOAL CAVE"); -static const u8 LandmarkName_SeafloorCavern[] = _("SEAFLOOR CAVERN"); -static const u8 LandmarkName_GraniteCave[] = _("GRANITE CAVE"); -static const u8 LandmarkName_OceanCurrent[] = _("OCEAN CURRENT"); -static const u8 LandmarkName_LanettesHouse[] = _("LANETTE'S HOUSE"); -static const u8 LandmarkName_FieryPath[] = _("FIERY PATH"); -static const u8 LandmarkName_JaggedPass[] = _("JAGGED PASS"); -static const u8 LandmarkName_SkyPillar[] = _("SKY PILLAR"); -static const u8 LandmarkName_BerryMastersHouse[] = _("BERRY MASTER'S HOUSE"); -static const u8 LandmarkName_IslandCave[] = _("ISLAND CAVE"); -static const u8 LandmarkName_DesertRuins[] = _("DESERT RUINS"); -static const u8 LandmarkName_ScorchedSlab[] = _("SCORCHED SLAB"); -static const u8 LandmarkName_AncientTomb[] = _("ANCIENT TOMB"); -static const u8 LandmarkName_SealedChamber[] = _("SEALED CHAMBER"); -static const u8 LandmarkName_FossilManiacsHouse[] = _("FOSSIL MANIAC'S HOUSE"); -static const u8 LandmarkName_HuntersHouse[] = _("HUNTER'S HOUSE"); -static const u8 LandmarkName_MagmaHideout[] = _("MAGMA HIDEOUT"); -static const u8 LandmarkName_MirageTower[] = _("MIRAGE TOWER"); -static const u8 LandmarkName_AlteringCave[] = _("ALTERING CAVE"); -static const u8 LandmarkName_DesertUnderpass[] = _("DESERT UNDERPASS"); -static const u8 LandmarkName_TrainerHill[] = _("TRAINER HILL"); +static const u8 LandmarkName_MagmaHideout[] = _("MAGMA HIDEOUT"); //Unused -static const struct Landmark Landmark_FlowerShop = {LandmarkName_FlowerShop, FLAG_LANDMARK_FLOWER_SHOP}; -static const struct Landmark Landmark_PetalburgWoods = {LandmarkName_PetalburgWoods, -1}; -static const struct Landmark Landmark_MrBrineysCottage = {LandmarkName_MrBrineysCottage, FLAG_LANDMARK_MR_BRINEY_HOUSE}; -static const struct Landmark Landmark_AbandonedShip = {LandmarkName_AbandonedShip, FLAG_LANDMARK_ABANDONED_SHIP}; -static const struct Landmark Landmark_SeashoreHouse = {LandmarkName_SeashoreHouse, FLAG_LANDMARK_SEASHORE_HOUSE}; -static const struct Landmark Landmark_SlateportBeach = {LandmarkName_SlateportBeach, -1}; -static const struct Landmark Landmark_CyclingRoad = {LandmarkName_CyclingRoad, -1}; -static const struct Landmark Landmark_NewMauville = {LandmarkName_NewMauville, FLAG_LANDMARK_NEW_MAUVILLE}; -static const struct Landmark Landmark_TrickHouse = {LandmarkName_TrickHouse, FLAG_LANDMARK_TRICK_HOUSE}; -static const struct Landmark Landmark_OldLadysRestShop = {LandmarkName_OldLadysRestShop, FLAG_LANDMARK_OLD_LADY_REST_SHOP}; -static const struct Landmark Landmark_Desert = {LandmarkName_Desert, -1}; -static const struct Landmark Landmark_WinstrateFamily = {LandmarkName_WinstrateFamily, FLAG_LANDMARK_WINSTRATE_FAMILY}; -static const struct Landmark Landmark_CableCar = {LandmarkName_CableCar, -1}; -static const struct Landmark Landmark_GlassWorkshop = {LandmarkName_GlassWorkshop, FLAG_LANDMARK_GLASS_WORKSHOP}; -static const struct Landmark Landmark_WeatherInstitute = {LandmarkName_WeatherInstitute, -1}; -static const struct Landmark Landmark_MeteorFalls = {LandmarkName_MeteorFalls, -1}; -static const struct Landmark Landmark_TunnelersRestHouse = {LandmarkName_TunnelersRestHouse, FLAG_LANDMARK_TUNNELERS_REST_HOUSE}; -static const struct Landmark Landmark_RusturfTunnel = {LandmarkName_RusturfTunnel, -1}; -static const struct Landmark Landmark_PokemonDayCare = {LandmarkName_PokemonDayCare, FLAG_LANDMARK_POKEMON_DAYCARE}; -static const struct Landmark Landmark_SafariZoneEntrance = {LandmarkName_SafariZoneEntrance, -1}; -static const struct Landmark Landmark_MtPyre = {LandmarkName_MtPyre, -1}; -static const struct Landmark Landmark_ShoalCave = {LandmarkName_ShoalCave, -1}; -static const struct Landmark Landmark_SeafloorCavern = {LandmarkName_SeafloorCavern, FLAG_LANDMARK_SEAFLOOR_CAVERN}; -static const struct Landmark Landmark_GraniteCave = {LandmarkName_GraniteCave, -1}; -static const struct Landmark Landmark_OceanCurrent = {LandmarkName_OceanCurrent, -1}; -static const struct Landmark Landmark_LanettesHouse = {LandmarkName_LanettesHouse, FLAG_LANDMARK_LANETTES_HOUSE}; -static const struct Landmark Landmark_FieryPath = {LandmarkName_FieryPath, FLAG_LANDMARK_FIERY_PATH}; -static const struct Landmark Landmark_JaggedPass = {LandmarkName_JaggedPass, -1}; -static const struct Landmark Landmark_BerryMastersHouse = {LandmarkName_BerryMastersHouse, FLAG_LANDMARK_BERRY_MASTERS_HOUSE}; -static const struct Landmark Landmark_IslandCave = {LandmarkName_IslandCave, FLAG_LANDMARK_ISLAND_CAVE}; -static const struct Landmark Landmark_DesertRuins = {LandmarkName_DesertRuins, FLAG_LANDMARK_DESERT_RUINS}; -static const struct Landmark Landmark_ScorchedSlab = {LandmarkName_ScorchedSlab, FLAG_LANDMARK_SCORCHED_SLAB}; -static const struct Landmark Landmark_AncientTomb = {LandmarkName_AncientTomb, FLAG_LANDMARK_ANCIENT_TOMB}; -static const struct Landmark Landmark_SealedChamber = {LandmarkName_SealedChamber, FLAG_LANDMARK_SEALED_CHAMBER}; -static const struct Landmark Landmark_FossilManiacsHouse = {LandmarkName_FossilManiacsHouse, FLAG_LANDMARK_FOSSIL_MANIACS_HOUSE}; -static const struct Landmark Landmark_HuntersHouse = {LandmarkName_HuntersHouse, FLAG_LANDMARK_HUNTERS_HOUSE}; -static const struct Landmark Landmark_SkyPillar = {LandmarkName_SkyPillar, FLAG_LANDMARK_SKY_PILLAR}; -static const struct Landmark Landmark_MirageTower = {LandmarkName_MirageTower, FLAG_LANDMARK_MIRAGE_TOWER}; -static const struct Landmark Landmark_AlteringCave = {LandmarkName_AlteringCave, FLAG_LANDMARK_ALTERING_CAVE}; -static const struct Landmark Landmark_DesertUnderpass = {LandmarkName_DesertUnderpass, FLAG_LANDMARK_DESERT_UNDERPASS}; -static const struct Landmark Landmark_TrainerHill = {LandmarkName_TrainerHill, FLAG_LANDMARK_TRAINER_HILL}; +static const struct Landmark Landmark_FlowerShop = {COMPOUND_STRING("FLOWER SHOP"), FLAG_LANDMARK_FLOWER_SHOP}; +static const struct Landmark Landmark_PetalburgWoods = {COMPOUND_STRING("PETALBURG WOODS"), -1}; +static const struct Landmark Landmark_MrBrineysCottage = {COMPOUND_STRING("MR. BRINEY'S COTTAGE"), FLAG_LANDMARK_MR_BRINEY_HOUSE}; +static const struct Landmark Landmark_AbandonedShip = {COMPOUND_STRING("ABANDONED SHIP"), FLAG_LANDMARK_ABANDONED_SHIP}; +static const struct Landmark Landmark_SeashoreHouse = {COMPOUND_STRING("SEASHORE HOUSE"), FLAG_LANDMARK_SEASHORE_HOUSE}; +static const struct Landmark Landmark_SlateportBeach = {COMPOUND_STRING("SLATEPORT BEACH"), -1}; +static const struct Landmark Landmark_CyclingRoad = {COMPOUND_STRING("CYCLING ROAD"), -1}; +static const struct Landmark Landmark_NewMauville = {COMPOUND_STRING("NEW MAUVILLE"), FLAG_LANDMARK_NEW_MAUVILLE}; +static const struct Landmark Landmark_TrickHouse = {COMPOUND_STRING("TRICK HOUSE"), FLAG_LANDMARK_TRICK_HOUSE}; +static const struct Landmark Landmark_OldLadysRestShop = {COMPOUND_STRING("OLD LADY'S REST STOP"), FLAG_LANDMARK_OLD_LADY_REST_SHOP}; +static const struct Landmark Landmark_Desert = {COMPOUND_STRING("DESERT"), -1}; +static const struct Landmark Landmark_WinstrateFamily = {COMPOUND_STRING("THE WINSTRATE FAMILY"), FLAG_LANDMARK_WINSTRATE_FAMILY}; +static const struct Landmark Landmark_CableCar = {COMPOUND_STRING("CABLE CAR"), -1}; +static const struct Landmark Landmark_GlassWorkshop = {COMPOUND_STRING("GLASS WORKSHOP"), FLAG_LANDMARK_GLASS_WORKSHOP}; +static const struct Landmark Landmark_WeatherInstitute = {COMPOUND_STRING("WEATHER INSTITUTE"), -1}; +static const struct Landmark Landmark_MeteorFalls = {COMPOUND_STRING("METEOR FALLS"), -1}; +static const struct Landmark Landmark_TunnelersRestHouse = {COMPOUND_STRING("TUNNELER'S RESTHOUSE"), FLAG_LANDMARK_TUNNELERS_REST_HOUSE}; +static const struct Landmark Landmark_RusturfTunnel = {COMPOUND_STRING("RUSTURF TUNNEL"), -1}; +static const struct Landmark Landmark_PokemonDayCare = {COMPOUND_STRING("POKéMON DAY CARE"), FLAG_LANDMARK_POKEMON_DAYCARE}; +static const struct Landmark Landmark_SafariZoneEntrance = {COMPOUND_STRING("SAFARI ZONE ENTRANCE"), -1}; +static const struct Landmark Landmark_MtPyre = {COMPOUND_STRING("MT. PYRE"), -1}; +static const struct Landmark Landmark_ShoalCave = {COMPOUND_STRING("SHOAL CAVE"), -1}; +static const struct Landmark Landmark_SeafloorCavern = {COMPOUND_STRING("SEAFLOOR CAVERN"), FLAG_LANDMARK_SEAFLOOR_CAVERN}; +static const struct Landmark Landmark_GraniteCave = {COMPOUND_STRING("GRANITE CAVE"), -1}; +static const struct Landmark Landmark_OceanCurrent = {COMPOUND_STRING("OCEAN CURRENT"), -1}; +static const struct Landmark Landmark_LanettesHouse = {COMPOUND_STRING("LANETTE'S HOUSE"), FLAG_LANDMARK_LANETTES_HOUSE}; +static const struct Landmark Landmark_FieryPath = {COMPOUND_STRING("FIERY PATH"), FLAG_LANDMARK_FIERY_PATH}; +static const struct Landmark Landmark_JaggedPass = {COMPOUND_STRING("JAGGED PASS"), -1}; +static const struct Landmark Landmark_BerryMastersHouse = {COMPOUND_STRING("BERRY MASTER'S HOUSE"), FLAG_LANDMARK_BERRY_MASTERS_HOUSE}; +static const struct Landmark Landmark_IslandCave = {COMPOUND_STRING("ISLAND CAVE"), FLAG_LANDMARK_ISLAND_CAVE}; +static const struct Landmark Landmark_DesertRuins = {COMPOUND_STRING("DESERT RUINS"), FLAG_LANDMARK_DESERT_RUINS}; +static const struct Landmark Landmark_ScorchedSlab = {COMPOUND_STRING("SCORCHED SLAB"), FLAG_LANDMARK_SCORCHED_SLAB}; +static const struct Landmark Landmark_AncientTomb = {COMPOUND_STRING("ANCIENT TOMB"), FLAG_LANDMARK_ANCIENT_TOMB}; +static const struct Landmark Landmark_SealedChamber = {COMPOUND_STRING("SEALED CHAMBER"), FLAG_LANDMARK_SEALED_CHAMBER}; +static const struct Landmark Landmark_FossilManiacsHouse = {COMPOUND_STRING("FOSSIL MANIAC'S HOUSE"), FLAG_LANDMARK_FOSSIL_MANIACS_HOUSE}; +static const struct Landmark Landmark_HuntersHouse = {COMPOUND_STRING("HUNTER'S HOUSE"), FLAG_LANDMARK_HUNTERS_HOUSE}; +static const struct Landmark Landmark_SkyPillar = {COMPOUND_STRING("SKY PILLAR"), FLAG_LANDMARK_SKY_PILLAR}; +static const struct Landmark Landmark_MirageTower = {COMPOUND_STRING("MIRAGE TOWER"), FLAG_LANDMARK_MIRAGE_TOWER}; +static const struct Landmark Landmark_AlteringCave = {COMPOUND_STRING("ALTERING CAVE"), FLAG_LANDMARK_ALTERING_CAVE}; +static const struct Landmark Landmark_DesertUnderpass = {COMPOUND_STRING("DESERT UNDERPASS"), FLAG_LANDMARK_DESERT_UNDERPASS}; +static const struct Landmark Landmark_TrainerHill = {COMPOUND_STRING("TRAINER HILL"), FLAG_LANDMARK_TRAINER_HILL}; static const struct Landmark *const Landmarks_Route103_2[] = { diff --git a/src/list_menu.c b/src/list_menu.c index 64512b12d8..1a129e9f20 100644 --- a/src/list_menu.c +++ b/src/list_menu.c @@ -396,7 +396,10 @@ s32 ListMenu_ProcessInput(u8 listTaskId) if (JOY_NEW(A_BUTTON)) { - return list->template.items[list->scrollOffset + list->selectedRow].id; + if (list->template.isDynamic) + return list->scrollOffset + list->selectedRow; + else + return list->template.items[list->scrollOffset + list->selectedRow].id; } else if (JOY_NEW(B_BUTTON)) { @@ -616,7 +619,6 @@ static void ListMenuPrintEntries(struct ListMenu *list, u16 startIndex, u16 yOff s32 i; u8 x, y; u8 yMultiplier = GetFontAttribute(list->template.fontId, FONTATTR_MAX_LETTER_HEIGHT) + list->template.itemVerticalPadding; - for (i = 0; i < count; i++) { if (list->template.items[startIndex].id != LIST_HEADER) @@ -625,10 +627,16 @@ static void ListMenuPrintEntries(struct ListMenu *list, u16 startIndex, u16 yOff x = list->template.header_X; y = (yOffset + i) * yMultiplier + list->template.upText_Y; - if (list->template.itemPrintFunc != NULL) - list->template.itemPrintFunc(list->template.windowId, list->template.items[startIndex].id, y); - - ListMenuPrint(list, list->template.items[startIndex].name, x, y); + if (list->template.isDynamic) + { + list->template.itemPrintFunc(list->template.windowId, startIndex, y); + } + else + { + if (list->template.itemPrintFunc != NULL) + list->template.itemPrintFunc(list->template.windowId, list->template.items[startIndex].id, y); + ListMenuPrint(list, list->template.items[startIndex].name, x, y); + } startIndex++; } } @@ -715,7 +723,7 @@ static u8 ListMenuUpdateSelectedRowIndexAndScrollOffset(struct ListMenu *list, b while (selectedRow != 0) { selectedRow--; - if (list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) + if (list->template.isDynamic || list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) { list->selectedRow = selectedRow; return 1; @@ -729,7 +737,7 @@ static u8 ListMenuUpdateSelectedRowIndexAndScrollOffset(struct ListMenu *list, b while (selectedRow > newRow) { selectedRow--; - if (list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) + if (list->template.isDynamic || list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) { list->selectedRow = selectedRow; return 1; @@ -751,7 +759,7 @@ static u8 ListMenuUpdateSelectedRowIndexAndScrollOffset(struct ListMenu *list, b while (selectedRow < list->template.maxShowed - 1) { selectedRow++; - if (list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) + if (list->template.isDynamic || list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) { list->selectedRow = selectedRow; return 1; @@ -765,7 +773,7 @@ static u8 ListMenuUpdateSelectedRowIndexAndScrollOffset(struct ListMenu *list, b while (selectedRow < newRow) { selectedRow++; - if (list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) + if (list->template.isDynamic || list->template.items[scrollOffset + selectedRow].id != LIST_HEADER) { list->selectedRow = selectedRow; return 1; @@ -829,16 +837,26 @@ bool8 ListMenuChangeSelectionFull(struct ListMenu *list, bool32 updateCursor, bo oldSelectedRow = list->selectedRow; cursorCount = 0; selectionChange = 0; + for (i = 0; i < count; i++) { - do + if (list->template.isDynamic) { u8 ret = ListMenuUpdateSelectedRowIndexAndScrollOffset(list, movingDown); selectionChange |= ret; - if (ret != 2) - break; cursorCount++; - } while (list->template.items[list->scrollOffset + list->selectedRow].id == LIST_HEADER); + } + else + { + do + { + u8 ret = ListMenuUpdateSelectedRowIndexAndScrollOffset(list, movingDown); + selectionChange |= ret; + if (ret != 2) + break; + cursorCount++; + } while (list->template.items[list->scrollOffset + list->selectedRow].id == LIST_HEADER); + } } if (updateCursor) diff --git a/src/main.c b/src/main.c index 3fd080c75b..7abc47265e 100644 --- a/src/main.c +++ b/src/main.c @@ -116,7 +116,7 @@ void AgbMain(void) gSoftResetDisabled = FALSE; if (gFlashMemoryPresent != TRUE) - SetMainCallback2((SAVE_TYPE_ERROR_SCREEN) ? CB2_FlashNotDetectedScreen : NULL); + SetMainCallback2(CB2_FlashNotDetectedScreen); gLinkTransferringData = FALSE; diff --git a/src/match_call.c b/src/match_call.c index 9c2022524b..e8782cf60e 100644 --- a/src/match_call.c +++ b/src/match_call.c @@ -27,6 +27,7 @@ #include "task.h" #include "wild_encounter.h" #include "window.h" +#include "field_name_box.h" #include "constants/abilities.h" #include "constants/battle_frontier.h" #include "constants/event_objects.h" @@ -1321,9 +1322,11 @@ static bool32 MatchCall_PrintIntro(u8 taskId) { FillWindowPixelBuffer(tWindowId, PIXEL_FILL(8)); - // Ready the message + // Ready the message (and the speaker's name if possible) if (!sMatchCallState.triggeredFromScript) SelectMatchCallMessage(sMatchCallState.trainerId, gStringVar4); + + TrySpawnAndShowNamebox(gSpeakerName, NAME_BOX_BASE_TILE_NUM); InitMatchCallTextPrinter(tWindowId, gStringVar4); return TRUE; } @@ -1348,9 +1351,9 @@ static bool32 MatchCall_PrintMessage(u8 taskId) static bool32 MatchCall_SlideWindowOut(u8 taskId) { s16 *data = gTasks[taskId].data; - if (ChangeBgY(0, 0x600, BG_COORD_SUB) <= -0x2000) + if (ChangeBgY(0, 0x600, BG_COORD_SUB) <= -0x4000) { - FillBgTilemapBufferRect_Palette0(0, 0, 0, 14, 30, 6); + FillBgTilemapBufferRect_Palette0(0, 0, 0, 12, 30, 8); DestroyTask(tIconTaskId); RemoveWindow(tWindowId); CopyBgTilemapBufferToVram(0); @@ -1404,6 +1407,31 @@ static void DrawMatchCallTextBoxBorder_Internal(u32 windowId, u32 tileOffset, u3 FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 7), x + width, y + height, 1, 1); } +static u8 GetMatchCallWindowId(void) +{ + if (!IsMatchCallTaskActive()) + return WINDOW_NONE; + + u32 taskId = FindTaskIdByFunc(ExecuteMatchCall); + return gTasks[taskId].tWindowId; +} + +// redraw only the top-half +void RedrawMatchCallTextBoxBorder(void) +{ + u32 windowId = GetMatchCallWindowId(); + u32 bg = GetWindowAttribute(windowId, WINDOW_BG); + u32 x = GetWindowAttribute(windowId, WINDOW_TILEMAP_LEFT); + u32 y = GetWindowAttribute(windowId, WINDOW_TILEMAP_TOP); + u32 width = GetWindowAttribute(windowId, WINDOW_WIDTH); + u32 tileNum = TILE_MC_WINDOW + GetBgAttribute(bg, BG_ATTR_BASETILE); + u32 paletteId = 14; + + FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 0), x - 1, y - 1, 1, 1); + FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 1), x, y - 1, width, 1); + FillBgTilemapBufferRect_Palette0(bg, ((paletteId << 12) & 0xF000) | (tileNum + 2), x + width, y - 1, 1, 1); +} + static void InitMatchCallTextPrinter(int windowId, const u8 *str) { struct TextPrinterTemplate printerTemplate; diff --git a/src/menu.c b/src/menu.c index 48bbc01dc9..4e7d5920a3 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1,14 +1,16 @@ #include "global.h" -#include "malloc.h" #include "bg.h" #include "blit.h" #include "decompress.h" #include "dma3.h" #include "event_data.h" +#include "field_name_box.h" #include "field_weather.h" #include "graphics.h" #include "main.h" +#include "malloc.h" #include "map_name_popup.h" +#include "match_call.h" #include "menu.h" #include "menu_helpers.h" #include "palette.h" @@ -22,7 +24,6 @@ #include "task.h" #include "text_window.h" #include "window.h" -#include "config/overworld.h" #include "constants/songs.h" struct MenuInfoIcon @@ -75,13 +76,6 @@ static EWRAM_DATA void *sTempTileDataBuffer[0x20] = {NULL}; const u16 gStandardMenuPalette[] = INCBIN_U16("graphics/interface/std_menu.gbapal"); -static const u8 sTextSpeedFrameDelays[] = -{ - [OPTIONS_TEXT_SPEED_SLOW] = 8, - [OPTIONS_TEXT_SPEED_MID] = 4, - [OPTIONS_TEXT_SPEED_FAST] = 1 -}; - static const struct WindowTemplate sStandardTextBox_WindowTemplates[] = { { @@ -145,6 +139,7 @@ static const struct MenuInfoIcon sMenuInfoIcons[] = void InitStandardTextBoxWindows(void) { + ResetNameboxData(); InitWindows(sStandardTextBox_WindowTemplates); sStartMenuWindowId = WINDOW_NONE; sMapNamePopupWindowId = WINDOW_NONE; @@ -194,13 +189,6 @@ u16 AddTextPrinterParameterized2(u8 windowId, u8 fontId, const u8 *str, u8 speed } void AddTextPrinterForMessage(bool8 allowSkippingDelayWithButtonPress) -{ - void (*callback)(struct TextPrinterTemplate *, u16) = NULL; - gTextFlags.canABSpeedUpPrint = allowSkippingDelayWithButtonPress; - AddTextPrinterParameterized2(0, FONT_NORMAL, gStringVar4, GetPlayerTextSpeedDelay(), callback, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); -} - -void AddTextPrinterForMessage_2(bool8 allowSkippingDelayWithButtonPress) { gTextFlags.canABSpeedUpPrint = allowSkippingDelayWithButtonPress; AddTextPrinterParameterized2(0, FONT_NORMAL, gStringVar4, GetPlayerTextSpeedDelay(), NULL, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_WHITE, TEXT_COLOR_LIGHT_GRAY); @@ -341,6 +329,53 @@ void DrawDialogueFrame(u8 windowId, bool8 copyToVram) CopyWindowToVram(windowId, COPYWIN_FULL); } +static void WindowFunc_RedrawDialogueFrame(u8 bg, u8 tilemapLeft, u8 tilemapTop, u8 width, u8 height, u8 paletteNum) +{ + FillBgTilemapBufferRect(bg, + DLG_WINDOW_BASE_TILE_NUM + 1, + tilemapLeft - 2, + tilemapTop - 1, + 1, + 1, + DLG_WINDOW_PALETTE_NUM); + FillBgTilemapBufferRect(bg, + DLG_WINDOW_BASE_TILE_NUM + 3, + tilemapLeft - 1, + tilemapTop - 1, + 1, + 1, + DLG_WINDOW_PALETTE_NUM); + FillBgTilemapBufferRect(bg, + DLG_WINDOW_BASE_TILE_NUM + 4, + tilemapLeft, + tilemapTop - 1, + width - 1, + 1, + DLG_WINDOW_PALETTE_NUM); + FillBgTilemapBufferRect(bg, + DLG_WINDOW_BASE_TILE_NUM + 5, + tilemapLeft + width - 1, + tilemapTop - 1, + 1, + 1, + DLG_WINDOW_PALETTE_NUM); + FillBgTilemapBufferRect(bg, + DLG_WINDOW_BASE_TILE_NUM + 6, + tilemapLeft + width, + tilemapTop - 1, + 1, + 1, + DLG_WINDOW_PALETTE_NUM); +} + +void RedrawDialogueFrame(void) +{ + if (IsMatchCallTaskActive()) + RedrawMatchCallTextBoxBorder(); + else + CallWindowFunction(0, WindowFunc_RedrawDialogueFrame); +} + void DrawStdWindowFrame(u8 windowId, bool8 copyToVram) { CallWindowFunction(windowId, WindowFunc_DrawStandardFrame); @@ -370,8 +405,6 @@ void ClearStdWindowAndFrame(u8 windowId, bool8 copyToVram) static void WindowFunc_DrawStandardFrame(u8 bg, u8 tilemapLeft, u8 tilemapTop, u8 width, u8 height, u8 paletteNum) { - int i; - FillBgTilemapBufferRect(bg, STD_WINDOW_BASE_TILE_NUM + 0, tilemapLeft - 1, @@ -393,25 +426,20 @@ static void WindowFunc_DrawStandardFrame(u8 bg, u8 tilemapLeft, u8 tilemapTop, u 1, 1, STD_WINDOW_PALETTE_NUM); - - for (i = tilemapTop; i < tilemapTop + height; i++) - { - FillBgTilemapBufferRect(bg, - STD_WINDOW_BASE_TILE_NUM + 3, - tilemapLeft - 1, - i, - 1, - 1, - STD_WINDOW_PALETTE_NUM); - FillBgTilemapBufferRect(bg, - STD_WINDOW_BASE_TILE_NUM + 5, - tilemapLeft + width, - i, - 1, - 1, - STD_WINDOW_PALETTE_NUM); - } - + FillBgTilemapBufferRect(bg, + STD_WINDOW_BASE_TILE_NUM + 3, + tilemapLeft - 1, + tilemapTop, + 1, + height, + STD_WINDOW_PALETTE_NUM); + FillBgTilemapBufferRect(bg, + STD_WINDOW_BASE_TILE_NUM + 5, + tilemapLeft + width, + tilemapTop, + 1, + height, + STD_WINDOW_PALETTE_NUM); FillBgTilemapBufferRect(bg, STD_WINDOW_BASE_TILE_NUM + 6, tilemapLeft - 1, @@ -590,22 +618,6 @@ void DisplayYesNoMenuWithDefault(u8 initialCursorPos) CreateYesNoMenu(&sYesNo_WindowTemplates, STD_WINDOW_BASE_TILE_NUM, STD_WINDOW_PALETTE_NUM, initialCursorPos); } -u32 GetPlayerTextSpeed(void) -{ - if (gTextFlags.forceMidTextSpeed) - return OPTIONS_TEXT_SPEED_MID; - return gSaveBlock2Ptr->optionsTextSpeed; -} - -u8 GetPlayerTextSpeedDelay(void) -{ - u32 speed; - if (gSaveBlock2Ptr->optionsTextSpeed > OPTIONS_TEXT_SPEED_FAST) - gSaveBlock2Ptr->optionsTextSpeed = OPTIONS_TEXT_SPEED_MID; - speed = GetPlayerTextSpeed(); - return sTextSpeedFrameDelays[speed]; -} - u8 AddStartMenuWindow(u8 numActions) { if (sStartMenuWindowId == WINDOW_NONE) diff --git a/src/menu_specialized.c b/src/menu_specialized.c index df4233fd14..33f26a5b90 100644 --- a/src/menu_specialized.c +++ b/src/menu_specialized.c @@ -1,9 +1,11 @@ #include "global.h" #include "malloc.h" #include "battle_main.h" +#include "contest.h" #include "contest_effect.h" #include "data.h" #include "decompress.h" +#include "event_data.h" #include "gpu_regs.h" #include "graphics.h" #include "menu.h" @@ -836,10 +838,10 @@ static void MoveRelearnerMenuLoadContestMoveDescription(u32 chosenMove) return; } - str = gContestMoveTypeTextPointers[GetMoveContestCategory(chosenMove)]; + str = gContestCategoryInfo[GetMoveContestCategory(chosenMove)].name; AddTextPrinterParameterized(RELEARNERWIN_DESC_CONTEST, FONT_NORMAL, str, 4, 25, TEXT_SKIP_DRAW, NULL); - str = gContestEffectDescriptionPointers[GetMoveContestEffect(chosenMove)]; + str = gContestEffects[GetMoveContestEffect(chosenMove)].description; AddTextPrinterParameterized(RELEARNERWIN_DESC_CONTEST, FONT_NARROW, str, 0, 65, TEXT_SKIP_DRAW, NULL); CopyWindowToVram(RELEARNERWIN_DESC_CONTEST, COPYWIN_GFX); diff --git a/src/metatile_behavior.c b/src/metatile_behavior.c index 687b98ca27..115a0d4c7b 100644 --- a/src/metatile_behavior.c +++ b/src/metatile_behavior.c @@ -331,7 +331,7 @@ bool8 MetatileBehavior_IsSouthArrowWarp(u8 metatileBehavior) bool8 UNUSED Unref_MetatileBehavior_IsArrowWarp(u8 metatileBehavior) { - u8 isArrowWarp = FALSE; + bool32 isArrowWarp = FALSE; if (MetatileBehavior_IsEastArrowWarp(metatileBehavior) || MetatileBehavior_IsWestArrowWarp(metatileBehavior) diff --git a/src/move_relearner.c b/src/move_relearner.c index ee700beb44..9aafbb4b59 100644 --- a/src/move_relearner.c +++ b/src/move_relearner.c @@ -9,6 +9,7 @@ #include "event_data.h" #include "field_screen_effect.h" #include "gpu_regs.h" +#include "item.h" #include "move_relearner.h" #include "list_menu.h" #include "malloc.h" @@ -134,7 +135,8 @@ #define MENU_STATE_CONFIRM_DELETE_OLD_MOVE 18 #define MENU_STATE_PRINT_WHICH_MOVE_PROMPT 19 #define MENU_STATE_SHOW_MOVE_SUMMARY_SCREEN 20 -// States 21, 22, and 23 are skipped. +#define MENU_STATE_RETURN_TO_PARTY_MENU 21 +// States 22 and 23 are skipped. #define MENU_STATE_PRINT_STOP_TEACHING 24 #define MENU_STATE_WAIT_FOR_STOP_TEACHING 25 #define MENU_STATE_CONFIRM_STOP_TEACHING 26 @@ -183,7 +185,8 @@ static EWRAM_DATA struct { bool8 showContestInfo; } sMoveRelearnerMenuState = {0}; -EWRAM_DATA u8 gOriginSummaryScreenPage = 0; // indicates summary screen page that the move relearner was opened from (if opened from PSS) +EWRAM_DATA enum MoveRelearnerStates gMoveRelearnerState = MOVE_RELEARNER_LEVEL_UP_MOVES; +EWRAM_DATA enum RelearnMode gRelearnMode = RELEARN_MODE_NONE; static const u16 sUI_Pal[] = INCBIN_U16("graphics/interface/ui_learn_move.gbapal"); @@ -402,11 +405,28 @@ void CB2_InitLearnMove(void) SetVBlankCallback(VBlankCB_MoveRelearner); InitMoveRelearnerBackgroundLayers(); - InitMoveRelearnerWindows(gOriginSummaryScreenPage == PSS_PAGE_CONTEST_MOVES); + InitMoveRelearnerWindows(gRelearnMode == RELEARN_MODE_PSS_PAGE_CONTEST_MOVES); sMoveRelearnerMenuState.listOffset = 0; sMoveRelearnerMenuState.listRow = 0; - sMoveRelearnerMenuState.showContestInfo = gOriginSummaryScreenPage == PSS_PAGE_CONTEST_MOVES; + sMoveRelearnerMenuState.showContestInfo = gRelearnMode == RELEARN_MODE_PSS_PAGE_CONTEST_MOVES; + + switch (gMoveRelearnerState) + { + case MOVE_RELEARNER_EGG_MOVES: + StringCopy(gStringVar3, MoveRelearner_Text_EggMoveLWR); + break; + case MOVE_RELEARNER_TM_MOVES: + StringCopy(gStringVar3, MoveRelearner_Text_TMMoveLWR); + break; + case MOVE_RELEARNER_TUTOR_MOVES: + StringCopy(gStringVar3, MoveRelearner_Text_TutorMoveLWR); + break; + case MOVE_RELEARNER_LEVEL_UP_MOVES: + default: + StringCopy(gStringVar3, MoveRelearner_Text_LevelUpMoveLWR); + break; + } CreateLearnableMovesList(); @@ -474,6 +494,18 @@ static void PrintMessageWithPlaceholders(const u8 *src) MoveRelearnerPrintMessage(gStringVar4); } +// If reusable TMs is off, remove the TM from the bag +static void RemoveRelearnerTMFromBag(u16 move) +{ + u16 item = GetTMHMItemIdFromMoveId(move); + + if (!I_REUSABLE_TMS && !P_ENABLE_ALL_TM_MOVES + && gMoveRelearnerState == MOVE_RELEARNER_TM_MOVES && GetItemTMHMIndex(item) <= NUM_TECHNICAL_MACHINES) + { + RemoveBagItem(item, 1); + } +} + // See the state machine doc at the top of the file. static void DoMoveRelearnerMain(void) { @@ -482,14 +514,14 @@ static void DoMoveRelearnerMain(void) case MENU_STATE_FADE_TO_BLACK: sMoveRelearnerStruct->state++; HideHeartSpritesAndShowTeachMoveText(FALSE); - if (gOriginSummaryScreenPage == PSS_PAGE_CONTEST_MOVES) + if (gRelearnMode == RELEARN_MODE_PSS_PAGE_CONTEST_MOVES) MoveRelearnerShowHideHearts(GetCurrentSelectedMove()); BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); break; case MENU_STATE_WAIT_FOR_FADE: if (!gPaletteFade.active) { - if (gOriginSummaryScreenPage == PSS_PAGE_CONTEST_MOVES) + if (gRelearnMode == RELEARN_MODE_PSS_PAGE_CONTEST_MOVES) sMoveRelearnerStruct->state = MENU_STATE_IDLE_CONTEST_MODE; else sMoveRelearnerStruct->state = MENU_STATE_IDLE_BATTLE_MODE; @@ -499,7 +531,6 @@ static void DoMoveRelearnerMain(void) sMoveRelearnerStruct->state++; break; case MENU_STATE_SETUP_BATTLE_MODE: - HideHeartSpritesAndShowTeachMoveText(FALSE); sMoveRelearnerStruct->state++; AddScrollArrows(); @@ -684,10 +715,11 @@ static void DoMoveRelearnerMain(void) FreeMoveRelearnerResources(); } break; - case 21: - if (!MoveRelearnerRunTextPrinters()) + case MENU_STATE_RETURN_TO_PARTY_MENU: + if (!gPaletteFade.active) { - sMoveRelearnerStruct->state = MENU_STATE_FADE_AND_RETURN; + FreeMoveRelearnerResources(); + SetMainCallback2(CB2_ReturnToPartyMenuFromSummaryScreen); } break; case 22: @@ -695,26 +727,28 @@ static void DoMoveRelearnerMain(void) break; case MENU_STATE_FADE_AND_RETURN: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); - sMoveRelearnerStruct->state++; + if (gRelearnMode == RELEARN_MODE_PARTY_MENU) + sMoveRelearnerStruct->state = MENU_STATE_RETURN_TO_PARTY_MENU; + else + sMoveRelearnerStruct->state++; break; case MENU_STATE_RETURN_TO_FIELD: if (!gPaletteFade.active) { if (gInitialSummaryScreenCallback != NULL) { - switch (gOriginSummaryScreenPage) + switch (gRelearnMode) { - case PSS_PAGE_BATTLE_MOVES: + case RELEARN_MODE_PSS_PAGE_BATTLE_MOVES: ShowPokemonSummaryScreen(SUMMARY_MODE_RELEARNER_BATTLE, gPlayerParty, sMoveRelearnerStruct->partyMon, gPlayerPartyCount - 1, gInitialSummaryScreenCallback); break; - case PSS_PAGE_CONTEST_MOVES: + case RELEARN_MODE_PSS_PAGE_CONTEST_MOVES: ShowPokemonSummaryScreen(SUMMARY_MODE_RELEARNER_CONTEST, gPlayerParty, sMoveRelearnerStruct->partyMon, gPlayerPartyCount - 1, gInitialSummaryScreenCallback); break; default: ShowPokemonSummaryScreen(SUMMARY_MODE_NORMAL, gPlayerParty, sMoveRelearnerStruct->partyMon, gPlayerPartyCount - 1, gInitialSummaryScreenCallback); break; } - gOriginSummaryScreenPage = 0; } else { @@ -722,6 +756,7 @@ static void DoMoveRelearnerMain(void) } FreeMoveRelearnerResources(); + gRelearnMode = RELEARN_MODE_NONE; } break; case MENU_STATE_FADE_FROM_SUMMARY_SCREEN: @@ -754,7 +789,8 @@ static void DoMoveRelearnerMain(void) RemoveMonPPBonus(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->moveSlot); SetMonMoveSlot(&gPlayerParty[sMoveRelearnerStruct->partyMon], GetCurrentSelectedMove(), sMoveRelearnerStruct->moveSlot); u8 newPP = GetMonData(&gPlayerParty[sMoveRelearnerStruct->partyMon], MON_DATA_PP1 + sMoveRelearnerStruct->moveSlot); - if (!P_SUMMARY_MOVE_RELEARNER_FULL_PP && gOriginSummaryScreenPage != 0 && originalPP < newPP) + if (!P_SUMMARY_MOVE_RELEARNER_FULL_PP + && (gRelearnMode == RELEARN_MODE_PSS_PAGE_BATTLE_MOVES || gRelearnMode == RELEARN_MODE_PSS_PAGE_BATTLE_MOVES) && originalPP < newPP) SetMonData(&gPlayerParty[sMoveRelearnerStruct->partyMon], MON_DATA_PP1 + sMoveRelearnerStruct->moveSlot, &originalPP); StringCopy(gStringVar2, GetMoveName(GetCurrentSelectedMove())); PrintMessageWithPlaceholders(gText_MoveRelearnerAndPoof); @@ -775,6 +811,7 @@ static void DoMoveRelearnerMain(void) if (!MoveRelearnerRunTextPrinters()) { PlayFanfare(MUS_LEVEL_UP); + RemoveRelearnerTMFromBag(GetCurrentSelectedMove()); sMoveRelearnerStruct->state = MENU_STATE_WAIT_FOR_FANFARE; } break; @@ -953,7 +990,22 @@ static void CreateLearnableMovesList(void) s32 i; u8 nickname[POKEMON_NAME_LENGTH + 1]; - sMoveRelearnerStruct->numMenuChoices = GetMoveRelearnerMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn); + switch (gMoveRelearnerState) + { + case MOVE_RELEARNER_EGG_MOVES: + sMoveRelearnerStruct->numMenuChoices = GetRelearnerEggMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn); + break; + case MOVE_RELEARNER_TM_MOVES: + sMoveRelearnerStruct->numMenuChoices = GetRelearnerTMMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn); + break; + case MOVE_RELEARNER_TUTOR_MOVES: + sMoveRelearnerStruct->numMenuChoices = GetRelearnerTutorMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn); + break; + case MOVE_RELEARNER_LEVEL_UP_MOVES: + default: + sMoveRelearnerStruct->numMenuChoices = GetRelearnerLevelUpMoves(&gPlayerParty[sMoveRelearnerStruct->partyMon], sMoveRelearnerStruct->movesToLearn); + break; + } for (i = 0; i < sMoveRelearnerStruct->numMenuChoices; i++) { diff --git a/src/option_menu.c b/src/option_menu.c index fda3a24c47..a55d4da4e4 100644 --- a/src/option_menu.c +++ b/src/option_menu.c @@ -72,19 +72,35 @@ static void DrawBgWindowFrames(void); EWRAM_DATA static bool8 sArrowPressed = FALSE; +static const u8 gText_Option[] = _("OPTION"); +static const u8 gText_TextSpeedSlow[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}SLOW"); +static const u8 gText_TextSpeedMid[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}MID"); +static const u8 gText_TextSpeedFast[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}FAST"); +static const u8 gText_BattleSceneOn[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}ON"); +static const u8 gText_BattleSceneOff[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}OFF"); +static const u8 gText_BattleStyleShift[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}SHIFT"); +static const u8 gText_BattleStyleSet[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}SET"); +static const u8 gText_SoundMono[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}MONO"); +static const u8 gText_SoundStereo[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}STEREO"); +static const u8 gText_FrameType[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}TYPE"); +static const u8 gText_FrameTypeNumber[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}"); +static const u8 gText_ButtonTypeNormal[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}NORMAL"); +static const u8 gText_ButtonTypeLR[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}LR"); +static const u8 gText_ButtonTypeLEqualsA[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}L=A"); + static const u16 sOptionMenuText_Pal[] = INCBIN_U16("graphics/interface/option_menu_text.gbapal"); // note: this is only used in the Japanese release static const u8 sEqualSignGfx[] = INCBIN_U8("graphics/interface/option_menu_equals_sign.4bpp"); static const u8 *const sOptionMenuItemsNames[MENUITEM_COUNT] = { - [MENUITEM_TEXTSPEED] = gText_TextSpeed, - [MENUITEM_BATTLESCENE] = gText_BattleScene, - [MENUITEM_BATTLESTYLE] = gText_BattleStyle, - [MENUITEM_SOUND] = gText_Sound, - [MENUITEM_BUTTONMODE] = gText_ButtonMode, - [MENUITEM_FRAMETYPE] = gText_Frame, - [MENUITEM_CANCEL] = gText_OptionMenuCancel, + [MENUITEM_TEXTSPEED] = COMPOUND_STRING("TEXT SPEED"), + [MENUITEM_BATTLESCENE] = COMPOUND_STRING("BATTLE SCENE"), + [MENUITEM_BATTLESTYLE] = COMPOUND_STRING("BATTLE STYLE"), + [MENUITEM_SOUND] = COMPOUND_STRING("SOUND"), + [MENUITEM_BUTTONMODE] = COMPOUND_STRING("BUTTON MODE"), + [MENUITEM_FRAMETYPE] = COMPOUND_STRING("FRAME"), + [MENUITEM_CANCEL] = COMPOUND_STRING("CANCEL"), }; static const struct WindowTemplate sOptionMenuWinTemplates[] = diff --git a/src/oras_dowse.c b/src/oras_dowse.c new file mode 100644 index 0000000000..237c456187 --- /dev/null +++ b/src/oras_dowse.c @@ -0,0 +1,562 @@ +#include "global.h" +#include "oras_dowse.h" +#include "bike.h" +#include "event_data.h" +#include "event_object_lock.h" +#include "event_object_movement.h" +#include "field_effect.h" +#include "field_effect_helpers.h" +#include "field_player_avatar.h" +#include "fldeff.h" +#include "item_use.h" +#include "palette.h" +#include "script.h" +#include "sound.h" +#include "task.h" +#include "constants/field_effects.h" +#include "constants/songs.h" +#include "constants/rgb.h" + +static void StartORASDowseFieldEffect(void); +static void UpdateORASDowsingFieldEffect(struct Sprite *sprite); +static void ChangeDowsingColor(u8 direction, struct Sprite *sprite); +static void ClearDowsingColor(struct Sprite *sprite); +static void PlayDowseSound(u32 dowseState); + +const u32 gFieldEffectObjectPic_ORASDowsingBrendan[] = INCBIN_U32("graphics/field_effects/pics/oras_dowsing_brendan.4bpp"); +const u32 gFieldEffectObjectPic_ORASDowsingMay[] = INCBIN_U32("graphics/field_effects/pics/oras_dowsing_may.4bpp"); +const u16 gFieldEffectPal_ORASDowsing[] = INCBIN_U16("graphics/field_effects/palettes/oras_dowsing.gbapal"); + +static const struct SpriteFrameImage sPicTable_ORASDowsingBrendan[] = { + overworld_ascending_frames(gFieldEffectObjectPic_ORASDowsingBrendan, 2, 4), +}; + +static const struct SpriteFrameImage sPicTable_ORASDowsingMay[] = { + overworld_ascending_frames(gFieldEffectObjectPic_ORASDowsingMay, 2, 4), +}; + +static const union AnimCmd sAnim_FaceSouth[] = +{ + ANIMCMD_FRAME(0, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_FaceNorth[] = +{ + ANIMCMD_FRAME(1, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_FaceWest[] = +{ + ANIMCMD_FRAME(2, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_FaceEast[] = +{ + ANIMCMD_FRAME(2, 16, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouthSlow[] = +{ + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(4, 32), + ANIMCMD_FRAME(4, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorthSlow[] = +{ + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(6, 32), + ANIMCMD_FRAME(6, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWestSlow[] = +{ + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(8, 32), + ANIMCMD_FRAME(8, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEastSlow[] = +{ + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(8, 32, .hFlip = TRUE), + ANIMCMD_FRAME(8, 32, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouth[] = +{ + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(3, 32), + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(4, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorth[] = +{ + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(5, 32), + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(6, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWest[] = +{ + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(7, 32), + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(8, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEast[] = +{ + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(7, 32, .hFlip = TRUE), + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(8, 32, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouthFast[] = +{ + ANIMCMD_FRAME(0, 16), + ANIMCMD_FRAME(3, 16), + ANIMCMD_FRAME(0, 16), + ANIMCMD_FRAME(4, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorthFast[] = +{ + ANIMCMD_FRAME(1, 16), + ANIMCMD_FRAME(5, 16), + ANIMCMD_FRAME(1, 16), + ANIMCMD_FRAME(6, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWestFast[] = +{ + ANIMCMD_FRAME(2, 16), + ANIMCMD_FRAME(7, 16), + ANIMCMD_FRAME(2, 16), + ANIMCMD_FRAME(8, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEastFast[] = +{ + ANIMCMD_FRAME(2, 16, .hFlip = TRUE), + ANIMCMD_FRAME(7, 16, .hFlip = TRUE), + ANIMCMD_FRAME(2, 16, .hFlip = TRUE), + ANIMCMD_FRAME(8, 16, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouthFaster[] = +{ + ANIMCMD_FRAME(0, 8), + ANIMCMD_FRAME(3, 8), + ANIMCMD_FRAME(0, 8), + ANIMCMD_FRAME(4, 8), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorthFaster[] = +{ + ANIMCMD_FRAME(1, 8), + ANIMCMD_FRAME(5, 8), + ANIMCMD_FRAME(1, 8), + ANIMCMD_FRAME(6, 8), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWestFaster[] = +{ + ANIMCMD_FRAME(2, 8), + ANIMCMD_FRAME(7, 8), + ANIMCMD_FRAME(2, 8), + ANIMCMD_FRAME(8, 8), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEastFaster[] = +{ + ANIMCMD_FRAME(2, 8, .hFlip = TRUE), + ANIMCMD_FRAME(7, 8, .hFlip = TRUE), + ANIMCMD_FRAME(2, 8, .hFlip = TRUE), + ANIMCMD_FRAME(8, 8, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd *const sAnimTable_ORASDowsing[] = +{ + [ANIM_STD_FACE_SOUTH] = sAnim_FaceSouth, + [ANIM_STD_FACE_NORTH] = sAnim_FaceNorth, + [ANIM_STD_FACE_WEST] = sAnim_FaceWest, + [ANIM_STD_FACE_EAST] = sAnim_FaceEast, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH_SLOW] = sAnim_ORASDowseWiggleSouthSlow, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH_SLOW] = sAnim_ORASDowseWiggleNorthSlow, + [ANIM_ORAS_DOWSE_WIGGLE_WEST_SLOW] = sAnim_ORASDowseWiggleWestSlow, + [ANIM_ORAS_DOWSE_WIGGLE_EAST_SLOW] = sAnim_ORASDowseWiggleEastSlow, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH] = sAnim_ORASDowseWiggleSouth, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH] = sAnim_ORASDowseWiggleNorth, + [ANIM_ORAS_DOWSE_WIGGLE_WEST] = sAnim_ORASDowseWiggleWest, + [ANIM_ORAS_DOWSE_WIGGLE_EAST] = sAnim_ORASDowseWiggleEast, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FAST] = sAnim_ORASDowseWiggleSouthFast, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH_FAST] = sAnim_ORASDowseWiggleNorthFast, + [ANIM_ORAS_DOWSE_WIGGLE_WEST_FAST] = sAnim_ORASDowseWiggleWestFast, + [ANIM_ORAS_DOWSE_WIGGLE_EAST_FAST] = sAnim_ORASDowseWiggleEastFast, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FASTER] = sAnim_ORASDowseWiggleSouthFaster, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH_FASTER] = sAnim_ORASDowseWiggleNorthFaster, + [ANIM_ORAS_DOWSE_WIGGLE_WEST_FASTER] = sAnim_ORASDowseWiggleWestFaster, + [ANIM_ORAS_DOWSE_WIGGLE_EAST_FASTER] = sAnim_ORASDowseWiggleEastFaster, +}; + +static const struct OamData gObjectEventOam_ORASDowse = { + .shape = SPRITE_SHAPE(16x32), + .size = SPRITE_SIZE(16x32), + .priority = 2 +}; + +const struct SpriteTemplate gFieldEffectObjectTemplate_ORASDowsingBrendan = { + .tileTag = TAG_NONE, + .paletteTag = FLDEFF_PAL_TAG_ORAS_DOWSE, + .oam = &gObjectEventOam_ORASDowse, + .anims = sAnimTable_ORASDowsing, + .images = sPicTable_ORASDowsingBrendan, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = UpdateORASDowsingFieldEffect, +}; + +const struct SpriteTemplate gFieldEffectObjectTemplate_ORASDowsingMay = { + .tileTag = TAG_NONE, + .paletteTag = FLDEFF_PAL_TAG_ORAS_DOWSE, + .oam = &gObjectEventOam_ORASDowse, + .anims = sAnimTable_ORASDowsing, + .images = sPicTable_ORASDowsingMay, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = UpdateORASDowsingFieldEffect, +}; + +void Task_UseORASDowsingMachine(u8 taskId) +{ + if (FlagGet(I_ORAS_DOWSING_FLAG)) + { + EndORASDowsing(); + } + else + { + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE)) + GetOnOffBike(0); + + StartORASDowseFieldEffect(); + } + ScriptUnfreezeObjectEvents(); + UnlockPlayerFieldControls(); + DestroyTask(taskId); +} + +static void StartORASDowseFieldEffect(void) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + + gFieldEffectArguments[0] = playerObj->currentCoords.x; + gFieldEffectArguments[1] = playerObj->currentCoords.y; + FieldEffectStart(FLDEFF_ORAS_DOWSE); +} + +void ResumeORASDowseFieldEffect(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + StartORASDowseFieldEffect(); +} + +static const struct SpritePalette gSpritePalette_ORASDowsing = {gFieldEffectPal_ORASDowsing, FLDEFF_PAL_TAG_ORAS_DOWSE}; + +// Sprite data for ORAS Dowsing Machine +#define tItemDistanceX data[0] +#define tItemDistanceY data[1] +#define sItemFound data[2] +#define sCounter data[3] +#define sSoundTimer data[4] +#define sDowseState data[5] +#define sPrevDowseState data[6] +#define sMoveActive data[7] + +#define fPlayerX gFieldEffectArguments[0] +#define fPlayerY gFieldEffectArguments[1] + +// Create the ORAS Dowsing Machine sprite. +u32 FldEff_ORASDowsing(void) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + u32 spriteId; + u32 palNum; + + FlagSet(I_ORAS_DOWSING_FLAG); + SetSpritePosToOffsetMapCoords((s16 *)&fPlayerX, (s16 *)&fPlayerY, 8, 0); + if (gPlayerAvatar.gender == MALE) + spriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[FLDEFFOBJ_ORAS_DOWSE_BRENDAN], fPlayerX, fPlayerY, 1); + else + spriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[FLDEFFOBJ_ORAS_DOWSE_MAY], fPlayerX, fPlayerY, 1); + + if (spriteId != MAX_SPRITES) + { + struct Sprite *sprite = &gSprites[spriteId]; + sprite->coordOffsetEnabled = TRUE; + palNum = LoadSpritePalette(&gSpritePalette_ORASDowsing); + if (palNum != 0xFF) + sprite->oam.paletteNum = palNum; + else + sprite->oam.paletteNum = LoadPlayerObjectEventPalette(gSaveBlock2Ptr->playerGender); + + playerObj->fieldEffectSpriteId = spriteId; + sprite->sDowseState = ORASD_WIGGLE_NONE; + UpdateDowseState(sprite); + } + FieldEffectActiveListRemove(FLDEFF_ORAS_DOWSE); + return spriteId; +} + +// Callback for ORAS Dowsing Machine sprite. +static void UpdateORASDowsingFieldEffect(struct Sprite *sprite) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + struct Sprite *playerSprite = &gSprites[playerObj->spriteId]; + + if (!FlagGet(I_ORAS_DOWSING_FLAG)) + { + DestroySpriteAndFreeResources(sprite); + return; + } + + sprite->x = playerSprite->x; + sprite->y = playerSprite->y; + sprite->x2 = playerSprite->x2; + sprite->y2 = playerSprite->y2; + + if (playerSprite->anims[playerSprite->animNum][playerSprite->animCmdIndex].frame.imageValue > 2) + sprite->y2++; + + if (playerObj->previousMovementDirection != playerObj->movementDirection) + UpdateDowsingAnimDirection(sprite, playerObj); + + if (playerObj->movementActionId != MOVEMENT_ACTION_NONE) + { + if (playerObj->heldMovementFinished == FALSE) + { + if (sprite->sCounter == 0) + { + sprite->sMoveActive = TRUE; + sprite->sCounter++; + } + } + else if (playerObj->heldMovementFinished == TRUE && sprite->sMoveActive) + { + sprite->sMoveActive = FALSE; + sprite->sCounter = 0; + UpdateDowseState(sprite); + } + } + + if (I_ORAS_DOWSING_SOUNDS && sprite->sDowseState == ORASD_WIGGLE_FASTER && playerObj->heldMovementFinished != FALSE) + { + if (++sprite->sSoundTimer == 70) + { + PlaySE(SE_ITEMFINDER); + sprite->sSoundTimer = 0; + } + } + sprite->oam.priority = playerSprite->oam.priority; +} + +static const u8 sClockwiseDirections[] = {DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST}; + +void UpdateDowseState(struct Sprite *sprite) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + + sprite->tItemDistanceX = 0; + sprite->tItemDistanceY = 0; + sprite->sPrevDowseState = sprite->sDowseState; + if (ItemfinderCheckForHiddenItems(gMapHeader.events, TASK_NONE) == TRUE) + { + s8 distX = sprite->tItemDistanceX; + s8 distY = sprite->tItemDistanceY; + u8 directionToItem = CARDINAL_DIRECTION_COUNT; + u8 playerDirToItem = GetDirectionToHiddenItem(distX, distY); + if (playerDirToItem != DIR_NONE) + directionToItem = sClockwiseDirections[GetDirectionToHiddenItem(distX, distY) - 1]; + + if (distX < 0) + distX *= -1; + + if (distY < 0) + distY *= -1; + + // If the player is facing the item's direction. + if (directionToItem == playerObj->movementDirection) + { + ChangeDowsingColor(directionToItem, sprite); + } + // If x and y distances are equal, make sure item can bee seen from both facing directions. + else if (distX == distY && distX != 0) + { + if ((directionToItem == DIR_NORTH || directionToItem == DIR_SOUTH) && sprite->tItemDistanceX > 0 && playerObj->movementDirection == DIR_EAST) + ChangeDowsingColor(DIR_EAST, sprite); + else if ((directionToItem == DIR_NORTH || directionToItem == DIR_SOUTH) && sprite->tItemDistanceX < 0 && playerObj->movementDirection == DIR_WEST) + ChangeDowsingColor(DIR_WEST, sprite); + else + ClearDowsingColor(sprite); + } + else + { + ClearDowsingColor(sprite); + } + } + else + { + ClearDowsingColor(sprite); + } + UpdateDowsingAnimDirection(sprite, playerObj); +} + +static void ChangeDowsingColor(u8 direction, struct Sprite *sprite) +{ + s16 distance; + u16 color = I_ORAS_DOWSING_COLOR_NONE; + + if (direction == DIR_NORTH || direction == DIR_SOUTH) + distance = sprite->tItemDistanceY; + else + distance = sprite->tItemDistanceX; + + // Absolute value. + if (distance < 0) + distance *= -1; + + switch (distance) + { + case 1: + if (sprite->tItemDistanceX == 0 || sprite->tItemDistanceY == 0) + { + color = I_ORAS_DOWSING_COLOR_FASTER; + sprite->sDowseState = ORASD_WIGGLE_FASTER; + break; + } + case 2: + color = I_ORAS_DOWSING_COLOR_FAST; + sprite->sDowseState = ORASD_WIGGLE_FAST; + break; + case 3: + case 4: + color = I_ORAS_DOWSING_COLOR_NORMAL; + sprite->sDowseState = ORASD_WIGGLE_NORMAL; + break; + case 5: + case 6: + case 7: + color = I_ORAS_DOWSING_COLOR_SLOW; + sprite->sDowseState = ORASD_WIGGLE_SLOW; + break; + } + + if (I_ORAS_DOWSING_SOUNDS && sprite->sDowseState != sprite->sPrevDowseState) + { + sprite->sSoundTimer = 0; + PlayDowseSound(sprite->sDowseState); + } + + FillPalette(color, (OBJ_PLTT_ID(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)) + I_ORAS_DOWSING_COLOR_PAL), PLTT_SIZEOF(1)); + UpdateSpritePaletteWithTime(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)); +} + +static void ClearDowsingColor(struct Sprite *sprite) +{ + sprite->sDowseState = ORASD_WIGGLE_NONE; + FillPalette(I_ORAS_DOWSING_COLOR_NONE, (OBJ_PLTT_ID(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)) + I_ORAS_DOWSING_COLOR_PAL), PLTT_SIZEOF(1)); + UpdateSpritePaletteWithTime(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)); +} + +static void PlayDowseSound(u32 dowseState) +{ + switch (dowseState) + { + case ORASD_WIGGLE_SLOW: + PlaySE(SE_CONTEST_ICON_CLEAR); + return; + case ORASD_WIGGLE_NORMAL: + PlaySE(SE_PIN); + return; + case ORASD_WIGGLE_FAST: + PlaySE(SE_SUCCESS); + return; + case ORASD_WIGGLE_FASTER: + PlaySE(SE_ITEMFINDER); + return; + } +} + +void UpdateDowsingAnimDirection(struct Sprite *sprite, struct ObjectEvent *playerObj) +{ + u32 anim = (playerObj->facingDirection - 1); + + switch (sprite->sDowseState) + { + case ORASD_WIGGLE_SLOW: + anim += 4; + break; + case ORASD_WIGGLE_NORMAL: + anim += 8; + break; + case ORASD_WIGGLE_FAST: + anim += 12; + break; + case ORASD_WIGGLE_FASTER: + anim += 16; + break; + } + + // Don't completely restart anim if wiggling didn't stop. + if (sprite->sPrevDowseState != ORASD_WIGGLE_NONE && sprite->sDowseState != ORASD_WIGGLE_NONE) + SetAndStartSpriteAnim(sprite, anim, sprite->animCmdIndex); + else + StartSpriteAnimIfDifferent(sprite, anim); +} + +void EndORASDowsing(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + FlagClear(I_ORAS_DOWSING_FLAG); +} + +void Script_ClearDowsingColor(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + { + struct Sprite *sprite = &gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId]; + ClearDowsingColor(sprite); + UpdateDowsingAnimDirection(sprite, &gObjectEvents[gPlayerAvatar.objectEventId]); + } +} + +void Script_UpdateDowseState(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + UpdateDowseState(&gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId]); +} diff --git a/src/overworld.c b/src/overworld.c index 1afce582cd..5f16de1f2e 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -43,6 +43,7 @@ #include "mirage_tower.h" #include "money.h" #include "new_game.h" +#include "oras_dowse.h" #include "palette.h" #include "play_time.h" #include "random.h" @@ -429,10 +430,13 @@ void Overworld_ResetBattleFlagsAndVars(void) VarSet(B_VAR_WILD_AI_FLAGS,0); #endif + #if B_VAR_NO_BAG_USE != 0 + VarSet(B_VAR_NO_BAG_USE, 0); + #endif + FlagClear(B_FLAG_INVERSE_BATTLE); FlagClear(B_FLAG_FORCE_DOUBLE_WILD); FlagClear(B_SMART_WILD_AI_FLAG); - FlagClear(B_FLAG_NO_BAG_USE); FlagClear(B_FLAG_NO_CATCHING); FlagClear(B_FLAG_NO_RUNNING); FlagClear(B_FLAG_DYNAMAX_BATTLE); @@ -1621,7 +1625,7 @@ void UpdateTimeOfDay(void) #undef DEFAULT_WEIGHT // Whether a map type is naturally lit/outside -bool32 MapHasNaturalLight(u8 mapType) +bool32 MapHasNaturalLight(enum MapType mapType) { return (OW_ENABLE_DNS && (mapType == MAP_TYPE_TOWN @@ -2237,6 +2241,7 @@ static bool32 ReturnToFieldLocal(u8 *state) InitViewGraphics(); TryLoadTrainerHillEReaderPalette(); FollowerNPC_BindToSurfBlobOnReloadScreen(); + ResumeORASDowseFieldEffect(); (*state)++; break; case 2: diff --git a/src/party_menu.c b/src/party_menu.c index 34d2e6c677..8498a80e97 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -43,6 +43,7 @@ #include "menu_helpers.h" #include "menu_specialized.h" #include "metatile_behavior.h" +#include "move_relearner.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" @@ -99,6 +100,11 @@ enum { MENU_REGISTER, MENU_TRADE1, MENU_TRADE2, + MENU_LEVEL_UP_MOVES, + MENU_EGG_MOVES, + MENU_TM_MOVES, + MENU_TUTOR_MOVES, + MENU_SUB_MOVES, MENU_TOSS, MENU_CATALOG_BULB, MENU_CATALOG_OVEN, @@ -126,6 +132,7 @@ enum { ACTIONS_REGISTER, ACTIONS_TRADE, ACTIONS_SPIN_TRADE, + ACTIONS_MOVES_SUB, ACTIONS_TAKEITEM_TOSS, ACTIONS_ROTOM_CATALOG, ACTIONS_ZYGARDE_CUBE, @@ -335,13 +342,13 @@ static void Task_CancelParticipationYesNo(u8); static void Task_HandleCancelParticipationYesNoInput(u8); static bool8 ShouldUseChooseMonText(void); static void SetPartyMonFieldSelectionActions(struct Pokemon *, u8); +static void SetPartyMonLearnMoveSelectionActions(struct Pokemon*, u8); static u8 GetPartyMenuActionsTypeInBattle(struct Pokemon *); static u8 GetPartySlotEntryStatus(s8); static void Task_UpdateHeldItemSprite(u8); static void Task_HandleSelectionMenuInput(u8); static void CB2_ShowPokemonSummaryScreen(void); static void UpdatePartyToBattleOrder(void); -static void CB2_ReturnToPartyMenuFromSummaryScreen(void); static void SlidePartyMenuBoxOneStep(u8); static void Task_SlideSelectedSlotsOffscreen(u8); static void SwitchPartyMon(void); @@ -478,6 +485,11 @@ static void CursorCb_Trade1(u8); static void CursorCb_Trade2(u8); static void CursorCb_Toss(u8); static void CursorCb_FieldMove(u8); +static void CursorCb_ChangeLevelUpMoves(u8); +static void CursorCb_ChangeEggMoves(u8); +static void CursorCb_ChangeTMMoves(u8); +static void CursorCb_ChangeTutorMoves(u8); +static void CursorCb_LearnMovesSubMenu(u8); static void CursorCb_CatalogBulb(u8); static void CursorCb_CatalogOven(u8); static void CursorCb_CatalogWashing(u8); @@ -1081,10 +1093,27 @@ static void DisplayPartyPokemonDataForContest(u8 slot) static void DisplayPartyPokemonDataForRelearner(u8 slot) { - if (GetNumberOfRelearnableMoves(&gPlayerParty[slot]) == 0) - DisplayPartyPokemonDescriptionData(slot, PARTYBOX_DESC_NOT_ABLE_2); - else - DisplayPartyPokemonDescriptionData(slot, PARTYBOX_DESC_ABLE_2); + struct Pokemon *mon = &gPlayerParty[slot]; + bool32 hasMoves = FALSE; + + switch (gMoveRelearnerState) + { + case MOVE_RELEARNER_EGG_MOVES: + hasMoves = (GetNumberOfEggMoves(mon) > 0); + break; + case MOVE_RELEARNER_TM_MOVES: + hasMoves = (GetNumberOfTMMoves(mon) > 0); + break; + case MOVE_RELEARNER_TUTOR_MOVES: + hasMoves = (GetNumberOfTutorMoves(mon) > 0); + break; + default: + hasMoves = (GetNumberOfLevelUpMoves(mon) > 0); + break; + } + + u32 desc = (hasMoves ? PARTYBOX_DESC_ABLE_2 : PARTYBOX_DESC_NOT_ABLE_2); + DisplayPartyPokemonDescriptionData(slot, desc); } static void DisplayPartyPokemonDataForWirelessMinigame(u8 slot) @@ -2771,7 +2800,13 @@ static u8 DisplaySelectionWindow(u8 windowType) for (i = 0; i < sPartyMenuInternal->numActions; i++) { const u8 *text; - u8 fontColorsId = (sPartyMenuInternal->actions[i] >= MENU_FIELD_MOVES) ? 4 : 3; + u8 fontColorsId = 3; + + if (sPartyMenuInternal->actions[i] >= MENU_FIELD_MOVES) + fontColorsId = 4; + if (sPartyMenuInternal->actions[i] >= MENU_LEVEL_UP_MOVES && sPartyMenuInternal->actions[i] <= MENU_SUB_MOVES) + fontColorsId = 6; + if (sPartyMenuInternal->actions[i] >= MENU_FIELD_MOVES) text = GetMoveName(FieldMove_GetMoveId(sPartyMenuInternal->actions[i] - MENU_FIELD_MOVES)); else @@ -2819,6 +2854,11 @@ static void SetPartyMonSelectionActions(struct Pokemon *mons, u8 slotId, u8 acti { SetPartyMonFieldSelectionActions(mons, slotId); } + else if (action == ACTIONS_MOVES_SUB && P_PARTY_MOVE_RELEARNER) + { + sPartyMenuInternal->numActions = 0; + SetPartyMonLearnMoveSelectionActions(mons, slotId); + } else { sPartyMenuInternal->numActions = sPartyMenuActionCounts[action]; @@ -2834,6 +2874,12 @@ static void SetPartyMonFieldSelectionActions(struct Pokemon *mons, u8 slotId) sPartyMenuInternal->numActions = 0; AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_SUMMARY); + if (P_PARTY_MOVE_RELEARNER + && (GetMonData(&mons[slotId], MON_DATA_SPECIES) + && (GetNumberOfLevelUpMoves(&mons[slotId]) || GetNumberOfEggMoves(&mons[slotId]) + || GetNumberOfTMMoves(&mons[slotId]) || GetNumberOfTutorMoves(&mons[slotId])))) + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_SUB_MOVES); + // Add field moves to action list for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2859,6 +2905,32 @@ static void SetPartyMonFieldSelectionActions(struct Pokemon *mons, u8 slotId) AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_CANCEL1); } +static void SetPartyMonLearnMoveSelectionActions(struct Pokemon *mons, u8 slotId) +{ + if (GetMonData(&mons[slotId], MON_DATA_SPECIES) != SPECIES_NONE && GetNumberOfLevelUpMoves(&mons[slotId]) > 0) + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_LEVEL_UP_MOVES); + + if (P_ENABLE_MOVE_RELEARNERS || (P_FLAG_EGG_MOVES != 0 && FlagGet(P_FLAG_EGG_MOVES))) + { + if (GetMonData(&mons[slotId], MON_DATA_SPECIES) != SPECIES_NONE && GetNumberOfEggMoves(&mons[slotId]) > 0) + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_EGG_MOVES); + } + + if (P_ENABLE_MOVE_RELEARNERS || P_TM_MOVES_RELEARNER) + { + if (GetMonData(&mons[slotId], MON_DATA_SPECIES) != SPECIES_NONE && GetNumberOfTMMoves(&mons[slotId]) > 0) + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_TM_MOVES); + } + + if (P_ENABLE_MOVE_RELEARNERS || (P_FLAG_TUTOR_MOVES != 0 && FlagGet(P_FLAG_TUTOR_MOVES))) + { + if (GetMonData(&mons[slotId], MON_DATA_SPECIES) != SPECIES_NONE && GetNumberOfTutorMoves(&mons[slotId]) > 0) + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_TUTOR_MOVES); + } + + AppendToList(sPartyMenuInternal->actions, &sPartyMenuInternal->numActions, MENU_CANCEL1); +} + static u8 GetPartyMenuActionsType(struct Pokemon *mon) { u32 actionType; @@ -3020,7 +3092,7 @@ static void CB2_ShowPokemonSummaryScreen(void) } } -static void CB2_ReturnToPartyMenuFromSummaryScreen(void) +void CB2_ReturnToPartyMenuFromSummaryScreen(void) { gPaletteFade.bufferTransferDisabled = TRUE; gPartyMenu.slotId = gLastViewedMonIndex; @@ -7512,19 +7584,12 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba { u8 partyIndexes[PARTY_SIZE]; int i, j; - u8 leftBattler; - u8 rightBattler; + u8 leftBattler; if (IsOnPlayerSide(battler)) - { leftBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - rightBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); - } else - { leftBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); - rightBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - } if (IsMultiBattle() == TRUE) { @@ -7557,6 +7622,12 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba } else { + u8 rightBattler; + if (IsOnPlayerSide(battler)) + rightBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + else + rightBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + j = 2; partyIndexes[0] = gBattlerPartyIndexes[leftBattler]; partyIndexes[1] = gBattlerPartyIndexes[rightBattler]; @@ -7869,6 +7940,7 @@ static void Task_ChoosePartyMon(u8 taskId) void ChooseMonForMoveRelearner(void) { + gRelearnMode = RELEARN_MODE_SCRIPT; LockPlayerFieldControls(); FadeScreen(FADE_TO_BLACK, 0); CreateTask(Task_ChooseMonForMoveRelearner, 10); @@ -7888,9 +7960,27 @@ static void CB2_ChooseMonForMoveRelearner(void) { gSpecialVar_0x8004 = GetCursorSelectionMonId(); if (gSpecialVar_0x8004 >= PARTY_SIZE) + { gSpecialVar_0x8004 = PARTY_NOTHING_CHOSEN; + } else - gSpecialVar_0x8005 = GetNumberOfRelearnableMoves(&gPlayerParty[gSpecialVar_0x8004]); + { + switch(gMoveRelearnerState) + { + case MOVE_RELEARNER_EGG_MOVES: + gSpecialVar_0x8005 = GetNumberOfEggMoves(&gPlayerParty[gSpecialVar_0x8004]); + break; + case MOVE_RELEARNER_TM_MOVES: + gSpecialVar_0x8005 = GetNumberOfTMMoves(&gPlayerParty[gSpecialVar_0x8004]); + break; + case MOVE_RELEARNER_TUTOR_MOVES: + gSpecialVar_0x8005 = GetNumberOfTutorMoves(&gPlayerParty[gSpecialVar_0x8004]); + break; + default: + gSpecialVar_0x8005 = GetNumberOfLevelUpMoves(&gPlayerParty[gSpecialVar_0x8004]); + break; + } + } gFieldCallback2 = CB2_FadeFromPartyMenu; SetMainCallback2(CB2_ReturnToField); } @@ -8020,6 +8110,62 @@ void IsLastMonThatKnowsSurf(void) } } +static void CursorCb_ChangeLevelUpMoves(u8 taskId) +{ + PlaySE(SE_SELECT); + gMoveRelearnerState = MOVE_RELEARNER_LEVEL_UP_MOVES; + gRelearnMode = RELEARN_MODE_PARTY_MENU; + gLastViewedMonIndex = gPartyMenu.slotId; + gSpecialVar_0x8004 = gLastViewedMonIndex; + TeachMoveRelearnerMove(); + Task_ClosePartyMenu(taskId); +} + +static void CursorCb_ChangeEggMoves(u8 taskId) +{ + PlaySE(SE_SELECT); + gMoveRelearnerState = MOVE_RELEARNER_EGG_MOVES; + gRelearnMode = RELEARN_MODE_PARTY_MENU; + gLastViewedMonIndex = gPartyMenu.slotId; + gSpecialVar_0x8004 = gLastViewedMonIndex; + TeachMoveRelearnerMove(); + Task_ClosePartyMenu(taskId); +} + +static void CursorCb_ChangeTMMoves(u8 taskId) +{ + PlaySE(SE_SELECT); + gMoveRelearnerState = MOVE_RELEARNER_TM_MOVES; + gRelearnMode = RELEARN_MODE_PARTY_MENU; + gLastViewedMonIndex = gPartyMenu.slotId; + gSpecialVar_0x8004 = gLastViewedMonIndex; + TeachMoveRelearnerMove(); + Task_ClosePartyMenu(taskId); +} + +static void CursorCb_ChangeTutorMoves(u8 taskId) +{ + PlaySE(SE_SELECT); + gMoveRelearnerState = MOVE_RELEARNER_TUTOR_MOVES; + gRelearnMode = RELEARN_MODE_PARTY_MENU; + gLastViewedMonIndex = gPartyMenu.slotId; + gSpecialVar_0x8004 = gLastViewedMonIndex; + TeachMoveRelearnerMove(); + Task_ClosePartyMenu(taskId); +} + +static void CursorCb_LearnMovesSubMenu(u8 taskId) +{ + PlaySE(SE_SELECT); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]); + PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); + SetPartyMonSelectionActions(gPlayerParty, gPartyMenu.slotId, ACTIONS_MOVES_SUB); + DisplaySelectionWindow(SELECTWINDOW_ACTIONS); + DisplayPartyMenuStdMessage(PARTY_MSG_DO_WHAT_WITH_MON); + gTasks[taskId].data[0] = 0xFF; + gTasks[taskId].func = Task_HandleSelectionMenuInput; +} + void CursorCb_MoveItemCallback(u8 taskId) { u16 item1, item2; diff --git a/src/pokedex.c b/src/pokedex.c index 7f2ebe2d9c..d8265a4cee 100644 --- a/src/pokedex.c +++ b/src/pokedex.c @@ -1426,7 +1426,7 @@ static const u8 sOrderOptions[] = ORDER_SMALLEST, }; -static const u8 sDexSearchTypeIds[NUMBER_OF_MON_TYPES] = +static const enum Type sDexSearchTypeIds[NUMBER_OF_MON_TYPES] = { TYPE_NONE, TYPE_NORMAL, @@ -4940,12 +4940,12 @@ static u16 CreateSizeScreenTrainerPic(u16 species, s16 x, s16 y, s8 paletteSlot) return CreateTrainerPicSprite(species, TRUE, x, y, paletteSlot, TAG_NONE); } -static int DoPokedexSearch(u8 dexMode, u8 order, u8 abcGroup, enum BodyColor bodyColor, u8 type1, u8 type2) +static int DoPokedexSearch(u8 dexMode, u8 order, u8 abcGroup, enum BodyColor bodyColor, enum Type type1, enum Type type2) { u16 species; u16 i; u16 resultsCount; - u8 types[2]; + enum Type types[2]; CreatePokedexList(dexMode, order); @@ -5352,8 +5352,8 @@ static void Task_StartPokedexSearch(u8 taskId) u8 order = GetSearchModeSelection(taskId, SEARCH_ORDER); u8 abcGroup = GetSearchModeSelection(taskId, SEARCH_NAME); enum BodyColor bodyColor = GetSearchModeSelection(taskId, SEARCH_COLOR); - u8 type1 = GetSearchModeSelection(taskId, SEARCH_TYPE_LEFT); - u8 type2 = GetSearchModeSelection(taskId, SEARCH_TYPE_RIGHT); + enum Type type1 = GetSearchModeSelection(taskId, SEARCH_TYPE_LEFT); + enum Type type2 = GetSearchModeSelection(taskId, SEARCH_TYPE_RIGHT); DoPokedexSearch(dexMode, order, abcGroup, bodyColor, type1, type2); gTasks[taskId].func = Task_WaitAndCompleteSearch; diff --git a/src/pokedex_area_screen.c b/src/pokedex_area_screen.c index f48db5eacb..76e3b71c6c 100644 --- a/src/pokedex_area_screen.c +++ b/src/pokedex_area_screen.c @@ -248,7 +248,7 @@ static const struct WindowTemplate sTimeOfDayWindowLabelTemplates[] = .baseBlock = 0x16C }, - [DEX_AREA_LABEL_AREA_UNKNOWN] = + [DEX_AREA_LABEL_AREA_UNKNOWN] = { .bg = LABEL_WINDOW_BG, .tilemapLeft = 12, diff --git a/src/pokedex_cry_screen.c b/src/pokedex_cry_screen.c index b567aac391..810a8dae6a 100644 --- a/src/pokedex_cry_screen.c +++ b/src/pokedex_cry_screen.c @@ -228,7 +228,7 @@ static const struct SpritePalette sCryMeterNeedleSpritePalettes[] = bool8 LoadCryWaveformWindow(struct CryScreenWindow *window, u8 windowId) { u8 i; - u8 finished = FALSE; + bool32 finished = FALSE; switch (gDexCryScreenState) { diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index 03cf7bb8d2..ea96e764c3 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -2,6 +2,7 @@ #include "battle_main.h" #include "battle_util.h" #include "bg.h" +#include "contest.h" #include "contest_effect.h" #include "data.h" #include "daycare.h" @@ -360,9 +361,9 @@ struct PokemonStats u8 eggCycles; u16 expYield; u8 friendship; - u16 ability0; - u16 ability1; - u16 abilityHidden; + enum Ability ability0; + enum Ability ability1; + enum Ability abilityHidden; }; struct EvoScreenData @@ -1913,7 +1914,7 @@ static const u8 sOrderOptions[] = ORDER_SMALLEST, }; -static const u8 sDexSearchTypeIds[NUMBER_OF_MON_TYPES] = +static const enum Type sDexSearchTypeIds[NUMBER_OF_MON_TYPES] = { TYPE_NONE, TYPE_NORMAL, @@ -4340,14 +4341,7 @@ static void SetSpriteInvisibility(u8 spriteArrayId, bool8 invisible) { gSprites[sPokedexView->typeIconSpriteIds[spriteArrayId]].invisible = invisible; } -static const u8 sContestCategoryToOamPaletteNum[CONTEST_CATEGORIES_COUNT] = -{ - [CONTEST_CATEGORY_COOL] = 13, - [CONTEST_CATEGORY_BEAUTY] = 14, - [CONTEST_CATEGORY_CUTE] = 14, - [CONTEST_CATEGORY_SMART] = 15, - [CONTEST_CATEGORY_TOUGH] = 13, -}; + static void SetTypeIconPosAndPal(u8 typeId, u8 x, u8 y, u8 spriteArrayId) { struct Sprite *sprite; @@ -4357,14 +4351,14 @@ static void SetTypeIconPosAndPal(u8 typeId, u8 x, u8 y, u8 spriteArrayId) if (typeId < NUMBER_OF_MON_TYPES) sprite->oam.paletteNum = gTypesInfo[typeId].palette + TYPE_INFO_PALETTE_NUM_OFFSET; else - sprite->oam.paletteNum = sContestCategoryToOamPaletteNum[typeId - NUMBER_OF_MON_TYPES] + TYPE_INFO_PALETTE_NUM_OFFSET; + sprite->oam.paletteNum = gContestCategoryInfo[typeId - NUMBER_OF_MON_TYPES].palette; sprite->x = x + 16; sprite->y = y + 8; SetSpriteInvisibility(spriteArrayId, FALSE); } static void PrintCurrentSpeciesTypeInfo(u8 newEntry, u16 species) { - u8 type1, type2; + enum Type type1, type2; if (!newEntry) { @@ -5294,7 +5288,7 @@ static void PrintStatsScreen_Moves_Description(u8 taskId) } else { - StringCopy(gStringVar4, gContestEffectDescriptionPointers[GetMoveContestEffect(move)]); + StringCopy(gStringVar4, gContestEffects[GetMoveContestEffect(move)].description); PrintStatsScreenTextSmall(WIN_STATS_MOVES_DESCRIPTION, gStringVar4, moves_x, moves_y); } } @@ -5881,9 +5875,9 @@ static void PrintStatsScreen_Abilities(u8 taskId) { u8 abilities_x = 5; u8 abilities_y = 3; - u16 ability0; - u16 ability1; - u16 abilityHidden; + enum Ability ability0; + enum Ability ability1; + enum Ability abilityHidden; //Abilitie(s) @@ -6637,7 +6631,8 @@ static void PrintEvolutionTargetSpeciesAndMethod(u8 taskId, u16 species, u8 dept StringAppend(gStringVar4, COMPOUND_STRING(", ")); } - switch((enum EvolutionConditions)evolutions[i].params[j].condition) + enum EvolutionConditions condition = evolutions[i].params[j].condition; + switch(condition) { // Gen 2 case IF_GENDER: @@ -6694,10 +6689,10 @@ static void PrintEvolutionTargetSpeciesAndMethod(u8 taskId, u16 species, u8 dept case IF_PID_UPPER_MODULO_10_EQ: case IF_PID_UPPER_MODULO_10_LT: arg = evolutions[i].params[j].arg1; - if ((enum EvolutionConditions)evolutions[i].params[j].condition == IF_PID_UPPER_MODULO_10_GT + if (condition == IF_PID_UPPER_MODULO_10_GT && arg < 10 && arg >= 0) arg = 9 - arg; - else if ((enum EvolutionConditions)evolutions[i].params[j].condition == IF_PID_UPPER_MODULO_10_EQ + else if (condition == IF_PID_UPPER_MODULO_10_EQ && arg < 10 && arg >= 0) arg = 1; ConvertIntToDecimalStringN(gStringVar2, arg * 10, STR_CONV_MODE_LEFT_ALIGN, 3); @@ -6756,6 +6751,33 @@ static void PrintEvolutionTargetSpeciesAndMethod(u8 taskId, u16 species, u8 dept StringAppend(gStringVar4, gTypesInfo[evolutions[i].params[j].arg1].name); StringAppend(gStringVar4, COMPOUND_STRING(" move")); break; + case IF_REGION: + case IF_NOT_REGION: + { + if (condition == IF_REGION) + StringAppend(gStringVar4, COMPOUND_STRING("in ")); + else if (condition == IF_NOT_REGION) + StringAppend(gStringVar4, COMPOUND_STRING("out of ")); + + switch ((enum Region)evolutions[i].params[j].arg1) + { + case REGION_NONE: + case REGIONS_COUNT: + StringAppend(gStringVar4, COMPOUND_STRING("???")); + break; + case REGION_KANTO: StringAppend(gStringVar4, COMPOUND_STRING("Kanto")); break; + case REGION_JOHTO: StringAppend(gStringVar4, COMPOUND_STRING("Johto")); break; + case REGION_HOENN: StringAppend(gStringVar4, COMPOUND_STRING("Hoenn")); break; + case REGION_SINNOH: StringAppend(gStringVar4, COMPOUND_STRING("Sinnoh")); break; + case REGION_UNOVA: StringAppend(gStringVar4, COMPOUND_STRING("Unova")); break; + case REGION_KALOS: StringAppend(gStringVar4, COMPOUND_STRING("Kalos")); break; + case REGION_ALOLA: StringAppend(gStringVar4, COMPOUND_STRING("Alola")); break; + case REGION_GALAR: StringAppend(gStringVar4, COMPOUND_STRING("Galar")); break; + case REGION_HISUI: StringAppend(gStringVar4, COMPOUND_STRING("Hisui")); break; + case REGION_PALDEA: StringAppend(gStringVar4, COMPOUND_STRING("Paldea")); break; + } + break; + } // Gen 8 case IF_NATURE: StringCopy(gStringVar2, gNaturesInfo[evolutions[i].params[j].arg1].name); @@ -6807,10 +6829,10 @@ static void PrintEvolutionTargetSpeciesAndMethod(u8 taskId, u16 species, u8 dept case IF_PID_MODULO_100_EQ: case IF_PID_MODULO_100_LT: arg = evolutions[i].params[j].arg1; - if ((enum EvolutionConditions)evolutions[i].params[j].condition == IF_PID_MODULO_100_GT + if (condition == IF_PID_MODULO_100_GT && arg < 100 && arg >= 0) arg = 99 - arg; - else if ((enum EvolutionConditions)evolutions[i].params[j].condition == IF_PID_MODULO_100_EQ + else if (condition == IF_PID_MODULO_100_EQ && arg < 100 && arg >= 0) arg = 1; ConvertIntToDecimalStringN(gStringVar2, arg, STR_CONV_MODE_LEFT_ALIGN, 3); @@ -7814,12 +7836,12 @@ static void Task_ClosePokedexFromSearchResultsStartMenu(u8 taskId) //* Search code * //* * //************************************ -static int DoPokedexSearch(u8 dexMode, u8 order, u8 abcGroup, enum BodyColor bodyColor, u8 type1, u8 type2) +static int DoPokedexSearch(u8 dexMode, u8 order, u8 abcGroup, enum BodyColor bodyColor, enum Type type1, enum Type type2) { u16 species; u16 i; u16 resultsCount; - u8 types[2]; + enum Type types[2]; CreatePokedexList(dexMode, order); @@ -8231,8 +8253,8 @@ static void Task_StartPokedexSearch(u8 taskId) u8 order = GetSearchModeSelection(taskId, SEARCH_ORDER); u8 abcGroup = GetSearchModeSelection(taskId, SEARCH_NAME); enum BodyColor bodyColor = GetSearchModeSelection(taskId, SEARCH_COLOR); - u8 type1 = GetSearchModeSelection(taskId, SEARCH_TYPE_LEFT); - u8 type2 = GetSearchModeSelection(taskId, SEARCH_TYPE_RIGHT); + enum Type type1 = GetSearchModeSelection(taskId, SEARCH_TYPE_LEFT); + enum Type type2 = GetSearchModeSelection(taskId, SEARCH_TYPE_RIGHT); DoPokedexSearch(dexMode, order, abcGroup, bodyColor, type1, type2); gTasks[taskId].func = Task_WaitAndCompleteSearch; diff --git a/src/pokemon.c b/src/pokemon.c index a2aad772df..16c3844527 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -12,6 +12,7 @@ #include "battle_tower.h" #include "battle_z_move.h" #include "data.h" +#include "daycare.h" #include "dexnav.h" #include "event_data.h" #include "event_object_movement.h" @@ -19,12 +20,14 @@ #include "field_player_avatar.h" #include "field_specials.h" #include "field_weather.h" +#include "fishing.h" #include "follower_npc.h" #include "graphics.h" #include "item.h" #include "caps.h" #include "link.h" #include "main.h" +#include "move_relearner.h" #include "overworld.h" #include "m4a.h" #include "party_menu.h" @@ -37,6 +40,7 @@ #include "pokemon_storage_system.h" #include "random.h" #include "recorded_battle.h" +#include "regions.h" #include "rtc.h" #include "sound.h" #include "string_util.h" @@ -55,7 +59,6 @@ #include "constants/cries.h" #include "constants/event_objects.h" #include "constants/form_change_types.h" -#include "constants/hold_effects.h" #include "constants/item_effects.h" #include "constants/items.h" #include "constants/layouts.h" @@ -65,7 +68,6 @@ #include "constants/trainers.h" #include "constants/union_room.h" #include "constants/weather.h" -#include "wild_encounter.h" #define FRIENDSHIP_EVO_THRESHOLD ((P_FRIENDSHIP_EVO_THRESHOLD >= GEN_8) ? 160 : 220) @@ -852,7 +854,7 @@ static const u8 sGetMonDataEVConstants[] = }; // For stat-raising items -static const u8 sStatsToRaise[] = +static const enum Stat sStatsToRaise[] = { STAT_ATK, STAT_ATK, STAT_DEF, STAT_SPEED, STAT_SPATK, STAT_SPDEF, STAT_ACC }; @@ -1042,8 +1044,8 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, u32 value; u16 checksum; u8 i; - u8 availableIVs[NUM_STATS]; - u8 selectedIvs[NUM_STATS]; + enum Stat availableIVs[NUM_STATS]; + enum Stat selectedIvs[NUM_STATS]; bool32 isShiny; ZeroBoxMonData(boxMon); @@ -1089,8 +1091,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, totalRerolls += I_SHINY_CHARM_ADDITIONAL_ROLLS; if (LURE_STEP_COUNT != 0) totalRerolls += 1; - if (I_FISHING_CHAIN && gIsFishingEncounter) - totalRerolls += CalculateChainFishingShinyRolls(); + totalRerolls += CalculateChainFishingShinyRolls(); if (gDexNavSpecies) totalRerolls += CalculateDexNavShinyRolls(); @@ -1129,7 +1130,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, SetBoxMonData(boxMon, MON_DATA_POKEBALL, &value); SetBoxMonData(boxMon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender); - u32 teraType = (boxMon->personality & 0x1) == 0 ? GetSpeciesType(species, 0) : GetSpeciesType(species, 1); + enum Type teraType = (boxMon->personality & 0x1) == 0 ? GetSpeciesType(species, 0) : GetSpeciesType(species, 1); SetBoxMonData(boxMon, MON_DATA_TERA_TYPE, &teraType); if (fixedIV < USE_RANDOM_IVS) @@ -1201,6 +1202,8 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, case STAT_SPDEF: SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv); break; + default: + break; } } } @@ -2739,7 +2742,7 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data) } else if (substruct0->teraType == TYPE_NONE) // Tera Type hasn't been modified so we can just use the personality { - const u8 *types = gSpeciesInfo[substruct0->species].types; + const enum Type *types = gSpeciesInfo[substruct0->species].types; retVal = (boxMon->personality & 0x1) == 0 ? types[0] : types[1]; } else @@ -2843,7 +2846,7 @@ u32 GetBoxMonData2(struct BoxPokemon *boxMon, s32 field) #define SET16(lhs) (lhs) = data[0] + (data[1] << 8) #define SET32(lhs) (lhs) = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24) // -// Prefer SET_BY_WIDTH for fields whose types might be extended (e.g. +// Prefer SET_BY_WIDTH for fields whose types might be extended (e.g. // anything whose typedef is in gametypes.h). // #define SET_BY_WIDTH(lhs) \ @@ -3409,7 +3412,7 @@ u8 GetMonsStateToDoubles_2(void) return (aliveCount > 1) ? PLAYER_HAS_TWO_USABLE_MONS : PLAYER_HAS_ONE_USABLE_MON; } -u16 GetAbilityBySpecies(u16 species, u8 abilityNum) +enum Ability GetAbilityBySpecies(u16 species, u8 abilityNum) { int i; @@ -3434,7 +3437,7 @@ u16 GetAbilityBySpecies(u16 species, u8 abilityNum) return gLastUsedAbility; } -u16 GetMonAbility(struct Pokemon *mon) +enum Ability GetMonAbility(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u8 abilityNum = GetMonData(mon, MON_DATA_ABILITY_NUM, NULL); @@ -3545,12 +3548,12 @@ u32 GetSpeciesWeight(u16 species) return gSpeciesInfo[SanitizeSpeciesId(species)].weight; } -u32 GetSpeciesType(u16 species, u8 slot) +enum Type GetSpeciesType(u16 species, u8 slot) { return gSpeciesInfo[SanitizeSpeciesId(species)].types[slot]; } -u32 GetSpeciesAbility(u16 species, u8 slot) +enum Ability GetSpeciesAbility(u16 species, u8 slot) { return gSpeciesInfo[SanitizeSpeciesId(species)].abilities[slot]; } @@ -3772,9 +3775,9 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov u8 itemEffectParam = ITEM_EFFECT_ARG_START; u32 temp1, temp2; s8 friendshipChange = 0; - u8 holdEffect; + enum HoldEffect holdEffect; u8 battler = MAX_BATTLERS_COUNT; - u32 friendshipOnly = FALSE; + bool32 friendshipOnly = FALSE; u16 heldItem; u8 effectFlags; s8 evChange; @@ -4358,7 +4361,7 @@ u8 GetItemEffectParamOffset(u32 battler, u16 itemId, u8 effectByte, u8 effectBit return offset; } -static void BufferStatRoseMessage(s32 statIdx) +static void BufferStatRoseMessage(enum Stat statIdx) { gBattlerTarget = gBattlerInMenuId; StringCopy(gBattleTextBuff1, gStatNamesTable[sStatsToRaise[statIdx]]); @@ -4472,7 +4475,7 @@ bool32 DoesMonMeetAdditionalConditions(struct Pokemon *mon, const struct Evoluti u32 removeBagItemCount = 0; u32 evolutionTracker = GetMonData(mon, MON_DATA_EVOLUTION_TRACKER, 0); u32 partnerSpecies, partnerHeldItem; - enum ItemHoldEffect partnerHoldEffect; + enum HoldEffect partnerHoldEffect; if (tradePartner != NULL) { @@ -4499,7 +4502,7 @@ bool32 DoesMonMeetAdditionalConditions(struct Pokemon *mon, const struct Evoluti for (i = 0; params != NULL && params[i].condition != CONDITIONS_END; i++) { enum EvolutionConditions condition = params[i].condition; - u32 currentCondition = FALSE; + bool32 currentCondition = FALSE; switch(condition) { @@ -4751,6 +4754,14 @@ bool32 DoesMonMeetAdditionalConditions(struct Pokemon *mon, const struct Evoluti *canStopEvo = FALSE; } break; + case IF_REGION: + if (GetCurrentRegion() == params[i].arg1) + currentCondition = TRUE; + break; + case IF_NOT_REGION: + if (GetCurrentRegion() != params[i].arg1) + currentCondition = TRUE; + break; case CONDITIONS_END: break; } @@ -4782,7 +4793,7 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 u32 species = GetMonData(mon, MON_DATA_SPECIES, 0); u32 heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0); u32 level = GetMonData(mon, MON_DATA_LEVEL, 0); - u32 holdEffect; + enum HoldEffect holdEffect; const struct Evolution *evolutions = GetSpeciesEvolutions(species); if (evolutions == NULL) @@ -5225,7 +5236,7 @@ u8 GetTrainerEncounterMusicId(u16 trainerOpponentId) return gTrainers[difficulty][sanitizedTrainerId].encounterMusic_gender & (F_TRAINER_FEMALE - 1); } -u16 ModifyStatByNature(u8 nature, u16 stat, u8 statIndex) +u16 ModifyStatByNature(u8 nature, u16 stat, enum Stat statIndex) { // Don't modify HP, Accuracy, or Evasion by nature if (statIndex <= STAT_HP || statIndex > NUM_NATURE_STATS || gNaturesInfo[nature].statUp == gNaturesInfo[nature].statDown) @@ -5241,7 +5252,7 @@ u16 ModifyStatByNature(u8 nature, u16 stat, u8 statIndex) void AdjustFriendship(struct Pokemon *mon, u8 event) { u16 species, heldItem; - u8 holdEffect; + enum HoldEffect holdEffect; s8 mod; if (ShouldSkipFriendshipChange()) @@ -5306,7 +5317,7 @@ void AdjustFriendship(struct Pokemon *mon, u8 event) } } -u8 CalculateFriendshipBonuses(struct Pokemon *mon, u32 modifier, enum ItemHoldEffect itemHoldEffect) +u8 CalculateFriendshipBonuses(struct Pokemon *mon, u32 modifier, enum HoldEffect itemHoldEffect) { u32 bonus = 0; @@ -5333,8 +5344,9 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) u16 evIncrease = 0; u16 totalEVs = 0; u16 heldItem; - u8 holdEffect; - int i, multiplier; + enum HoldEffect holdEffect; + enum Stat i; + int multiplier; u8 stat; u8 bonus; u32 currentEVCap = GetCurrentEVCap(); @@ -5413,6 +5425,8 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) else evIncrease = gSpeciesInfo[defeatedSpecies].evYield_SpDefense * multiplier; break; + default: + break; } if (holdEffect == HOLD_EFFECT_MACHO_BRACE) @@ -5697,46 +5711,282 @@ u8 CanLearnTeachableMove(u16 species, u16 move) } } -u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves) +static void QuickSortMoves(u16 *moves, s32 left, s32 right) { - u16 learnedMoves[4]; - u8 numMoves = 0; - u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); - u8 level = GetMonData(mon, MON_DATA_LEVEL, 0); - const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); - int i, j, k; + if (left >= right) + return; - for (i = 0; i < MAX_MON_MOVES; i++) - learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + u16 pivot = moves[(left + right) / 2]; + s32 i = left, j = right; - for (i = 0; i < MAX_LEVEL_UP_MOVES; i++) + while (i <= j) { - u16 moveLevel; + while (moves[i] != MOVE_NONE && StringCompare(GetMoveName(moves[i]), GetMoveName(pivot)) < 0) + i++; + while (moves[j] != MOVE_NONE && StringCompare(GetMoveName(moves[j]), GetMoveName(pivot)) > 0) + j--; - if (learnset[i].move == LEVEL_UP_MOVE_END) - break; - - moveLevel = learnset[i].level; - - if (moveLevel <= level) + if (i <= j) { - for (j = 0; j < MAX_MON_MOVES && learnedMoves[j] != learnset[i].move; j++) - ; - - if (j == MAX_MON_MOVES) - { - for (k = 0; k < numMoves && moves[k] != learnset[i].move; k++) - ; - - if (k == numMoves) - moves[numMoves++] = learnset[i].move; - } + u16 temp = moves[i]; + moves[i] = moves[j]; + moves[j] = temp; + i++; + j--; } } + QuickSortMoves(moves, left, j); + QuickSortMoves(moves, i, right); +} + +static void SortMovesAlphabetically(u16 *moves, u8 numMoves) +{ + if (numMoves > 1) + QuickSortMoves(moves, 0, numMoves - 1); +} + +u8 GetRelearnerLevelUpMoves(struct Pokemon *mon, u16 *moves) +{ + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); + u8 level = (P_ENABLE_ALL_LEVEL_UP_MOVES ? MAX_LEVEL : GetMonData(mon, MON_DATA_LEVEL, 0)); + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + do + { + const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); + + for (u16 i = 0; i < MAX_LEVEL_UP_MOVES && learnset[i].move != LEVEL_UP_MOVE_END; i++) + { + if (learnset[i].level > level) + continue; + + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == learnset[i].move) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == learnset[i].move) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = learnset[i].move; + } + + species = (P_PRE_EVO_MOVES ? GetSpeciesPreEvolution(species) : SPECIES_NONE); + } while (species != SPECIES_NONE); + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + return numMoves; } +u8 GetRelearnerEggMoves(struct Pokemon *mon, u16 *moves) +{ + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES); + + while (GetSpeciesPreEvolution(species) != SPECIES_NONE) + species = GetSpeciesPreEvolution(species); + const u16 *eggMoves = GetSpeciesEggMoves(species); + + if (eggMoves == sNoneEggMoveLearnset) + return numMoves; + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + for (u16 i = 0; eggMoves[i] != MOVE_UNAVAILABLE; i++) + { + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == eggMoves[i]) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == eggMoves[i]) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = eggMoves[i]; + } + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + + return numMoves; +} + +u8 GetRelearnerTMMoves(struct Pokemon *mon, u16 *moves) +{ + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES); + u16 allMoves[NUM_ALL_MACHINES]; + u16 totalMoveCount = 0; + + for (u16 i = 0; i < NUM_ALL_MACHINES; i++) + { + enum TMHMItemId item = GetTMHMItemId(i + 1); + u16 move = GetTMHMMoveId(i + 1); + if ((P_ENABLE_ALL_TM_MOVES || CheckBagHasItem(item, 1)) && CanLearnTeachableMove(species, move) && move != MOVE_NONE) + allMoves[totalMoveCount++] = move; + } + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + for (u16 i = 0; i < totalMoveCount; i++) + { + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == allMoves[i]) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == allMoves[i]) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = allMoves[i]; + } + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + + return numMoves; +} + +u8 GetRelearnerTutorMoves(struct Pokemon *mon, u16 *moves) +{ +#if P_TUTOR_MOVES_ARRAY + u16 learnedMoves[MAX_MON_MOVES] = {0}; + u8 numMoves = 0; + u16 species = GetMonData(mon, MON_DATA_SPECIES, 0); + + for (u8 i = 0; i < MAX_MON_MOVES; i++) + learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); + + for (u16 i = 0; gTutorMoves[i] != MOVE_UNAVAILABLE; i++) + { + u16 move = gTutorMoves[i]; + + if (!CanLearnTeachableMove(species, move)) + continue; + + u16 j; + for (j = 0; j < MAX_MON_MOVES; j++) + { + if (learnedMoves[j] == move) + break; + } + if (j < MAX_MON_MOVES) + continue; + + for (j = 0; j < numMoves; j++) + { + if (moves[j] == move) + break; + } + if (j < numMoves) + continue; + + moves[numMoves++] = move; + } + + if (P_SORT_MOVES) + SortMovesAlphabetically(moves, numMoves); + + return numMoves; +#else + return 0; +#endif // P_TUTOR_MOVES_ARRAY +} + +u8 GetNumberOfLevelUpMoves(struct Pokemon *mon) +{ + u16 moves[MAX_RELEARNER_MOVES] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerLevelUpMoves(mon, moves); +} + +u8 GetNumberOfEggMoves(struct Pokemon *mon) +{ + if (!FlagGet(P_FLAG_EGG_MOVES) && !P_ENABLE_MOVE_RELEARNERS) + return 0; + + u16 moves[EGG_MOVES_ARRAY_COUNT] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerEggMoves(mon, moves); +} + +u8 GetNumberOfTMMoves(struct Pokemon *mon) +{ + if (!P_TM_MOVES_RELEARNER) + return 0; + + if (!P_ENABLE_ALL_TM_MOVES && !IsBagPocketNonEmpty(POCKET_TM_HM)) + return 0; + + u16 moves[MAX_RELEARNER_MOVES] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerTMMoves(mon, moves); +} + +u8 GetNumberOfTutorMoves(struct Pokemon *mon) +{ + if (!FlagGet(P_FLAG_TUTOR_MOVES) && !P_ENABLE_MOVE_RELEARNERS) + return 0; + + u16 moves[MAX_RELEARNER_MOVES] = {0}; + u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); + + if (species == SPECIES_EGG) + return 0; + + return GetRelearnerTutorMoves(mon, moves); +} + u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves) { u8 numMoves = 0; @@ -5749,50 +5999,6 @@ u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves) return numMoves; } -u8 GetNumberOfRelearnableMoves(struct Pokemon *mon) -{ - u16 learnedMoves[MAX_MON_MOVES]; - u16 moves[MAX_LEVEL_UP_MOVES]; - u8 numMoves = 0; - u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0); - u8 level = GetMonData(mon, MON_DATA_LEVEL, 0); - const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); - int i, j, k; - - if (species == SPECIES_EGG) - return 0; - - for (i = 0; i < MAX_MON_MOVES; i++) - learnedMoves[i] = GetMonData(mon, MON_DATA_MOVE1 + i, 0); - - for (i = 0; i < MAX_LEVEL_UP_MOVES; i++) - { - u16 moveLevel; - - if (learnset[i].move == LEVEL_UP_MOVE_END) - break; - - moveLevel = learnset[i].level; - - if (moveLevel <= level) - { - for (j = 0; j < MAX_MON_MOVES && learnedMoves[j] != learnset[i].move; j++) - ; - - if (j == MAX_MON_MOVES) - { - for (k = 0; k < numMoves && moves[k] != learnset[i].move; k++) - ; - - if (k == numMoves) - moves[numMoves++] = learnset[i].move; - } - } - } - - return numMoves; -} - u16 SpeciesToPokedexNum(u16 species) { if (IsNationalPokedexEnabled()) @@ -6090,7 +6296,7 @@ static s32 GetWildMonTableIdInAlteringCave(u16 species) static inline bool32 CanFirstMonBoostHeldItemRarity(void) { - u32 ability; + enum Ability ability; if (GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) return FALSE; @@ -6630,7 +6836,7 @@ u32 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, enum FormChanges u32 targetSpecies = species; const struct FormChange *formChanges = GetSpeciesFormChanges(species); u16 heldItem; - u32 ability; + enum Ability ability; if (formChanges != NULL) { @@ -6896,7 +7102,7 @@ bool32 SpeciesHasGenderDifferences(u16 species) return FALSE; } -bool32 TryFormChange(u32 monId, u32 side, enum FormChanges method) +bool32 TryFormChange(u32 monId, enum BattleSide side, enum FormChanges method) { struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; @@ -7014,7 +7220,7 @@ void UpdateMonPersonality(struct BoxPokemon *boxMon, u32 personality) bool32 isShiny = GetBoxMonData(boxMon, MON_DATA_IS_SHINY, NULL); u32 hiddenNature = GetBoxMonData(boxMon, MON_DATA_HIDDEN_NATURE, NULL); - u32 teraType = GetBoxMonData(boxMon, MON_DATA_TERA_TYPE, NULL); + enum Type teraType = GetBoxMonData(boxMon, MON_DATA_TERA_TYPE, NULL); old = *boxMon; old0 = &(GetSubstruct(&old, old.personality, SUBSTRUCT_TYPE_0)->type0); @@ -7129,9 +7335,9 @@ void UpdateDaysPassedSinceFormChange(u16 days) } } -u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) +enum Type CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum MonState state) { - u32 moveType = GetDynamicMoveType(mon, move, battler, state); + enum Type moveType = GetDynamicMoveType(mon, move, battler, state); if (moveType != TYPE_NONE) return moveType; return GetMoveType(move); @@ -7211,7 +7417,7 @@ bool32 IsSpeciesForeignRegionalForm(u32 species, u32 currentRegion) return FALSE; } -u32 GetTeraTypeFromPersonality(struct Pokemon *mon) +enum Type GetTeraTypeFromPersonality(struct Pokemon *mon) { const u8 *types = gSpeciesInfo[GetMonData(mon, MON_DATA_SPECIES)].types; return (GetMonData(mon, MON_DATA_PERSONALITY) & 0x1) == 0 ? types[0] : types[1]; @@ -7232,7 +7438,7 @@ void SavePlayerPartyMon(u32 index, struct Pokemon *mon) gSaveBlock1Ptr->playerParty[index] = *mon; } -u32 IsSpeciesOfType(u32 species, u32 type) +bool32 IsSpeciesOfType(u32 species, enum Type type) { if (gSpeciesInfo[species].types[0] == type || gSpeciesInfo[species].types[1] == type) diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index 9016066db7..ca94df5321 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -44,7 +44,6 @@ #include "tv.h" #include "window.h" #include "constants/battle_move_effects.h" -#include "constants/hold_effects.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/party_menu.h" @@ -164,7 +163,7 @@ static EWRAM_DATA struct PokemonSummaryScreenData u8 sanity; // 0x35 u8 OTName[17]; // 0x36 u32 OTID; // 0x48 - u8 teraType; + enum Type teraType; u8 mintNature; } summary; u16 bgTilemapBuffers[PSS_PAGE_COUNT][2][0x400]; @@ -552,12 +551,12 @@ static const struct WindowTemplate sSummaryTemplate[] = }, [PSS_LABEL_WINDOW_PROMPT_RELEARN] = { .bg = 0, - .tilemapLeft = 22, + .tilemapLeft = 18, .tilemapTop = 2, - .width = 8, + .width = 11, .height = 2, .paletteNum = 15, - .baseBlock = 387, + .baseBlock = 800, }, [PSS_LABEL_WINDOW_PORTRAIT_DEX_NUMBER] = { .bg = 0, @@ -977,14 +976,7 @@ const struct SpriteTemplate gSpriteTemplate_MoveTypes = .affineAnims = gDummySpriteAffineAnimTable, .callback = SpriteCallbackDummy }; -static const u8 sContestCategoryToOamPaletteNum[CONTEST_CATEGORIES_COUNT] = -{ - [CONTEST_CATEGORY_COOL] = 13, - [CONTEST_CATEGORY_BEAUTY] = 14, - [CONTEST_CATEGORY_CUTE] = 14, - [CONTEST_CATEGORY_SMART] = 15, - [CONTEST_CATEGORY_TOUGH] = 13, -}; + static const struct OamData sOamData_MoveSelector = { .y = 0, @@ -1232,6 +1224,9 @@ void ShowPokemonSummaryScreen(u8 mode, void *mons, u8 monIndex, u8 maxMonIndex, if (gMonSpritesGfxPtr == NULL) CreateMonSpritesGfxManager(MON_SPR_GFX_MANAGER_A, MON_SPR_GFX_MODE_NORMAL); + if (ShouldShowMoveRelearner()) + TryUpdateRelearnType(TRY_SET_UPDATE); + SetMainCallback2(CB2_InitSummaryScreen); } @@ -1544,7 +1539,6 @@ static bool8 ExtractMonDataToSummaryStruct(struct Pokemon *mon) sum->ribbonCount = GetMonData(mon, MON_DATA_RIBBON_COUNT); sum->teraType = GetMonData(mon, MON_DATA_TERA_TYPE); sum->isShiny = GetMonData(mon, MON_DATA_IS_SHINY); - sMonSummaryScreen->relearnableMovesNum = P_SUMMARY_SCREEN_MOVE_RELEARNER ? GetNumberOfRelearnableMoves(mon) : 0; return TRUE; } sMonSummaryScreen->switchCounter++; @@ -1704,11 +1698,11 @@ static void Task_HandleInput(u8 taskId) { ChangeSummaryPokemon(taskId, 1); } - else if ((JOY_NEW(DPAD_LEFT)) || GetLRKeysPressed() == MENU_L_PRESSED) + else if (JOY_NEW(DPAD_LEFT)) { ChangePage(taskId, -1); } - else if ((JOY_NEW(DPAD_RIGHT)) || GetLRKeysPressed() == MENU_R_PRESSED) + else if (JOY_NEW(DPAD_RIGHT)) { ChangePage(taskId, 1); } @@ -1756,7 +1750,7 @@ static void Task_HandleInput(u8 taskId) { sMonSummaryScreen->callback = CB2_InitLearnMove; gSpecialVar_0x8004 = sMonSummaryScreen->curMonIndex; - gOriginSummaryScreenPage = sMonSummaryScreen->currPageIndex; + gRelearnMode = sMonSummaryScreen->currPageIndex; StopPokemonAnimations(); PlaySE(SE_SELECT); BeginCloseSummaryScreen(taskId); @@ -1768,6 +1762,24 @@ static void Task_HandleInput(u8 taskId) PlaySE(SE_SELECT); CloseSummaryScreen(taskId); } + else if (JOY_NEW(R_BUTTON)) // R means increase. Level -> Egg -> TM -> Tutor + { + if (P_SUMMARY_SCREEN_MOVE_RELEARNER && (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES || sMonSummaryScreen->currPageIndex == PSS_PAGE_CONTEST_MOVES) && !gMain.inBattle) + { + TryUpdateRelearnType(TRY_INCREMENT); + PlaySE(SE_SELECT); + ShowRelearnPrompt(); + } + } + else if (JOY_NEW(L_BUTTON)) // L means decrease. Level <- Egg <- TM <- Tutor + { + if (P_SUMMARY_SCREEN_MOVE_RELEARNER && (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES || sMonSummaryScreen->currPageIndex == PSS_PAGE_CONTEST_MOVES) && !gMain.inBattle) + { + TryUpdateRelearnType(TRY_DECREMENT); + PlaySE(SE_SELECT); + ShowRelearnPrompt(); + } + } } } @@ -1890,6 +1902,120 @@ void ExtractMonSkillEvData(struct Pokemon *mon, struct PokeSummary *sum) sum->speed = GetMonData(mon, MON_DATA_SPEED_EV); } +u32 GetRelearnMovesCount(enum MoveRelearnerStates state) +{ + struct Pokemon *mon = &sMonSummaryScreen->currentMon; + + switch (state) + { + case MOVE_RELEARNER_EGG_MOVES: + return GetNumberOfEggMoves(mon); + case MOVE_RELEARNER_TM_MOVES: + return GetNumberOfTMMoves(mon); + case MOVE_RELEARNER_TUTOR_MOVES: + return GetNumberOfTutorMoves(mon); + case MOVE_RELEARNER_LEVEL_UP_MOVES: + return GetNumberOfLevelUpMoves(mon); + default: + return 0; + } +} + +u32 GetCurrentRelearnMovesCount(void) +{ + return GetRelearnMovesCount(gMoveRelearnerState); +} + +bool32 NoMovesAvailableToRelearn(void) +{ + u32 zeroCounter = 0; + for (enum MoveRelearnerStates state = MOVE_RELEARNER_LEVEL_UP_MOVES; state < MOVE_RELEARNER_COUNT; state++) + { + if (GetRelearnMovesCount(state) == 0) + zeroCounter++; + } + + return zeroCounter == MOVE_RELEARNER_COUNT; +} + +bool32 CheckRelearnerStateFlag(enum MoveRelearnerStates state) +{ + if (P_ENABLE_MOVE_RELEARNERS) + return TRUE; + + switch (state) + { + case MOVE_RELEARNER_LEVEL_UP_MOVES: + return TRUE; + case MOVE_RELEARNER_EGG_MOVES: + return FlagGet(P_FLAG_EGG_MOVES); + case MOVE_RELEARNER_TM_MOVES: + return P_TM_MOVES_RELEARNER; + case MOVE_RELEARNER_TUTOR_MOVES: + return FlagGet(P_FLAG_TUTOR_MOVES); + default: + return FALSE; + } +} + +void TryUpdateRelearnType(enum IncrDecrUpdateValues delta) +{ + u32 moveCount = 0; + u32 zeroCounter = 0; + enum MoveRelearnerStates state = gMoveRelearnerState; + + // just in case everything is off, default to level up moves + if ((!P_ENABLE_MOVE_RELEARNERS + && !P_TM_MOVES_RELEARNER + && !FlagGet(P_FLAG_EGG_MOVES) + && !FlagGet(P_FLAG_TUTOR_MOVES))) + { + sMonSummaryScreen->relearnableMovesNum = GetRelearnMovesCount(MOVE_RELEARNER_LEVEL_UP_MOVES); + return; + } + + do + { + switch (delta) + { + default: + case TRY_SET_UPDATE: + moveCount = GetCurrentRelearnMovesCount(); + if (moveCount == 0) + { + delta = TRY_INCREMENT; + continue; + } + else + { + sMonSummaryScreen->relearnableMovesNum = moveCount; + return; + } + // should never reach this, but just in case + break; + case TRY_INCREMENT: + state = state >= MOVE_RELEARNER_TUTOR_MOVES ? MOVE_RELEARNER_LEVEL_UP_MOVES : state + 1; + break; + case TRY_DECREMENT: + state = state == MOVE_RELEARNER_LEVEL_UP_MOVES ? MOVE_RELEARNER_TUTOR_MOVES : state - 1; + break; + } + + if (!CheckRelearnerStateFlag(state)) + continue; + + moveCount = GetRelearnMovesCount(state); + if (moveCount != 0) + { + gMoveRelearnerState = state; + sMonSummaryScreen->relearnableMovesNum = moveCount; + return; + } + zeroCounter++; + + } while (zeroCounter <= MOVE_RELEARNER_COUNT && moveCount == 0); +} + static void ChangeSummaryPokemon(u8 taskId, s8 delta) { s8 monId; @@ -1961,27 +2087,32 @@ static void Task_ChangeSummaryMon(u8 taskId) sMonSummaryScreen->switchCounter = 0; break; case 4: + if (ExtractMonDataToSummaryStruct(&sMonSummaryScreen->currentMon) == FALSE) + return; + if (P_SUMMARY_SCREEN_RENAME && sMonSummaryScreen->currPageIndex == PSS_PAGE_INFO) ShowUtilityPrompt(SUMMARY_MODE_NORMAL); + if (ShouldShowIvEvPrompt() && sMonSummaryScreen->currPageIndex == PSS_PAGE_SKILLS) { sMonSummaryScreen->skillsPageMode = SUMMARY_SKILLS_MODE_STATS; ChangeStatLabel(SUMMARY_SKILLS_MODE_STATS); } - if (ExtractMonDataToSummaryStruct(&sMonSummaryScreen->currentMon) == FALSE) + + if (P_SUMMARY_SCREEN_MOVE_RELEARNER + && (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES + || sMonSummaryScreen->currPageIndex == PSS_PAGE_CONTEST_MOVES)) { - return; + gMoveRelearnerState = MOVE_RELEARNER_LEVEL_UP_MOVES; + TryUpdateRelearnType(TRY_SET_UPDATE); + if (ShouldShowMoveRelearner()) + ShowRelearnPrompt(); + else + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); } else { - if (P_SUMMARY_SCREEN_MOVE_RELEARNER - && (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES || sMonSummaryScreen->currPageIndex == PSS_PAGE_CONTEST_MOVES)) - { - if (ShouldShowMoveRelearner()) - PutWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); - else - ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); - } + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); } break; case 5: @@ -2097,6 +2228,7 @@ static void ChangePage(u8 taskId, s8 delta) { struct PokeSummary *summary = &sMonSummaryScreen->summary; s16 *data = gTasks[taskId].data; + u32 currPageIndex; if (summary->isEgg) return; @@ -2107,17 +2239,17 @@ static void ChangePage(u8 taskId, s8 delta) PlaySE(SE_SELECT); ClearPageWindowTilemaps(sMonSummaryScreen->currPageIndex); - sMonSummaryScreen->currPageIndex += delta; + currPageIndex = sMonSummaryScreen->currPageIndex += delta; data[0] = 0; if (delta == 1) SetTaskFuncWithFollowupFunc(taskId, PssScrollRight, gTasks[taskId].func); else SetTaskFuncWithFollowupFunc(taskId, PssScrollLeft, gTasks[taskId].func); - CreateTextPrinterTask(sMonSummaryScreen->currPageIndex); + CreateTextPrinterTask(currPageIndex); HidePageSpecificSprites(); - if (sMonSummaryScreen->currPageIndex == PSS_PAGE_SKILLS - || (sMonSummaryScreen->currPageIndex + delta) == PSS_PAGE_SKILLS) + if (currPageIndex == PSS_PAGE_SKILLS + || (currPageIndex + delta) == PSS_PAGE_SKILLS) { struct Pokemon *mon = &sMonSummaryScreen->currentMon; @@ -2133,6 +2265,19 @@ static void ChangePage(u8 taskId, s8 delta) { ShowUtilityPrompt(SUMMARY_MODE_NORMAL); } + + // acts like a quick reset + if (currPageIndex == PSS_PAGE_SKILLS) + { + gMoveRelearnerState = MOVE_RELEARNER_LEVEL_UP_MOVES; + TryUpdateRelearnType(TRY_SET_UPDATE); + } + + // to prevent nothing showing + if (currPageIndex >= PSS_PAGE_BATTLE_MOVES && sMonSummaryScreen->relearnableMovesNum == 0) + TryUpdateRelearnType(TRY_SET_UPDATE); + else + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); } static void PssScrollRight(u8 taskId) // Scroll right @@ -2176,6 +2321,7 @@ static void PssScrollRightEnd(u8 taskId) // display right SetTypeIcons(); TryDrawExperienceProgressBar(); SwitchTaskToFollowupFunc(taskId); + ShowRelearnPrompt(); } static void PssScrollLeft(u8 taskId) // Scroll left @@ -2228,6 +2374,7 @@ static void PssScrollLeftEnd(u8 taskId) // display left SetTypeIcons(); TryDrawExperienceProgressBar(); SwitchTaskToFollowupFunc(taskId); + ShowRelearnPrompt(); } static void TryDrawExperienceProgressBar(void) @@ -3239,7 +3386,13 @@ static void PrintPageNamesAndStats(void) PrintTextOnWindow(PSS_LABEL_WINDOW_MOVES_POWER_ACC, gText_Accuracy2, 0, 17, 0, 1); PrintTextOnWindow(PSS_LABEL_WINDOW_MOVES_APPEAL_JAM, gText_Appeal, 0, 1, 0, 1); PrintTextOnWindow(PSS_LABEL_WINDOW_MOVES_APPEAL_JAM, gText_Jam, 0, 17, 0, 1); - PrintTextOnWindowWithFont(PSS_LABEL_WINDOW_PROMPT_RELEARN, gText_Relearn, 0, 4, 0, 0, FONT_SMALL); + + if (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES + || sMonSummaryScreen->currPageIndex == PSS_PAGE_CONTEST_MOVES) + { + TryUpdateRelearnType(TRY_SET_UPDATE); + ShowRelearnPrompt(); + } } static void PutPageWindowTilemaps(u8 page) @@ -3315,6 +3468,7 @@ static void ClearPageWindowTilemaps(u8 page) if (InBattleFactory() == TRUE || InSlateportBattleTent() == TRUE) ClearWindowTilemap(PSS_LABEL_WINDOW_POKEMON_INFO_RENTAL); ClearWindowTilemap(PSS_LABEL_WINDOW_POKEMON_INFO_TYPE); + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); break; case PSS_PAGE_SKILLS: ClearWindowTilemap(PSS_LABEL_WINDOW_POKEMON_SKILLS_STATS_LEFT); @@ -3322,6 +3476,7 @@ static void ClearPageWindowTilemaps(u8 page) ClearWindowTilemap(PSS_LABEL_WINDOW_POKEMON_SKILLS_EXP); if (ShouldShowIvEvPrompt()) ClearPageWindowTilemaps(PSS_LABEL_WINDOW_PROMPT_UTILITY); + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); break; case PSS_PAGE_BATTLE_MOVES: if (sMonSummaryScreen->mode == SUMMARY_MODE_SELECT_MOVE) @@ -3332,11 +3487,8 @@ static void ClearPageWindowTilemaps(u8 page) gSprites[sMonSummaryScreen->categoryIconSpriteId].invisible = TRUE; } } - else - { - if (ShouldShowMoveRelearner()) - ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); - } + + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); break; case PSS_PAGE_CONTEST_MOVES: if (sMonSummaryScreen->mode == SUMMARY_MODE_SELECT_MOVE) @@ -3344,11 +3496,8 @@ static void ClearPageWindowTilemaps(u8 page) if (sMonSummaryScreen->newMove != MOVE_NONE || sMonSummaryScreen->firstMoveIndex != MAX_MON_MOVES) ClearWindowTilemap(PSS_LABEL_WINDOW_MOVES_APPEAL_JAM); } - else - { - if (ShouldShowMoveRelearner()) - ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); - } + + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); break; } @@ -3474,13 +3623,13 @@ static void PrintMonOTID(void) static void PrintMonAbilityName(void) { - u16 ability = GetAbilityBySpecies(sMonSummaryScreen->summary.species, sMonSummaryScreen->summary.abilityNum); + enum Ability ability = GetAbilityBySpecies(sMonSummaryScreen->summary.species, sMonSummaryScreen->summary.abilityNum); PrintTextOnWindow(AddWindowFromTemplateList(sPageInfoTemplate, PSS_DATA_WINDOW_INFO_ABILITY), gAbilitiesInfo[ability].name, 0, 1, 0, 1); } static void PrintMonAbilityDescription(void) { - u16 ability = GetAbilityBySpecies(sMonSummaryScreen->summary.species, sMonSummaryScreen->summary.abilityNum); + enum Ability ability = GetAbilityBySpecies(sMonSummaryScreen->summary.species, sMonSummaryScreen->summary.abilityNum); PrintTextOnWindow(AddWindowFromTemplateList(sPageInfoTemplate, PSS_DATA_WINDOW_INFO_ABILITY), gAbilitiesInfo[ability].description, 0, 17, 0, 0); } @@ -3766,7 +3915,7 @@ static void PrintRibbonCount(void) PrintTextOnWindow(AddWindowFromTemplateList(sPageSkillsTemplate, PSS_DATA_WINDOW_SKILLS_RIBBON_COUNT), text, x, 1, 0, 0); } -static void BufferStat(u8 *dst, u8 statIndex, u32 stat, u32 strId, u32 n) +static void BufferStat(u8 *dst, enum Stat statIndex, u32 stat, u32 strId, u32 n) { static const u8 sTextNatureDown[] = _("{COLOR}{08}"); static const u8 sTextNatureUp[] = _("{COLOR}{05}"); @@ -4109,7 +4258,7 @@ static void PrintContestMoveDescription(u8 moveSlot) if (move != MOVE_NONE) { u8 windowId = AddWindowFromTemplateList(sPageMovesTemplate, PSS_DATA_WINDOW_MOVE_DESCRIPTION); - PrintTextOnWindow(windowId, gContestEffectDescriptionPointers[GetMoveContestEffect(move)], 6, 1, 0, 0); + PrintTextOnWindow(windowId, gContestEffects[GetMoveContestEffect(move)].description, 6, 1, 0, 0); } } @@ -4128,7 +4277,7 @@ static void PrintMoveDetails(u16 move) } else { - PrintTextOnWindow(windowId, gContestEffectDescriptionPointers[GetMoveContestEffect(move)], 6, 1, 0, 0); + PrintTextOnWindow(windowId, gContestEffects[GetMoveContestEffect(move)].description, 6, 1, 0, 0); } PutWindowTilemap(windowId); } @@ -4261,14 +4410,14 @@ static void CreateMoveTypeIcons(void) } } -void SetTypeSpritePosAndPal(u8 typeId, u8 x, u8 y, u8 spriteArrayId) +void SetTypeSpritePosAndPal(enum Type typeId, u8 x, u8 y, u8 spriteArrayId) { struct Sprite *sprite = &gSprites[sMonSummaryScreen->spriteIds[spriteArrayId]]; StartSpriteAnim(sprite, typeId); if (typeId < NUMBER_OF_MON_TYPES) sprite->oam.paletteNum = gTypesInfo[typeId].palette; else - sprite->oam.paletteNum = sContestCategoryToOamPaletteNum[typeId - NUMBER_OF_MON_TYPES]; + sprite->oam.paletteNum = gContestCategoryInfo[typeId - NUMBER_OF_MON_TYPES].palette; sprite->x = x + 16; sprite->y = y + 8; SetSpriteInvisibility(spriteArrayId, FALSE); @@ -4306,7 +4455,7 @@ static void SetMoveTypeIcons(void) u32 i; struct PokeSummary *summary = &sMonSummaryScreen->summary; struct Pokemon *mon = &sMonSummaryScreen->currentMon; - u32 type; + enum Type type; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -4343,7 +4492,7 @@ static void SetContestMoveTypeIcons(void) static void SetNewMoveTypeIcon(void) { - u32 type = GetMoveType(sMonSummaryScreen->newMove); + enum Type type = GetMoveType(sMonSummaryScreen->newMove); struct Pokemon *mon = &sMonSummaryScreen->currentMon; if (P_SHOW_DYNAMIC_TYPES) @@ -4662,7 +4811,8 @@ static inline bool32 ShouldShowMoveRelearner(void) && sMonSummaryScreen->mode != SUMMARY_MODE_BOX_CURSOR && sMonSummaryScreen->relearnableMovesNum > 0 && !InBattleFactory() - && !InSlateportBattleTent()); + && !InSlateportBattleTent() + && !NoMovesAvailableToRelearn()); } static inline bool32 ShouldShowRename(void) @@ -4683,7 +4833,7 @@ static inline bool32 ShouldShowIvEvPrompt(void) if (P_SUMMARY_SCREEN_IV_EV_BOX_ONLY) { return (P_SUMMARY_SCREEN_IV_EV_INFO || FlagGet(P_FLAG_SUMMARY_SCREEN_IV_EV_INFO)) - && (sMonSummaryScreen->mode == SUMMARY_MODE_BOX|| sMonSummaryScreen->mode == SUMMARY_MODE_BOX_CURSOR); + && (sMonSummaryScreen->mode == SUMMARY_MODE_BOX || sMonSummaryScreen->mode == SUMMARY_MODE_BOX_CURSOR); } else if (!P_SUMMARY_SCREEN_IV_EV_BOX_ONLY) { @@ -4758,6 +4908,49 @@ static inline void ShowUtilityPrompt(s16 mode) PrintTextOnWindow(PSS_LABEL_WINDOW_PROMPT_UTILITY, promptText, stringXPos, 1, 0, 0); } +void ShowRelearnPrompt(void) +{ + u32 currPage = sMonSummaryScreen->currPageIndex; + + if (!ShouldShowMoveRelearner() || !(currPage >= PSS_PAGE_BATTLE_MOVES)) + { + ClearWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); + return; + } + + if (GetCurrentRelearnMovesCount() == 0) + return; + + const u8* relearnText; + + int relearnTextXPos; + + switch (gMoveRelearnerState) + { + case MOVE_RELEARNER_LEVEL_UP_MOVES: + relearnText = gText_Relearn_LevelUp; + break; + case MOVE_RELEARNER_EGG_MOVES: + relearnText = gText_Relearn_Egg; + break; + case MOVE_RELEARNER_TM_MOVES: + relearnText = gText_Relearn_TM; + break; + case MOVE_RELEARNER_TUTOR_MOVES: + relearnText = gText_Relearn_Tutor; + break; + default: + relearnText = gText_Relearn; + break; + } + + relearnTextXPos = GetStringRightAlignXOffset(FONT_NORMAL, relearnText, 0); + + FillWindowPixelBuffer(PSS_LABEL_WINDOW_PROMPT_RELEARN, PIXEL_FILL(0)); + PutWindowTilemap(PSS_LABEL_WINDOW_PROMPT_RELEARN); + PrintTextOnWindowWithFont(PSS_LABEL_WINDOW_PROMPT_RELEARN, relearnText, relearnTextXPos, 4, 0, 0, FONT_SMALL); +} + static void CB2_ReturnToSummaryScreenFromNamingScreen(void) { SetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, gStringVar2); diff --git a/src/recorded_battle.c b/src/recorded_battle.c index 500a83e888..5b61a8b4dd 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -49,7 +49,7 @@ EWRAM_DATA static u8 sFrontierPassFlag = 0; EWRAM_DATA static u8 sBattleScene = 0; EWRAM_DATA static u8 sTextSpeed = 0; EWRAM_DATA static u32 sBattleFlags = 0; -EWRAM_DATA static u64 sAI_Scripts = 0; +EWRAM_DATA static u64 sAI_Scripts[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA static struct Pokemon sSavedPlayerParty[PARTY_SIZE] = {0}; EWRAM_DATA static struct Pokemon sSavedOpponentParty[PARTY_SIZE] = {0}; EWRAM_DATA static u16 sPlayerMonMoves[MAX_BATTLERS_COUNT / 2][MAX_MON_MOVES] = {0}; @@ -87,7 +87,7 @@ void RecordedBattle_Init(u8 mode) for (j = 0; j < BATTLER_RECORD_SIZE; j++) sBattleRecords[i][j] = 0xFF; sBattleFlags = gBattleTypeFlags; - sAI_Scripts = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; + sAI_Scripts[i] = gAiThinkingStruct->aiFlags[i]; } } } @@ -312,6 +312,7 @@ bool32 MoveRecordedBattleToSaveData(void) battleSave->playersLanguage[i] = sPlayers[i].language; battleSave->playersBattlers[i] = sPlayers[i].battler; battleSave->playersTrainerId[i] = sPlayers[i].trainerId; + battleSave->AI_scripts[i] = sAI_Scripts[i]; } battleSave->rngSeed = gRecordedBattleRngSeed; @@ -358,7 +359,6 @@ bool32 MoveRecordedBattleToSaveData(void) battleSave->frontierBrainSymbol = sFrontierBrainSymbol; battleSave->battleScene = gSaveBlock2Ptr->optionsBattleSceneOff; battleSave->textSpeed = gSaveBlock2Ptr->optionsTextSpeed; - battleSave->AI_scripts = sAI_Scripts; if (TRAINER_BATTLE_PARAM.opponentA >= TRAINER_RECORD_MIXING_FRIEND && TRAINER_BATTLE_PARAM.opponentA < TRAINER_RECORD_MIXING_APPRENTICE) { @@ -523,6 +523,7 @@ void SetVariablesForRecordedBattle(struct RecordedBattleSave *src) gLinkPlayers[i].language = src->playersLanguage[i]; gLinkPlayers[i].id = src->playersBattlers[i]; gLinkPlayers[i].trainerId = src->playersTrainerId[i]; + sAI_Scripts[i] = src->AI_scripts[i]; if (var) ConvertInternationalString(gLinkPlayers[i].name, gLinkPlayers[i].language); @@ -539,7 +540,6 @@ void SetVariablesForRecordedBattle(struct RecordedBattleSave *src) sFrontierBrainSymbol = src->frontierBrainSymbol; sBattleScene = src->battleScene; sTextSpeed = src->textSpeed; - sAI_Scripts = src->AI_scripts; for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) sRecordMixFriendName[i] = src->recordMixFriendName[i]; @@ -779,16 +779,16 @@ void RecordedBattle_CheckMovesetChanges(u8 mode) SetMonData(mon, MON_DATA_PP_BONUSES, &ppBonusSet); } - gChosenMoveByBattler[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; + gChosenMoveByBattler[battler] = GetChosenMoveFromPosition(battler); } } } } } -u64 GetAiScriptsInRecordedBattle(void) +u64 GetAiScriptsInRecordedBattle(u32 battler) { - return sAI_Scripts; + return sAI_Scripts[battler]; } // Used to determine when the player is allowed to press B to end a recorded battle's playback diff --git a/src/rom_header_rhh.c b/src/rom_header_rhh.c index 9a97948e8a..3a88a2c413 100644 --- a/src/rom_header_rhh.c +++ b/src/rom_header_rhh.c @@ -21,7 +21,7 @@ struct RHHRomHeader /*0x0A*/ u16 movesCount; /*0x0C*/ u16 numSpecies; /*0x0E*/ u16 abilitiesCount; - /*0x10*/ const struct Ability *abilities; + /*0x10*/ const struct AbilityInfo *abilities; /*0x14*/ u16 itemsCount; /*0x16*/ u8 itemNameLength; /*0x17*/ u8 padding; diff --git a/src/rtc.c b/src/rtc.c index fb2518f210..555c86b87e 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -334,7 +334,8 @@ enum TimeOfDay GetTimeOfDay(void) enum TimeOfDay GetTimeOfDayForDex(void) { - return OW_TIME_OF_DAY_ENCOUNTERS ? GetTimeOfDay() : TIME_OF_DAY_DEFAULT; + enum TimeOfDay timeOfDay = OW_TIME_OF_DAY_ENCOUNTERS ? GetTimeOfDay() : TIME_OF_DAY_DEFAULT; + return GenConfigTimeOfDay(timeOfDay); } void RtcInitLocalTimeOffset(s32 hour, s32 minute) @@ -456,12 +457,24 @@ enum Weekday GetDayOfWeek(void) return dateTime.dayOfWeek; } +enum TimeOfDay GenConfigTimeOfDay(enum TimeOfDay timeOfDay) +{ + if ((((timeOfDay == TIME_MORNING || timeOfDay == TIME_EVENING) && OW_TIMES_OF_DAY == GEN_3) + || (timeOfDay == TIME_EVENING && OW_TIMES_OF_DAY == GEN_4)) + && timeOfDay < TIME_LAST) + timeOfDay++; + + return timeOfDay; +} + enum TimeOfDay TryIncrementTimeOfDay(enum TimeOfDay timeOfDay) { - return timeOfDay == TIME_NIGHT ? TIME_MORNING : timeOfDay + 1; + timeOfDay = timeOfDay == TIME_LAST ? TIME_FIRST : timeOfDay + 1; + return GenConfigTimeOfDay(timeOfDay); } enum TimeOfDay TryDecrementTimeOfDay(enum TimeOfDay timeOfDay) { - return timeOfDay == TIME_MORNING ? TIME_NIGHT : timeOfDay - 1; + timeOfDay = timeOfDay == TIME_FIRST ? TIME_LAST : timeOfDay - 1; + return GenConfigTimeOfDay(timeOfDay); } diff --git a/src/save.c b/src/save.c index 5d17cea210..ff7cef5989 100644 --- a/src/save.c +++ b/src/save.c @@ -855,7 +855,7 @@ bool8 WriteSaveBlock2(void) // It returns TRUE when finished. bool8 WriteSaveBlock1Sector(void) { - u8 finished = FALSE; + bool32 finished = FALSE; u16 sectorId = ++gIncrementalSectorId; // Because WriteSaveBlock2 will have been called prior, this will be SECTOR_ID_SAVEBLOCK1_START if (sectorId <= SECTOR_ID_SAVEBLOCK1_END) { diff --git a/src/scrcmd.c b/src/scrcmd.c index 40ed11a9d0..cf1fb1ab67 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -34,6 +34,7 @@ #include "menu.h" #include "money.h" #include "move.h" +#include "move_relearner.h" #include "mystery_event_script.h" #include "palette.h" #include "party_menu.h" @@ -3255,3 +3256,38 @@ void Script_EndTrainerCanSeeIf(struct ScriptContext *ctx) if (ctx->breakOnTrainerBattle && sScriptConditionTable[condition][ctx->comparisonResult] == 1) StopScript(ctx); } + +bool8 ScrCmd_setmoverelearnerstate(struct ScriptContext *ctx) +{ + enum MoveRelearnerStates state = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1); + + gMoveRelearnerState = state; + return FALSE; +} + +bool8 ScrCmd_getmoverelearnerstate(struct ScriptContext *ctx) +{ + u32 varId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + + u16 *varPointer = GetVarPointer(varId); + *varPointer = gMoveRelearnerState; + return FALSE; +} + +bool8 ScrCmd_istmrelearneractive(struct ScriptContext *ctx) +{ + const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + + Script_RequestEffects(SCREFF_V1); + + if ((P_TM_MOVES_RELEARNER || P_ENABLE_MOVE_RELEARNERS) + && (P_ENABLE_ALL_TM_MOVES || IsBagPocketNonEmpty(POCKET_TM_HM))) + ScriptCall(ctx, ptr); + + return FALSE; +} diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index d4fba87859..ae503d1016 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -319,7 +319,7 @@ void CheckTeraType(struct ScriptContext *ctx) void SetTeraType(struct ScriptContext *ctx) { - u32 type = ScriptReadByte(ctx); + enum Type type = ScriptReadByte(ctx); u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); @@ -332,7 +332,7 @@ void SetTeraType(struct ScriptContext *ctx) * if side/slot are assigned, it will create the mon at the assigned party location * if slot == PARTY_SIZE, it will give the mon to first available party or storage slot */ -static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u16 item, enum PokeBall ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, enum ShinyMode shinyMode, bool8 gmaxFactor, u8 teraType, u8 dmaxLevel) +static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u16 item, enum PokeBall ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, enum ShinyMode shinyMode, bool8 gmaxFactor, enum Type teraType, u8 dmaxLevel) { enum NationalDexOrder nationalDexNum; int sentToPc; @@ -518,8 +518,8 @@ void ScrCmd_createmon(struct ScriptContext *ctx) // Perfect IV calculation u32 i; - u8 availableIVs[NUM_STATS]; - u8 selectedIvs[NUM_STATS]; + enum Stat availableIVs[NUM_STATS]; + enum Stat selectedIvs[NUM_STATS]; if (gSpeciesInfo[species].perfectIVCount != 0) { // Initialize a list of IV indices. @@ -543,6 +543,7 @@ void ScrCmd_createmon(struct ScriptContext *ctx) case STAT_SPEED: speedIv = MAX_PER_STAT_IVS; break; case STAT_SPATK: spAtkIv = MAX_PER_STAT_IVS; break; case STAT_SPDEF: spDefIv = MAX_PER_STAT_IVS; break; + default: break; } } } @@ -558,7 +559,7 @@ void ScrCmd_createmon(struct ScriptContext *ctx) u16 move4 = PARSE_FLAG(20, MOVE_NONE); enum ShinyMode shinyMode = PARSE_FLAG(21, SHINY_MODE_RANDOM); bool8 gmaxFactor = PARSE_FLAG(22, FALSE); - u8 teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES); + enum Type teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES); u8 dmaxLevel = PARSE_FLAG(24, 0); u8 evs[NUM_STATS] = {hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv}; diff --git a/src/start_menu.c b/src/start_menu.c index 719dc087a7..6566ee2e8e 100644 --- a/src/start_menu.c +++ b/src/start_menu.c @@ -957,7 +957,7 @@ static void ShowSaveMessage(const u8 *message, u8 (*saveCallback)(void)) { StringExpandPlaceholders(gStringVar4, message); LoadMessageBoxAndFrameGfx(0, TRUE); - AddTextPrinterForMessage_2(TRUE); + AddTextPrinterForMessage(TRUE); sSavingComplete = TRUE; sSaveDialogCallback = saveCallback; } diff --git a/src/string_util.c b/src/string_util.c index fd4a0861ee..fe8b6fa592 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -706,6 +706,7 @@ u8 GetExtCtrlCodeLength(u8 code) [EXT_CTRL_CODE_ENG] = 1, [EXT_CTRL_CODE_PAUSE_MUSIC] = 1, [EXT_CTRL_CODE_RESUME_MUSIC] = 1, + [EXT_CTRL_CODE_SPEAKER] = 1, }; u8 length = 0; diff --git a/src/strings.c b/src/strings.c index 1c8f252fcf..34c15fe35a 100644 --- a/src/strings.c +++ b/src/strings.c @@ -972,6 +972,9 @@ ALIGNED(4) const u8 gText_FrontierFacilityRoomsCleared[] = _("Rooms cleared: {ST ALIGNED(4) const u8 gText_FrontierFacilityKOsStreak[] = _("KOs in a row: {STR_VAR_2}"); ALIGNED(4) const u8 gText_FrontierFacilityFloorsCleared[] = _("Floors cleared: {STR_VAR_2}"); ALIGNED(4) const u8 gText_123Dot[][3] = {_("1."), _("2."), _("3.")}; +const u8 gText_FrontierFacilityTotalCaughtSpeciesBanned[] = _(" and {STR_VAR_2} of the POKéMON species\nyou caught are inelegible"); +const u8 gText_FrontierFacilityIncluding[] = _(".\pThese include "); +const u8 gText_FrontierFacilityAreInelegible[] = _(" are inelegible"); const u8 gText_SavingDontTurnOff2[] = _("SAVING…\nDON'T TURN OFF THE POWER."); const u8 gText_BlenderMaxSpeedRecord[] = _("BERRY BLENDER\nMAXIMUM SPEED RECORD!"); @@ -984,28 +987,6 @@ const u8 gText_CommErrorEllipsis[] = _("Communication error…"); const u8 gText_MoveCloserToLinkPartner[] = _("Move closer to your link partner(s).\nAvoid obstacles between partners."); const u8 gText_ABtnRegistrationCounter[] = _("A Button: Registration Counter"); const u8 gText_ABtnTitleScreen[] = _("A Button: Title Screen"); -const u8 gText_Option[] = _("OPTION"); -const u8 gText_TextSpeed[] = _("TEXT SPEED"); -const u8 gText_BattleScene[] = _("BATTLE SCENE"); -const u8 gText_BattleStyle[] = _("BATTLE STYLE"); -const u8 gText_Sound[] = _("SOUND"); -const u8 gText_Frame[] = _("FRAME"); -const u8 gText_OptionMenuCancel[] = _("CANCEL"); -const u8 gText_ButtonMode[] = _("BUTTON MODE"); -const u8 gText_TextSpeedSlow[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}SLOW"); -const u8 gText_TextSpeedMid[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}MID"); -const u8 gText_TextSpeedFast[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}FAST"); -const u8 gText_BattleSceneOn[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}ON"); -const u8 gText_BattleSceneOff[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}OFF"); -const u8 gText_BattleStyleShift[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}SHIFT"); -const u8 gText_BattleStyleSet[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}SET"); -const u8 gText_SoundMono[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}MONO"); -const u8 gText_SoundStereo[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}STEREO"); -const u8 gText_FrameType[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}TYPE"); -const u8 gText_FrameTypeNumber[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}"); -const u8 gText_ButtonTypeNormal[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}NORMAL"); -const u8 gText_ButtonTypeLR[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}LR"); -const u8 gText_ButtonTypeLEqualsA[] = _("{COLOR GREEN}{SHADOW LIGHT_GREEN}L=A"); const u8 gText_NumPlayerLink[] = _("{STR_VAR_1}P LINK"); const u8 gText_BronzeCard[] = _("BRONZE"); const u8 gText_CopperCard[] = _("COPPER"); @@ -1237,7 +1218,7 @@ const u8 gText_TrainerHill1F[] = _("1F"); const u8 gText_TrainerHill2F[] = _("2F"); const u8 gText_TrainerHill3F[] = _("3F"); const u8 gText_TrainerHill4F[] = _("4F"); -const u8 gText_TeachWhichMoveToPkmn[] = _("Teach which move to\n{STR_VAR_1}?"); +const u8 gText_TeachWhichMoveToPkmn[] = _("Teach which {STR_VAR_3} to\n{STR_VAR_1}?"); const u8 gText_MoveRelearnerTeachMoveConfirm[] = _("Teach {STR_VAR_2}?"); const u8 gText_MoveRelearnerPkmnLearnedMove[] = _("{STR_VAR_1} learned\n{STR_VAR_2}!"); const u8 gText_MoveRelearnerPkmnTryingToLearnMove[] = _("{STR_VAR_1} is trying to learn\n{STR_VAR_2}.\pBut {STR_VAR_1} can't learn more\nthan four moves.\pDelete an older move to make\nroom for {STR_VAR_2}?"); @@ -1298,6 +1279,10 @@ const u8 gText_BasePointsResetToZero[] = _("{STR_VAR_1}'s base points\nwere all const u8 gText_AM[] = _("AM"); const u8 gText_PM[] = _("PM"); const u8 gText_Relearn[] = _("{START_BUTTON} RELEARN"); // future note: don't decap this, because it mimics the summary screen BG graphics which will not get decapped +const u8 gText_Relearn_LevelUp[] = _("{START_BUTTON} RELEARN LEVEL"); +const u8 gText_Relearn_Egg[] = _("{START_BUTTON} RELEARN EGG"); +const u8 gText_Relearn_TM[] = _("{START_BUTTON} RELEARN TM"); +const u8 gText_Relearn_Tutor[] = _("{START_BUTTON} RELEARN TUTOR"); const u8 gText_Rename[] = _("RENAME"); const u8 gText_CannotSendMonToBoxHM[] = _("Cannot send that mon to the box,\nbecause it knows a HM move.{PAUSE_UNTIL_PRESS}"); const u8 gText_CannotSendMonToBoxActive[] = _("Cannot send an active battler\nto the box.{PAUSE_UNTIL_PRESS}"); diff --git a/src/text.c b/src/text.c index 29ffc5ea3a..a08d304e34 100644 --- a/src/text.c +++ b/src/text.c @@ -1,17 +1,20 @@ #include "global.h" #include "battle.h" -#include "main.h" +#include "blit.h" +#include "dynamic_placeholder_text_util.h" +#include "event_data.h" +#include "field_name_box.h" +#include "fonts.h" #include "m4a.h" +#include "main.h" +#include "menu.h" #include "palette.h" #include "sound.h" -#include "constants/songs.h" #include "string_util.h" -#include "window.h" #include "text.h" -#include "blit.h" -#include "menu.h" -#include "dynamic_placeholder_text_util.h" -#include "fonts.h" +#include "window.h" +#include "constants/songs.h" +#include "constants/speaker_names.h" static u16 RenderText(struct TextPrinter *); static u32 RenderFont(struct TextPrinter *); @@ -85,11 +88,6 @@ static const u8 sDarkDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow_alt static const u8 sUnusedFRLGBlankedDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_blanked_down_arrow.4bpp"); static const u8 sUnusedFRLGDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_down_arrow.4bpp"); static const u8 sDownArrowYCoords[] = { 0, 1, 2, 1 }; -static const u8 sWindowVerticalScrollSpeeds[] = { - [OPTIONS_TEXT_SPEED_SLOW] = 1, - [OPTIONS_TEXT_SPEED_MID] = 2, - [OPTIONS_TEXT_SPEED_FAST] = 4, -}; static const struct GlyphWidthFunc sGlyphWidthFuncs[] = { @@ -294,6 +292,31 @@ static const u8 sMenuCursorDimensions[][2] = [FONT_SHORT_NARROWER] = { 8, 14 }, }; +// these three arrays are most for readability, ie instead of returning a magic number 8 +static const u8 sTextSpeedFrameDelays[] = +{ + [OPTIONS_TEXT_SPEED_SLOW] = 8, + [OPTIONS_TEXT_SPEED_MID] = 4, + [OPTIONS_TEXT_SPEED_FAST] = 1, + [OPTIONS_TEXT_SPEED_INSTANT] = 1, +}; + +static const u8 sTextSpeedModifiers[] = +{ + [OPTIONS_TEXT_SPEED_SLOW] = TEXT_SPEED_SLOW_MODIFIER, + [OPTIONS_TEXT_SPEED_MID] = TEXT_SPEED_MEDIUM_MODIFIER, + [OPTIONS_TEXT_SPEED_FAST] = TEXT_SPEED_FAST_MODIFIER, + [OPTIONS_TEXT_SPEED_INSTANT] = TEXT_SPEED_INSTANT_MODIFIER, +}; + +static const u8 sTextScrollSpeeds[] = +{ + [OPTIONS_TEXT_SPEED_SLOW] = 1, + [OPTIONS_TEXT_SPEED_MID] = 2, + [OPTIONS_TEXT_SPEED_FAST] = 4, + [OPTIONS_TEXT_SPEED_INSTANT] = 6, +}; + static const u16 sFontBoldJapaneseGlyphs[] = INCBIN_U16("graphics/fonts/bold.hwjpnfont"); static void SetFontsPointer(const struct FontInfo *fonts) @@ -301,6 +324,40 @@ static void SetFontsPointer(const struct FontInfo *fonts) gFonts = fonts; } +u32 GetPlayerTextSpeed(void) +{ + if (gTextFlags.forceMidTextSpeed) + return OPTIONS_TEXT_SPEED_MID; + + if (gSaveBlock2Ptr->optionsTextSpeed > OPTIONS_TEXT_SPEED_INSTANT) + gSaveBlock2Ptr->optionsTextSpeed = OPTIONS_TEXT_SPEED_FAST; + + if (FlagGet(FLAG_TEXT_SPEED_INSTANT) || TEXT_SPEED_INSTANT) + return OPTIONS_TEXT_SPEED_INSTANT; + + return gSaveBlock2Ptr->optionsTextSpeed; +} + +u32 GetPlayerTextSpeedDelay(void) +{ + return sTextSpeedFrameDelays[GetPlayerTextSpeed()]; +} + +u32 GetPlayerTextSpeedModifier(void) +{ + return sTextSpeedModifiers[GetPlayerTextSpeed()]; +} + +u32 GetPlayerTextScrollSpeed(void) +{ + return sTextScrollSpeeds[GetPlayerTextSpeed()]; +} + +bool32 IsPlayerTextSpeedInstant(void) +{ + return GetPlayerTextSpeed() == OPTIONS_TEXT_SPEED_INSTANT; +} + void DeactivateAllTextPrinters(void) { int printer; @@ -378,30 +435,53 @@ bool32 AddTextPrinter(struct TextPrinterTemplate *printerTemplate, u8 speed, voi void RunTextPrinters(void) { - int i; + bool32 isInstantText = IsPlayerTextSpeedInstant(); + u32 textRepeats = GetPlayerTextSpeedModifier(); - if (!gDisableTextPrinters) + if (gDisableTextPrinters) + return; + + do { - for (i = 0; i < WINDOWS_MAX; ++i) + u32 numEmpty = 0; + for (u32 windowId = 0; windowId < WINDOWS_MAX; windowId++) { - if (sTextPrinters[i].active) + if (sTextPrinters[windowId].active) { - u16 renderCmd = RenderFont(&sTextPrinters[i]); - switch (renderCmd) + for (u32 repeat = 0; repeat < textRepeats; repeat++) { - case RENDER_PRINT: - CopyWindowToVram(sTextPrinters[i].printerTemplate.windowId, COPYWIN_GFX); - case RENDER_UPDATE: - if (sTextPrinters[i].callback != NULL) - sTextPrinters[i].callback(&sTextPrinters[i].printerTemplate, renderCmd); - break; - case RENDER_FINISH: - sTextPrinters[i].active = FALSE; - break; + u32 renderState = RenderFont(&sTextPrinters[windowId]); + switch (renderState) + { + case RENDER_PRINT: + CopyWindowToVram(sTextPrinters[windowId].printerTemplate.windowId, COPYWIN_GFX); + if (sTextPrinters[windowId].callback != NULL) + sTextPrinters[windowId].callback(&sTextPrinters[windowId].printerTemplate, renderState); + break; + case RENDER_UPDATE: + if (sTextPrinters[windowId].callback != NULL) + sTextPrinters[windowId].callback(&sTextPrinters[windowId].printerTemplate, renderState); + isInstantText = FALSE; + break; + case RENDER_FINISH: + sTextPrinters[windowId].active = FALSE; + isInstantText = FALSE; + break; + } + + if (!sTextPrinters[windowId].active) + break; } } + else + { + numEmpty++; + } } - } + + if (numEmpty == WINDOWS_MAX) + return; + } while (isInstantText); } bool32 IsTextPrinterActive(u8 id) @@ -427,6 +507,13 @@ void GenerateFontHalfRowLookupTable(u8 fgColor, u8 bgColor, u8 shadowColor) u16 *current = sFontHalfRowLookupTable; + if (fgColor == sLastTextFgColor + && bgColor == sLastTextBgColor + && shadowColor == sLastTextShadowColor) + { + return; + } + sLastTextBgColor = bgColor; sLastTextFgColor = fgColor; sLastTextShadowColor = shadowColor; @@ -629,27 +716,35 @@ static u8 UNUSED GetLastTextColor(u8 colorType) } } -inline static void GLYPH_COPY(u8 *windowTiles, u32 widthOffset, u32 j, u32 i, u32 *glyphPixels, s32 width, s32 height) +inline static void GLYPH_COPY(u8 *windowTiles, u32 widthOffset, u32 x0, u32 y0, u32 *glyphPixels, s32 width, s32 height) { - u32 xAdd, yAdd, pixelData, bits, toOrr, dummyX; - u8 *dst; + if (width <= 0) + return; - xAdd = j + width; - yAdd = i + height; - dummyX = j; - for (; i < yAdd; i++) + u32 widthMask = (1 << (width * 4)) - 1; + + u32 shift0 = (x0 % 8) * 4, shift8 = 32 - shift0; + + u32 *alignedWindowTilesX = (u32 *)(windowTiles + ((x0 / 8) * TILE_SIZE_4BPP)); + + u32 y1 = y0 + height; + for (u32 y = y0; y < y1; y++) { - pixelData = *glyphPixels++; - for (j = dummyX; j < xAdd; j++) - { - if ((toOrr = pixelData & 0xF)) - { - dst = windowTiles + ((j / 8) * 32) + ((j % 8) / 2) + ((i / 8) * widthOffset) + ((i % 8) * 4); - bits = ((j & 1) * 4); - *dst = (toOrr << bits) | (*dst & (0xF0 >> bits)); - } - pixelData >>= 4; - } + u32 pixels = *glyphPixels++ & widthMask; + + u32 mask = pixels; + mask = mask | (mask >> 2); + mask = mask | (mask >> 1); + mask = mask & 0x11111111; + mask = mask * 0xF; + + u32 pixels0 = pixels << shift0, pixels8 = pixels >> shift8; + u32 mask0 = mask << shift0, mask8 = mask >> shift8; + + u32 *alignedWindowTiles = (u32 *)((u8 *)alignedWindowTilesX + ((y / 8) * widthOffset) + ((y % 8) * 4)); + + alignedWindowTiles[0] = (alignedWindowTiles[0] & ~mask0) | pixels0; + alignedWindowTiles[8] = (alignedWindowTiles[8] & ~mask8) | pixels8; } } @@ -888,7 +983,7 @@ void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) else { subStruct->downArrowYPosIdx = 0; - subStruct->downArrowDelay = 0; + subStruct->utilityCounter = 0; } } @@ -899,9 +994,9 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) if (gTextFlags.autoScroll == 0) { - if (subStruct->downArrowDelay != 0) + if (subStruct->utilityCounter != 0) { - subStruct->downArrowDelay--; + subStruct->utilityCounter--; } else { @@ -937,7 +1032,7 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) 16); CopyWindowToVram(textPrinter->printerTemplate.windowId, COPYWIN_GFX); - subStruct->downArrowDelay = 8; + subStruct->utilityCounter = 8 * GetPlayerTextSpeedModifier(); subStruct->downArrowYPosIdx++; } } @@ -1041,7 +1136,7 @@ void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool32 drawArrow, u8 * BlitBitmapRectToWindow(windowId, arrowTiles, 0, sDownArrowYCoords[*yCoordIndex & 3], 8, 16, x, y - 2, 8, 16); CopyWindowToVram(windowId, COPYWIN_GFX); - *counter = 8; + *counter = 8 * GetPlayerTextSpeedModifier(); ++*yCoordIndex; } } @@ -1057,7 +1152,7 @@ static u16 RenderText(struct TextPrinter *textPrinter) switch (textPrinter->state) { case RENDER_STATE_HANDLE_CHAR: - if (JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp) + if ((JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp) || IsPlayerTextSpeedInstant()) textPrinter->delayCounter = 0; if (textPrinter->delayCounter && textPrinter->textSpeed) @@ -1213,6 +1308,13 @@ static u16 RenderText(struct TextPrinter *textPrinter) case EXT_CTRL_CODE_ENG: textPrinter->japanese = FALSE; return RENDER_REPEAT; + case EXT_CTRL_CODE_SPEAKER: + { + enum SpeakerNames name = *textPrinter->printerTemplate.currentChar++; + TrySpawnAndShowNamebox(gSpeakerNamesTable[name], NAME_BOX_BASE_TILE_NUM); + + return RENDER_REPEAT; + } } break; case CHAR_PROMPT_CLEAR: @@ -1308,6 +1410,7 @@ static u16 RenderText(struct TextPrinter *textPrinter) case RENDER_STATE_SCROLL_START: if (TextPrinterWaitWithDownArrow(textPrinter)) { + subStruct->utilityCounter = 0; TextPrinterClearDownArrow(textPrinter); textPrinter->scrollDistance = gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing; textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; @@ -1317,18 +1420,31 @@ static u16 RenderText(struct TextPrinter *textPrinter) case RENDER_STATE_SCROLL: if (textPrinter->scrollDistance) { - int scrollSpeed = GetPlayerTextSpeed(); - int speed = sWindowVerticalScrollSpeeds[scrollSpeed]; - if (textPrinter->scrollDistance < speed) + u32 scrollSpeed = GetPlayerTextScrollSpeed(); + u32 speedModifier = GetPlayerTextSpeedModifier(); + + if (subStruct->utilityCounter != 0) + { + subStruct->utilityCounter--; + return RENDER_UPDATE; + } + + if (textPrinter->scrollDistance < scrollSpeed) { ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); textPrinter->scrollDistance = 0; } else { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, speed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance -= speed; + ScrollWindow(textPrinter->printerTemplate.windowId, 0, scrollSpeed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance -= scrollSpeed; } + + if (speedModifier > 1) + subStruct->utilityCounter = speedModifier; + else + subStruct->utilityCounter = 0; + CopyWindowToVram(textPrinter->printerTemplate.windowId, COPYWIN_GFX); } else @@ -1403,6 +1519,7 @@ static u32 UNUSED GetStringWidthFixedWidthFont(const u8 *str, u8 fontId, u8 lett case EXT_CTRL_CODE_SKIP: case EXT_CTRL_CODE_CLEAR_TO: case EXT_CTRL_CODE_MIN_LETTER_SPACING: + case EXT_CTRL_CODE_SPEAKER: ++strPos; break; case EXT_CTRL_CODE_RESET_FONT: @@ -1551,6 +1668,7 @@ s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing) case EXT_CTRL_CODE_ESCAPE: case EXT_CTRL_CODE_SHIFT_RIGHT: case EXT_CTRL_CODE_SHIFT_DOWN: + case EXT_CTRL_CODE_SPEAKER: ++str; break; case EXT_CTRL_CODE_FONT: @@ -1720,6 +1838,7 @@ u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str) case EXT_CTRL_CODE_SKIP: case EXT_CTRL_CODE_CLEAR_TO: case EXT_CTRL_CODE_MIN_LETTER_SPACING: + case EXT_CTRL_CODE_SPEAKER: ++strPos; break; case EXT_CTRL_CODE_RESET_FONT: diff --git a/src/trade.c b/src/trade.c index 2a0d920a91..01cd6f15ca 100644 --- a/src/trade.c +++ b/src/trade.c @@ -138,7 +138,7 @@ enum { #define NUM_CHOOSE_PKMN_SPRITES (1 + GFXTAG_CHOOSE_PKMN_EMPTY_3 - GFXTAG_CHOOSE_PKMN_L) // Values for signaling to/from the link partner -enum { +enum SignalStatus { STATUS_NONE, STATUS_READY, STATUS_CANCEL, @@ -2482,7 +2482,7 @@ s32 GetGameProgressForLinkTrade(void) return TRADE_BOTH_PLAYERS_READY; } -int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData player, struct RfuGameCompatibilityData partner, u16 playerSpecies2, u16 partnerSpecies, u8 requestedType, u16 playerSpecies, bool8 isModernFatefulEncounter) +int GetUnionRoomTradeMessageId(struct RfuGameCompatibilityData player, struct RfuGameCompatibilityData partner, u16 playerSpecies2, u16 partnerSpecies, enum Type requestedType, u16 playerSpecies, bool8 isModernFatefulEncounter) { bool8 playerHasNationalDex = player.hasNationalDex; bool8 playerCanLinkNationally = player.canLinkNationally; diff --git a/src/trainer_pools.c b/src/trainer_pools.c index ec38c7a01f..6f0e57fdb2 100644 --- a/src/trainer_pools.c +++ b/src/trainer_pools.c @@ -1,5 +1,6 @@ #include "global.h" #include "data.h" +#include "item.h" #include "malloc.h" #include "pokemon.h" #include "random.h" @@ -227,6 +228,10 @@ static u32 PickMonFromPool(const struct Trainer *trainer, u8 *poolIndexArray, u3 poolIndexArray[currIndex] = POOL_SLOT_DISABLED; } } + if (rules->megaStoneClause && gItemsInfo[currentItem].sortType == ITEM_TYPE_MEGA_STONE && gItemsInfo[chosenItem].sortType == ITEM_TYPE_MEGA_STONE) + poolIndexArray[currIndex] = POOL_SLOT_DISABLED; + if (rules->zCrystalClause && gItemsInfo[currentItem].sortType == ITEM_TYPE_Z_CRYSTAL && gItemsInfo[chosenItem].sortType == ITEM_TYPE_Z_CRYSTAL) + poolIndexArray[currIndex] = POOL_SLOT_DISABLED; } } return monIndex; diff --git a/src/trainer_see.c b/src/trainer_see.c index 4ac9c513b2..bf66f66e2e 100644 --- a/src/trainer_see.c +++ b/src/trainer_see.c @@ -361,6 +361,8 @@ static const struct SpriteTemplate sSpriteTemplate_Emote = bool8 CheckForTrainersWantingBattle(void) { u8 i; + u8 trainerObjects[OBJECT_EVENTS_COUNT] = {0}; + u8 trainerObjectsCount = 0; if (FlagGet(OW_FLAG_NO_TRAINER_SEE)) return FALSE; @@ -368,17 +370,34 @@ bool8 CheckForTrainersWantingBattle(void) gNoOfApproachingTrainers = 0; gApproachingTrainerId = 0; + // Adds trainers wanting to battle to array for (i = 0; i < OBJECT_EVENTS_COUNT; i++) - { - u8 numTrainers; - + { if (!gObjectEvents[i].active) continue; if (gObjectEvents[i].trainerType != TRAINER_TYPE_NORMAL && gObjectEvents[i].trainerType != TRAINER_TYPE_SEE_ALL_DIRECTIONS && gObjectEvents[i].trainerType != TRAINER_TYPE_BURIED) continue; + trainerObjects[trainerObjectsCount++] = i; + } - numTrainers = CheckTrainer(i); - if (numTrainers == 0xFF) // non-trainerbatle script + // Sorts array by localId + for (i = 1; i <= trainerObjectsCount; i++) + { + u8 x = trainerObjects[i]; + u8 j = i; + while (j > 0 && gObjectEvents[trainerObjects[j-1]].localId > gObjectEvents[x].localId) + { + trainerObjects[j] = trainerObjects[j-1]; + j--; + } + trainerObjects[j] = x; + } + + for (i = 0; i <= trainerObjectsCount; i++) + { + u8 numTrainers; + numTrainers = CheckTrainer(trainerObjects[i]); + if (numTrainers == 0xFF) // non-trainerbattle script { u32 objectEventId = gApproachingTrainers[gNoOfApproachingTrainers - 1].objectEventId; gApproachingTrainers[gNoOfApproachingTrainers - 1].trainerScriptPtr = GetObjectEventScriptPointerByObjectEventId(objectEventId); diff --git a/src/trainer_slide.c b/src/trainer_slide.c index 3b94894a79..080c1d4bbc 100644 --- a/src/trainer_slide.c +++ b/src/trainer_slide.c @@ -312,7 +312,7 @@ static bool32 IsSlideInitalizedOrPlayed(enum TrainerSlideType slideId) return FALSE; } -void TryInitializeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, u32 moveType) +void TryInitializeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, enum Type moveType) { enum TrainerSlideType slideId = TRAINER_SLIDE_PLAYER_LANDS_FIRST_STAB_MOVE; diff --git a/src/type_icons.c b/src/type_icons.c index ba13f86027..237c2c9a4f 100644 --- a/src/type_icons.c +++ b/src/type_icons.c @@ -14,18 +14,18 @@ static void LoadTypeIconsPerBattler(u32, u32); static bool32 UseDoubleBattleCoords(u32); -static u32 GetMonPublicType(u32, u32); +static enum Type GetMonPublicType(u32, u32); static bool32 ShouldHideUncaughtType(u32 species); static bool32 ShouldHideUnseenType(u32 species); -static u32 GetMonDefensiveTeraType(struct Pokemon *, struct Pokemon*, u32, u32, u32, u32); -static u32 IsIllusionActiveAndTypeUnchanged(struct Pokemon*, u32, u32); +static enum Type GetMonDefensiveTeraType(struct Pokemon *, struct Pokemon*, u32, u32, u32, u32); +static bool32 IsIllusionActiveAndTypeUnchanged(struct Pokemon*, u32, u32); -static void CreateSpriteFromType(u32, bool32, u32[], u32, u32); -static bool32 ShouldSkipSecondType(u32[], u32); +static void CreateSpriteFromType(u32, bool32, enum Type[], u32, u32); +static bool32 ShouldSkipSecondType(enum Type[], u32); static void SetTypeIconXY(s32*, s32*, u32, bool32, u32); -static void CreateSpriteAndSetTypeSpriteAttributes(u32, u32 x, u32 y, u32, u32, bool32); -static bool32 ShouldFlipTypeIcon(bool32, u32, u32); +static void CreateSpriteAndSetTypeSpriteAttributes(enum Type, u32 x, u32 y, u32, u32, bool32); +static bool32 ShouldFlipTypeIcon(bool32, u32, enum Type); static void SpriteCB_TypeIcon(struct Sprite*); static void DestroyTypeIcon(struct Sprite*); @@ -266,7 +266,8 @@ static void LoadTypeSpritesAndPalettes(void) static void LoadTypeIconsPerBattler(u32 battler, u32 position) { - u32 typeNum, types[2]; + u32 typeNum; + enum Type types[2]; u32 battlerId = GetBattlerAtPosition(position); bool32 useDoubleBattleCoords = UseDoubleBattleCoords(battlerId); @@ -294,11 +295,11 @@ static bool32 UseDoubleBattleCoords(u32 position) return TRUE; } -static u32 GetMonPublicType(u32 battlerId, u32 typeNum) +static enum Type GetMonPublicType(u32 battlerId, u32 typeNum) { - struct Pokemon* mon = GetBattlerMon(battlerId); + struct Pokemon *mon = GetBattlerMon(battlerId); u32 monSpecies = GetMonData(mon,MON_DATA_SPECIES,NULL); - struct Pokemon* monIllusion; + struct Pokemon *monIllusion; u32 illusionSpecies; if (ShouldHideUncaughtType(monSpecies) || ShouldHideUnseenType(monSpecies)) @@ -338,9 +339,9 @@ static bool32 ShouldHideUnseenType(u32 species) return TRUE; } -static u32 GetMonDefensiveTeraType(struct Pokemon * mon, struct Pokemon* monIllusion, u32 battlerId, u32 typeNum, u32 illusionSpecies, u32 monSpecies) +static enum Type GetMonDefensiveTeraType(struct Pokemon *mon, struct Pokemon *monIllusion, u32 battlerId, u32 typeNum, u32 illusionSpecies, u32 monSpecies) { - u32 teraType = GetBattlerTeraType(battlerId); + enum Type teraType = GetBattlerTeraType(battlerId); u32 targetSpecies; if (teraType != TYPE_STELLAR) @@ -351,7 +352,7 @@ static u32 GetMonDefensiveTeraType(struct Pokemon * mon, struct Pokemon* monIllu return GetSpeciesType(targetSpecies, typeNum); } -static u32 IsIllusionActiveAndTypeUnchanged(struct Pokemon* monIllusion, u32 monSpecies, u32 battlerId) +static bool32 IsIllusionActiveAndTypeUnchanged(struct Pokemon *monIllusion, u32 monSpecies, u32 battlerId) { u32 typeNum; @@ -365,7 +366,7 @@ static u32 IsIllusionActiveAndTypeUnchanged(struct Pokemon* monIllusion, u32 mon return TRUE; } -static void CreateSpriteFromType(u32 position, bool32 useDoubleBattleCoords, u32 types[], u32 typeNum, u32 battler) +static void CreateSpriteFromType(u32 position, bool32 useDoubleBattleCoords, enum Type types[], u32 typeNum, u32 battler) { s32 x = 0, y = 0; @@ -377,7 +378,7 @@ static void CreateSpriteFromType(u32 position, bool32 useDoubleBattleCoords, u32 CreateSpriteAndSetTypeSpriteAttributes(types[typeNum], x, y, position, battler, useDoubleBattleCoords); } -static bool32 ShouldSkipSecondType(u32 types[], u32 typeNum) +static bool32 ShouldSkipSecondType(enum Type types[], u32 typeNum) { if (!typeNum) return FALSE; @@ -394,7 +395,7 @@ static void SetTypeIconXY(s32* x, s32* y, u32 position, bool32 useDoubleBattleCo *y = sTypeIconPositions[position][useDoubleBattleCoords].y + (11 * typeNum); } -static void CreateSpriteAndSetTypeSpriteAttributes(u32 type, u32 x, u32 y, u32 position, u32 battler, bool32 useDoubleBattleCoords) +static void CreateSpriteAndSetTypeSpriteAttributes(enum Type type, u32 x, u32 y, u32 position, u32 battler, bool32 useDoubleBattleCoords) { struct Sprite* sprite; const struct SpriteTemplate* spriteTemplate = gTypesInfo[type].useSecondTypeIconPalette ? &sSpriteTemplate_TypeIcons2 : &sSpriteTemplate_TypeIcons1; @@ -413,9 +414,9 @@ static void CreateSpriteAndSetTypeSpriteAttributes(u32 type, u32 x, u32 y, u32 p StartSpriteAnim(sprite, type); } -static bool32 ShouldFlipTypeIcon(bool32 useDoubleBattleCoords, u32 position, u32 typeId) +static bool32 ShouldFlipTypeIcon(bool32 useDoubleBattleCoords, u32 position, enum Type typeId) { - bool32 side = (useDoubleBattleCoords) ? B_SIDE_OPPONENT : B_SIDE_PLAYER; + enum BattleSide side = (useDoubleBattleCoords) ? B_SIDE_OPPONENT : B_SIDE_PLAYER; if (GetBattlerSide(GetBattlerAtPosition(position)) != side) return FALSE; @@ -423,7 +424,7 @@ static bool32 ShouldFlipTypeIcon(bool32 useDoubleBattleCoords, u32 position, u32 return !gTypesInfo[typeId].isSpecialCaseType; } -static void SpriteCB_TypeIcon(struct Sprite* sprite) +static void SpriteCB_TypeIcon(struct Sprite *sprite) { u32 position = sprite->tMonPosition; u32 battlerId = sprite->tBattlerId; @@ -487,7 +488,7 @@ static void FreeAllTypeIconResources(void) } } -static void (* const sShowTypesControllerFuncs[])(u32 battler) = +static void (*const sShowTypesControllerFuncs[])(u32 battler) = { PlayerHandleChooseMove, HandleChooseMoveAfterDma3, @@ -562,7 +563,7 @@ static s32 GetTypeIconSlideMovement(bool32 useDoubleBattleCoords, u32 position, static s32 GetTypeIconBounceMovement(s32 originalY, u32 position) { - struct Sprite* healthbox = &gSprites[gHealthboxSpriteIds[GetBattlerAtPosition(position)]]; + struct Sprite *healthbox = &gSprites[gHealthboxSpriteIds[GetBattlerAtPosition(position)]]; return originalY + healthbox->y2; } diff --git a/src/union_room.c b/src/union_room.c index 135cf3e982..368becd0a2 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -205,7 +205,7 @@ static EWRAM_DATA union } sWirelessLinkMain = {}; EWRAM_DATA struct RfuGameCompatibilityData gRfuPartnerCompatibilityData = {}; EWRAM_DATA u16 gUnionRoomOfferedSpecies = 0; -EWRAM_DATA u8 gUnionRoomRequestedMonType = 0; +EWRAM_DATA enum Type gUnionRoomRequestedMonType = 0; static EWRAM_DATA struct UnionRoomTrade sUnionRoomTrade = {}; static struct WirelessLink_Leader *sLeader; @@ -270,7 +270,7 @@ static void GetURoomActivityRejectMsg(u8 *, s32, u32); static u32 ConvPartnerUnameAndGetWhetherMetAlready(struct RfuPlayer *); static void GetURoomActivityStartMsg(u8 *, u8); static void UR_ClearBg0(void); -static s32 IsRequestedTradeInPlayerParty(u32, u32); +static s32 IsRequestedTradeInPlayerParty(enum Type, u32); static bool32 UR_PrintFieldMessage(const u8 *); static s32 GetChatLeaderActionRequestMessage(u8 *, u32, u16 *, struct WirelessLink_URoom *); static void Task_InitUnionRoom(u8 taskId); @@ -3612,7 +3612,7 @@ static bool8 PrintOnTextbox(u8 *textState, const u8 *str) LoadMessageBoxAndBorderGfx(); DrawDialogueFrame(0, TRUE); StringExpandPlaceholders(gStringVar4, str); - AddTextPrinterForMessage_2(TRUE); + AddTextPrinterForMessage(TRUE); (*textState)++; break; case 1: @@ -4104,7 +4104,7 @@ static void TradeBoardPrintItemInfo(u8 windowId, u8 y, struct RfuGameData *data, { u8 levelStr[4]; u16 species = data->tradeSpecies; - u8 type = data->tradeType; + enum Type type = data->tradeType; u8 level = data->tradeLevel; PrintUnionRoomText(windowId, FONT_NORMAL, playerName, 8, y, colorIdx); @@ -4174,7 +4174,7 @@ static s32 GetUnionRoomPlayerGender(s32 playerIdx, struct RfuPlayerList *list) return list->players[playerIdx].rfu.data.playerGender; } -static s32 IsRequestedTradeInPlayerParty(u32 type, u32 species) +static s32 IsRequestedTradeInPlayerParty(enum Type type, u32 species) { s32 i; diff --git a/src/wallclock.c b/src/wallclock.c index bca008ac24..6bc87513dd 100644 --- a/src/wallclock.c +++ b/src/wallclock.c @@ -61,9 +61,9 @@ enum { }; enum { - MOVE_NONE, - MOVE_BACKWARD, - MOVE_FORWARD, + CLOCK_MOVE_NONE, + CLOCK_MOVE_BACKWARD, + CLOCK_MOVE_FORWARD, }; enum { @@ -806,15 +806,15 @@ static void Task_SetClock_HandleInput(u8 taskId) } else { - gTasks[taskId].tMoveDir = MOVE_NONE; + gTasks[taskId].tMoveDir = CLOCK_MOVE_NONE; if (JOY_HELD(DPAD_LEFT)) - gTasks[taskId].tMoveDir = MOVE_BACKWARD; + gTasks[taskId].tMoveDir = CLOCK_MOVE_BACKWARD; if (JOY_HELD(DPAD_RIGHT)) - gTasks[taskId].tMoveDir = MOVE_FORWARD; + gTasks[taskId].tMoveDir = CLOCK_MOVE_FORWARD; - if (gTasks[taskId].tMoveDir != MOVE_NONE) + if (gTasks[taskId].tMoveDir != CLOCK_MOVE_NONE) { if (gTasks[taskId].tMoveSpeed < 0xFF) gTasks[taskId].tMoveSpeed++; @@ -916,13 +916,13 @@ static u16 CalcNewMinHandAngle(u16 angle, u8 direction, u8 speed) u8 delta = CalcMinHandDelta(speed); switch (direction) { - case MOVE_BACKWARD: + case CLOCK_MOVE_BACKWARD: if (angle) angle -= delta; else angle = 360 - delta; break; - case MOVE_FORWARD: + case CLOCK_MOVE_FORWARD: if (angle < 360 - delta) angle += delta; else @@ -936,7 +936,7 @@ static bool32 AdvanceClock(u8 taskId, u8 direction) { switch (direction) { - case MOVE_BACKWARD: + case CLOCK_MOVE_BACKWARD: if (gTasks[taskId].tMinutes > 0) { gTasks[taskId].tMinutes--; @@ -953,7 +953,7 @@ static bool32 AdvanceClock(u8 taskId, u8 direction) UpdateClockPeriod(taskId, direction); } break; - case MOVE_FORWARD: + case CLOCK_MOVE_FORWARD: if (gTasks[taskId].tMinutes < 59) { gTasks[taskId].tMinutes++; @@ -979,7 +979,7 @@ static void UpdateClockPeriod(u8 taskId, u8 direction) u8 hours = gTasks[taskId].tHours; switch (direction) { - case MOVE_BACKWARD: + case CLOCK_MOVE_BACKWARD: switch (hours) { case 11: @@ -990,7 +990,7 @@ static void UpdateClockPeriod(u8 taskId, u8 direction) break; } break; - case MOVE_FORWARD: + case CLOCK_MOVE_FORWARD: switch (hours) { case 0: diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 5d8e22c11b..4c81fa371c 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -4,6 +4,7 @@ #include "battle_pyramid.h" #include "event_data.h" #include "fieldmap.h" +#include "fishing.h" #include "follower_npc.h" #include "random.h" #include "field_player_avatar.h" @@ -46,15 +47,14 @@ extern const u8 EventScript_SprayWoreOff[]; static u16 FeebasRandom(void); static void FeebasSeedRng(u16 seed); -static void UpdateChainFishingStreak(); static bool8 IsWildLevelAllowedByRepel(u8 level); static void ApplyFluteEncounterRateMod(u32 *encRate); static void ApplyCleanseTagEncounterRateMod(u32 *encRate); static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 species, enum WildPokemonArea area); #ifdef BUGFIX -static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, u8 type, u16 ability, u8 *monIndex, u32 size); +static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, enum Type type, enum Ability ability, u8 *monIndex, u32 size); #else -static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, u8 type, u16 ability, u8 *monIndex); +static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, enum Type type, enum Ability ability, u8 *monIndex); #endif static bool8 IsAbilityAllowingEncounter(u8 level); @@ -353,7 +353,7 @@ static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon, u8 wildMonIn // check ability for max level mon if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) { - u16 ability = GetMonAbility(&gPlayerParty[0]); + enum Ability ability = GetMonAbility(&gPlayerParty[0]); if (ability == ABILITY_HUSTLE || ability == ABILITY_VITAL_SPIRIT || ability == ABILITY_PRESSURE) { if (Random() % 2 == 0) @@ -415,36 +415,32 @@ enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area return TIME_OF_DAY_DEFAULT; if (InBattlePike() || CurrentBattlePyramidLocation() != PYRAMID_LOCATION_NONE) - { return OW_TIME_OF_DAY_FALLBACK; - } - else + + switch (area) { - switch (area) - { - default: - case WILD_AREA_LAND: - wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo; - break; - case WILD_AREA_WATER: - wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo; - break; - case WILD_AREA_ROCKS: - wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo; - break; - case WILD_AREA_FISHING: - wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo; - break; - case WILD_AREA_HIDDEN: - wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo; - break; - } + default: + case WILD_AREA_LAND: + wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo; + break; + case WILD_AREA_WATER: + wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo; + break; + case WILD_AREA_ROCKS: + wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo; + break; + case WILD_AREA_FISHING: + wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo; + break; + case WILD_AREA_HIDDEN: + wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo; + break; } if (wildMonInfo == NULL && !OW_TIME_OF_DAY_DISABLE_FALLBACK) return OW_TIME_OF_DAY_FALLBACK; else - return timeOfDay; + return GenConfigTimeOfDay(timeOfDay); } u8 PickWildMonNature(void) @@ -637,7 +633,7 @@ static bool8 WildEncounterCheck(u32 encounterRate, bool8 ignoreAbility) encounterRate *= 2; if (!ignoreAbility && !GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) { - u32 ability = GetMonAbility(&gPlayerParty[0]); + enum Ability ability = GetMonAbility(&gPlayerParty[0]); if (ability == ABILITY_STENCH && gMapHeader.mapLayoutId == LAYOUT_BATTLE_FRONTIER_BATTLE_PYRAMID_FLOOR) encounterRate = encounterRate * 3 / 4; @@ -967,22 +963,6 @@ bool8 DoesCurrentMapHaveFishingMons(void) return FALSE; } -u32 CalculateChainFishingShinyRolls(void) -{ - return (2 * min(gChainFishingDexNavStreak, FISHING_CHAIN_SHINY_STREAK_MAX)); -} - -static void UpdateChainFishingStreak() -{ - if (!I_FISHING_CHAIN) - return; - - if (gChainFishingDexNavStreak >= FISHING_CHAIN_LENGTH_MAX) - return; - - gChainFishingDexNavStreak++; -} - void FishingWildEncounter(u8 rod) { u16 species; @@ -1126,7 +1106,7 @@ static bool8 IsWildLevelAllowedByRepel(u8 wildLevel) static bool8 IsAbilityAllowingEncounter(u8 level) { - u16 ability; + enum Ability ability; if (GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) return TRUE; @@ -1142,7 +1122,7 @@ static bool8 IsAbilityAllowingEncounter(u8 level) return TRUE; } -static bool8 TryGetRandomWildMonIndexByType(const struct WildPokemon *wildMon, u8 type, u8 numMon, u8 *monIndex) +static bool8 TryGetRandomWildMonIndexByType(const struct WildPokemon *wildMon, enum Type type, u8 numMon, u8 *monIndex) { u8 validIndexes[numMon]; // variable length array, an interesting feature u8 i, validMonCount; @@ -1196,9 +1176,9 @@ static u8 GetMaxLevelOfSpeciesInWildTable(const struct WildPokemon *wildMon, u16 } #ifdef BUGFIX -static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, u8 type, u16 ability, u8 *monIndex, u32 size) +static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, enum Type type, enum Ability ability, u8 *monIndex, u32 size) #else -static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, u8 type, u16 ability, u8 *monIndex) +static bool8 TryGetAbilityInfluencedWildMonIndex(const struct WildPokemon *wildMon, enum Type type, enum Ability ability, u8 *monIndex) #endif { if (GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) diff --git a/test/battle/ability/adaptability.c b/test/battle/ability/adaptability.c index 4c1c8439b7..876dac212c 100644 --- a/test/battle/ability/adaptability.c +++ b/test/battle/ability/adaptability.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Adaptability increases same-type attack bonus from x1.5 to x2", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_HYPER_CUTTER; } PARAMETRIZE { ability = ABILITY_ADAPTABILITY; } GIVEN { diff --git a/test/battle/ability/anger_shell.c b/test/battle/ability/anger_shell.c index 875088c945..6c9064ee0d 100644 --- a/test/battle/ability/anger_shell.c +++ b/test/battle/ability/anger_shell.c @@ -93,3 +93,23 @@ SINGLE_BATTLE_TEST("Anger Shell activates after all hits from a multi-hit move") EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); } } + +SINGLE_BATTLE_TEST("Anger Shell does not activate if move is boosted by Sheer Force") +{ + u16 maxHp = 500; + GIVEN { + PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + NOT ABILITY_POPUP(player, ABILITY_ANGER_SHELL); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/ability/anticipation.c b/test/battle/ability/anticipation.c index a4a3bef77f..ee5b602a13 100644 --- a/test/battle/ability/anticipation.c +++ b/test/battle/ability/anticipation.c @@ -100,7 +100,8 @@ SINGLE_BATTLE_TEST("Anticipation doesn't consider Gravity into their effectivene SINGLE_BATTLE_TEST("Anticipation counts Counter, Metal Burst or Mirror Coat as attacking moves of their types (Gen5+)") { - u32 move, species, typeAtk, typeDef; + u32 move, species; + enum Type typeAtk, typeDef; PARAMETRIZE { move = MOVE_COUNTER; species = SPECIES_RATICATE; typeAtk = TYPE_FIGHTING; typeDef = TYPE_NORMAL; } PARAMETRIZE { move = MOVE_METAL_BURST; species = SPECIES_ROGGENROLA; typeAtk = TYPE_STEEL; typeDef = TYPE_ROCK; } PARAMETRIZE { move = MOVE_MIRROR_COAT; species = SPECIES_NIDORINO; typeAtk = TYPE_PSYCHIC; typeDef = TYPE_POISON; } diff --git a/test/battle/ability/battle_armor.c b/test/battle/ability/battle_armor.c index b5e28c5a0d..abf7396f60 100644 --- a/test/battle/ability/battle_armor.c +++ b/test/battle/ability/battle_armor.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Battle Armor and Shell Armor block critical hits") { u32 species; - u32 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_KINGLER; ability = ABILITY_SHELL_ARMOR; } PARAMETRIZE { species = SPECIES_ARMALDO; ability = ABILITY_BATTLE_ARMOR; } diff --git a/test/battle/ability/beads_of_ruin.c b/test/battle/ability/beads_of_ruin.c index 37240d2d68..86172459ab 100644 --- a/test/battle/ability/beads_of_ruin.c +++ b/test/battle/ability/beads_of_ruin.c @@ -4,6 +4,7 @@ ASSUMPTIONS { ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); ASSUME(GetMoveEffect(MOVE_ROLE_PLAY) == EFFECT_ROLE_PLAY); } @@ -74,4 +75,117 @@ SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battler } } -TO_DO_BATTLE_TEST("Beads of Ruin reduce Defense if Wonder Room is active"); +DOUBLE_BATTLE_TEST("Beads of Ruin increases damage taken by physical moves in Wonder Room", s16 damage) +{ + bool32 useWonderRoom; + u32 move; + + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_ROUND; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_ROUND; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_WONDER_ROOM) == EFFECT_WONDER_ROOM); + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_ROUND) != EFFECT_PSYSHOCK); + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useWonderRoom) + TURN { MOVE(opponentLeft, MOVE_WONDER_ROOM); MOVE(playerRight, move, target: opponentLeft); } + else + TURN { MOVE(playerRight, move, target: opponentLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, playerRight); + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_GT(results[2].damage, results[0].damage); // In Wonder Room, physical move deals more damage + EXPECT_LT(results[3].damage, results[1].damage); // In Wonder Room, special move deals less damage + } +} + +SINGLE_BATTLE_TEST("Beads of Ruin doesn't activate when dragged out by Mold Breaker attacker") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_DRAGON_TAIL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, opponent); + if (ability == ABILITY_MOLD_BREAKER) + { + NONE_OF { + ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + } + } + else + { + ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + } + } +} + +DOUBLE_BATTLE_TEST("Beads of Ruin's Sp. Def reduction is not ignored by Mold Breaker", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_ROUND, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROUND, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +DOUBLE_BATTLE_TEST("Beads of Ruin's Sp. Def reduction is ignored by Gastro Acid", s16 damage) +{ + u32 move; + + PARAMETRIZE { move = MOVE_GASTRO_ACID; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); + PLAYER(SPECIES_CHI_YU) { Ability(ABILITY_BEADS_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, move, target: playerLeft); MOVE(opponentLeft, MOVE_ROUND, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROUND, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_LT(results[0].damage, results[1].damage); + } +} diff --git a/test/battle/ability/berserk.c b/test/battle/ability/berserk.c index 80e418e3c5..fe356bc671 100644 --- a/test/battle/ability/berserk.c +++ b/test/battle/ability/berserk.c @@ -73,3 +73,64 @@ SINGLE_BATTLE_TEST("Berserk activates after all hits from a multi-hit move") EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); } } + +SINGLE_BATTLE_TEST("Berserk does not activate if move is boosted by Sheer Force") +{ + u16 maxHp = 500; + GIVEN { + PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(maxHp / 2 + 1); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + NOT ABILITY_POPUP(player, ABILITY_BERSERK); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("Berserk will not activate if the last multi hit move activates a restore berry") +{ + u32 j; + GIVEN { + ASSUME(GetMoveEffect(MOVE_DOUBLE_SLAP) == EFFECT_MULTI_HIT); + PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); Item(ITEM_SITRUS_BERRY); MaxHP(100); HP(90); } + OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } // Always hits 5 times. + } WHEN { + TURN { MOVE(opponent, MOVE_DOUBLE_SLAP); } + } SCENE { + for (j = 0; j < 4; j++) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent); + NOT ABILITY_POPUP(player, ABILITY_BERSERK); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + NOT ABILITY_POPUP(player, ABILITY_BERSERK); + + } THEN { + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("Berserk activates before the hp can be restored on non multi hit moves") +{ + u16 maxHp = 500; + GIVEN { + ASSUME(!IsBattleMoveStatus(MOVE_SCRATCH)); + PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); Item(ITEM_SITRUS_BERRY); MaxHP(maxHp); HP(maxHp / 2 + 1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + ABILITY_POPUP(player, ABILITY_BERSERK); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + } +} diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 46185791a3..f5b9573fe0 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -5,7 +5,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent intimid { s16 turnOneHit; s16 turnTwoHit; - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } @@ -40,7 +41,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent intimid SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent stat stage reduction from moves") { u16 move = MOVE_NONE; - u32 j, species = SPECIES_NONE, ability = ABILITY_NONE; + u32 j, species = SPECIES_NONE; + enum Ability ability = ABILITY_NONE; static const u16 statReductionMoves[] = { MOVE_GROWL, MOVE_LEER, @@ -86,7 +88,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent stat st SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent Sticky Web effect on switchin") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } PARAMETRIZE{ species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } @@ -114,7 +117,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent Sticky SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent stat stage reduction from moves used by the user") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } PARAMETRIZE{ species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } @@ -137,8 +141,9 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent s SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body and White Smoke, but not Full Metal Body") { - u32 j, k, species = SPECIES_NONE, ability = ABILITY_NONE; - u16 breakerAbility = ABILITY_NONE; + u32 j, k, species = SPECIES_NONE; + enum Ability ability = ABILITY_NONE; + enum Ability breakerAbility = ABILITY_NONE; u16 move = ABILITY_NONE; static const u16 breakerAbilities[] = { ABILITY_MOLD_BREAKER, @@ -197,7 +202,8 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body and SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent Speed reduction from Iron Ball") { - u32 j, species = SPECIES_NONE, ability = ABILITY_NONE; + u32 j, species = SPECIES_NONE; + enum Ability ability = ABILITY_NONE; u16 heldItem = ITEM_NONE; static const u16 heldItems[] = { ITEM_NONE, @@ -239,7 +245,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent S SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent Speed reduction from paralysis") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } @@ -276,7 +283,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent S SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent Attack reduction from burn", s16 damage) { bool32 burned = FALSE; - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; burned = FALSE; } PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; burned = TRUE; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; burned = FALSE; } @@ -299,7 +307,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent A SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent receiving negative stat changes from Baton Pass") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } @@ -329,7 +338,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent r SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent Topsy-Turvy") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } @@ -370,7 +380,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent T SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent Spectral Thief from resetting positive stat changes") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE{ species = SPECIES_METANG; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } @@ -417,7 +428,7 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke protect from Pr { u32 move = MOVE_NONE; u32 species = SPECIES_NONE; - u32 ability = ABILITY_NONE; + enum Ability ability = ABILITY_NONE; static const u32 moves[] = { MOVE_SPIKY_SHIELD, diff --git a/test/battle/ability/cloud_nine.c b/test/battle/ability/cloud_nine.c index 613ea86e0a..a4eddd1e1c 100644 --- a/test/battle/ability/cloud_nine.c +++ b/test/battle/ability/cloud_nine.c @@ -3,7 +3,8 @@ SINGLE_BATTLE_TEST("Cloud Nine/Air Lock prevent basic weather effects, but without them disappearing - Sandstorm") { - u32 species = 0, ability = 0; + u32 species = 0; + enum Ability ability = 0; PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_CLOUD_NINE; } PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } GIVEN { diff --git a/test/battle/ability/color_change.c b/test/battle/ability/color_change.c index 6ea5d9537b..49eaa3e916 100644 --- a/test/battle/ability/color_change.c +++ b/test/battle/ability/color_change.c @@ -173,3 +173,16 @@ SINGLE_BATTLE_TEST("Color Change does not change the type to Normal when a Pokem } } } + +SINGLE_BATTLE_TEST("Color Change does not activate if move is boosted by Sheer Force") +{ + GIVEN { + PLAYER(SPECIES_KECLEON) { Ability(ABILITY_COLOR_CHANGE); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + NOT ABILITY_POPUP(player, ABILITY_COLOR_CHANGE); + } +} diff --git a/test/battle/ability/contrary.c b/test/battle/ability/contrary.c index 850ca60734..ef5b4c6c7d 100644 --- a/test/battle/ability/contrary.c +++ b/test/battle/ability/contrary.c @@ -8,7 +8,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Contrary raises Attack when Intimidated in a single battle", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Contrary raises Attack when Intimidated in a single battle", DOUBLE_BATTLE_TEST("Contrary raises Attack when Intimidated in a double battle", s16 damageLeft, s16 damageRight) { - u32 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE { abilityLeft = ABILITY_CONTRARY; abilityRight = ABILITY_CONTRARY; } PARAMETRIZE { abilityLeft = ABILITY_TANGLED_FEET; abilityRight = ABILITY_TANGLED_FEET; } @@ -78,7 +78,7 @@ DOUBLE_BATTLE_TEST("Contrary raises Attack when Intimidated in a double battle", SINGLE_BATTLE_TEST("Contrary raises stats after using a move which would normally lower them: Overheat", s16 damageBefore, s16 damageAfter) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { @@ -122,7 +122,7 @@ SINGLE_BATTLE_TEST("Contrary raises stats after using a move which would normall SINGLE_BATTLE_TEST("Contrary lowers a stat after using a move which would normally raise it: Swords Dance", s16 damageBefore, s16 damageAfter) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { @@ -159,7 +159,7 @@ SINGLE_BATTLE_TEST("Contrary lowers a stat after using a move which would normal SINGLE_BATTLE_TEST("Contrary raises a stat after using a move which would normally lower it: Growl", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { @@ -190,7 +190,7 @@ SINGLE_BATTLE_TEST("Contrary raises a stat after using a move which would normal SINGLE_BATTLE_TEST("Contrary lowers a stat after using a move which would normally raise it: Belly Drum", s16 damageBefore, s16 damageAfter) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { diff --git a/test/battle/ability/curious_medicine.c b/test/battle/ability/curious_medicine.c index 3844170eb0..7c3e200c7a 100644 --- a/test/battle/ability/curious_medicine.c +++ b/test/battle/ability/curious_medicine.c @@ -3,7 +3,7 @@ DOUBLE_BATTLE_TEST("Curious Medicine resets ally's stat stages upon entering battle") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CURIOUS_MEDICINE; } PARAMETRIZE { ability = ABILITY_OWN_TEMPO; } diff --git a/test/battle/ability/dazzling.c b/test/battle/ability/dazzling.c index 7541b8a566..ea7b2ba1b8 100644 --- a/test/battle/ability/dazzling.c +++ b/test/battle/ability/dazzling.c @@ -9,7 +9,8 @@ ASSUMPTIONS DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect the user from priority moves") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } @@ -31,7 +32,8 @@ DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect the user fr DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect users partner from priority moves") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } @@ -53,7 +55,8 @@ DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect users partn DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail don't protect the user from negative priority") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } @@ -74,7 +77,8 @@ DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail don't protect the u SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect from all multi hit hits with one activation") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } @@ -96,3 +100,25 @@ SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect from all mu } } } + +SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail prevent Protean activation") +{ + u32 species, ability; + + PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } + PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } + PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } + + GIVEN { + PLAYER(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_WATER_SHURIKEN); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_SHURIKEN, player); + ABILITY_POPUP(player, ABILITY_PROTEAN); + } + ABILITY_POPUP(opponent, ability); + } +} diff --git a/test/battle/ability/defiant.c b/test/battle/ability/defiant.c index 3102980378..517077dc68 100644 --- a/test/battle/ability/defiant.c +++ b/test/battle/ability/defiant.c @@ -3,7 +3,7 @@ DOUBLE_BATTLE_TEST("Defiant sharply raises player's Attack after Intimidate") { - u32 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE { abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_DEFIANT; } @@ -61,7 +61,7 @@ DOUBLE_BATTLE_TEST("Defiant sharply raises player's Attack after Intimidate") // Same as above, but for opponent. DOUBLE_BATTLE_TEST("Defiant sharply raises opponent's Attack after Intimidate") { - u32 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE { abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_DEFIANT; } diff --git a/test/battle/ability/download.c b/test/battle/ability/download.c index 7219e32329..f275b7c262 100644 --- a/test/battle/ability/download.c +++ b/test/battle/ability/download.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Download raises Attack if player has lower Def than Sp. Def", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_TRACE; } PARAMETRIZE { ability = ABILITY_DOWNLOAD; } GIVEN { @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Download raises Attack if player has lower Def than Sp. Def" SINGLE_BATTLE_TEST("Download raises Sp.Attack if enemy has lower Sp. Def than Def", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_TRACE; } PARAMETRIZE { ability = ABILITY_DOWNLOAD; } GIVEN { @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Download raises Sp.Attack if enemy has lower Sp. Def than De SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet", s16 damagePhysical, s16 damageSpecial) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_TRACE; } PARAMETRIZE { ability = ABILITY_DOWNLOAD; } @@ -97,7 +97,7 @@ SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet DOUBLE_BATTLE_TEST("Download raises Sp.Attack if enemies have lower total Sp. Def than Def", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_TRACE; } PARAMETRIZE { ability = ABILITY_DOWNLOAD; } GIVEN { diff --git a/test/battle/ability/dragons_maw.c b/test/battle/ability/dragons_maw.c index 64280cfb5a..950cb1db0f 100644 --- a/test/battle/ability/dragons_maw.c +++ b/test/battle/ability/dragons_maw.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Dragon's Maw increases Dragon-type move damage", s16 damage) { u32 move; - u16 ability; + enum Ability ability; PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_KLUTZ; } PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_DRAGONS_MAW; } diff --git a/test/battle/ability/drizzle.c b/test/battle/ability/drizzle.c index ce0fc9514b..fd56704830 100644 --- a/test/battle/ability/drizzle.c +++ b/test/battle/ability/drizzle.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Drizzle summons rain", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_DRIZZLE; } PARAMETRIZE { ability = ABILITY_DAMP; } diff --git a/test/battle/ability/dry_skin.c b/test/battle/ability/dry_skin.c index 097251565f..aab5658618 100644 --- a/test/battle/ability/dry_skin.c +++ b/test/battle/ability/dry_skin.c @@ -35,7 +35,7 @@ TO_DO_BATTLE_TEST("Dry Skin doesn't heal in Rain if Cloud Nine/Air Lock is on th SINGLE_BATTLE_TEST("Dry Skin increases damage taken from Fire-type moves by 25%", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_EFFECT_SPORE; } PARAMETRIZE { ability = ABILITY_DRY_SKIN; } GIVEN { diff --git a/test/battle/ability/embody_aspect.c b/test/battle/ability/embody_aspect.c index fffc8cf423..e7ac53a9e8 100644 --- a/test/battle/ability/embody_aspect.c +++ b/test/battle/ability/embody_aspect.c @@ -4,7 +4,8 @@ SINGLE_BATTLE_TEST("Embody Aspect raises a stat depending on the users form by one stage") { - u16 species, ability; + u16 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_OGERPON_TEAL_TERA; ability = ABILITY_EMBODY_ASPECT_TEAL_MASK; } PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_TERA; ability = ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK; } diff --git a/test/battle/ability/emergency_exit.c b/test/battle/ability/emergency_exit.c index 1dcd0be21b..3592b91b01 100644 --- a/test/battle/ability/emergency_exit.c +++ b/test/battle/ability/emergency_exit.c @@ -81,6 +81,23 @@ SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and fal } } +SINGLE_BATTLE_TEST("Emergency Exit activates when healing from under 50% max-hp and taking residual damage to under 50% max-hp - Burn") +{ + // Might fail if users set healing higher than burn damage + GIVEN { + ASSUME(GetMoveEffect(MOVE_AQUA_RING) == EFFECT_AQUA_RING); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(130); Status1(STATUS1_BURN); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_AQUA_RING); SEND_OUT(opponent, 1); } + } SCENE { + HP_BAR(opponent); + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); + } +} + SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and falling under 50% max-hp - Weather") { GIVEN { @@ -95,6 +112,24 @@ SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and fal } } +SINGLE_BATTLE_TEST("Emergency Exit activates when healing from under 50% max-hp and taking residual damage to under 50% max-hp - Sticky Barb") +{ + // Might fail if users set healing higher than sticky barb damage + GIVEN { + ASSUME(GetMoveEffect(MOVE_AQUA_RING) == EFFECT_AQUA_RING); + ASSUME(GetItemHoldEffect(ITEM_STICKY_BARB) == HOLD_EFFECT_STICKY_BARB); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GOLISOPOD) { Ability(ABILITY_EMERGENCY_EXIT); MaxHP(263); HP(130); Item(ITEM_STICKY_BARB); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_AQUA_RING); SEND_OUT(opponent, 1); } + } SCENE { + HP_BAR(opponent); + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); + } +} + SINGLE_BATTLE_TEST("Emergency Exit activates when taking residual damage and falling under 50% max-hp - Salt Cure") { GIVEN { diff --git a/test/battle/ability/filter.c b/test/battle/ability/filter.c index 69c0e96278..db3d353b79 100644 --- a/test/battle/ability/filter.c +++ b/test/battle/ability/filter.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Filter reduces damage to Super Effective moves by 0.75", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_SOUNDPROOF; } PARAMETRIZE { ability = ABILITY_FILTER; } GIVEN { diff --git a/test/battle/ability/flower_gift.c b/test/battle/ability/flower_gift.c index 29f5820191..30cc7926e5 100644 --- a/test/battle/ability/flower_gift.c +++ b/test/battle/ability/flower_gift.c @@ -65,7 +65,8 @@ SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal when its abili SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal under Cloud Nine/Air Lock") { - u32 species = 0, ability = 0; + u32 species = 0; + enum Ability ability = 0; PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_CLOUD_NINE; } PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } GIVEN { diff --git a/test/battle/ability/fluffy.c b/test/battle/ability/fluffy.c index 6525c73212..68afbd8993 100644 --- a/test/battle/ability/fluffy.c +++ b/test/battle/ability/fluffy.c @@ -12,7 +12,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct contact", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_KLUTZ; } PARAMETRIZE { ability = ABILITY_FLUFFY; } GIVEN { @@ -30,7 +30,7 @@ SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct conta SINGLE_BATTLE_TEST("Fluffy doubles damage taken from fire type moves", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_KLUTZ; } PARAMETRIZE { ability = ABILITY_FLUFFY; } GIVEN { @@ -48,7 +48,7 @@ SINGLE_BATTLE_TEST("Fluffy doubles damage taken from fire type moves", s16 damag SINGLE_BATTLE_TEST("Fluffy does not alter damage of fire-type moves that make direct contact", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_KLUTZ; } PARAMETRIZE { ability = ABILITY_FLUFFY; } GIVEN { @@ -66,7 +66,7 @@ SINGLE_BATTLE_TEST("Fluffy does not alter damage of fire-type moves that make di SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct contact even if protected by Protective Pads", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_KLUTZ; } PARAMETRIZE { ability = ABILITY_FLUFFY; } GIVEN { @@ -84,7 +84,7 @@ SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct conta SINGLE_BATTLE_TEST("Fluffy does not halve damage taken from moves that make direct contact but are ignored by Punching Glove", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_KLUTZ; } PARAMETRIZE { ability = ABILITY_FLUFFY; } GIVEN { diff --git a/test/battle/ability/forecast.c b/test/battle/ability/forecast.c index 418c8058d2..b6889620ab 100644 --- a/test/battle/ability/forecast.c +++ b/test/battle/ability/forecast.c @@ -157,7 +157,8 @@ DOUBLE_BATTLE_TEST("Forecast transforms all Castforms present in weather") SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from an ability") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_KYOGRE; ability = ABILITY_DRIZZLE; } PARAMETRIZE { species = SPECIES_GROUDON; ability = ABILITY_DROUGHT; } PARAMETRIZE { species = SPECIES_ABOMASNOW; ability = ABILITY_SNOW_WARNING; } @@ -183,13 +184,16 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform in weather from an ability") case ABILITY_SNOW_WARNING: EXPECT_EQ(player->species, SPECIES_CASTFORM_SNOWY); break; + default: + break; } } } SINGLE_BATTLE_TEST("Forecast transforms Castform in primal weather") { - u32 species, item, ability; + u32 species, item; + enum Ability ability; PARAMETRIZE { species = SPECIES_KYOGRE; ability = ABILITY_PRIMORDIAL_SEA; item = ITEM_BLUE_ORB; } PARAMETRIZE { species = SPECIES_GROUDON; ability = ABILITY_DESOLATE_LAND; item = ITEM_RED_ORB; } GIVEN { @@ -212,6 +216,8 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform in primal weather") case ABILITY_PRIMORDIAL_SEA: EXPECT_EQ(player->species, SPECIES_CASTFORM_RAINY); break; + default: + break; } } } @@ -266,7 +272,8 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal when Sandstorm i SINGLE_BATTLE_TEST("Forecast transforms Castform back to normal under Cloud Nine/Air Lock") { - u32 species = 0, ability = 0; + u32 species = 0; + enum Ability ability = 0; PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_CLOUD_NINE; } PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } GIVEN { @@ -400,7 +407,8 @@ SINGLE_BATTLE_TEST("Forecast transforms Castform back when it uses a move that f SINGLE_BATTLE_TEST("Forecast transforms Castform when Cloud Nine ability user leaves the field") { - u32 species = 0, ability = 0; + u32 species = 0; + enum Ability ability = 0; PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_CLOUD_NINE; } PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } diff --git a/test/battle/ability/galvanize.c b/test/battle/ability/galvanize.c index e6569aedaf..01add35fd3 100644 --- a/test/battle/ability/galvanize.c +++ b/test/battle/ability/galvanize.c @@ -44,7 +44,8 @@ SINGLE_BATTLE_TEST("Galvanize can not turn certain moves into Electric type move SINGLE_BATTLE_TEST("Galvanize boosts power of affected moves by 20% (Gen7+) or 30% (Gen1-6)", s16 damage) { - u32 ability, genConfig; + enum Ability ability; + u32 genConfig; PARAMETRIZE { ability = ABILITY_STURDY; genConfig = GEN_7; } PARAMETRIZE { ability = ABILITY_STURDY; genConfig = GEN_6; } PARAMETRIZE { ability = ABILITY_GALVANIZE; genConfig = GEN_7; } @@ -68,7 +69,8 @@ SINGLE_BATTLE_TEST("Galvanize boosts power of affected moves by 20% (Gen7+) or 3 SINGLE_BATTLE_TEST("Galvanize doesn't affect Weather Ball's type", s16 damage) { - u16 move, ability; + u16 move; + enum Ability ability; PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_STURDY; } PARAMETRIZE { move = MOVE_SUNNY_DAY; ability = ABILITY_STURDY; } PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_GALVANIZE; } @@ -96,7 +98,7 @@ SINGLE_BATTLE_TEST("Galvanize doesn't affect Weather Ball's type", s16 damage) SINGLE_BATTLE_TEST("Galvanize doesn't affect Natural Gift's type") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_STURDY; } PARAMETRIZE { ability = ABILITY_GALVANIZE; } GIVEN { diff --git a/test/battle/ability/grim_neigh.c b/test/battle/ability/grim_neigh.c index 69d60db93e..bb212e589b 100644 --- a/test/battle/ability/grim_neigh.c +++ b/test/battle/ability/grim_neigh.c @@ -3,7 +3,8 @@ DOUBLE_BATTLE_TEST("Grim Neigh raises Sp. Attack by one stage after directly causing a Pokemon to faint") { - u32 species = 0, ability = 0, abilityPopUp = 0; + u32 species = 0, abilityPopUp = 0; + enum Ability ability = 0; PARAMETRIZE { species = SPECIES_SPECTRIER; ability = ABILITY_GRIM_NEIGH; abilityPopUp = ABILITY_GRIM_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; abilityPopUp = ABILITY_GRIM_NEIGH; } GIVEN { @@ -33,7 +34,8 @@ DOUBLE_BATTLE_TEST("Grim Neigh raises Sp. Attack by one stage after directly cau DOUBLE_BATTLE_TEST("Grim Neigh does not trigger if Pokemon faint to indirect damage or damage from other Pokemon") { - u32 species = 0, ability = 0, abilityPopUp = 0; + u32 species = 0, abilityPopUp = 0; + enum Ability ability = 0; PARAMETRIZE { species = SPECIES_SPECTRIER; ability = ABILITY_GRIM_NEIGH; abilityPopUp = ABILITY_GRIM_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; abilityPopUp = ABILITY_GRIM_NEIGH; } GIVEN { @@ -70,7 +72,8 @@ DOUBLE_BATTLE_TEST("Grim Neigh does not trigger if Pokemon faint to indirect dam DOUBLE_BATTLE_TEST("Grim Neigh does not increase damage done by the same move that causes another Pokemon to faint") { s16 damage[2]; - u32 species = 0, ability = 0, abilityPopUp = 0; + u32 species = 0, abilityPopUp = 0; + enum Ability ability = 0; PARAMETRIZE { species = SPECIES_SPECTRIER; ability = ABILITY_GRIM_NEIGH; abilityPopUp = ABILITY_GRIM_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; abilityPopUp = ABILITY_GRIM_NEIGH; } diff --git a/test/battle/ability/guard_dog.c b/test/battle/ability/guard_dog.c index 4327140d68..b8ebbafbad 100644 --- a/test/battle/ability/guard_dog.c +++ b/test/battle/ability/guard_dog.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Guard Dog raises Attack when intimidated", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_INTIMIDATE; } PARAMETRIZE { ability = ABILITY_SHED_SKIN; } GIVEN { diff --git a/test/battle/ability/gulp_missile.c b/test/battle/ability/gulp_missile.c index 13a684dc8c..5a3266ff17 100644 --- a/test/battle/ability/gulp_missile.c +++ b/test/battle/ability/gulp_missile.c @@ -137,7 +137,8 @@ SINGLE_BATTLE_TEST("(Gulp Missile) triggers even if the user is fainted by oppos SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant Gulping lowers defense but is prevented by stat reduction preventing abilities") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_METAGROSS; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE { species = SPECIES_CORVIKNIGHT; ability = ABILITY_MIRROR_ARMOR; } PARAMETRIZE { species = SPECIES_CHATOT; ability = ABILITY_BIG_PECKS; } @@ -163,7 +164,7 @@ SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant Gulping lowers defense SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant Gulping lowers defense and still triggers other effects after") { // Make sure attacker and target are correct after triggering the ability - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_INFILTRATOR; } PARAMETRIZE { ability = ABILITY_CLEAR_BODY; } GIVEN { diff --git a/test/battle/ability/ice_scales.c b/test/battle/ability/ice_scales.c index 0d49bb4996..ea96f64961 100644 --- a/test/battle/ability/ice_scales.c +++ b/test/battle/ability/ice_scales.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Ice Scales halves the damage from special moves", s16 damage) { u32 move; - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_SHIELD_DUST; move = MOVE_PSYCHIC; } PARAMETRIZE { ability = ABILITY_ICE_SCALES; move = MOVE_PSYCHIC; } PARAMETRIZE { ability = ABILITY_SHIELD_DUST; move = MOVE_PSYSHOCK; } diff --git a/test/battle/ability/illusion.c b/test/battle/ability/illusion.c index 56fad1b62e..26c8daabc7 100644 --- a/test/battle/ability/illusion.c +++ b/test/battle/ability/illusion.c @@ -102,7 +102,7 @@ SINGLE_BATTLE_TEST("Illusion breaks if affected by Gastro Acid") SINGLE_BATTLE_TEST("Illusion breaks if user loses Illusion due to Worry Seed") { GIVEN { - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); PLAYER(SPECIES_ZOROARK); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/immunity.c b/test/battle/ability/immunity.c index e18aef667c..9199638ad5 100644 --- a/test/battle/ability/immunity.c +++ b/test/battle/ability/immunity.c @@ -27,7 +27,7 @@ SINGLE_BATTLE_TEST("Immunity prevents Toxic bad poison") } SCENE { MESSAGE("Wobbuffet used Toxic!"); ABILITY_POPUP(opponent, ABILITY_IMMUNITY); - MESSAGE("The opposing Snorlax's Immunity prevents poisoning!"); + MESSAGE("It doesn't affect the opposing Snorlax…"); NOT STATUS_ICON(opponent, poison: TRUE); } } diff --git a/test/battle/ability/intimidate.c b/test/battle/ability/intimidate.c index b0e4b19a19..0606938d45 100644 --- a/test/battle/ability/intimidate.c +++ b/test/battle/ability/intimidate.c @@ -8,7 +8,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after switch out", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_INTIMIDATE; } PARAMETRIZE { ability = ABILITY_SHED_SKIN; } GIVEN { @@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after switch ou SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after KO", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_INTIMIDATE; } PARAMETRIZE { ability = ABILITY_SHED_SKIN; } GIVEN { diff --git a/test/battle/ability/keen_eye.c b/test/battle/ability/keen_eye.c index ee10c446fb..4e645a2183 100644 --- a/test/battle/ability/keen_eye.c +++ b/test/battle/ability/keen_eye.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye prevent accuracy stage reduction from moves") { - u16 ability; + enum Ability ability; u32 species; PARAMETRIZE { species = SPECIES_HITMONCHAN; ability = ABILITY_KEEN_EYE; } @@ -38,7 +38,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye prevent accuracy stag SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye ignore target's evasion stat") { - u16 ability; + enum Ability ability; u32 species; PARAMETRIZE { species = SPECIES_HITMONCHAN; ability = ABILITY_KEEN_EYE; } @@ -62,7 +62,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye ignore target's evasi SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye are ignored by Mold Breaker abilities") { - u16 abilityPlayer = ABILITY_NONE, abilityOpponent = ABILITY_NONE; + enum Ability abilityPlayer = ABILITY_NONE, abilityOpponent = ABILITY_NONE; u16 speciesPlayer = SPECIES_NONE, speciesOpponent = SPECIES_NONE; u32 j; @@ -96,7 +96,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye are ignored by Mold B SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent Topsy-Turvy") { - u16 ability; + enum Ability ability; u32 species; PARAMETRIZE { species = SPECIES_HITMONCHAN; ability = ABILITY_KEEN_EYE; } @@ -137,7 +137,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent Topsy-T SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent receiving negative Attack stage changes from Baton Pass") { - u16 ability; + enum Ability ability; u32 species; PARAMETRIZE { species = SPECIES_HITMONCHAN; ability = ABILITY_KEEN_EYE; } PARAMETRIZE { species = SPECIES_STARYU; ability = ABILITY_ILLUMINATE; } @@ -170,7 +170,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent receivi SINGLE_BATTLE_TEST("Keen Eye & Gen9+ Illuminate don't prevent Spectral Thief from resetting positive accuracy stage changes") { - u16 ability; + enum Ability ability; u32 species; PARAMETRIZE { species = SPECIES_HITMONCHAN; ability = ABILITY_KEEN_EYE; } diff --git a/test/battle/ability/levitate.c b/test/battle/ability/levitate.c index 348d347f3b..51ac0dca2c 100644 --- a/test/battle/ability/levitate.c +++ b/test/battle/ability/levitate.c @@ -92,7 +92,7 @@ DOUBLE_BATTLE_TEST("Levitate does not cause single remaining target to take high AI_SINGLE_BATTLE_TEST("Levitate is seen correctly by switch AI") { - u32 ability = ABILITY_NONE, item = ITEM_NONE; + enum Ability ability = ABILITY_NONE, item = ITEM_NONE; PARAMETRIZE { ability = ABILITY_OWN_TEMPO, item = ITEM_NONE ; } PARAMETRIZE { ability = ABILITY_MOLD_BREAKER, item = ITEM_NONE ; } diff --git a/test/battle/ability/lightning_rod.c b/test/battle/ability/lightning_rod.c index ab2f0d89a0..aec2e7fea4 100644 --- a/test/battle/ability/lightning_rod.c +++ b/test/battle/ability/lightning_rod.c @@ -28,6 +28,8 @@ SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the HP_BAR(opponent); } ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } THEN { + EXPECT_EQ(gBattleHistory->abilities[1], ABILITY_LIGHTNING_ROD); // Check if the correct ability has been recorded } } diff --git a/test/battle/ability/limber.c b/test/battle/ability/limber.c index f89f9a1e74..fc4e398c1f 100644 --- a/test/battle/ability/limber.c +++ b/test/battle/ability/limber.c @@ -29,7 +29,7 @@ SINGLE_BATTLE_TEST("Limber prevents paralysis from Thunder Wave") } WHEN { TURN { MOVE(opponent, MOVE_THUNDER_WAVE); } } SCENE { - MESSAGE("Persian's Limber prevents paralysis!"); + MESSAGE("It doesn't affect Persian…"); NONE_OF { ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, player); STATUS_ICON(player, paralysis: TRUE); diff --git a/test/battle/ability/liquid_ooze.c b/test/battle/ability/liquid_ooze.c index ca7c88ebdd..a9e5fb4b90 100644 --- a/test/battle/ability/liquid_ooze.c +++ b/test/battle/ability/liquid_ooze.c @@ -113,7 +113,7 @@ SINGLE_BATTLE_TEST("Liquid Ooze causes Strength Sap users to lose HP instead of */ SINGLE_BATTLE_TEST("Liquid Ooze causes leech seed victim to faint before seeder") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CLEAR_BODY; } PARAMETRIZE { ability = ABILITY_LIQUID_OOZE; } GIVEN { diff --git a/test/battle/ability/mimicry.c b/test/battle/ability/mimicry.c index 67eab20575..5cdea7276f 100644 --- a/test/battle/ability/mimicry.c +++ b/test/battle/ability/mimicry.c @@ -13,7 +13,7 @@ SINGLE_BATTLE_TEST("Mimicry changes the battler's type based on Terrain") { u32 j; u32 terrainMove = MOVE_NONE; - u32 terrainType = TYPE_NONE; + enum Type terrainType = TYPE_NONE; for (j = 0; j < ARRAY_COUNT(terrainData); j++) PARAMETRIZE { terrainMove = terrainData[j][0]; terrainType = terrainData[j][1]; } diff --git a/test/battle/ability/minds_eye.c b/test/battle/ability/minds_eye.c index 0300c2e4d5..4ac339d899 100644 --- a/test/battle/ability/minds_eye.c +++ b/test/battle/ability/minds_eye.c @@ -44,7 +44,7 @@ SINGLE_BATTLE_TEST("Mind's Eye doesn't bypass a Ghost-type's Wonder Guard") AI_SINGLE_BATTLE_TEST("AI doesn't use accuracy-lowering moves if it knows that the foe has Mind's Eye") { - u32 abilityAI = ABILITY_NONE; + enum Ability abilityAI = ABILITY_NONE; PARAMETRIZE { abilityAI = ABILITY_SWIFT_SWIM; } PARAMETRIZE { abilityAI = ABILITY_MOLD_BREAKER; } @@ -60,7 +60,7 @@ AI_SINGLE_BATTLE_TEST("AI doesn't use accuracy-lowering moves if it knows that t if (abilityAI == ABILITY_MOLD_BREAKER) { SCORE_GT(opponent, MOVE_SAND_ATTACK, MOVE_CELEBRATE); } else { - SCORE_EQ(opponent, MOVE_SAND_ATTACK, MOVE_CELEBRATE); + SCORE_LT_VAL(opponent, MOVE_SAND_ATTACK, AI_SCORE_DEFAULT); } } } SCENE { diff --git a/test/battle/ability/moxie.c b/test/battle/ability/moxie.c index 1dda9f7926..01eb51b9e7 100644 --- a/test/battle/ability/moxie.c +++ b/test/battle/ability/moxie.c @@ -3,7 +3,8 @@ DOUBLE_BATTLE_TEST("Moxie/Chilling Neigh raises Attack by one stage after directly causing a Pokemon to faint") { - u32 species = 0, ability = 0, abilityPopUp = 0; + u32 species = 0, abilityPopUp = 0; + enum Ability ability = ABILITY_NONE; PARAMETRIZE { species = SPECIES_SALAMENCE; ability = ABILITY_MOXIE; abilityPopUp = ABILITY_MOXIE; } PARAMETRIZE { species = SPECIES_GLASTRIER; ability = ABILITY_CHILLING_NEIGH; abilityPopUp = ABILITY_CHILLING_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; abilityPopUp = ABILITY_CHILLING_NEIGH; } @@ -36,7 +37,8 @@ DOUBLE_BATTLE_TEST("Moxie/Chilling Neigh raises Attack by one stage after direct DOUBLE_BATTLE_TEST("Moxie/Chilling Neigh does not trigger if Pokemon faint to indirect damage or damage from other Pokemon") { - u32 species = 0, ability = 0, abilityPopUp = 0; + u32 species = 0, abilityPopUp = 0; + enum Ability ability = ABILITY_NONE; PARAMETRIZE { species = SPECIES_SALAMENCE; ability = ABILITY_MOXIE; abilityPopUp = ABILITY_MOXIE; } PARAMETRIZE { species = SPECIES_GLASTRIER; ability = ABILITY_CHILLING_NEIGH; abilityPopUp = ABILITY_CHILLING_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; abilityPopUp = ABILITY_CHILLING_NEIGH; } @@ -73,7 +75,8 @@ DOUBLE_BATTLE_TEST("Moxie/Chilling Neigh does not trigger if Pokemon faint to in SINGLE_BATTLE_TEST("Moxie/Chilling Neigh does not trigger when already at maximum Attack stage") { - u32 species = 0, ability = 0, abilityPopUp = 0; + u32 species = 0, abilityPopUp = 0; + enum Ability ability = ABILITY_NONE; PARAMETRIZE { species = SPECIES_SALAMENCE; ability = ABILITY_MOXIE; abilityPopUp = ABILITY_MOXIE; } PARAMETRIZE { species = SPECIES_GLASTRIER; ability = ABILITY_CHILLING_NEIGH; abilityPopUp = ABILITY_CHILLING_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; abilityPopUp = ABILITY_CHILLING_NEIGH; } @@ -111,7 +114,8 @@ SINGLE_BATTLE_TEST("Moxie/Chilling Neigh does not trigger when already at maximu DOUBLE_BATTLE_TEST("Moxie/Chilling Neigh does not increase damage done by the same move that causes another Pokemon to faint") { s16 damage[2]; - u32 species = 0, ability = 0, abilityPopUp = 0; + u32 species = 0, abilityPopUp = 0; + enum Ability ability = ABILITY_NONE; PARAMETRIZE { species = SPECIES_SALAMENCE; ability = ABILITY_MOXIE; abilityPopUp = ABILITY_MOXIE; } PARAMETRIZE { species = SPECIES_GLASTRIER; ability = ABILITY_CHILLING_NEIGH; abilityPopUp = ABILITY_CHILLING_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; abilityPopUp = ABILITY_CHILLING_NEIGH; } diff --git a/test/battle/ability/mummy.c b/test/battle/ability/mummy.c index f03e453e5c..990fba7a0d 100644 --- a/test/battle/ability/mummy.c +++ b/test/battle/ability/mummy.c @@ -3,7 +3,8 @@ SINGLE_BATTLE_TEST("Mummy/Lingering Aroma replace the attacker's ability on contact") { - u32 move, ability, species; + u32 move, species; + enum Ability ability; PARAMETRIZE { move = MOVE_AQUA_JET; ability = ABILITY_MUMMY; species = SPECIES_YAMASK; } PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_MUMMY; species = SPECIES_YAMASK;} @@ -37,7 +38,7 @@ SINGLE_BATTLE_TEST("Mummy/Lingering Aroma replace the attacker's ability on cont SINGLE_BATTLE_TEST("Mummy and Lingering Aroma don't replace each other") { - u32 ability1, species1, ability2, species2; + enum Ability ability1, species1, ability2, species2; PARAMETRIZE { ability1 = ability2 = ABILITY_MUMMY; species1 = species2 = SPECIES_YAMASK; } PARAMETRIZE { ability1 = ABILITY_MUMMY; species1 = SPECIES_YAMASK; ability2 = ABILITY_LINGERING_AROMA; species2 = SPECIES_OINKOLOGNE; } @@ -66,7 +67,8 @@ SINGLE_BATTLE_TEST("Mummy and Lingering Aroma don't replace each other") SINGLE_BATTLE_TEST("Mummy doesn't replace abilities that can't be suppressed") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; } diff --git a/test/battle/ability/neuroforce.c b/test/battle/ability/neuroforce.c index bd581b9b7d..32f3e91e56 100644 --- a/test/battle/ability/neuroforce.c +++ b/test/battle/ability/neuroforce.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Neuroforce increases the strength of super-effective moves by 25%", s16 damage) { u32 move; - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NEUROFORCE; move = MOVE_SHADOW_BALL; } PARAMETRIZE { ability = ABILITY_KLUTZ; move = MOVE_SHADOW_BALL; } PARAMETRIZE { ability = ABILITY_NEUROFORCE; move = MOVE_SCRATCH; } diff --git a/test/battle/ability/neutralizing_gas.c b/test/battle/ability/neutralizing_gas.c index 9971d53c44..02f7323af2 100644 --- a/test/battle/ability/neutralizing_gas.c +++ b/test/battle/ability/neutralizing_gas.c @@ -83,7 +83,7 @@ DOUBLE_BATTLE_TEST("Neutralizing Gas ignores all battlers' ability effects") SINGLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from attacker's ability", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { @@ -102,7 +102,7 @@ SINGLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from attacker's ability SINGLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from target's ability", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { @@ -122,7 +122,7 @@ SINGLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from target's ability", DOUBLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from target's ally's ability", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { @@ -142,7 +142,7 @@ DOUBLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from target's ally's ab DOUBLE_BATTLE_TEST("Neutralizing Gas ignores multipliers from ally's ability", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { diff --git a/test/battle/ability/normalize.c b/test/battle/ability/normalize.c index 23ecbee592..79f41d2040 100644 --- a/test/battle/ability/normalize.c +++ b/test/battle/ability/normalize.c @@ -11,7 +11,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Normalize turns a move into a Normal-type move") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } GIVEN { @@ -36,7 +36,7 @@ SINGLE_BATTLE_TEST("Normalize turns a move into a Normal-type move") SINGLE_BATTLE_TEST("Normalize affects status moves") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } GIVEN { @@ -62,7 +62,7 @@ SINGLE_BATTLE_TEST("Normalize affects status moves") SINGLE_BATTLE_TEST("Normalize still makes Freeze-Dry do super effective damage to Water-type Pokémon", s16 damage) { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } GIVEN { @@ -82,7 +82,7 @@ SINGLE_BATTLE_TEST("Normalize still makes Freeze-Dry do super effective damage t SINGLE_BATTLE_TEST("Normalize doesn't boost power of unaffected moves by 20% (< Gen7)", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } @@ -101,7 +101,7 @@ SINGLE_BATTLE_TEST("Normalize doesn't boost power of unaffected moves by 20% (< SINGLE_BATTLE_TEST("Normalize boosts power of unaffected moves by 20% (Gen7+)", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } @@ -120,7 +120,7 @@ SINGLE_BATTLE_TEST("Normalize boosts power of unaffected moves by 20% (Gen7+)", SINGLE_BATTLE_TEST("Normalize doesn't boost power of affected moves by 20% (< Gen7)", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } @@ -139,7 +139,7 @@ SINGLE_BATTLE_TEST("Normalize doesn't boost power of affected moves by 20% (< Ge SINGLE_BATTLE_TEST("Normalize boosts power of affected moves by 20% (Gen7+)", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } @@ -184,7 +184,8 @@ SINGLE_BATTLE_TEST("Normalize-affected moves become Electric-type under Ion Delu SINGLE_BATTLE_TEST("Normalize doesn't affect Weather Ball's type", s16 damage) { - u16 move, ability; + u16 move; + enum Ability ability; PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { move = MOVE_SUNNY_DAY; ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_NORMALIZE; } @@ -212,7 +213,7 @@ SINGLE_BATTLE_TEST("Normalize doesn't affect Weather Ball's type", s16 damage) SINGLE_BATTLE_TEST("Normalize doesn't affect Natural Gift's type") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_NORMALIZE; } GIVEN { diff --git a/test/battle/ability/opportunist.c b/test/battle/ability/opportunist.c index 3fac02b5b7..6e5b13dd31 100644 --- a/test/battle/ability/opportunist.c +++ b/test/battle/ability/opportunist.c @@ -8,7 +8,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Opportunist only copies foe's positive stat changes in a turn", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_FRISK; } PARAMETRIZE { ability = ABILITY_OPPORTUNIST; } GIVEN { @@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Opportunist only copies foe's positive stat changes in a tur DOUBLE_BATTLE_TEST("Opportunist raises Attack only once when partner has Intimidate against Contrary foe in a double battle", s16 damageLeft, s16 damageRight) { - u32 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE { abilityLeft = ABILITY_CONTRARY; abilityRight = ABILITY_CONTRARY; } PARAMETRIZE { abilityLeft = ABILITY_TANGLED_FEET; abilityRight = ABILITY_TANGLED_FEET; } @@ -294,3 +294,24 @@ SINGLE_BATTLE_TEST("Opportunist and Mirror Herb stack stat increases") EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); } } + +DOUBLE_BATTLE_TEST("Opportunist and Mirror Herb resolve correctly") +{ + GIVEN { + PLAYER(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); } + PLAYER(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); } + OPPONENT(SPECIES_MEOWSCARADA) { Item(ITEM_MIRROR_HERB); } + OPPONENT(SPECIES_ESPATHRA) { Ability(ABILITY_OPPORTUNIST); Item(ITEM_MIRROR_HERB); } + } WHEN { + TURN { } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_INTREPID_SWORD); + ABILITY_POPUP(opponentRight, ABILITY_OPPORTUNIST); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(opponentLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} diff --git a/test/battle/ability/parental_bond.c b/test/battle/ability/parental_bond.c index fc128dba64..c4b83d2e3b 100644 --- a/test/battle/ability/parental_bond.c +++ b/test/battle/ability/parental_bond.c @@ -105,7 +105,9 @@ DOUBLE_BATTLE_TEST("Parental Bond does not convert multi-target moves into a two SINGLE_BATTLE_TEST("Parental Bond-converted moves only hit once on Lightning Rod/Storm Drain mons") { - u16 move, species, ability, type; + u16 move, species; + enum Type type; + enum Ability ability; PARAMETRIZE { move = MOVE_THUNDERBOLT; ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; type = TYPE_ELECTRIC; } PARAMETRIZE { move = MOVE_SURF; ability = ABILITY_STORM_DRAIN; species = SPECIES_LILEEP; type = TYPE_WATER; } GIVEN { diff --git a/test/battle/ability/pastel_veil.c b/test/battle/ability/pastel_veil.c index 1c0926ac80..11bf32bb9a 100644 --- a/test/battle/ability/pastel_veil.c +++ b/test/battle/ability/pastel_veil.c @@ -80,7 +80,7 @@ SINGLE_BATTLE_TEST("Pastel Veil prevents Toxic bad poison") } SCENE { MESSAGE("Wobbuffet used Toxic!"); ABILITY_POPUP(opponent, ABILITY_PASTEL_VEIL); - MESSAGE("The opposing Ponyta is protected by a pastel veil!"); + MESSAGE("It doesn't affect the opposing Ponyta…"); NOT STATUS_ICON(opponent, badPoison: TRUE); } } @@ -97,7 +97,7 @@ DOUBLE_BATTLE_TEST("Pastel Veil prevents Toxic bad poison on partner - right tar } SCENE { MESSAGE("Wobbuffet used Toxic!"); ABILITY_POPUP(opponentLeft, ABILITY_PASTEL_VEIL); - MESSAGE("The opposing Wynaut is protected by a pastel veil!"); + MESSAGE("It doesn't affect the opposing Wynaut…"); NOT STATUS_ICON(opponentRight, badPoison: TRUE); } } @@ -114,7 +114,7 @@ DOUBLE_BATTLE_TEST("Pastel Veil prevents Toxic bad poison on partner - left targ } SCENE { MESSAGE("Wobbuffet used Toxic!"); ABILITY_POPUP(opponentRight, ABILITY_PASTEL_VEIL); - MESSAGE("The opposing Wynaut is protected by a pastel veil!"); + MESSAGE("It doesn't affect the opposing Wynaut…"); NOT STATUS_ICON(opponentLeft, badPoison: TRUE); } } diff --git a/test/battle/ability/pixilate.c b/test/battle/ability/pixilate.c index 7e0d98f519..faa9b35734 100644 --- a/test/battle/ability/pixilate.c +++ b/test/battle/ability/pixilate.c @@ -23,7 +23,8 @@ SINGLE_BATTLE_TEST("Pixilate turns a Normal-type move into a Fairy-type move") SINGLE_BATTLE_TEST("Pixilate boosts power of affected moves by 20% (Gen7+) or 30% (Gen1-6)", s16 damage) { - u32 ability, genConfig; + enum Ability ability; + u32 genConfig; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; genConfig = GEN_7; } PARAMETRIZE { ability = ABILITY_CUTE_CHARM; genConfig = GEN_6; } PARAMETRIZE { ability = ABILITY_PIXILATE; genConfig = GEN_7; } @@ -47,7 +48,8 @@ SINGLE_BATTLE_TEST("Pixilate boosts power of affected moves by 20% (Gen7+) or 30 SINGLE_BATTLE_TEST("Pixilate doesn't affect Weather Ball's type", s16 damage) { - u16 move, ability; + u16 move; + enum Ability ability; PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_STURDY; } PARAMETRIZE { move = MOVE_SUNNY_DAY; ability = ABILITY_STURDY; } PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_PIXILATE; } @@ -75,7 +77,7 @@ SINGLE_BATTLE_TEST("Pixilate doesn't affect Weather Ball's type", s16 damage) SINGLE_BATTLE_TEST("Pixilate doesn't affect Natural Gift's type") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CUTE_CHARM; } PARAMETRIZE { ability = ABILITY_PIXILATE; } GIVEN { diff --git a/test/battle/ability/prankster.c b/test/battle/ability/prankster.c index e927c2d94f..32627c59ff 100644 --- a/test/battle/ability/prankster.c +++ b/test/battle/ability/prankster.c @@ -197,7 +197,7 @@ SINGLE_BATTLE_TEST("Prankster-affected moves can still be bounced back by Dark-t SINGLE_BATTLE_TEST("Prankster-affected moves which are reflected by Magic Coat can affect Dark-type Pokémon, unless the Pokémon that bounced the move also has Prankster") { - u16 sableyeAbility; + enum Ability sableyeAbility; PARAMETRIZE { sableyeAbility = ABILITY_PRANKSTER; } PARAMETRIZE { sableyeAbility = ABILITY_KEEN_EYE; } diff --git a/test/battle/ability/prism_armor.c b/test/battle/ability/prism_armor.c index 69bdde0a0f..36fbc27f99 100644 --- a/test/battle/ability/prism_armor.c +++ b/test/battle/ability/prism_armor.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Prism Armor reduces damage to Super Effective moves by 0.75", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { diff --git a/test/battle/ability/protosynthesis.c b/test/battle/ability/protosynthesis.c index d455b23911..3ff45a9cf5 100644 --- a/test/battle/ability/protosynthesis.c +++ b/test/battle/ability/protosynthesis.c @@ -185,7 +185,8 @@ SINGLE_BATTLE_TEST("Protosynthesis activates even if the Pokémon is holding an SINGLE_BATTLE_TEST("Protosynthesis doesn't activate if Cloud Nine/Air Lock is on the field") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } diff --git a/test/battle/ability/purifying_salt.c b/test/battle/ability/purifying_salt.c index 23f097e8aa..80dc786117 100644 --- a/test/battle/ability/purifying_salt.c +++ b/test/battle/ability/purifying_salt.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Purifying Salt halves damage from Ghost-type moves", s16 damage) { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_STURDY; } PARAMETRIZE { ability = ABILITY_PURIFYING_SALT; } GIVEN { @@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("Purifying Salt halves damage from Ghost-type moves", s16 dam SINGLE_BATTLE_TEST("Purifying Salt halves damage from dynamic Ghost-type moves", s16 damage) { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_STURDY; } PARAMETRIZE { ability = ABILITY_PURIFYING_SALT; } GIVEN { diff --git a/test/battle/ability/refrigerate.c b/test/battle/ability/refrigerate.c index c5e7f5687a..7183267806 100644 --- a/test/battle/ability/refrigerate.c +++ b/test/battle/ability/refrigerate.c @@ -22,7 +22,8 @@ SINGLE_BATTLE_TEST("Refrigerate turns a Normal-type move into a Ice-type move") SINGLE_BATTLE_TEST("Refrigerate boosts power of affected moves by 20% (Gen7+) or 30% (Gen1-6)", s16 damage) { - u32 ability, genConfig; + enum Ability ability; + u32 genConfig; PARAMETRIZE { ability = ABILITY_SNOW_WARNING; genConfig = GEN_7; } PARAMETRIZE { ability = ABILITY_SNOW_WARNING; genConfig = GEN_6; } PARAMETRIZE { ability = ABILITY_REFRIGERATE; genConfig = GEN_7; } @@ -46,7 +47,8 @@ SINGLE_BATTLE_TEST("Refrigerate boosts power of affected moves by 20% (Gen7+) or SINGLE_BATTLE_TEST("Refrigerate doesn't affect Weather Ball's type", s16 damage) { - u16 move, ability; + u16 move; + enum Ability ability; PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_SNOW_WARNING; } PARAMETRIZE { move = MOVE_SUNNY_DAY; ability = ABILITY_SNOW_WARNING; } PARAMETRIZE { move = MOVE_CELEBRATE; ability = ABILITY_REFRIGERATE; } @@ -74,7 +76,7 @@ SINGLE_BATTLE_TEST("Refrigerate doesn't affect Weather Ball's type", s16 damage) SINGLE_BATTLE_TEST("Refrigerate doesn't affect Natural Gift's type") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_SNOW_WARNING; } PARAMETRIZE { ability = ABILITY_REFRIGERATE; } GIVEN { diff --git a/test/battle/ability/rivalry.c b/test/battle/ability/rivalry.c index aef7361af5..fbb4ba4530 100644 --- a/test/battle/ability/rivalry.c +++ b/test/battle/ability/rivalry.c @@ -10,7 +10,8 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Rivalry increases power by x1.25 towards Pokémon of the same gender", s16 damage) { - u16 species, ability; + u16 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_NIDOKING; ability = ABILITY_POISON_POINT; } PARAMETRIZE { species = SPECIES_NIDOKING; ability = ABILITY_RIVALRY; } PARAMETRIZE { species = SPECIES_NIDOQUEEN; ability = ABILITY_POISON_POINT; } @@ -32,7 +33,8 @@ SINGLE_BATTLE_TEST("Rivalry increases power by x1.25 towards Pokémon of the sam SINGLE_BATTLE_TEST("Rivalry decreases power by x0.75 towards Pokémon of different gender", s16 damage) { - u16 species1, species2, ability; + u16 species1, species2; + enum Ability ability; PARAMETRIZE { species1 = SPECIES_NIDOKING; species2 = SPECIES_NIDOQUEEN; ability = ABILITY_POISON_POINT; } PARAMETRIZE { species1 = SPECIES_NIDOKING; species2 = SPECIES_NIDOQUEEN; ability = ABILITY_RIVALRY; } PARAMETRIZE { species1 = SPECIES_NIDOQUEEN; species2 = SPECIES_NIDOKING; ability = ABILITY_POISON_POINT; } @@ -54,7 +56,8 @@ SINGLE_BATTLE_TEST("Rivalry decreases power by x0.75 towards Pokémon of differe SINGLE_BATTLE_TEST("Rivalry doesn't modify power if the attacker is genderless", s16 damage) { - u16 species, ability; + u16 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_NIDOKING; ability = ABILITY_POISON_POINT; } PARAMETRIZE { species = SPECIES_NIDOKING; ability = ABILITY_RIVALRY; } PARAMETRIZE { species = SPECIES_NIDOQUEEN; ability = ABILITY_POISON_POINT; } @@ -78,7 +81,8 @@ SINGLE_BATTLE_TEST("Rivalry doesn't modify power if the attacker is genderless", SINGLE_BATTLE_TEST("Rivalry doesn't modify power if the target is genderless", s16 damage) { - u16 species, ability; + u16 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_NIDOKING; ability = ABILITY_POISON_POINT; } PARAMETRIZE { species = SPECIES_NIDOKING; ability = ABILITY_RIVALRY; } PARAMETRIZE { species = SPECIES_NIDOQUEEN; ability = ABILITY_POISON_POINT; } diff --git a/test/battle/ability/rocky_payload.c b/test/battle/ability/rocky_payload.c index a185efb4f9..d688e5c87e 100644 --- a/test/battle/ability/rocky_payload.c +++ b/test/battle/ability/rocky_payload.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Rocky Payload increases Rock-type move damage", s16 damage) { u32 move; - u16 ability; + enum Ability ability; PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_BIG_PECKS; } PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_ROCKY_PAYLOAD; } diff --git a/test/battle/ability/sand_force.c b/test/battle/ability/sand_force.c index 7592c5afec..ba062f3fa3 100644 --- a/test/battle/ability/sand_force.c +++ b/test/battle/ability/sand_force.c @@ -3,8 +3,8 @@ SINGLE_BATTLE_TEST("Sand Force prevents damage from sandstorm") { - u32 type1 = GetSpeciesType(SPECIES_SHELLOS, 0); - u32 type2 = GetSpeciesType(SPECIES_SHELLOS, 1); + enum Type type1 = GetSpeciesType(SPECIES_SHELLOS, 0); + enum Type type2 = GetSpeciesType(SPECIES_SHELLOS, 1); GIVEN { ASSUME(type1 != TYPE_ROCK && type2 != TYPE_ROCK); ASSUME(type1 != TYPE_GROUND && type2 != TYPE_GROUND); diff --git a/test/battle/ability/sand_rush.c b/test/battle/ability/sand_rush.c index 4d557348e5..9d6ef98274 100644 --- a/test/battle/ability/sand_rush.c +++ b/test/battle/ability/sand_rush.c @@ -3,8 +3,8 @@ SINGLE_BATTLE_TEST("Sand Rush prevents damage from sandstorm") { - u32 type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); - u32 type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); + enum Type type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); + enum Type type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); GIVEN { ASSUME(type1 != TYPE_ROCK && type2 != TYPE_ROCK); ASSUME(type1 != TYPE_GROUND && type2 != TYPE_GROUND); diff --git a/test/battle/ability/sharpness.c b/test/battle/ability/sharpness.c index 9b89614c36..f737bab72a 100644 --- a/test/battle/ability/sharpness.c +++ b/test/battle/ability/sharpness.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Sharpness increases the power of slicing moves by 50%", s16 damage) { u32 move; - u16 ability; + enum Ability ability; PARAMETRIZE { move = MOVE_AERIAL_ACE; ability = ABILITY_SHARPNESS; } PARAMETRIZE { move = MOVE_AERIAL_ACE; ability = ABILITY_STEADFAST; } PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_SHARPNESS; } diff --git a/test/battle/ability/sheer_force.c b/test/battle/ability/sheer_force.c index d14d53571d..abeee88ce7 100644 --- a/test/battle/ability/sheer_force.c +++ b/test/battle/ability/sheer_force.c @@ -8,7 +8,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Sheer Force doesn't boost Magnitude", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -25,7 +25,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Magnitude", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Eruption", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Eruption", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Water Spout", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -59,14 +59,16 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Water Spout", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Present", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { PLAYER(SPECIES_TAUROS) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_PRESENT); } + //Test will fail if present heals because the hp change would be 0 + //so we want a damaging version of present + TURN { MOVE(player, MOVE_PRESENT, WITH_RNG(RNG_PRESENT, 1)); } } SCENE { HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { @@ -76,7 +78,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Present", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Psywave", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -93,7 +95,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Psywave", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Round", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -110,7 +112,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Round", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Gyro Ball", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -127,7 +129,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Gyro Ball", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Electro Ball", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -144,7 +146,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Electro Ball", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Dragon Energy", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -161,7 +163,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Dragon Energy", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Belch", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -178,7 +180,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Belch", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Shell Trap", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -195,7 +197,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Shell Trap", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Burn Up", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ZEN_MODE; } GIVEN { @@ -229,7 +231,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Double Shock", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Steel Roller", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -246,7 +248,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Steel Roller", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Synchronoise", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -297,7 +299,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Hyperspace Fury", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Bolt Beak", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -314,7 +316,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Bolt Beak", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Fishious Rend", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -331,7 +333,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Fishious Rend", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -348,7 +350,7 @@ SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage) } SINGLE_BATTLE_TEST("Sheer Force doesn't boost Payback", s16 damage) { - u16 ability = 0; + enum Ability ability = 0; PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { @@ -1358,3 +1360,20 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to EXPECT_EQ(damage2, damage1); } } + +AI_SINGLE_BATTLE_TEST("AI sees Sheer Force skips additional effects") +{ + u16 ability, expectedMove, move; + + PARAMETRIZE { ability = ABILITY_ROUGH_SKIN; move = MOVE_KARATE_CHOP; expectedMove = MOVE_POWER_UP_PUNCH; } + PARAMETRIZE { ability = ABILITY_ROUGH_SKIN; move = MOVE_BRICK_BREAK; expectedMove = MOVE_POWER_UP_PUNCH; } + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; move = MOVE_BRICK_BREAK; expectedMove = MOVE_BRICK_BREAK; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_DRUDDIGON) { Ability(ability); Moves(MOVE_POWER_UP_PUNCH, move); } + } WHEN { + TURN { EXPECT_MOVE(opponent, expectedMove); } + } +} diff --git a/test/battle/ability/solid_rock.c b/test/battle/ability/solid_rock.c index d15b87e236..d25fca6259 100644 --- a/test/battle/ability/solid_rock.c +++ b/test/battle/ability/solid_rock.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Solid Rock reduces damage to Super Effective moves by 0.75", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_STURDY; } PARAMETRIZE { ability = ABILITY_SOLID_ROCK; } GIVEN { diff --git a/test/battle/ability/stalwart.c b/test/battle/ability/stalwart.c index 22debe74cd..6bebe17cb6 100644 --- a/test/battle/ability/stalwart.c +++ b/test/battle/ability/stalwart.c @@ -20,7 +20,8 @@ DOUBLE_BATTLE_TEST("Stalwart ignores redirection from Follow-Me") DOUBLE_BATTLE_TEST("Stalwart stops Lightning Rod and Storm Drain from redirecting moves") { - u32 ability, species; + enum Ability ability; + u32 species; PARAMETRIZE { ability = ABILITY_STORM_DRAIN; species = SPECIES_LUMINEON; } PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; } GIVEN { diff --git a/test/battle/ability/stamina.c b/test/battle/ability/stamina.c index e9823b7068..39113fd15a 100644 --- a/test/battle/ability/stamina.c +++ b/test/battle/ability/stamina.c @@ -49,7 +49,7 @@ SINGLE_BATTLE_TEST("Stamina raises Defense by 1 when hit by a move") DOUBLE_BATTLE_TEST("Stamina activates correctly for every battler with the ability when hit by a multi target move") { - u16 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE {abilityLeft = ABILITY_NONE, abilityRight = ABILITY_STAMINA; } PARAMETRIZE {abilityLeft = ABILITY_STAMINA, abilityRight = ABILITY_NONE; } diff --git a/test/battle/ability/steelworker.c b/test/battle/ability/steelworker.c index eaf36165f6..b4fa720cdc 100644 --- a/test/battle/ability/steelworker.c +++ b/test/battle/ability/steelworker.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Steelworker increases Steel-type move damage", s16 damage) { u32 move; - u16 ability; + enum Ability ability; PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_KLUTZ; } PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_STEELWORKER; } diff --git a/test/battle/ability/sword_of_ruin.c b/test/battle/ability/sword_of_ruin.c index 395cd3fd68..a891f7d5a7 100644 --- a/test/battle/ability/sword_of_ruin.c +++ b/test/battle/ability/sword_of_ruin.c @@ -73,3 +73,118 @@ SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battler MESSAGE("The opposing Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); } } + +DOUBLE_BATTLE_TEST("Sword of Ruin increases damage taken by special moves in Wonder Room", s16 damage) +{ + bool32 useWonderRoom; + u32 move; + + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = FALSE; move = MOVE_ROUND; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_SCRATCH; } + PARAMETRIZE { useWonderRoom = TRUE; move = MOVE_ROUND; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_WONDER_ROOM) == EFFECT_WONDER_ROOM); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveEffect(MOVE_ROUND) != EFFECT_PSYSHOCK); + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useWonderRoom) + TURN { MOVE(opponentLeft, MOVE_WONDER_ROOM); MOVE(playerRight, move, target: opponentLeft); } + else + TURN { MOVE(playerRight, move, target: opponentLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, playerRight); + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_LT(results[2].damage, results[0].damage); // In Wonder Room, physical move deals less damage + EXPECT_GT(results[3].damage, results[1].damage); // In Wonder Room, special move deals more damage + } +} + +SINGLE_BATTLE_TEST("Sword of Ruin doesn't activate when dragged out by Mold Breaker attacker") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_DRAGON_TAIL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, opponent); + if (ability == ABILITY_MOLD_BREAKER) + { + NONE_OF { + ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + } + } + else + { + ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + } + } +} + +DOUBLE_BATTLE_TEST("Sword of Ruin's Defense reduction is not ignored by Mold Breaker", s16 damage) +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + PARAMETRIZE { ability = ABILITY_SAND_RUSH; } + + GIVEN { + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_EXCADRILL) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +DOUBLE_BATTLE_TEST("Sword of Ruin's Defense reduction is ignored by Gastro Acid", s16 damage) +{ + u32 move; + + PARAMETRIZE { move = MOVE_GASTRO_ACID; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, move, target: playerLeft); MOVE(opponentLeft, MOVE_SCRATCH, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); + HP_BAR(playerRight, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_LT(results[0].damage, results[1].damage); + } +} diff --git a/test/battle/ability/tangling_hair.c b/test/battle/ability/tangling_hair.c index 849c83df64..fdae4de06d 100644 --- a/test/battle/ability/tangling_hair.c +++ b/test/battle/ability/tangling_hair.c @@ -97,3 +97,17 @@ SINGLE_BATTLE_TEST("Tangling Hair does not trigger on Clear Body") NOT ABILITY_POPUP(player, ABILITY_TANGLING_HAIR); } } + +SINGLE_BATTLE_TEST("Tangling Hair will trigger if move is boosted by Sheer Force") +{ + ASSUME(MoveIsAffectedBySheerForce(MOVE_POISON_JAB)); + GIVEN { + PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_TANGLING_HAIR); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, MOVE_POISON_JAB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_POISON_JAB, opponent); + ABILITY_POPUP(player, ABILITY_TANGLING_HAIR); + } +} diff --git a/test/battle/ability/teraform_zero.c b/test/battle/ability/teraform_zero.c index 96186f2047..f6620d6625 100644 --- a/test/battle/ability/teraform_zero.c +++ b/test/battle/ability/teraform_zero.c @@ -39,11 +39,12 @@ DOUBLE_BATTLE_TEST("Teraform Zero can be supressed") SINGLE_BATTLE_TEST("Teraform Zero can be replaced") { GIVEN { - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_TERAPAGOS); OPPONENT(SPECIES_WHIMSICOTT) { Ability(ABILITY_PRANKSTER); } } WHEN { + TURN { MOVE(opponent, MOVE_POUND); } TURN { MOVE(opponent, MOVE_WORRY_SEED); MOVE(player, MOVE_REST, gimmick: GIMMICK_TERA); } } SCENE { MESSAGE("The opposing Whimsicott used Worry Seed!"); diff --git a/test/battle/ability/trace.c b/test/battle/ability/trace.c index 6dbd9bda26..71d5035084 100644 --- a/test/battle/ability/trace.c +++ b/test/battle/ability/trace.c @@ -46,7 +46,7 @@ SINGLE_BATTLE_TEST("Trace copies opponents ability on switch-in even if opponent DOUBLE_BATTLE_TEST("Trace copies opponents ability randomly") { - u16 ability1, ability2; + enum Ability ability1, ability2; PARAMETRIZE { ability1 = ABILITY_SPEED_BOOST; ability2 = ABILITY_BLAZE;} PARAMETRIZE { ability1 = ABILITY_BLAZE; ability2 = ABILITY_SPEED_BOOST; } diff --git a/test/battle/ability/transistor.c b/test/battle/ability/transistor.c index 8b8f098d52..e57043a5c2 100644 --- a/test/battle/ability/transistor.c +++ b/test/battle/ability/transistor.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Transistor increases Electric-type attack / special attack", s16 damage) { u32 move; - u16 ability; + enum Ability ability; PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_KLUTZ; } PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_TRANSISTOR; } @@ -38,7 +38,7 @@ SINGLE_BATTLE_TEST("Transistor increases Electric-type attack / special attack", SINGLE_BATTLE_TEST("Transistor is blocked by neutralizing gas", s16 damage) { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NEUTRALIZING_GAS; } PARAMETRIZE { ability = ABILITY_LEVITATE; } diff --git a/test/battle/ability/unburden.c b/test/battle/ability/unburden.c index 0ddce0f227..4498bb4922 100644 --- a/test/battle/ability/unburden.c +++ b/test/battle/ability/unburden.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Unburden doubles speed once user uses item") { GIVEN { - ASSUME(GetItemHoldEffect(ITEM_GRASSY_SEED) == HOLD_EFFECT_SEEDS); + ASSUME(GetItemHoldEffect(ITEM_GRASSY_SEED) == HOLD_EFFECT_TERRAIN_SEED); ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); PLAYER(SPECIES_DRIFBLIM) { Ability(ABILITY_UNBURDEN); Item(ITEM_GRASSY_SEED); Speed(5); } OPPONENT(SPECIES_WOBBUFFET) { Speed(7); } diff --git a/test/battle/ability/unnerve.c b/test/battle/ability/unnerve.c index e53b510fe6..a1eabbcf5a 100644 --- a/test/battle/ability/unnerve.c +++ b/test/battle/ability/unnerve.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Unnerve prevents opposing Pokémon from eating their own berries") { u16 mon; - u16 ability; + enum Ability ability; PARAMETRIZE { mon = SPECIES_JOLTIK, ability = ABILITY_UNNERVE; } PARAMETRIZE { mon = SPECIES_CALYREX_ICE, ability = ABILITY_AS_ONE_ICE_RIDER; } GIVEN { @@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Unnerve prevents opposing Pokémon from eating their own ber SINGLE_BATTLE_TEST("Unnerve doesn't prevent opposing Pokémon from using Natural Gift") { u16 mon; - u16 ability; + enum Ability ability; PARAMETRIZE { mon = SPECIES_JOLTIK, ability = ABILITY_UNNERVE; } PARAMETRIZE { mon = SPECIES_CALYREX_ICE, ability = ABILITY_AS_ONE_ICE_RIDER; } GIVEN { @@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Unnerve doesn't prevent opposing Pokémon from using Natural SINGLE_BATTLE_TEST("Unnerve prints the correct string (player)") { u16 mon; - u16 ability; + enum Ability ability; PARAMETRIZE { mon = SPECIES_JOLTIK, ability = ABILITY_UNNERVE; } PARAMETRIZE { mon = SPECIES_CALYREX_ICE, ability = ABILITY_AS_ONE_ICE_RIDER; } GIVEN { @@ -59,7 +59,7 @@ SINGLE_BATTLE_TEST("Unnerve prints the correct string (player)") SINGLE_BATTLE_TEST("Unnerve prints the correct string (opponent)") { u16 mon; - u16 ability; + enum Ability ability; PARAMETRIZE { mon = SPECIES_JOLTIK, ability = ABILITY_UNNERVE; } PARAMETRIZE { mon = SPECIES_CALYREX_ICE, ability = ABILITY_AS_ONE_ICE_RIDER; } GIVEN { @@ -76,7 +76,7 @@ SINGLE_BATTLE_TEST("Unnerve prints the correct string (opponent)") SINGLE_BATTLE_TEST("Unnerve activates only once per switch-in") { u16 mon; - u16 ability; + enum Ability ability; PARAMETRIZE { mon = SPECIES_JOLTIK, ability = ABILITY_UNNERVE; } PARAMETRIZE { mon = SPECIES_CALYREX_ICE, ability = ABILITY_AS_ONE_ICE_RIDER; } GIVEN { diff --git a/test/battle/ability/vessel_of_ruin.c b/test/battle/ability/vessel_of_ruin.c index 30c7520c36..1a075db8cf 100644 --- a/test/battle/ability/vessel_of_ruin.c +++ b/test/battle/ability/vessel_of_ruin.c @@ -73,3 +73,76 @@ SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battle MESSAGE("The opposing Ting-Lu's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!"); } } + +DOUBLE_BATTLE_TEST("Vessel of Ruin does not reduce Sp. Atk if Neutralizing Gas is on the field") +{ + s16 damage[2]; + + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_TING_LU) { Ability(ABILITY_VESSEL_OF_RUIN); } + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); } + } WHEN { + TURN { + MOVE(playerLeft, MOVE_WATER_GUN, target: opponentLeft); + } + TURN { + SWITCH(opponentRight, 2); + MOVE(playerLeft, MOVE_WATER_GUN, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); + } THEN { + EXPECT_MUL_EQ(damage[0], Q_4_12(1.33), damage[1]); + } +} + +SINGLE_BATTLE_TEST("Vessel of Ruin is still active if removed by Mold Breaker + Entrainment") +{ + s16 damage[2]; + + GIVEN { + PLAYER(SPECIES_TING_LU) { Ability(ABILITY_VESSEL_OF_RUIN); } + OPPONENT(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } + } WHEN { + TURN { MOVE(opponent, MOVE_WATER_GUN); } + TURN { MOVE(opponent, MOVE_ENTRAINMENT); } + TURN { MOVE(opponent, MOVE_WATER_GUN); } + } SCENE { + ABILITY_POPUP(player, ABILITY_VESSEL_OF_RUIN); + MESSAGE("Ting-Lu's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); + HP_BAR(player, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENTRAINMENT, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); + HP_BAR(player, captureDamage: &damage[1]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + } +} + +DOUBLE_BATTLE_TEST("Vessel of Ruin is active if removed by Mold Breaker Entrainment and Sword of Ruin is active after obtaining it") +{ + GIVEN { + PLAYER(SPECIES_TING_LU) { Ability(ABILITY_VESSEL_OF_RUIN); } + PLAYER(SPECIES_CHIEN_PAO) { Ability(ABILITY_SWORD_OF_RUIN); } + OPPONENT(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); } + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_ENTRAINMENT, target: playerLeft); + MOVE(opponentRight, MOVE_SKILL_SWAP, target: playerLeft); + MOVE(playerRight, MOVE_SKILL_SWAP, target: playerLeft); + } + } THEN { + bool32 isVesselOfRuinActive = gBattleMons[B_POSITION_PLAYER_LEFT].volatiles.vesselOfRuin; + bool32 isSwordOfRuinActive = gBattleMons[B_POSITION_PLAYER_LEFT].volatiles.swordOfRuin; + EXPECT_EQ(isVesselOfRuinActive, TRUE); + EXPECT_EQ(isSwordOfRuinActive, TRUE); + } +} diff --git a/test/battle/ability/water_bubble.c b/test/battle/ability/water_bubble.c index d140dac040..1d1d3956d4 100644 --- a/test/battle/ability/water_bubble.c +++ b/test/battle/ability/water_bubble.c @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Water Bubble prevents burn from Will-o-Wisp") TURN { MOVE(opponent, MOVE_WILL_O_WISP); } } SCENE { ABILITY_POPUP(player, ABILITY_WATER_BUBBLE); - MESSAGE("Dewpider's Water Bubble prevents burns!"); + MESSAGE("It doesn't affect Dewpider…"); NONE_OF { ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, player); STATUS_ICON(player, burn: TRUE); diff --git a/test/battle/ability/water_compaction.c b/test/battle/ability/water_compaction.c index e4e32e2713..8e7751e376 100644 --- a/test/battle/ability/water_compaction.c +++ b/test/battle/ability/water_compaction.c @@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Water Compaction raises Defense 2 stages on each hit of a mu SINGLE_BATTLE_TEST("Water Compaction does not affect damage taken from Water type moves", s16 damage) { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_SAND_VEIL; } PARAMETRIZE { ability = ABILITY_WATER_COMPACTION; } GIVEN { diff --git a/test/battle/ability/weak_armor.c b/test/battle/ability/weak_armor.c index cae8383dde..c443d39c20 100644 --- a/test/battle/ability/weak_armor.c +++ b/test/battle/ability/weak_armor.c @@ -29,14 +29,10 @@ SINGLE_BATTLE_TEST("Weak Armor lowers Defense by 1 and boosts Speed by 1 (Gen5-6 if (move == MOVE_SCRATCH) { ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Slugma's Weak Armor lowered its Defense!"); - MESSAGE("Slugma's Weak Armor raised its Speed!"); } else { NONE_OF { ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Slugma's Weak Armor lowered its Defense!"); - MESSAGE("Slugma's Weak Armor raised its Speed!"); } } } THEN { @@ -73,7 +69,7 @@ SINGLE_BATTLE_TEST("Weak Armor does not trigger when brought in by Dragon Tail a ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Slugma's Weak Armor lowered its Defense!"); - MESSAGE("Slugma's Weak Armor raised its Speed!"); + MESSAGE("Slugma's Weak Armor sharply raised its Speed!"); } } THEN { EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); @@ -106,7 +102,11 @@ SINGLE_BATTLE_TEST("Weak Armor still boosts Speed if Defense can't go any lower" } MESSAGE("Slugma's Defense won't go any lower!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Slugma's Weak Armor raised its Speed!"); + if (gen == GEN_6) + MESSAGE("Slugma's Weak Armor raised its Speed!"); + else + MESSAGE("Slugma's Weak Armor sharply raised its Speed!"); + } THEN { EXPECT_EQ(player->statStages[STAT_DEF], MIN_STAT_STAGE); EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + (gen == GEN_7 ? 2 : 1)); @@ -131,7 +131,7 @@ SINGLE_BATTLE_TEST("Weak Armor still lowers Defense if Speed can't go any higher MESSAGE("Slugma's Weak Armor lowered its Defense!"); NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Slugma's Weak Armor raised its Speed!"); + MESSAGE("Slugma's Weak Armor sharply raised its Speed!"); } MESSAGE("Slugma's Speed won't go any higher!"); } THEN { @@ -157,12 +157,12 @@ SINGLE_BATTLE_TEST("Weak Armor doesn't interrupt multi hit moves if Defense can' ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, opponent); ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); MESSAGE("Magcargo's Weak Armor lowered its Defense!"); - MESSAGE("Magcargo's Weak Armor raised its Speed!"); + MESSAGE("Magcargo's Weak Armor sharply raised its Speed!"); } ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, opponent); ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); MESSAGE("Magcargo's Defense won't go any lower!"); - MESSAGE("Magcargo's Weak Armor raised its Speed!"); + MESSAGE("Magcargo's Weak Armor sharply raised its Speed!"); for (j = 0; j < 2; j++) { ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, opponent); @@ -194,7 +194,7 @@ SINGLE_BATTLE_TEST("Weak Armor doesn't interrupt multi hit moves if Speed can't ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, opponent); ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); MESSAGE("Magcargo's Weak Armor lowered its Defense!"); - MESSAGE("Magcargo's Weak Armor raised its Speed!"); + MESSAGE("Magcargo's Weak Armor sharply raised its Speed!"); for (j = 0; j < 4; j++) { ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, opponent); diff --git a/test/battle/ability/wind_power.c b/test/battle/ability/wind_power.c index 279d51f623..c38bbf3569 100644 --- a/test/battle/ability/wind_power.c +++ b/test/battle/ability/wind_power.c @@ -107,7 +107,7 @@ SINGLE_BATTLE_TEST("Wind Power sets up Charge for opponent when hit by a wind mo DOUBLE_BATTLE_TEST("Wind Power activates correctly for every battler with the ability when hit by a 2/3 target move") { - u16 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE {abilityLeft = ABILITY_NONE, abilityRight = ABILITY_WIND_POWER;} PARAMETRIZE {abilityLeft = ABILITY_WIND_POWER, abilityRight = ABILITY_NONE; } @@ -148,7 +148,7 @@ DOUBLE_BATTLE_TEST("Wind Power activates correctly for every battler with the ab DOUBLE_BATTLE_TEST("Wind Power activates correctly for every battler with the ability when hit by a 3 target move") { - u16 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE {abilityLeft = ABILITY_NONE, abilityRight = ABILITY_WIND_POWER; } PARAMETRIZE {abilityLeft = ABILITY_WIND_POWER, abilityRight = ABILITY_NONE; } diff --git a/test/battle/ability/zero_to_hero.c b/test/battle/ability/zero_to_hero.c index dcac9b8540..7df3f07702 100644 --- a/test/battle/ability/zero_to_hero.c +++ b/test/battle/ability/zero_to_hero.c @@ -84,8 +84,8 @@ SINGLE_BATTLE_TEST("Gastro Acid, Worry Seed, and Simple Beam fail if the target GIVEN { ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); - ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_SIMPLE_BEAM); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); + ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_OVERWRITE_ABILITY); PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index c3b69b9c4c..368a8a2c63 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -30,7 +30,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers Bubble over Water Gun if it's slower") AI_SINGLE_BATTLE_TEST("AI prefers Water Gun over Bubble if it knows that foe has Contrary") { - u32 abilityAI; + enum Ability abilityAI; PARAMETRIZE { abilityAI = ABILITY_MOXIE; } PARAMETRIZE { abilityAI = ABILITY_MOLD_BREAKER; } // Mold Breaker ignores Contrary. @@ -54,7 +54,8 @@ AI_SINGLE_BATTLE_TEST("AI prefers Water Gun over Bubble if it knows that foe has AI_SINGLE_BATTLE_TEST("AI prefers moves with better accuracy, but only if they both require the same number of hits to ko") { u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE; - u16 hp, expectedMove, turns, abilityAtk, expectedMove2; + u16 hp, expectedMove, turns, expectedMove2; + enum Ability abilityAtk; abilityAtk = ABILITY_NONE; expectedMove2 = MOVE_NONE; @@ -138,7 +139,8 @@ AI_SINGLE_BATTLE_TEST("AI prefers moves which deal more damage instead of moves { u8 turns = 0; u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE; - u16 expectedMove, abilityAtk, abilityDef; + u16 expectedMove; + enum Ability abilityAtk, abilityDef; abilityAtk = ABILITY_NONE; @@ -264,7 +266,8 @@ AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking { u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE; u16 expectedMove, expectedMove2 = MOVE_NONE; - u16 abilityAtk = ABILITY_NONE, holdItemAtk = ITEM_NONE; + enum Ability abilityAtk = ABILITY_NONE; + u32 holdItemAtk = ITEM_NONE; // Psychic is not very effective, but always hits. Solarbeam requires a charging turn, Double Edge has recoil and Focus Blast can miss; PARAMETRIZE { abilityAtk = ABILITY_STURDY; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SOLAR_BEAM; move3 = MOVE_PSYCHIC; move4 = MOVE_DOUBLE_EDGE; expectedMove = MOVE_PSYCHIC; } @@ -301,7 +304,8 @@ AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking { u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE; u16 expectedMove, expectedMove2 = MOVE_NONE; - u16 abilityAtk = ABILITY_NONE, holdItemAtk = ITEM_NONE; + enum Ability abilityAtk = ABILITY_NONE; + u32 holdItemAtk = ITEM_NONE; // Fiery Dance and Skull Bash are chosen because user is holding Power Herb PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_FIERY_DANCE; move4 = MOVE_DOUBLE_EDGE; @@ -328,7 +332,7 @@ AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking AI_SINGLE_BATTLE_TEST("AI won't use Solar Beam if there is no Sun up or the user is not holding Power Herb") { - u16 abilityAtk = ABILITY_NONE; + enum Ability abilityAtk = ABILITY_NONE; u16 holdItemAtk = ITEM_NONE; PARAMETRIZE { abilityAtk = ABILITY_DROUGHT; } @@ -449,7 +453,7 @@ AI_SINGLE_BATTLE_TEST("First Impression is preferred on the first turn of the sp AI_SINGLE_BATTLE_TEST("First Impression is not chosen if it's blocked by certain abilities") { u16 species; - u16 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } @@ -516,7 +520,7 @@ AI_SINGLE_BATTLE_TEST("AI will choose Thunderbolt then Surf 2/3 times if the opp AI_SINGLE_BATTLE_TEST("AI will choose Scratch over Power-up Punch with Contrary") { - u32 ability; + enum Ability ability; PARAMETRIZE {ability = ABILITY_SUCTION_CUPS; } PARAMETRIZE {ability = ABILITY_CONTRARY; } @@ -542,7 +546,7 @@ AI_SINGLE_BATTLE_TEST("AI will choose Scratch over Power-up Punch with Contrary" AI_SINGLE_BATTLE_TEST("AI will choose Superpower over Outrage with Contrary") { - u32 ability; + enum Ability ability; PARAMETRIZE {ability = ABILITY_SUCTION_CUPS; } PARAMETRIZE {ability = ABILITY_CONTRARY; } @@ -568,7 +572,7 @@ AI_SINGLE_BATTLE_TEST("AI will choose Superpower over Outrage with Contrary") AI_SINGLE_BATTLE_TEST("AI calculates guaranteed criticals and detects critical immunity") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_SWIFT_SWIM; } PARAMETRIZE { ability = ABILITY_SHELL_ARMOR; } @@ -645,7 +649,8 @@ AI_SINGLE_BATTLE_TEST("AI uses a guaranteed KO move instead of the move with the AI_SINGLE_BATTLE_TEST("AI stays choice locked into moves in spite of the player's ability disabling them") { - u32 playerMon, ability, aiMove; + u32 playerMon, aiMove; + enum Ability ability; PARAMETRIZE { ability = ABILITY_DAZZLING; playerMon = SPECIES_BRUXISH; aiMove = MOVE_QUICK_ATTACK; } PARAMETRIZE { ability = ABILITY_QUEENLY_MAJESTY; playerMon = SPECIES_TSAREENA; aiMove = MOVE_QUICK_ATTACK; } PARAMETRIZE { ability = ABILITY_ARMOR_TAIL; playerMon = SPECIES_FARIGIRAF; aiMove = MOVE_QUICK_ATTACK; } @@ -855,7 +860,7 @@ AI_DOUBLE_BATTLE_TEST("AI sees opposing drain ability") AI_SINGLE_BATTLE_TEST("AI will not set up Weather if it wont have any affect") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CLOUD_NINE; } PARAMETRIZE { ability = ABILITY_DAMP; } diff --git a/test/battle/ai/ai_check_viability.c b/test/battle/ai/ai_check_viability.c index 25f3a7763c..dfc71fc62e 100644 --- a/test/battle/ai/ai_check_viability.c +++ b/test/battle/ai/ai_check_viability.c @@ -178,7 +178,7 @@ AI_SINGLE_BATTLE_TEST("AI can choose Counter or Mirror Coat if the predicted mov AI_SINGLE_BATTLE_TEST("AI chooses moves with secondary effect that have a 100% chance to trigger") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_NONE; } PARAMETRIZE { ability = ABILITY_SERENE_GRACE; } @@ -234,7 +234,8 @@ AI_DOUBLE_BATTLE_TEST("AI chooses moves that cure self or partner") AI_SINGLE_BATTLE_TEST("AI chooses moves that cure inactive party members") { - u32 status, ability, config; + u32 status, config; + enum Ability ability; PARAMETRIZE { status = STATUS1_TOXIC_POISON; ability = ABILITY_SCRAPPY; } PARAMETRIZE { status = STATUS1_NONE; ability = ABILITY_SCRAPPY; } @@ -314,7 +315,7 @@ AI_SINGLE_BATTLE_TEST("AI uses Worry Seed against Rest") AI_SINGLE_BATTLE_TEST("AI uses Simple Beam against Contrary Leaf Storm") { - u32 ability, move; + enum Ability ability, move; PARAMETRIZE { ability = ABILITY_CONTRARY; move = MOVE_LEAF_STORM; } PARAMETRIZE { ability = ABILITY_CONTRARY; move = MOVE_CHARGE_BEAM; } PARAMETRIZE { ability = ABILITY_OVERGROW; move = MOVE_CHARGE_BEAM; } @@ -393,3 +394,69 @@ AI_SINGLE_BATTLE_TEST("AI uses Wide Guard against Earthquake when opponent would TURN { MOVE(player, MOVE_EARTHQUAKE); EXPECT_MOVE(opponent, MOVE_WIDE_GUARD); } } } + +AI_SINGLE_BATTLE_TEST("AI sees Shield Dust immunity to additional effects") +{ + enum Ability ability; + PARAMETRIZE { ability = ABILITY_SHIELD_DUST; } + PARAMETRIZE { ability = ABILITY_TINTED_LENS; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_VENOMOTH) { Ability(ability); Moves(MOVE_CELEBRATE, MOVE_POUND); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CHILLING_WATER, MOVE_BRINE); } + } WHEN { + if (ability == ABILITY_SHIELD_DUST) + TURN { EXPECT_MOVE(opponent, MOVE_BRINE); } + else + TURN { EXPECT_MOVE(opponent, MOVE_CHILLING_WATER); } + } +} + +AI_DOUBLE_BATTLE_TEST("AI sees type-changing moves as the correct type") +{ + u32 species, fieldStatus, ability; + u64 aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; + + PARAMETRIZE { fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_NONE; } + PARAMETRIZE { fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_LIQUID_VOICE; } + PARAMETRIZE { fieldStatus = MOVE_ELECTRIC_TERRAIN; species = SPECIES_GEODUDE_ALOLA; ability = ABILITY_GALVANIZE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_NONE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + fieldStatus = MOVE_RAIN_DANCE; species = SPECIES_PRIMARINA; ability = ABILITY_LIQUID_VOICE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + fieldStatus = MOVE_ELECTRIC_TERRAIN; species = SPECIES_GEODUDE_ALOLA; ability = ABILITY_GALVANIZE; } + + GIVEN { + AI_FLAGS(aiFlags); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(fieldStatus, MOVE_RETURN, MOVE_TAUNT); } + OPPONENT(species) { Ability(ability); Moves(MOVE_HYPER_VOICE); } + } WHEN { + if (ability != ABILITY_NONE) + TURN { EXPECT_MOVE(opponentLeft, fieldStatus); } + else + TURN { NOT_EXPECT_MOVE(opponentLeft, fieldStatus); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Sparkling Aria to cure an enemy with Guts") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_GUTS; } + PARAMETRIZE { ability = ABILITY_BULLETPROOF; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_URSALUNA) { Ability(ability); Moves(MOVE_HEADLONG_RUSH, MOVE_CELEBRATE); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_PRIMARINA) { Moves(MOVE_SPARKLING_ARIA, MOVE_SCALD); } + } WHEN { + if (ability == ABILITY_GUTS) + TURN { EXPECT_MOVE(opponent, MOVE_SPARKLING_ARIA); } + else + TURN { EXPECT_MOVE(opponent, MOVE_SCALD); } + } +} diff --git a/test/battle/ai/ai_choice.c b/test/battle/ai/ai_choice.c index d7ff7e021f..e8d3a8e42a 100644 --- a/test/battle/ai/ai_choice.c +++ b/test/battle/ai/ai_choice.c @@ -10,7 +10,8 @@ ASSUMPTIONS AI_SINGLE_BATTLE_TEST("Choiced Pokémon switch out after using a status move once") { - u32 j, ability = ABILITY_NONE, heldItem = ITEM_NONE; + u32 j, heldItem = ITEM_NONE; + enum Ability ability = ABILITY_NONE; static const u32 choiceItems[] = { ITEM_CHOICE_SPECS, @@ -46,7 +47,7 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon switch out after using a status move onc AI_SINGLE_BATTLE_TEST("Choiced Pokémon only consider their own status moves when determining if they should switch") { - GIVEN + GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_RISKY | AI_FLAG_SMART_SWITCHING | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_ZIGZAGOON) { Speed(4); Moves(MOVE_TAIL_WHIP, MOVE_SCRATCH); } @@ -61,7 +62,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon only consider their own status moves whe AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use stat boosting moves") { // Moves defined by MOVE_TARGET_USER (with exceptions?) - u32 j, ability = ABILITY_NONE, heldItem = ITEM_NONE; + u32 j, heldItem = ITEM_NONE; + enum Ability ability = ABILITY_NONE; static const u32 choiceItems[] = { ITEM_CHOICE_SPECS, @@ -93,8 +95,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use stat boosting moves") AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are the only party member") { - u32 j, ability = ABILITY_NONE, isAlive = 0, heldItem = ITEM_NONE; - + u32 j, isAlive = 0, heldItem = ITEM_NONE; + enum Ability ability = ABILITY_NONE; static const u32 choiceItems[] = { ITEM_CHOICE_SPECS, ITEM_CHOICE_BAND, @@ -128,8 +130,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are the on AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they don't have a good switchin") { - u32 j, ability = ABILITY_NONE, move = MOVE_NONE, species = SPECIES_NONE, heldItem = ITEM_NONE; - + u32 j, move = MOVE_NONE, species = SPECIES_NONE, heldItem = ITEM_NONE; + enum Ability ability = ABILITY_NONE; static const u32 choiceItems[] = { ITEM_CHOICE_SPECS, ITEM_CHOICE_BAND, diff --git a/test/battle/ai/ai_doubles.c b/test/battle/ai/ai_doubles.c index 055b1c5f81..08ed4d7807 100644 --- a/test/battle/ai/ai_doubles.c +++ b/test/battle/ai/ai_doubles.c @@ -69,13 +69,14 @@ AI_DOUBLE_BATTLE_TEST("AI will not use a status move if partner already chose He } GIVEN { - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HELPING_HAND); } - OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SCRATCH, statusMove); } + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, statusMove, MOVE_WATER_GUN); } + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, statusMove, MOVE_WATER_GUN); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HELPING_HAND, MOVE_EXPLOSION); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SCRATCH, statusMove, MOVE_WATER_GUN); } } WHEN { - TURN { NOT_EXPECT_MOVE(opponentRight, statusMove); + TURN { EXPECT_MOVE(opponentLeft, MOVE_HELPING_HAND); + NOT_EXPECT_MOVE(opponentRight, statusMove); SCORE_LT_VAL(opponentRight, statusMove, AI_SCORE_DEFAULT, target:playerLeft); SCORE_LT_VAL(opponentRight, statusMove, AI_SCORE_DEFAULT, target:playerRight); SCORE_LT_VAL(opponentRight, statusMove, AI_SCORE_DEFAULT, target:opponentLeft); @@ -185,7 +186,8 @@ AI_DOUBLE_BATTLE_TEST("AI will choose Bulldoze if it triggers its ally's ability ASSUME(GetMoveType(MOVE_BULLDOZE) == TYPE_GROUND); ASSUME(MoveHasAdditionalEffect(MOVE_BULLDOZE, MOVE_EFFECT_SPD_MINUS_1)); - u32 species, ability, currentHP; + u32 species, currentHP; + enum Ability ability; PARAMETRIZE { species = SPECIES_KINGAMBIT; ability = ABILITY_DEFIANT; currentHP = 400; } PARAMETRIZE { species = SPECIES_SHUCKLE; ability = ABILITY_CONTRARY; currentHP = 400; } @@ -212,7 +214,7 @@ AI_DOUBLE_BATTLE_TEST("AI will choose Beat Up on an ally with Justified if it wi ASSUME(GetMoveEffect(MOVE_BEAT_UP) == EFFECT_BEAT_UP); ASSUME(GetMoveType(MOVE_BEAT_UP) == TYPE_DARK); - u32 defAbility, atkAbility, currentHP; + enum Ability defAbility, atkAbility, currentHP; PARAMETRIZE { defAbility = ABILITY_FLASH_FIRE; atkAbility = ABILITY_SCRAPPY; currentHP = 400; } PARAMETRIZE { defAbility = ABILITY_JUSTIFIED; atkAbility = ABILITY_SCRAPPY; currentHP = 400; } @@ -336,7 +338,7 @@ AI_DOUBLE_BATTLE_TEST("AI will trigger its ally's Weakness Policy") } } -AI_DOUBLE_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide") +AI_DOUBLE_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide (doubles)") { ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); @@ -361,6 +363,36 @@ AI_DOUBLE_BATTLE_TEST("AI will only explode and kill everything on the field wit } } +AI_DOUBLE_BATTLE_TEST("Battler 3 has Battler 1 AI flags set correctly (doubles)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + OPPONENT(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0 || battler == 3) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_EXPLOSION, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_EXPLOSION); } + } +} + AI_DOUBLE_BATTLE_TEST("AI sees corresponding absorbing abilities on partners") { ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); @@ -372,7 +404,8 @@ AI_DOUBLE_BATTLE_TEST("AI sees corresponding absorbing abilities on partners") ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); ASSUME(GetMoveType(MOVE_EARTHQUAKE) == TYPE_GROUND); - u32 ability, move, species; + enum Ability ability; + u32 move, species; PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_CLOUD_NINE; move = MOVE_DISCHARGE; } PARAMETRIZE { species = SPECIES_PIKACHU; ability = ABILITY_LIGHTNING_ROD; move = MOVE_DISCHARGE; } @@ -409,7 +442,8 @@ AI_DOUBLE_BATTLE_TEST("AI treats an ally's redirection ability appropriately (ge ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); ASSUME(GetMoveType(MOVE_SURF) == TYPE_WATER); - u32 ability, move, species; + enum Ability ability; + u32 move, species; PARAMETRIZE { species = SPECIES_SEAKING; ability = ABILITY_LIGHTNING_ROD; move = MOVE_DISCHARGE; } PARAMETRIZE { species = SPECIES_SHELLOS; ability = ABILITY_STORM_DRAIN; move = MOVE_SURF; } @@ -433,7 +467,8 @@ AI_DOUBLE_BATTLE_TEST("AI treats an ally's redirection ability appropriately (ge ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); ASSUME(GetMoveType(MOVE_SURF) == TYPE_WATER); - u32 ability, move, species; + enum Ability ability; + u32 move, species; PARAMETRIZE { species = SPECIES_SEAKING; ability = ABILITY_LIGHTNING_ROD; move = MOVE_DISCHARGE; } PARAMETRIZE { species = SPECIES_SHELLOS; ability = ABILITY_STORM_DRAIN; move = MOVE_SURF; } @@ -640,6 +675,7 @@ AI_DOUBLE_BATTLE_TEST("AI uses Helping Hand if it's about to die") AI_DOUBLE_BATTLE_TEST("AI uses Helping Hand if the ally does notably more damage") { + KNOWN_FAILING; // Failure was masked by test runner issues GIVEN { ASSUME(GetMoveEffect(MOVE_HELPING_HAND) == EFFECT_HELPING_HAND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); diff --git a/test/battle/ai/ai_multi.c b/test/battle/ai/ai_multi.c new file mode 100644 index 0000000000..b46573b4ca --- /dev/null +++ b/test/battle/ai/ai_multi.c @@ -0,0 +1,224 @@ +#include "global.h" +#include "test/battle.h" +#include "battle_ai_util.h" + +AI_MULTI_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide (multi)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_PARTNER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_OPPONENT_A(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + MULTI_OPPONENT_B(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(&gBattleMons[BATTLE_PARTNER(battler)], MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(&gBattleMons[battler], MOVE_EXPLOSION); } + } +} + +AI_ONE_VS_TWO_BATTLE_TEST("AI will only explode and kill everything on the field with Risky or Will Suicide (1v2)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_OPPONENT_A(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + MULTI_OPPONENT_B(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(&gBattleMons[BATTLE_PARTNER(battler)], MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(&gBattleMons[battler], MOVE_EXPLOSION); } + } +} + +// Used to test EXPECT_MOVE only on partner +AI_MULTI_BATTLE_TEST("AI partner makes sensible move selections in battle (multi)") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL, MOVE_AURA_SPHERE); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); HP(1); } + MULTI_OPPONENT_B(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:opponentRight); EXPECT_MOVE(playerRight, MOVE_AURA_SPHERE, target:opponentLeft); }; + } +} + +// Used to test EXPECT_MOVE only on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner makes sensible move selections in battle (2v1)") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL, MOVE_AURA_SPHERE); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); HP(1); } + MULTI_OPPONENT_A(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:opponentRight); EXPECT_MOVE(playerRight, MOVE_AURA_SPHERE, target:opponentLeft); }; + } +} + +AI_TWO_VS_ONE_BATTLE_TEST("Battler 3 has Battler 1 AI flags set correctly (2v1)") +{ + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + + u32 aiFlags; + u32 battler; + + PARAMETRIZE { aiFlags = 0; battler = 1; } + PARAMETRIZE { aiFlags = 0; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_RISKY; battler = 3; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 1; } + PARAMETRIZE { aiFlags = AI_FLAG_WILL_SUICIDE; battler = 3; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(battler, aiFlags); + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_PARTNER(SPECIES_WOBBUFFET) { HP(1); } + MULTI_OPPONENT_A(SPECIES_VOLTORB) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + MULTI_OPPONENT_A(SPECIES_ELECTRODE) { Moves(MOVE_EXPLOSION, MOVE_ELECTRO_BALL); HP(1); } + } WHEN { + if (aiFlags == 0 || battler == 3) + TURN { EXPECT_MOVE(opponentLeft, MOVE_ELECTRO_BALL, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_ELECTRO_BALL, target: playerLeft); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_EXPLOSION, target: playerLeft); EXPECT_MOVE(opponentRight, MOVE_EXPLOSION); } + } +} + +AI_MULTI_BATTLE_TEST("Partner will not steal your pokemon when running out") +{ + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PARTNER(SPECIES_WYNAUT) { Moves(MOVE_MEMENTO); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN {EXPECT_MOVE(playerRight, MOVE_MEMENTO, target:opponentLeft);} + TURN {} + } THEN { + EXPECT_EQ(gAbsentBattlerFlags, (1u << GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT))); + } +} + +AI_MULTI_BATTLE_TEST("Partner will not steal your pokemon to delay using their ace") +{ + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(B_POSITION_PLAYER_RIGHT, AI_FLAG_ACE_POKEMON); + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PARTNER(SPECIES_WYNAUT) { Moves(MOVE_MEMENTO); } + MULTI_PARTNER(SPECIES_METAGROSS) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN {EXPECT_MOVE(playerRight, MOVE_MEMENTO, target:opponentLeft);} + TURN {} + } THEN { + EXPECT_EQ(SPECIES_METAGROSS, playerRight->species); + } +} + +AI_MULTI_BATTLE_TEST("AI opponents do not steal their partner pokemon in multi battle to delay using their ace") +{ + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(B_POSITION_OPPONENT_LEFT, AI_FLAG_ACE_POKEMON); + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PARTNER(SPECIES_WOBBUFFET) { } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); HP(1);} + MULTI_OPPONENT_A(SPECIES_VENUSAUR) { Moves(MOVE_GIGA_DRAIN); } + MULTI_OPPONENT_B(SPECIES_WYNAUT) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN {MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + TURN {MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + } THEN { + EXPECT_EQ(SPECIES_VENUSAUR, opponentLeft->species); + } +} + +AI_MULTI_BATTLE_TEST("AI opponents do not steal their partner pokemon in multi battle when forced out") +{ + u32 item, move; + PARAMETRIZE {item = ITEM_EJECT_BUTTON; move = MOVE_TACKLE;} + PARAMETRIZE {item = ITEM_EJECT_PACK; move = MOVE_TAIL_WHIP;} + PARAMETRIZE {item = ITEM_NONE; move = MOVE_ROAR;} + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(B_POSITION_OPPONENT_LEFT, AI_FLAG_ACE_POKEMON); + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PARTNER(SPECIES_WOBBUFFET) { } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); Item(item);} + MULTI_OPPONENT_A(SPECIES_VENUSAUR) { Moves(MOVE_GIGA_DRAIN); } + MULTI_OPPONENT_B(SPECIES_WYNAUT) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN {MOVE(playerLeft, move, target: opponentLeft); } + } THEN { + EXPECT_EQ(SPECIES_VENUSAUR, opponentLeft->species); + } +} + +AI_MULTI_BATTLE_TEST("AI opponents do not steal their partner pokemon in multi battle when forced out 2") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + BATTLER_AI_FLAGS(B_POSITION_OPPONENT_LEFT, AI_FLAG_ACE_POKEMON); + MULTI_PLAYER(SPECIES_WOBBUFFET) { } + MULTI_PARTNER(SPECIES_WOBBUFFET) { } + MULTI_OPPONENT_A(SPECIES_GOLISOPOD) { Moves(MOVE_CELEBRATE); HP(101); MaxHP(200); Ability(ABILITY_EMERGENCY_EXIT);} + MULTI_OPPONENT_A(SPECIES_VENUSAUR) { Moves(MOVE_GIGA_DRAIN); } + MULTI_OPPONENT_B(SPECIES_WYNAUT) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN {MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + } THEN { + EXPECT_EQ(SPECIES_VENUSAUR, opponentLeft->species); + } +} diff --git a/test/battle/ai/ai_smart_tera.c b/test/battle/ai/ai_smart_tera.c index 550ba7d2a1..7bed476b43 100644 --- a/test/battle/ai/ai_smart_tera.c +++ b/test/battle/ai/ai_smart_tera.c @@ -4,7 +4,6 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will tera if it enables a ko") { - KNOWN_FAILING; // Tests don't currently give the AI the capability to tera, even with a tera type set. GIVEN { ASSUME(GetMovePower(MOVE_SEED_BOMB) == 80); ASSUME(GetMovePower(MOVE_AQUA_TAIL) == 90); @@ -14,9 +13,9 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will tera if it enables a ko") OPPONENT(SPECIES_WOBBUFFET) { Speed(1); Moves(MOVE_AQUA_TAIL, MOVE_SEED_BOMB); TeraType(TYPE_GRASS); } OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); TeraType(TYPE_FIRE); } } WHEN { - TURN { EXPECT_MOVE(opponent, MOVE_SEED_BOMB); } + TURN { EXPECT_MOVE(opponent, MOVE_SEED_BOMB, gimmick: GIMMICK_TERA); SEND_OUT(player, 1); } } SCENE { - MESSAGE("The opposing Wobbuffet terastilized into the Grass type!"); + MESSAGE("The opposing Wobbuffet terastallized into the Grass type!"); MESSAGE("Wobbuffet fainted!"); } } @@ -34,7 +33,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will not tera if it gets outsped a } WHEN { TURN { } } SCENE { - NOT MESSAGE("The opposing Wobbuffet terastilized into the Grass type!"); + NOT MESSAGE("The opposing Wobbuffet terastallized into the Grass type!"); } } @@ -50,24 +49,23 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI will not tera if it gets ko'd by p } WHEN { TURN { } } SCENE { - NOT MESSAGE("The opposing Wobbuffet terastilized into the Grass type!"); + NOT MESSAGE("The opposing Wobbuffet terastallized into the Grass type!"); } } -// AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI might tera if it gets saved from a ko") -// { -// KNOWN_FAILING; // Tests don't currently give the AI the capability to tera, even with a tera type set. -// PASSES_RANDOMLY(90, 100, RNG_AI_CONSERVE_TERA); -// GIVEN { -// ASSUME(GetMovePower(MOVE_SEED_BOMB) == 80); -// AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_TERA | AI_FLAG_OMNISCIENT ); -// PLAYER(SPECIES_WOBBUFFET) { HP(47); Speed(100); Moves(MOVE_SEED_BOMB); } -// PLAYER(SPECIES_WOBBUFFET) { Speed(100); } -// OPPONENT(SPECIES_WOBBUFFET) { Speed(100); HP(30); Moves(MOVE_SEED_BOMB); TeraType(TYPE_FIRE); } -// OPPONENT(SPECIES_WOBBUFFET) { Speed(100); TeraType(TYPE_FIRE); } -// } WHEN { -// TURN { MOVE(player, MOVE_SEED_BOMB); } -// } SCENE { -// MESSAGE("The opposing Wobbuffet terastilized into the Fire type!"); -// } -// } \ No newline at end of file +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_TERA: AI might tera if it gets saved from a ko") +{ + PASSES_RANDOMLY(90, 100, RNG_AI_CONSERVE_TERA); + GIVEN { + ASSUME(GetMovePower(MOVE_SEED_BOMB) == 80); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_TERA | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET) { HP(47); Speed(100); Moves(MOVE_SEED_BOMB); } + PLAYER(SPECIES_WOBBUFFET) { Speed(100); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); HP(30); Moves(MOVE_SEED_BOMB); TeraType(TYPE_FIRE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); TeraType(TYPE_FIRE); } + } WHEN { + TURN { MOVE(player, MOVE_SEED_BOMB); } + } SCENE { + MESSAGE("The opposing Wobbuffet terastallized into the Fire type!"); + } +} diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index 947c9209c2..40a1d16778 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -91,6 +91,250 @@ AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same Pokémon for 2 spo } } +// Used to test EXPECT_SWITCH only on partner +AI_MULTI_BATTLE_TEST("AI partner will not switch mid-turn into a player Pokémon (multi)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_SWITCH(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SWITCH only on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner will not switch mid-turn into a player Pokémon (2v1)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_A(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_SWITCH(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " withdrew Gengar!"); + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SEND_OUT only on partner +AI_MULTI_BATTLE_TEST("AI partner will not switch into a player Pokémon after fainting (multi)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_GENGAR); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); HP(1); } + MULTI_PARTNER(SPECIES_GASTLY); + MULTI_PARTNER(SPECIES_HAUNTER); + MULTI_OPPONENT_A(SPECIES_TRAPINCH) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_VIBRAVA) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_MOVE(playerRight, MOVE_CELEBRATE); EXPECT_SEND_OUT(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Haunter!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SEND_OUT only on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner will not switch into a player Pokémon after fainting (2v1)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_GENGAR); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); HP(1); } + MULTI_PARTNER(SPECIES_GASTLY); + MULTI_PARTNER(SPECIES_HAUNTER); + MULTI_OPPONENT_A(SPECIES_TRAPINCH) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_A(SPECIES_VIBRAVA) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { EXPECT_MOVE(playerRight, MOVE_CELEBRATE); EXPECT_SEND_OUT(playerRight, 5); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Haunter!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SWITCH, EXPECT_SEND_OUT, and EXPECT_MOVE on partner +AI_MULTI_BATTLE_TEST("AI partner will not switch into a player Pokémon (multi)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); HP(1); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_B(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:playerRight); EXPECT_SWITCH(playerRight, 4); EXPECT_SEND_OUT(playerRight, 3); }; + TURN { EXPECT_MOVE(playerRight, MOVE_SHADOW_BALL, target:opponentLeft); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +// Used to test EXPECT_SWITCH, EXPECT_SEND_OUT, and EXPECT_MOVE on partner +AI_TWO_VS_ONE_BATTLE_TEST("AI partner will not switch into a player Pokémon (2v1)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_HAUNTER); + MULTI_PLAYER(SPECIES_RATTATA); + // No moves to damage opponents. + MULTI_PARTNER(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_PARTNER(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); HP(1); } + MULTI_OPPONENT_A(SPECIES_RATTATA) { Moves(MOVE_CELEBRATE); } + MULTI_OPPONENT_A(SPECIES_KANGASKHAN) { Moves(MOVE_CELEBRATE); } + + } WHEN { + TURN { MOVE(playerLeft, MOVE_AURA_SPHERE, target:playerRight); EXPECT_SWITCH(playerRight, 4); EXPECT_SEND_OUT(playerRight, 3); }; + TURN { EXPECT_MOVE(playerRight, MOVE_SHADOW_BALL, target:opponentLeft); }; + } SCENE { + MESSAGE(AI_PARTNER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_PARTNER_NAME " sent out Rattata!"); + } + } +} + +AI_TWO_VS_ONE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spots in a 2v1 battle (all bad moves)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_RATTATA); + MULTI_PLAYER(SPECIES_RATTATA); + MULTI_PARTNER(SPECIES_KANGASKHAN); + // No moves to damage player. + MULTI_OPPONENT_A(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_A(SPECIES_HAUNTER) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_A(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_OPPONENT_A(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + } WHEN { + TURN { EXPECT_SWITCH(opponentLeft, 3); }; + } SCENE { + MESSAGE(AI_TRAINER_NAME " withdrew Gengar!"); + MESSAGE(AI_TRAINER_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_TRAINER_NAME " withdrew Haunter!"); + MESSAGE(AI_TRAINER_NAME " sent out Raticate!"); + } + } +} + +AI_ONE_VS_TWO_BATTLE_TEST("AI will not switch into a partner Pokémon in a 1v2 battle (all bad moves)") +{ + u32 flags; + + PARAMETRIZE {flags = AI_FLAG_SMART_SWITCHING; } + PARAMETRIZE {flags = 0; } + + PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | flags); + MULTI_PLAYER(SPECIES_RATTATA); + MULTI_PLAYER(SPECIES_KANGASKHAN); + // No moves to damage player. + MULTI_OPPONENT_A(SPECIES_HAUNTER) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_B(SPECIES_GENGAR) { Moves(MOVE_SHADOW_BALL); } + MULTI_OPPONENT_B(SPECIES_GASTLY) { Moves(MOVE_LICK); } + MULTI_OPPONENT_B(SPECIES_RATICATE) { Moves(MOVE_HEADBUTT); } + + } WHEN { + TURN { EXPECT_SWITCH(opponentRight, 5); }; + } SCENE { + MESSAGE(AI_TRAINER_2_NAME " withdrew Gengar!"); + MESSAGE(AI_TRAINER_2_NAME " sent out Raticate!"); + NONE_OF { + MESSAGE(AI_TRAINER_NAME " withdrew Haunter!"); + MESSAGE(AI_TRAINER_NAME " sent out Raticate!"); + } + } +} + AI_SINGLE_BATTLE_TEST("AI will switch out if it has no move that affects the player") { PASSES_RANDOMLY(SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE, 100, RNG_AI_SWITCH_ALL_MOVES_BAD); @@ -115,7 +359,7 @@ AI_SINGLE_BATTLE_TEST("When AI switches out due to having no move that affects t OPPONENT(SPECIES_ABRA) { Moves(MOVE_TACKLE); } OPPONENT(SPECIES_ABRA) { Moves(MOVE_TACKLE); } } WHEN { - TURN { MOVE(player, MOVE_SHADOW_BALL); EXPECT_SWITCH(opponent, 2); EXPECT_SEND_OUT(opponent, 4); } + TURN { MOVE(player, MOVE_SHADOW_BALL); EXPECT_SWITCH(opponent, 2); EXPECT_SEND_OUT(opponent, 0);} TURN { MOVE(player, MOVE_SHADOW_BALL); EXPECT_MOVE(opponent, MOVE_TACKLE); } } } @@ -771,15 +1015,15 @@ AI_DOUBLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee } } -AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is semi-invulnerable and it has an absorber") +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is semi-invulnerable and it has a good switchin") { PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN); GIVEN { ASSUME(GetMoveType(MOVE_DIVE) == TYPE_WATER); - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); - PLAYER(SPECIES_LUVDISC) { Moves(MOVE_DIVE); } + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_LUVDISC) { Level(1); Moves(MOVE_DIVE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SCRATCH); } - OPPONENT(SPECIES_MANTINE) { Moves(MOVE_SCRATCH); Ability(ABILITY_WATER_ABSORB); } + OPPONENT(SPECIES_PIKACHU) { Moves(MOVE_THUNDERBOLT); } } WHEN { TURN { MOVE(player, MOVE_DIVE) ; EXPECT_MOVE(opponent, MOVE_SCRATCH); } TURN { SKIP_TURN(player); EXPECT_SWITCH(opponent, 1); } @@ -833,7 +1077,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is charging and it has a good switchin immunity (ability)") { - PASSES_RANDOMLY(SHOULD_SWITCH_FREE_TURN_PERCENTAGE, 100, RNG_AI_SWITCH_FREE_TURN); + PASSES_RANDOMLY(SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE, 100, RNG_AI_SWITCH_ABSORBING); GIVEN { ASSUME(GetMoveType(MOVE_DIG) == TYPE_GROUND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); @@ -848,7 +1092,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an absorber") { - u32 aiMon; u32 move; u32 absorbingAbility; + u32 aiMon; u32 move; + enum Ability absorbingAbility; PARAMETRIZE { aiMon = SPECIES_NINETALES; absorbingAbility = ABILITY_FLASH_FIRE; move = MOVE_FLAMETHROWER;} PARAMETRIZE { aiMon = SPECIES_MANTINE; absorbingAbility = ABILITY_WATER_ABSORB; move = MOVE_SURF;} PARAMETRIZE { aiMon = SPECIES_TOXICROAK; absorbingAbility = ABILITY_DRY_SKIN; move = MOVE_SURF;} @@ -1327,7 +1572,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI sees Echoed Voice damage co AI_SINGLE_BATTLE_TEST("AI_SMART_MON_CHOICES: AI sees its own weather setting ability when considering switchin candidates") { - u32 ability = ABILITY_NONE; + enum Ability ability = ABILITY_NONE; PARAMETRIZE { ability = ABILITY_WATER_ABSORB; } PARAMETRIZE { ability = ABILITY_DRIZZLE; } GIVEN { diff --git a/test/battle/ai/can_use_all_moves.c b/test/battle/ai/can_use_all_moves.c index efae2b7544..4b464d9745 100644 --- a/test/battle/ai/can_use_all_moves.c +++ b/test/battle/ai/can_use_all_moves.c @@ -314,7 +314,6 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 301-400") case EFFECT_COPYCAT: case EFFECT_LAST_RESORT: case EFFECT_AQUA_RING: - case EFFECT_GRAVITY: case EFFECT_HEALING_WISH: //TODO: AI TESTS @@ -328,6 +327,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 301-400") case EFFECT_MAGNET_RISE: // tests exist elsewhere + case EFFECT_GRAVITY: case EFFECT_HEAL_BELL: case EFFECT_ATTACK_UP_USER_ALLY: @@ -458,7 +458,6 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 501-600") case EFFECT_ION_DELUGE: case EFFECT_AROMATIC_MIST: case EFFECT_POWDER: - case EFFECT_FLOWER_SHIELD: case EFFECT_ELECTRIFY: //TODO: AI TESTS @@ -469,6 +468,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 501-600") case EFFECT_FAIRY_LOCK: // tests exist elsewhere + case EFFECT_FLOWER_SHIELD: case EFFECT_ROTOTILLER: case EFFECT_GRASSY_TERRAIN: case EFFECT_MISTY_TERRAIN: @@ -524,8 +524,6 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 601-700") switch (effect) { //TODO: AI HANDLING - case EFFECT_MAGNETIC_FLUX: - case EFFECT_GEAR_UP: case EFFECT_FAIL_IF_NOT_ARG_TYPE: case EFFECT_STUFF_CHEEKS: case EFFECT_NO_RETREAT: @@ -544,7 +542,9 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 601-700") case EFFECT_ELECTRIC_TERRAIN: case EFFECT_PSYCHIC_TERRAIN: case EFFECT_AURORA_VEIL: - + case EFFECT_GEAR_UP: + case EFFECT_MAGNETIC_FLUX: + // Skipped on purpose. case EFFECT_PROTECT: case EFFECT_NON_VOLATILE_STATUS: @@ -597,7 +597,6 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 701-800") { //TODO: AI HANDLING case EFFECT_CLANGOROUS_SOUL: - case EFFECT_LIFE_DEW: case EFFECT_POLTERGEIST: case EFFECT_COACHING: case EFFECT_REVIVAL_BLESSING: @@ -613,6 +612,7 @@ AI_DOUBLE_BATTLE_TEST("AI can use all moves, 701-800") // tests exist elsewhere case EFFECT_COURT_CHANGE: case EFFECT_DOODLE: + case EFFECT_LIFE_DEW: // Skipped on purpose. case EFFECT_PROTECT: diff --git a/test/battle/ai/check_bad_move.c b/test/battle/ai/check_bad_move.c index 776dcd7de2..ab6241dcbe 100644 --- a/test/battle/ai/check_bad_move.c +++ b/test/battle/ai/check_bad_move.c @@ -4,7 +4,8 @@ AI_SINGLE_BATTLE_TEST("AI will not try to lower opposing stats if target is protected by it's ability") { - u16 ability, species, move; + enum Ability ability; + u32 species, move; PARAMETRIZE { ability = ABILITY_SPEED_BOOST; species = SPECIES_TORCHIC; move = MOVE_SCARY_FACE; } PARAMETRIZE { ability = ABILITY_HYPER_CUTTER; species = SPECIES_KRABBY; move = MOVE_GROWL; } diff --git a/test/battle/ai/gimmick_dynamax.c b/test/battle/ai/gimmick_dynamax.c new file mode 100644 index 0000000000..99e6157c94 --- /dev/null +++ b/test/battle/ai/gimmick_dynamax.c @@ -0,0 +1,65 @@ +#include "global.h" +#include "test/battle.h" +#include "battle_ai_util.h" + +AI_SINGLE_BATTLE_TEST("AI uses Dynamax") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SCRATCH); DynamaxLevel(10); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_SCRATCH, gimmick: GIMMICK_DYNAMAX); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Dynamax -- Max Moves are scored based on max move effects, not base effects") +{ + KNOWN_FAILING; + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SCRATCH, MOVE_EXPLOSION); DynamaxLevel(10); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_EXPLOSION, gimmick: GIMMICK_DYNAMAX); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Dynamax -- AI does not dynamax before using a utility move") +{ + KNOWN_FAILING; + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_FAKE_OUT); DynamaxLevel(10); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_FAKE_OUT, gimmick: GIMMICK_NONE); } + } +} + +AI_TWO_VS_ONE_BATTLE_TEST("AI only Dynamaxes once per trainer in 2v1 multi battles") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + MULTI_PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_SPLASH); } + MULTI_PARTNER(SPECIES_WOBBUFFET) { Moves(MOVE_SPLASH); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(MOVE_SPLASH); DynamaxLevel(10); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(MOVE_SPLASH); DynamaxLevel(10); } + } WHEN { + TURN { + MOVE(playerLeft, MOVE_SPLASH); + MOVE(playerRight, MOVE_SPLASH); + EXPECT_MOVE(opponentLeft, MOVE_SPLASH, gimmick: GIMMICK_DYNAMAX); + EXPECT_MOVE(opponentRight, MOVE_SPLASH, gimmick: GIMMICK_NONE); + } + TURN { + MOVE(playerLeft, MOVE_SPLASH); + MOVE(playerRight, MOVE_SPLASH); + EXPECT_MOVE(opponentLeft, MOVE_SPLASH, gimmick: GIMMICK_NONE); + EXPECT_MOVE(opponentRight, MOVE_SPLASH, gimmick: GIMMICK_NONE); + } + } +} + +// Copycatting an ally's Max Guard rendition of Trick Room was a notable strategy. +TO_DO_BATTLE_TEST("TODO: AI uses Dynamax -- AI uses Copycat against a Dynamaxed Pokemon intelligently") diff --git a/test/battle/ai/gimmick_mega.c b/test/battle/ai/gimmick_mega.c new file mode 100644 index 0000000000..ef94223122 --- /dev/null +++ b/test/battle/ai/gimmick_mega.c @@ -0,0 +1,19 @@ +#include "global.h" +#include "test/battle.h" +#include "battle_ai_util.h" + +AI_SINGLE_BATTLE_TEST("AI uses Mega Evolution") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VENUSAUR) { Item(ITEM_VENUSAURITE); Moves(MOVE_SLUDGE_BOMB); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_SLUDGE_BOMB, gimmick: GIMMICK_MEGA); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent); + } THEN { + EXPECT_EQ(opponent->species, SPECIES_VENUSAUR_MEGA); + } +} + diff --git a/test/battle/ai/gimmick_z_move.c b/test/battle/ai/gimmick_z_move.c new file mode 100644 index 0000000000..fcc8d81658 --- /dev/null +++ b/test/battle/ai/gimmick_z_move.c @@ -0,0 +1,201 @@ +#include "global.h" +#include "test/battle.h" +#include "battle_ai_util.h" +#include "constants/battle_z_move_effects.h" + +AI_SINGLE_BATTLE_TEST("AI uses Z-moves.") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_QUICK_ATTACK); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); } + } +} + +AI_SINGLE_BATTLE_TEST("AI does not use damaging Z-moves if the player would faint anyway.") +{ + u32 currentHP; + PARAMETRIZE { currentHP = 1; } + PARAMETRIZE { currentHP = 500; } + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL); + PLAYER(SPECIES_WOBBUFFET) { HP(currentHP); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_QUICK_ATTACK); } + } WHEN { + if (currentHP != 1) + TURN { EXPECT_MOVE(opponent, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); } + else + TURN { EXPECT_MOVE(opponent, MOVE_QUICK_ATTACK, gimmick: GIMMICK_NONE); } + } +} +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Extreme Evoboost") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_EEVEE) { Item(ITEM_EEVIUM_Z); Moves(MOVE_POUND, MOVE_LAST_RESORT); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_LAST_RESORT, gimmick: GIMMICK_Z_MOVE); } + TURN { EXPECT_MOVE(opponent, MOVE_POUND, gimmick: GIMMICK_NONE); + SCORE_LT_VAL(opponent, MOVE_LAST_RESORT, AI_SCORE_DEFAULT); } + TURN { EXPECT_MOVE(opponent, MOVE_LAST_RESORT, gimmick: GIMMICK_NONE); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- 10,000,000 Volt Thunderbolt") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PIKACHU_PARTNER) { Item(ITEM_PIKASHUNIUM_Z); Moves(MOVE_THUNDERBOLT); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_THUNDERBOLT, gimmick: GIMMICK_Z_MOVE); } + } +} +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Z-Conversion") +{ + enum Ability ability; + PARAMETRIZE { ability = ABILITY_NONE; } + PARAMETRIZE { ability = ABILITY_OPPORTUNIST; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + ASSUME(GetMoveType(MOVE_CONVERSION) == TYPE_NORMAL); + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Ability(ABILITY_ADAPTABILITY); Moves(MOVE_THUNDERBOLT, MOVE_CONVERSION); } + } WHEN { + if (ability == ABILITY_OPPORTUNIST) + TURN { EXPECT_MOVE(opponent, MOVE_CONVERSION, gimmick: GIMMICK_NONE); } + else + TURN { EXPECT_MOVE(opponent, MOVE_CONVERSION, gimmick: GIMMICK_Z_MOVE); } + } +} + + +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Z-Destiny Bond is not used in singles") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_GHOSTIUM_Z); Moves(MOVE_DESTINY_BOND); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_DESTINY_BOND, gimmick: GIMMICK_NONE); } + } +} + +AI_DOUBLE_BATTLE_TEST("AI uses Z-Moves -- Z-Destiny Bond is used when about to die") +{ + u32 currentHP; + PARAMETRIZE { currentHP = 1; } + PARAMETRIZE { currentHP = 500; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_POUND); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(currentHP); Item(ITEM_GHOSTIUM_Z); Moves(MOVE_DESTINY_BOND); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (currentHP == 1) + TURN { EXPECT_MOVE(opponentLeft, MOVE_DESTINY_BOND, gimmick: GIMMICK_Z_MOVE); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_DESTINY_BOND, gimmick: GIMMICK_NONE); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Z-Detect") +{ + u32 move; + PARAMETRIZE { move = MOVE_THUNDERBOLT; } + PARAMETRIZE { move = MOVE_CLOSE_COMBAT; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT | AI_FLAG_PREDICT_MOVE ); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_FAKE_OUT); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_FIGHTINIUM_Z); Moves(MOVE_DETECT, move); } + } WHEN { + if (move == MOVE_CLOSE_COMBAT) + TURN { EXPECT_MOVE(opponent, MOVE_DETECT, gimmick: GIMMICK_NONE); } + else + TURN { EXPECT_MOVE(opponent, MOVE_DETECT, gimmick: GIMMICK_Z_MOVE); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Z-Happy Hour") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_POUND, MOVE_HAPPY_HOUR); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_HAPPY_HOUR, gimmick: GIMMICK_Z_MOVE); + SCORE_GT_VAL(opponent, MOVE_HAPPY_HOUR, AI_SCORE_DEFAULT); } + TURN { EXPECT_MOVE(opponent, MOVE_POUND, gimmick: GIMMICK_NONE); + SCORE_EQ_VAL(opponent, MOVE_HAPPY_HOUR, 90); } + } +} + +TO_DO_BATTLE_TEST("TODO: AI uses Z-Moves -- Z-Haze") + +TO_DO_BATTLE_TEST("TODO: AI uses Z-Moves -- Z-Mirror Move") + +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Z-Nature Power") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT | AI_FLAG_PREDICT_MOVE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_NATURE_POWER, MOVE_HEADBUTT); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_NATURE_POWER, gimmick: GIMMICK_Z_MOVE); } + } +} + +// Requires handling for Wish passing/Healing Wish/other ways to determine what pokemon to heal via switching into. +TO_DO_BATTLE_TEST("TODO: AI uses Z-Moves -- Z-Parting Shot") + +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Z-Splash") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_POUND, MOVE_SPLASH); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_SPLASH, gimmick: GIMMICK_Z_MOVE); + SCORE_GT_VAL(opponent, MOVE_SPLASH, AI_SCORE_DEFAULT); } + TURN { EXPECT_MOVE(opponent, MOVE_POUND, gimmick: GIMMICK_NONE); + SCORE_EQ_VAL(opponent, MOVE_SPLASH, 90); } + } +} + +TO_DO_BATTLE_TEST("TODO: AI uses Z-Moves -- Z-Tailwind") + +AI_SINGLE_BATTLE_TEST("AI uses Z-Moves -- Z-Transform") +{ + u32 currentHP, move; + PARAMETRIZE { currentHP = 1; move = MOVE_HEADBUTT; } + PARAMETRIZE { currentHP = 1; move = MOVE_THUNDERBOLT; } + PARAMETRIZE { currentHP = 500; move = MOVE_HEADBUTT; } + PARAMETRIZE { currentHP = 500; move = MOVE_THUNDERBOLT; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT ); + PLAYER(SPECIES_WOBBUFFET) { Moves(move, MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET) { HP(currentHP); Item(ITEM_NORMALIUM_Z); Moves(MOVE_TRANSFORM); } + } WHEN { + if (currentHP == 1 || move == MOVE_THUNDERBOLT) + TURN { EXPECT_MOVE(opponent, MOVE_TRANSFORM, gimmick: GIMMICK_Z_MOVE); } + else + TURN { EXPECT_MOVE(opponent, MOVE_TRANSFORM, gimmick: GIMMICK_NONE); } + } +} + +TO_DO_BATTLE_TEST("TODO: AI uses Z-Moves -- Z-Trick Room") + + diff --git a/test/battle/damage_formula.c b/test/battle/damage_formula.c index ded8cbdde2..7a38ae516d 100644 --- a/test/battle/damage_formula.c +++ b/test/battle/damage_formula.c @@ -119,7 +119,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Marshadow vs Mawile)") } } -DOUBLE_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move") +DOUBLE_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (double battle)") { s16 damage[6]; GIVEN { @@ -153,6 +153,108 @@ DOUBLE_BATTLE_TEST("A spread move will do correct damage to the second mon if th } } +MULTI_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (multibattle)") +{ + s16 damage[6]; + GIVEN { + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_PARTNER(SPECIES_REGIROCK); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(200); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); MOVE(playerRight, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + HP_BAR(opponentRight, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + HP_BAR(opponentRight, captureDamage: &damage[3]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[4]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentRight, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_EQ(damage[1], damage[3]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(0.75), damage[3]); + EXPECT_EQ(damage[4], damage[5]); + } +} + +TWO_VS_ONE_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (2v1)") +{ + s16 damage[6]; + GIVEN { + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_PARTNER(SPECIES_REGIROCK); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(200); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); MOVE(playerRight, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + HP_BAR(opponentRight, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + HP_BAR(opponentRight, captureDamage: &damage[3]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[4]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentRight, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_EQ(damage[1], damage[3]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(0.75), damage[3]); + EXPECT_EQ(damage[4], damage[5]); + } +} + +ONE_VS_TWO_BATTLE_TEST("A spread move will do correct damage to the second mon if the first target faints from first hit of the spread move (1v2)") +{ + s16 damage[6]; + GIVEN { + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_PLAYER(SPECIES_REGIROCK); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(200); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); MOVE(playerRight, MOVE_ROCK_SLIDE); } + TURN { MOVE(playerLeft, MOVE_ROCK_SLIDE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + HP_BAR(opponentRight, captureDamage: &damage[1]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); + HP_BAR(opponentRight, captureDamage: &damage[3]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[4]); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROCK_SLIDE, playerLeft); + HP_BAR(opponentRight, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_EQ(damage[1], damage[3]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(0.75), damage[3]); + EXPECT_EQ(damage[4], damage[5]); + } +} + SINGLE_BATTLE_TEST("Punching Glove vs Muscle Band Damage calculation") { s16 dmgPlayer, dmgOpponent; diff --git a/test/battle/end_turn_effects.c b/test/battle/end_turn_effects.c index 01c844f9b5..931f792efe 100644 --- a/test/battle/end_turn_effects.c +++ b/test/battle/end_turn_effects.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -DOUBLE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly") +DOUBLE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (double battle)") { s16 healed; s16 damage; @@ -53,3 +53,89 @@ DOUBLE_BATTLE_TEST("End Turn Effects: Effects are applied by Speed Order") HP_BAR(playerRight); } } + +MULTI_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (multibattle)") +{ + s16 healed; + s16 damage; + + GIVEN { + MULTI_PLAYER(SPECIES_WYNAUT) { HP(100); Speed(1); } + MULTI_PARTNER(SPECIES_EKANS) { HP(100); Ability(ABILITY_SHED_SKIN); Status1(STATUS1_BURN); Speed(2); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(100); Item(ITEM_LEFTOVERS); Speed(3); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { HP(100); Item(ITEM_BLACK_SLUDGE); Speed(4); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_GRASSY_TERRAIN); } + } SCENE { + MESSAGE("The opposing Wobbuffet is healed by the grassy terrain!"); + HP_BAR(opponentRight, captureDamage: &healed); + HP_BAR(opponentRight, captureDamage: &damage); + MESSAGE("The opposing Wobbuffet was hurt by the Black Sludge!"); + MESSAGE("The opposing Wynaut is healed by the grassy terrain!"); + MESSAGE("The opposing Wynaut restored a little HP using its Leftovers!"); + MESSAGE("Ekans is healed by the grassy terrain!"); + MESSAGE("Ekans's Shed Skin cured its burn problem!"); + MESSAGE("Wynaut is healed by the grassy terrain!"); + } THEN { + EXPECT_GT(0, healed); + EXPECT_GT(damage, 0); + } +} + + +TWO_VS_ONE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (2v1)") +{ + s16 healed; + s16 damage; + + GIVEN { + MULTI_PLAYER(SPECIES_WYNAUT) { HP(100); Speed(1);} + MULTI_PARTNER(SPECIES_EKANS) { HP(100); Ability(ABILITY_SHED_SKIN); Status1(STATUS1_BURN); Speed(2); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(100); Item(ITEM_LEFTOVERS); Speed(3); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(100); Item(ITEM_BLACK_SLUDGE); Speed(4); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_GRASSY_TERRAIN); } + } SCENE { + MESSAGE("The opposing Wobbuffet is healed by the grassy terrain!"); + HP_BAR(opponentRight, captureDamage: &healed); + HP_BAR(opponentRight, captureDamage: &damage); + MESSAGE("The opposing Wobbuffet was hurt by the Black Sludge!"); + MESSAGE("The opposing Wynaut is healed by the grassy terrain!"); + MESSAGE("The opposing Wynaut restored a little HP using its Leftovers!"); + MESSAGE("Ekans is healed by the grassy terrain!"); + MESSAGE("Ekans's Shed Skin cured its burn problem!"); + MESSAGE("Wynaut is healed by the grassy terrain!"); + } THEN { + EXPECT_GT(0, healed); + EXPECT_GT(damage, 0); + } +} + + +ONE_VS_TWO_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly (1v2)") +{ + s16 healed; + s16 damage; + + GIVEN { + MULTI_PLAYER(SPECIES_WYNAUT) { HP(100); Speed(1);} + MULTI_PLAYER(SPECIES_EKANS) { HP(100); Ability(ABILITY_SHED_SKIN); Status1(STATUS1_BURN); Speed(2); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(100); Item(ITEM_LEFTOVERS); Speed(3); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { HP(100); Item(ITEM_BLACK_SLUDGE); Speed(4); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_GRASSY_TERRAIN); } + } SCENE { + MESSAGE("The opposing Wobbuffet is healed by the grassy terrain!"); + HP_BAR(opponentRight, captureDamage: &healed); + HP_BAR(opponentRight, captureDamage: &damage); + MESSAGE("The opposing Wobbuffet was hurt by the Black Sludge!"); + MESSAGE("The opposing Wynaut is healed by the grassy terrain!"); + MESSAGE("The opposing Wynaut restored a little HP using its Leftovers!"); + MESSAGE("Ekans is healed by the grassy terrain!"); + MESSAGE("Ekans's Shed Skin cured its burn problem!"); + MESSAGE("Wynaut is healed by the grassy terrain!"); + } THEN { + EXPECT_GT(0, healed); + EXPECT_GT(damage, 0); + } +} diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index c27e305c1c..3374935707 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -239,8 +239,8 @@ SINGLE_BATTLE_TEST("Dynamax: Dynamaxed Pokemon are affected by Grudge") } SCENE { MESSAGE("The opposing Wobbuffet used Grudge!"); MESSAGE("Wobbuffet used Max Strike!"); - MESSAGE("Wobbuffet's Scratch lost all its PP due to the grudge!"); MESSAGE("The opposing Wobbuffet fainted!"); + MESSAGE("Wobbuffet's Scratch lost all its PP due to the grudge!"); } } @@ -913,7 +913,7 @@ SINGLE_BATTLE_TEST("Dynamax: Max Mindstorm sets up Psychic Terrain") } SCENE { MESSAGE("The opposing Wobbuffet used Extreme Speed!"); MESSAGE("Wobbuffet used Max Mindstorm!"); - MESSAGE("The opposing Wobbuffet cannot use Extreme Speed!"); + MESSAGE("Wobbuffet is protected by the Psychic Terrain!"); MESSAGE("Wobbuffet used Max Mindstorm!"); } } @@ -1609,7 +1609,8 @@ SINGLE_BATTLE_TEST("Dynamax: Max Attacks prints a message when hitting into Max SINGLE_BATTLE_TEST("Dynamax: Max Moves don't bypass absorbing abilities") { - u32 move, ability, species; + u32 move, species; + enum Ability ability; PARAMETRIZE { move = MOVE_SPARK; ability = ABILITY_VOLT_ABSORB; species = SPECIES_LANTURN; } PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_WATER_ABSORB; species = SPECIES_LANTURN; } PARAMETRIZE { move = MOVE_EMBER; ability = ABILITY_FLASH_FIRE; species = SPECIES_HEATRAN; } @@ -1659,19 +1660,6 @@ SINGLE_BATTLE_TEST("Dynamax: Dynamax is reverted before switch out") } } -SINGLE_BATTLE_TEST("Dynamax: Destiny Bond fails if a dynamaxed battler is present on field") -{ - GIVEN { - ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, MOVE_DESTINY_BOND); MOVE(player, MOVE_SCRATCH, gimmick: GIMMICK_DYNAMAX); } - } SCENE { - MESSAGE("The move was blocked by the power of Dynamax!"); - } -} - SINGLE_BATTLE_TEST("Dynamax: max move against semi-invulnerable target prints the correct message") { GIVEN { diff --git a/test/battle/gimmick/terastal.c b/test/battle/gimmick/terastal.c index d238ea0d51..bb9e3ce5bc 100644 --- a/test/battle/gimmick/terastal.c +++ b/test/battle/gimmick/terastal.c @@ -826,7 +826,7 @@ SINGLE_BATTLE_TEST("(TERA) Pokemon with Tera forms change upon Terastallizing") SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly") { - u32 type; + enum Type type; PARAMETRIZE { type = TYPE_NONE; } PARAMETRIZE { type = TYPE_NORMAL; } PARAMETRIZE { type = TYPE_FIGHTING; } @@ -858,7 +858,7 @@ SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly") SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly - Opponent") { - u32 type; + enum Type type; PARAMETRIZE { type = TYPE_NONE; } PARAMETRIZE { type = TYPE_NORMAL; } PARAMETRIZE { type = TYPE_FIGHTING; } diff --git a/test/battle/gimmick/zmove.c b/test/battle/gimmick/zmove.c index 52e111520a..e5244a3e6a 100644 --- a/test/battle/gimmick/zmove.c +++ b/test/battle/gimmick/zmove.c @@ -585,7 +585,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Extreme Evoboost boosts all the user's stats by two SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain") { GIVEN { - ASSUME(GetMoveEffect(MOVE_GENESIS_SUPERNOVA) == EFFECT_HIT_SET_TERRAIN); + ASSUME(MoveHasAdditionalEffect(MOVE_GENESIS_SUPERNOVA, MOVE_EFFECT_PSYCHIC_TERRAIN)); PLAYER(SPECIES_MEW) { Item(ITEM_MEWNIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -595,7 +595,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ZMOVE_ACTIVATE, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_GENESIS_SUPERNOVA, player); NOT { ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player); } - MESSAGE("Mew cannot use Quick Attack!"); + MESSAGE("The opposing Wobbuffet is protected by the Psychic Terrain!"); } } diff --git a/test/battle/hazards.c b/test/battle/hazards.c index 17ecb41f5c..ea0aef70e5 100644 --- a/test/battle/hazards.c +++ b/test/battle/hazards.c @@ -61,3 +61,113 @@ SINGLE_BATTLE_TEST("Hazards are applied correctly after a battler faints") MESSAGE("Pointed stones dug into Wynaut!"); } } + +SINGLE_BATTLE_TEST("Toxic Spikes can be removed after fainting to other hazards") +{ + KNOWN_FAILING; // tryfaintmon changes something that doesn't allow other switch-in effects on the battler + + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_GRIMER) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } + TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); } + TURN { MOVE(opponent, MOVE_STICKY_WEB); } + TURN { MOVE(opponent, MOVE_SPIKES); } + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); SWITCH(player, 1); SEND_OUT(player, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent); + MESSAGE("Pointed stones dug into Grimer!"); + MESSAGE("Grimer fainted!"); + MESSAGE("The poison spikes disappeared from the ground around your team!"); + NONE_OF { + MESSAGE("Grimer was caught in a sticky web!"); + MESSAGE("Grimer was hurt by the spikes!"); + } + } THEN { + EXPECT_EQ(gBattleStruct->hazardsQueue[0][0], HAZARDS_STEALTH_ROCK); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][1], HAZARDS_STICKY_WEB); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][2], HAZARDS_SPIKES); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][3], HAZARDS_NONE); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][4], HAZARDS_NONE); + EXPECT_EQ(gBattleStruct->hazardsQueue[0][5], HAZARDS_NONE); + } +} + +SINGLE_BATTLE_TEST("Hazards can trigger Emergency Exit and other hazards don't activate") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_GOLISOPOD) { HP(105); MaxHP(200); Ability(ABILITY_EMERGENCY_EXIT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } + TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); } + TURN { MOVE(opponent, MOVE_STICKY_WEB); } + TURN { MOVE(opponent, MOVE_SPIKES); } + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); SWITCH(player, 1); SEND_OUT(player, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent); + MESSAGE("Pointed stones dug into Golisopod!"); + ABILITY_POPUP(player, ABILITY_EMERGENCY_EXIT); + NONE_OF { + MESSAGE("Golisopod was poisoned!"); + MESSAGE("Golisopod was caught in a sticky web!"); + MESSAGE("Golisopod was hurt by the spikes!"); + } + MESSAGE("Pointed stones dug into Wobbuffet!"); + MESSAGE("Wobbuffet was poisoned!"); + MESSAGE("Wobbuffet was caught in a sticky web!"); + MESSAGE("Wobbuffet was hurt by the spikes!"); + NOT MESSAGE("Pointed stones dug into Wobbuffet!"); // Because the previous switch in effects instruction is still kept + } +} + +DOUBLE_BATTLE_TEST("Hazards can trigger Emergency Exit and hazards still activate for other battlers") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_FINAL_GAMBIT) == EFFECT_FINAL_GAMBIT); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_GOLISOPOD) { HP(105); MaxHP(200); Ability(ABILITY_EMERGENCY_EXIT); } + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_STEALTH_ROCK); MOVE(opponentRight, MOVE_TOXIC_SPIKES); } + TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); MOVE(opponentRight, MOVE_SPIKES); } + TURN { MOVE(playerLeft, MOVE_FINAL_GAMBIT, target: opponentRight); + MOVE(playerRight, MOVE_FINAL_GAMBIT, target: opponentRight); + SEND_OUT(playerLeft, 2); + SEND_OUT(playerRight, 3); + SEND_OUT(playerLeft, 4); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponentRight); + MESSAGE("Pointed stones dug into Golisopod!"); + ABILITY_POPUP(playerLeft, ABILITY_EMERGENCY_EXIT); + NONE_OF { + MESSAGE("Golisopod was poisoned!"); + MESSAGE("Golisopod was caught in a sticky web!"); + MESSAGE("Golisopod was hurt by the spikes!"); + } + MESSAGE("Pointed stones dug into Wobbuffet!"); + MESSAGE("Wobbuffet was poisoned!"); + MESSAGE("Wobbuffet was caught in a sticky web!"); + MESSAGE("Wobbuffet was hurt by the spikes!"); + MESSAGE("Pointed stones dug into Wynaut!"); + MESSAGE("Wynaut was poisoned!"); + MESSAGE("Wynaut was caught in a sticky web!"); + MESSAGE("Wynaut was hurt by the spikes!"); + } +} diff --git a/test/battle/hold_effect/berserk_gene.c b/test/battle/hold_effect/berserk_gene.c index 35e79bcaf4..c7b9ba0933 100644 --- a/test/battle/hold_effect/berserk_gene.c +++ b/test/battle/hold_effect/berserk_gene.c @@ -294,6 +294,7 @@ SINGLE_BATTLE_TEST("Berserker Gene confusion can be healed with used held items" OPPONENT(SPECIES_WOBBUFFET) { Item(item);}; } WHEN { TURN { MOVE(player, MOVE_COVET, WITH_RNG(RNG_CONFUSION, FALSE)); } + TURN {} } SCENE { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, player); diff --git a/test/battle/hold_effect/booster_energy.c b/test/battle/hold_effect/booster_energy.c index 696dbbb579..5e7fdbcfa8 100644 --- a/test/battle/hold_effect/booster_energy.c +++ b/test/battle/hold_effect/booster_energy.c @@ -157,7 +157,7 @@ SINGLE_BATTLE_TEST("Booster Energy activates Quark Drive and increases highest s SINGLE_BATTLE_TEST("Booster Energy's Quark Drive boost is preserved when terrain changes") { GIVEN { - PLAYER(SPECIES_IRON_MOTH) { Attack(110); Defense(100); Speed(100); SpAttack(100); SpDefense(100); Ability(ABILITY_QUARK_DRIVE); Item(ITEM_BOOSTER_ENERGY); } + PLAYER(SPECIES_IRON_MOTH) { Attack(110); Defense(100); Speed(100); SpAttack(100); SpDefense(100); Ability(ABILITY_QUARK_DRIVE); Item(ITEM_BOOSTER_ENERGY); Moves(MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_GRASSY_TERRAIN, MOVE_CELEBRATE); } } WHEN { TURN { MOVE(opponent, MOVE_GRASSY_TERRAIN); } @@ -180,7 +180,7 @@ SINGLE_BATTLE_TEST("Booster Energy's Quark Drive boost is preserved when terrain SINGLE_BATTLE_TEST("Booster Energy increases special attack by 30% if it is the highest stat", s16 damage) { u32 species; - u32 ability; + enum Ability ability; u32 item; PARAMETRIZE { species = SPECIES_RAGING_BOLT; ability = ABILITY_PROTOSYNTHESIS; item = ITEM_NONE; } @@ -206,7 +206,7 @@ SINGLE_BATTLE_TEST("Booster Energy increases special attack by 30% if it is the SINGLE_BATTLE_TEST("Booster Energy increases special defense by 30% if it is the highest stat", s16 damage) { u32 species; - u32 ability; + enum Ability ability; u32 item; PARAMETRIZE { species = SPECIES_RAGING_BOLT; ability = ABILITY_PROTOSYNTHESIS; item = ITEM_NONE; } diff --git a/test/battle/hold_effect/cure_status.c b/test/battle/hold_effect/cure_status.c index 0fa0f7ba07..dabf44e085 100644 --- a/test/battle/hold_effect/cure_status.c +++ b/test/battle/hold_effect/cure_status.c @@ -87,7 +87,7 @@ SINGLE_BATTLE_TEST("Aspear and Lum Berries cure freeze or frostbite") TURN { MOVE(player, MOVE_ICE_PUNCH); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_PUNCH, player); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + ANIMATION(ANIM_TYPE_STATUS, (B_USE_FROSTBITE ? B_ANIM_STATUS_FRB : B_ANIM_STATUS_FRZ), opponent); FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); FREEZE_OR_FROSTBURN_STATUS(opponent, FALSE); diff --git a/test/battle/hold_effect/kee_berry.c b/test/battle/hold_effect/kee_berry.c index c63da86841..d37a132be4 100644 --- a/test/battle/hold_effect/kee_berry.c +++ b/test/battle/hold_effect/kee_berry.c @@ -89,3 +89,19 @@ DOUBLE_BATTLE_TEST("Kee Berry doesn't trigger if partner was hit") EXPECT(opponentRight->item == ITEM_KEE_BERRY); } } + +SINGLE_BATTLE_TEST("Kee Berry doesn't trigger if the move was boosted by Sheer Force") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_KEE_BERRY); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + HP_BAR(player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + } +} \ No newline at end of file diff --git a/test/battle/hold_effect/maranga_berry.c b/test/battle/hold_effect/maranga_berry.c index 22b72ba201..785e040ca4 100644 --- a/test/battle/hold_effect/maranga_berry.c +++ b/test/battle/hold_effect/maranga_berry.c @@ -89,3 +89,19 @@ DOUBLE_BATTLE_TEST("Maranga Berry doesn't trigger if partner was hit") EXPECT(opponentRight->item == ITEM_MARANGA_BERRY); } } + +SINGLE_BATTLE_TEST("Maranga Berry doesn't trigger if the move was boosted by Sheer Force") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MARANGA_BERRY); } + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_FIRE_PUNCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_PUNCH, opponent); + HP_BAR(player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/hold_effect/protective_pads.c b/test/battle/hold_effect/protective_pads.c index e04f30ac9b..6f8d068d06 100644 --- a/test/battle/hold_effect/protective_pads.c +++ b/test/battle/hold_effect/protective_pads.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Protective Pads protected moves still make direct contact", s16 damage) { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_KLUTZ; } PARAMETRIZE { ability = ABILITY_FLUFFY; } GIVEN { diff --git a/test/battle/hold_effect/restore_hp.c b/test/battle/hold_effect/restore_hp.c index 9db149c023..ef96ead7e4 100644 --- a/test/battle/hold_effect/restore_hp.c +++ b/test/battle/hold_effect/restore_hp.c @@ -63,20 +63,3 @@ DOUBLE_BATTLE_TEST("Restore HP Item effects do not miss timing after a recoil mo ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight); } } - -#if B_HP_BERRIES <= GEN_3 -SINGLE_BATTLE_TEST("Restore HP Berry triggers only during the end turn") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT) { MaxHP(100); HP(51); Item(ITEM_ORAN_BERRY); } - } WHEN { - TURN { MOVE(player, MOVE_TACKLE); } - TURN {} - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); - } -} -#endif diff --git a/test/battle/hold_effect/restore_stats.c b/test/battle/hold_effect/restore_stats.c index f2508c45ee..4a8f020023 100644 --- a/test/battle/hold_effect/restore_stats.c +++ b/test/battle/hold_effect/restore_stats.c @@ -55,10 +55,10 @@ DOUBLE_BATTLE_TEST("White Herb restores stats after Attack was lowered by Intimi ABILITY_POPUP(playerLeft, ABILITY_INTIMIDATE); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft); MESSAGE("The opposing Wobbuffet returned its stats to normal using its White Herb!"); - - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentRight); MESSAGE("The opposing Wynaut returned its stats to normal using its White Herb!"); } THEN { @@ -97,7 +97,7 @@ SINGLE_BATTLE_TEST("White Herb restores stats after Attack was lowered by Intimi SINGLE_BATTLE_TEST("White Herb restores stats after all hits of a multi hit move happened") { u16 species; - u16 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_SLIGGOO_HISUI; ability = ABILITY_GOOEY; } PARAMETRIZE { species = SPECIES_DUGTRIO_ALOLA; ability = ABILITY_TANGLING_HAIR; } @@ -143,7 +143,7 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if it is knocked off o ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Slugma's Weak Armor lowered its Defense!"); - MESSAGE("Slugma's Weak Armor raised its Speed!"); + MESSAGE("Slugma's Weak Armor sharply raised its Speed!"); if (move == MOVE_KNOCK_OFF) { MESSAGE("The opposing Wobbuffet knocked off Slugma's White Herb!"); } else if (move == MOVE_THIEF) { @@ -171,7 +171,7 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if Magician steals it" ABILITY_POPUP(player, ABILITY_WEAK_ARMOR); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Slugma's Weak Armor lowered its Defense!"); - MESSAGE("Slugma's Weak Armor raised its Speed!"); + MESSAGE("Slugma's Weak Armor sharply raised its Speed!"); ABILITY_POPUP(opponent, ABILITY_MAGICIAN); MESSAGE("The opposing Fennekin stole Slugma's White Herb!"); NONE_OF { @@ -187,7 +187,7 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if Magician steals it" SINGLE_BATTLE_TEST("White Herb has correct interactions with Intimidate triggered Defiant and Competitive") { u16 species; - u16 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_IGGLYBUFF; ability = ABILITY_COMPETITIVE; } PARAMETRIZE { species = SPECIES_MANKEY; ability = ABILITY_DEFIANT; } diff --git a/test/battle/hold_effect/seeds.c b/test/battle/hold_effect/seeds.c index 53cca3c211..b54dd54f5b 100644 --- a/test/battle/hold_effect/seeds.c +++ b/test/battle/hold_effect/seeds.c @@ -1,22 +1,23 @@ #include "global.h" #include "test/battle.h" -ASSUMPTIONS +ASSUMPTIONS { - ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN); - ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_GRASSY_TERRAIN); - ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_MISTY_TERRAIN); - ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffect == HOLD_EFFECT_TERRAIN_SEED); ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN); } SINGLE_BATTLE_TEST("Electric Seed raises the holder's Defense on Electric Terrain") { - u32 ability, item; + enum Ability ability; + u32 item; PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_NONE; } PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_ELECTRIC_SEED; } PARAMETRIZE { ability = ABILITY_ELECTRIC_SURGE; item = ITEM_NONE; } @@ -47,7 +48,8 @@ SINGLE_BATTLE_TEST("Electric Seed raises the holder's Defense on Electric Terrai SINGLE_BATTLE_TEST("Grassy Seed raises the holder's Defense on Grassy Terrain") { - u32 ability, item; + enum Ability ability; + u32 item; PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_NONE; } PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_GRASSY_SEED; } PARAMETRIZE { ability = ABILITY_GRASSY_SURGE; item = ITEM_NONE; } @@ -78,7 +80,8 @@ SINGLE_BATTLE_TEST("Grassy Seed raises the holder's Defense on Grassy Terrain") SINGLE_BATTLE_TEST("Misty Seed raises the holder's Sp. Defense on Misty Terrain") { - u32 ability, item; + enum Ability ability; + u32 item; PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_NONE; } PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_MISTY_SEED; } PARAMETRIZE { ability = ABILITY_MISTY_SURGE; item = ITEM_NONE; } @@ -109,7 +112,8 @@ SINGLE_BATTLE_TEST("Misty Seed raises the holder's Sp. Defense on Misty Terrain" SINGLE_BATTLE_TEST("Psychic Seed raises the holder's Sp. Defense on Psychic Terrain") { - u32 ability, item; + enum Ability ability; + u32 item; PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_NONE; } PARAMETRIZE { ability = ABILITY_TELEPATHY; item = ITEM_PSYCHIC_SEED; } PARAMETRIZE { ability = ABILITY_PSYCHIC_SURGE; item = ITEM_NONE; } @@ -140,7 +144,8 @@ SINGLE_BATTLE_TEST("Psychic Seed raises the holder's Sp. Defense on Psychic Terr SINGLE_BATTLE_TEST("Seeds get consumed in Terrain even if holder is not affected by Terrain") { - u32 species, ability, item; + u32 species, item; + enum Ability ability; PARAMETRIZE { species = SPECIES_TAPU_KOKO; ability = ABILITY_ELECTRIC_SURGE; item = ITEM_ELECTRIC_SEED; } PARAMETRIZE { species = SPECIES_TAPU_BULU; ability = ABILITY_GRASSY_SURGE; item = ITEM_GRASSY_SEED; } PARAMETRIZE { species = SPECIES_TAPU_FINI; ability = ABILITY_MISTY_SURGE; item = ITEM_MISTY_SEED; } diff --git a/test/battle/hold_effect/sticky_barb.c b/test/battle/hold_effect/sticky_barb.c new file mode 100644 index 0000000000..59c1e12270 --- /dev/null +++ b/test/battle/hold_effect/sticky_barb.c @@ -0,0 +1,51 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetItemHoldEffect(ITEM_STICKY_BARB) == HOLD_EFFECT_STICKY_BARB); +} + +SINGLE_BATTLE_TEST("Sticky Barb hurts its holder at the end of the turn") +{ + s16 damage; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_STICKY_BARB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { } + } SCENE { + HP_BAR(player, captureDamage: &damage); + } THEN { + EXPECT_EQ(damage, player->maxHP / 8); + } +} + +SINGLE_BATTLE_TEST("Sticky Barb gets transferred if its holder is hit by a contact move") +{ + u32 move; + PARAMETRIZE { move = MOVE_SCRATCH; } + PARAMETRIZE { move = MOVE_GROWL; } + PARAMETRIZE { move = MOVE_HYPER_VOICE; } + GIVEN { + ASSUME(MoveMakesContact(MOVE_SCRATCH)); + ASSUME(!MoveMakesContact(MOVE_GROWL)); + ASSUME(!MoveMakesContact(MOVE_HYPER_VOICE)); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_STICKY_BARB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + if (MoveMakesContact(move)) + { + MESSAGE("The Sticky Barb attached itself to the opposing Wobbuffet!"); + MESSAGE("The opposing Wobbuffet was hurt by the Sticky Barb!"); + } + else + { + NOT MESSAGE("The Sticky Barb attached itself to the opposing Wobbuffet!"); + MESSAGE("Wobbuffet was hurt by the Sticky Barb!"); + } + } +} diff --git a/test/battle/hold_effect/weakness_berry.c b/test/battle/hold_effect/weakness_berry.c index 17adb08aa3..4958c67811 100644 --- a/test/battle/hold_effect/weakness_berry.c +++ b/test/battle/hold_effect/weakness_berry.c @@ -25,7 +25,8 @@ static const u16 sMoveItemTable[][4] = SINGLE_BATTLE_TEST("Weakness berries decrease the base power of moves by half", s16 damage) { - u32 move = 0, item = 0, type = 0, defender = 0; + u32 move = 0, item = 0, defender = 0; + enum Type type = TYPE_NONE; for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++) { @@ -62,7 +63,8 @@ SINGLE_BATTLE_TEST("Weakness berries decrease the base power of moves by half", SINGLE_BATTLE_TEST("Weakness berries do not activate unless a move is super effective", s16 damage) { - u32 move = 0, item = 0, type = 0, defender = 0; + u32 move = 0, item = 0, defender = 0; + enum Type type = TYPE_NONE; for (u32 j = 0; j < ARRAY_COUNT(sMoveItemTable); j++) { diff --git a/test/battle/move.c b/test/battle/move.c index f69c7b2eb4..3efab260a7 100644 --- a/test/battle/move.c +++ b/test/battle/move.c @@ -212,6 +212,50 @@ DOUBLE_BATTLE_TEST("Moves fail if they target the partner but they faint before } } +MULTI_BATTLE_TEST("Ally switch fails when used by either side in a multibattle") +{ + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_PARTNER(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_ALLY_SWITCH); MOVE(opponentRight, MOVE_ALLY_SWITCH); } + } SCENE { + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerRight); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight); } + } +} + +TWO_VS_ONE_BATTLE_TEST("Ally switch can only be used by the opponent in a 2v1 battle") +{ + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_PARTNER(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(playerRight, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_ALLY_SWITCH); } + } SCENE { + { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentLeft); } + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerRight); } + } +} + +ONE_VS_TWO_BATTLE_TEST("Ally switch can only be used by the player in a 1v2 battle") +{ + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_PLAYER(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_B(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); MOVE(opponentLeft, MOVE_ALLY_SWITCH); MOVE(opponentRight, MOVE_ALLY_SWITCH); } + } SCENE { + { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, playerLeft); } + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight); } + } +} + DOUBLE_BATTLE_TEST("Moves do not fail if an alive partner is the target") { GIVEN { diff --git a/test/battle/move_animations/all_anims.c b/test/battle/move_animations/all_anims.c index e69eb59750..87e6babf25 100644 --- a/test/battle/move_animations/all_anims.c +++ b/test/battle/move_animations/all_anims.c @@ -9,7 +9,7 @@ #define ANIM_TEST_END_MOVE MOVES_COUNT-1 // Last move to test -static void ParametrizeMovesAndSpecies(u32 j, u32 *pMove, u32 *pSpecies) +static void ParametrizeMovesAndSpecies(u32 j, u32 *pMove, u32 *pSpecies, u32 variation) { enum BattleMoveEffects effect = GetMoveEffect(j); if (effect == EFFECT_DARK_VOID) // User needs to be Darkrai @@ -59,6 +59,75 @@ static void ParametrizeMovesAndSpecies(u32 j, u32 *pMove, u32 *pSpecies) } } +static u32 ParametrizeFriendship(u32 move, u32 variation) +{ + if (gMovesInfo[move].effect == EFFECT_FRUSTRATION + || gMovesInfo[move].effect == EFFECT_RETURN + ) + { + if (variation == 0) + return 1; + else if (variation == 1) + return 61; + else if (variation == 2) + return 101; + else if (variation == 3) + return 201; + } + return 0; +} + +static u32 GetParametrizedHP(u32 move, u32 variation) +{ + if (gMovesInfo[move].effect == EFFECT_POWER_BASED_ON_USER_HP && variation > 0) + { + if (variation == 1) + return 6000; + else if (variation == 2) + return 4000; + else if (variation == 3) + return 2000; + } + return 9997; +} + +static u32 GetParametrizedItem(u32 move, u32 variation) +{ + if ((move == MOVE_TECHNO_BLAST) && variation > 0) + { + if (variation == 1) + return ITEM_DOUSE_DRIVE; + else if (variation == 2) + return ITEM_SHOCK_DRIVE; + else if (variation == 3) + return ITEM_BURN_DRIVE; + else if (variation == 4) + return ITEM_CHILL_DRIVE; + } + return ITEM_ORAN_BERRY; +} + +static u32 GetParametrizedLevel(u32 move, u32 variation) +{ + if (gMovesInfo[move].effect == EFFECT_LEVEL_DAMAGE && variation > 0) + { + if (variation == 1) + return 50; + else if (variation == 2) + return 20; + } + return 100; +} + +static bool32 GetParametrizedShinyness(u32 move, u32 variation) +{ + if ((gMovesInfo[move].effect == EFFECT_DRAGON_DARTS && variation == 2) + || (move == MOVE_SYRUP_BOMB && variation == 1) + ) + return TRUE; + return FALSE; +} + static bool32 TargetHasToMove(u32 move) // Opponent needs to hit the player first { enum BattleMoveEffects effect = GetMoveEffect(move); @@ -108,7 +177,37 @@ static bool32 UserHasToGoFirst(u32 move) // Player needs to go first return FALSE; } -static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattlePokemon *defender) +static u32 GetVariationsNumber(u32 move, bool8 isDouble) +{ + u32 variationsNumber; + + if (gMovesInfo[move].effect == EFFECT_WEATHER_BALL + || gMovesInfo[move].effect == EFFECT_TERRAIN_PULSE + || move == MOVE_TECHNO_BLAST) + variationsNumber = 5; + else if (gMovesInfo[move].effect == EFFECT_FRUSTRATION + || gMovesInfo[move].effect == EFFECT_RETURN + || gMovesInfo[move].effect == EFFECT_IVY_CUDGEL + || move == MOVE_WATER_SPOUT) //we don't use the effect because other moves with the water spout effect don't have animation variations + variationsNumber = 4; + else if (gMovesInfo[move].effect == EFFECT_SPIT_UP + || gMovesInfo[move].effect == EFFECT_SWALLOW + || gMovesInfo[move].effect == EFFECT_DRAGON_DARTS + || move == MOVE_SEISMIC_TOSS) + variationsNumber = 3; + else if (gMovesInfo[move].effect == EFFECT_CURSE + || gMovesInfo[move].effect == EFFECT_PRESENT + || gMovesInfo[move].effect == EFFECT_SHELL_SIDE_ARM + || gMovesInfo[move].effect == EFFECT_FICKLE_BEAM + || gMovesInfo[move].effect == EFFECT_MAGNITUDE + || (isDouble && gMovesInfo[move].effect == EFFECT_TERA_STARSTORM) + || move == MOVE_SYRUP_BOMB) + variationsNumber = 2; + else + variationsNumber = 1; + return variationsNumber; +} +static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 variation) { enum BattleMoveEffects effect = GetMoveEffect(move); // Setup turn @@ -120,7 +219,10 @@ static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattleP else if (effect == EFFECT_SPIT_UP || effect == EFFECT_SWALLOW) { // attacker needs to have used Stockpile - TURN { MOVE(attacker, MOVE_STOCKPILE); } + for (u32 i = 0; i <= variation; i++) + { + TURN { MOVE(attacker, MOVE_STOCKPILE); } + } } else if ((effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS && GetMoveEffectArg_Status(move) == STATUS1_PARALYSIS)) { // defender needs to be paralyzed @@ -162,6 +264,32 @@ static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattleP { // Needs a terrain TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } } + else if (gMovesInfo[move].effect == EFFECT_WEATHER_BALL && variation > 0) + { + if (variation == 1) + TURN { MOVE(attacker, MOVE_SUNNY_DAY); } + else if (variation == 2) + TURN { MOVE(attacker, MOVE_RAIN_DANCE); } + else if (variation == 3) + TURN { MOVE(attacker, MOVE_SANDSTORM); } + else + TURN { MOVE(attacker, MOVE_HAIL); } + } + else if (gMovesInfo[move].effect == EFFECT_TERRAIN_PULSE && variation > 0) + { + if (variation == 1) + TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } + else if (variation == 2) + TURN { MOVE(attacker, MOVE_GRASSY_TERRAIN); } + else if (variation == 3) + TURN { MOVE(attacker, MOVE_PSYCHIC_TERRAIN); } + else if (variation == 4) + TURN { MOVE(attacker, MOVE_MISTY_TERRAIN); } + } + else if (gBattleMoveEffects[gMovesInfo[move].effect].twoTurnEffect) + { + TURN { MOVE(attacker, move); } + } // Effective turn TURN { if (TargetHasToMove(move)) @@ -203,12 +331,62 @@ static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattleP { MOVE(attacker, move, target: attacker); } + else if (gBattleMoveEffects[gMovesInfo[move].effect].twoTurnEffect) + { + MOVE(defender, MOVE_HELPING_HAND); + SKIP_TURN(attacker); + } + else if (gMovesInfo[move].effect == EFFECT_PRESENT) + { + if (variation == 0) + MOVE(attacker, move, WITH_RNG(RNG_PRESENT, 1)); + else if (variation == 1) + MOVE(attacker, move, WITH_RNG(RNG_PRESENT, 254)); + } + else if (gMovesInfo[move].effect == EFFECT_MAGNITUDE) + { + if (variation == 0) + MOVE(attacker, move, WITH_RNG(RNG_MAGNITUDE, 50)); + else if (variation == 1) + MOVE(attacker, move, WITH_RNG(RNG_MAGNITUDE, 99)); + } + else if (gMovesInfo[move].effect == EFFECT_FICKLE_BEAM) + { + if (variation == 0) + MOVE(attacker, move, WITH_RNG(RNG_FICKLE_BEAM, FALSE)); + else if (variation == 1) + MOVE(attacker, move, WITH_RNG(RNG_FICKLE_BEAM, TRUE)); + } + else if (gMovesInfo[move].effect == EFFECT_SHELL_SIDE_ARM) + { + if (variation == 0) + MOVE(attacker, move, WITH_RNG(RNG_SHELL_SIDE_ARM, FALSE)); + else if (variation == 1) + MOVE(attacker, move, WITH_RNG(RNG_SHELL_SIDE_ARM, TRUE)); + } else { // All other moves MOVE(defender, MOVE_HELPING_HAND); // Helping Hand, so there's no anim on the defender's side. MOVE(attacker, move); } } + if (gMovesInfo[move].effect == EFFECT_WISH) + { + TURN {}; + } + else if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN {}; + TURN {}; + } + else if (gMovesInfo[move].effect == EFFECT_ROLLOUT) + { + TURN {MOVE(attacker, move);}; + TURN {MOVE(attacker, move);}; + TURN {MOVE(attacker, move);}; + TURN {MOVE(attacker, move);}; + TURN {MOVE(attacker, MOVE_HELPING_HAND);}; + } } static void SceneSingles(u32 move, struct BattlePokemon *mon) @@ -239,7 +417,7 @@ static void SceneSingles(u32 move, struct BattlePokemon *mon) } } -static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattlePokemon *target, struct BattlePokemon *ignore1, struct BattlePokemon *ignore2) +static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattlePokemon *target, struct BattlePokemon *ignore1, struct BattlePokemon *ignore2, u32 variation) { enum BattleMoveEffects effect = GetMoveEffect(move); // Setup turn @@ -251,7 +429,10 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP else if (effect == EFFECT_SPIT_UP || effect == EFFECT_SWALLOW) { // Player needs to have used Stockpile - TURN { MOVE(attacker, MOVE_STOCKPILE); } + for (u32 i = 0; i <= variation; i++) + { + TURN { MOVE(attacker, MOVE_STOCKPILE); } + } } else if ((effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS && GetMoveEffectArg_Status(move) == STATUS1_PARALYSIS)) { // Opponent needs to be paralyzed @@ -293,6 +474,32 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP { // Needs a terrain TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } } + else if (gMovesInfo[move].effect == EFFECT_WEATHER_BALL && variation > 0) + { + if (variation == 1) + TURN { MOVE(attacker, MOVE_SUNNY_DAY); } + else if (variation == 2) + TURN { MOVE(attacker, MOVE_RAIN_DANCE); } + else if (variation == 3) + TURN { MOVE(attacker, MOVE_SANDSTORM); } + else + TURN { MOVE(attacker, MOVE_HAIL); } + } + else if (gMovesInfo[move].effect == EFFECT_TERRAIN_PULSE && variation > 0) + { + if (variation == 1) + TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } + else if (variation == 2) + TURN { MOVE(attacker, MOVE_GRASSY_TERRAIN); } + else if (variation == 3) + TURN { MOVE(attacker, MOVE_PSYCHIC_TERRAIN); } + else if (variation == 4) + TURN { MOVE(attacker, MOVE_MISTY_TERRAIN); } + } + else if (gBattleMoveEffects[gMovesInfo[move].effect].twoTurnEffect) + { + TURN { MOVE(attacker, move, target: target); } + } // Effective turn TURN { if (TargetHasToMove(move)) @@ -337,6 +544,39 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP MOVE(attacker, move, target: target); MOVE(target, MOVE_QUICK_ATTACK, target: attacker); } + else if (gBattleMoveEffects[gMovesInfo[move].effect].twoTurnEffect) + { + MOVE(target, MOVE_LAST_RESORT, target: attacker); + SKIP_TURN(attacker); + } + else if (gMovesInfo[move].effect == EFFECT_PRESENT) + { + if (variation == 0) + MOVE(attacker, move, target: target, WITH_RNG(RNG_PRESENT, 1)); + else if (variation == 1) + MOVE(attacker, move, target: target, WITH_RNG(RNG_PRESENT, 254)); + } + else if (gMovesInfo[move].effect == EFFECT_MAGNITUDE) + { + if (variation == 0) + MOVE(attacker, move, WITH_RNG(RNG_MAGNITUDE, 50)); + else if (variation == 1) + MOVE(attacker, move, WITH_RNG(RNG_MAGNITUDE, 99)); + } + else if (gMovesInfo[move].effect == EFFECT_FICKLE_BEAM) + { + if (variation == 0) + MOVE(attacker, move, target: target, WITH_RNG(RNG_FICKLE_BEAM, FALSE)); + else if (variation == 1) + MOVE(attacker, move, target: target, WITH_RNG(RNG_FICKLE_BEAM, TRUE)); + } + else if (gMovesInfo[move].effect == EFFECT_SHELL_SIDE_ARM) + { + if (variation == 0) + MOVE(attacker, move, target: target, WITH_RNG(RNG_SHELL_SIDE_ARM, FALSE)); + else if (variation == 1) + MOVE(attacker, move, target: target, WITH_RNG(RNG_SHELL_SIDE_ARM, TRUE)); + } else { // All other moves MOVE(target, MOVE_LAST_RESORT, target: attacker); // Last Resort, so there's no anim on the opponent's side. @@ -349,6 +589,23 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP MOVE(ignore2, MOVE_CELEBRATE); } } + if (gMovesInfo[move].effect == EFFECT_WISH) + { + TURN {}; + } + else if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN {}; + TURN {}; + } + else if (gMovesInfo[move].effect == EFFECT_ROLLOUT) + { + TURN {MOVE(attacker, move, target: target);}; + TURN {MOVE(attacker, move, target: target);}; + TURN {MOVE(attacker, move, target: target);}; + TURN {MOVE(attacker, move, target: target);}; + TURN {MOVE(attacker, MOVE_LAST_RESORT, target: attacker);}; + } } static void DoublesScene(u32 move, struct BattlePokemon *attacker) @@ -380,18 +637,27 @@ static void DoublesScene(u32 move, struct BattlePokemon *attacker) SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (player to opponent)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, FALSE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND); @@ -404,7 +670,7 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (player to op } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - WhenSingles(move, player, opponent); + WhenSingles(move, player, opponent, variation); } SCENE { SceneSingles(move, player); } THEN { @@ -419,18 +685,27 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (player to op SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (opponent to player)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, FALSE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND); @@ -443,7 +718,7 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (opponent to } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - WhenSingles(move, opponent, player); + WhenSingles(move, opponent, player, variation); } SCENE { SceneSingles(move, opponent); } THEN { @@ -458,6 +733,8 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (opponent to DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft to opponentLeft)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = playerLeft; @@ -465,25 +742,35 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t struct BattlePokemon *ignore1 = playerRight; struct BattlePokemon *ignore2 = opponentRight; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(SPECIES_WOBBUFFET) { @@ -502,7 +789,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -517,6 +804,8 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft to playerLeft)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = opponentLeft; @@ -524,24 +813,34 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft struct BattlePokemon *ignore1 = opponentRight; struct BattlePokemon *ignore2 = playerRight; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(SPECIES_WOBBUFFET) { @@ -562,7 +861,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -577,6 +876,8 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft to opponentRight)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = playerLeft; @@ -584,24 +885,34 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t struct BattlePokemon *ignore1 = playerRight; struct BattlePokemon *ignore2 = opponentLeft; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(SPECIES_WOBBUFFET) { @@ -622,7 +933,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -637,6 +948,8 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRight to playerLeft)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = opponentRight; @@ -644,24 +957,34 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh struct BattlePokemon *ignore1 = opponentLeft; struct BattlePokemon *ignore2 = playerRight; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(SPECIES_WOBBUFFET) { @@ -682,7 +1005,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -697,6 +1020,8 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight to opponentLeft)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = playerRight; @@ -704,24 +1029,34 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight struct BattlePokemon *ignore1 = playerLeft; struct BattlePokemon *ignore2 = opponentRight; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(SPECIES_WOBBUFFET) { @@ -742,7 +1077,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -757,6 +1092,8 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft to playerRight)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = opponentLeft; @@ -764,24 +1101,34 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft struct BattlePokemon *ignore1 = playerLeft; struct BattlePokemon *ignore2 = opponentRight; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(SPECIES_WOBBUFFET) { @@ -802,7 +1149,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -817,6 +1164,8 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight to opponentRight)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = playerRight; @@ -824,24 +1173,34 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight struct BattlePokemon *ignore1 = playerLeft; struct BattlePokemon *ignore2 = opponentLeft; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } PLAYER(SPECIES_WOBBUFFET) { @@ -862,7 +1221,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -877,6 +1236,8 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRight to playerRight)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); struct BattlePokemon *attacker = opponentRight; @@ -884,24 +1245,34 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh struct BattlePokemon *ignore1 = playerLeft; struct BattlePokemon *ignore2 = opponentLeft; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, TRUE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } } OPPONENT(SPECIES_WOBBUFFET) { @@ -922,7 +1293,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - DoublesWhen(move, attacker, target, ignore1, ignore2); + DoublesWhen(move, attacker, target, ignore1, ignore2, variation); } SCENE { DoublesScene(move, attacker); } THEN { @@ -945,7 +1316,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t struct BattlePokemon *ignore1 = opponentRight; struct BattlePokemon *ignore2 = opponentLeft; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, 0); PARAMETRIZE { move = tempMove; species = tempSpecies; } } GIVEN { @@ -1004,7 +1375,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight struct BattlePokemon *ignore1 = opponentRight; struct BattlePokemon *ignore2 = opponentLeft; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, 0); PARAMETRIZE { move = tempMove; species = tempSpecies; } } GIVEN { @@ -1063,7 +1434,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentleft struct BattlePokemon *ignore1 = playerLeft; struct BattlePokemon *ignore2 = playerRight; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, 0); PARAMETRIZE { move = tempMove; species = tempSpecies; } } GIVEN { @@ -1122,7 +1493,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh struct BattlePokemon *ignore1 = playerLeft; struct BattlePokemon *ignore2 = playerRight; for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, 0); PARAMETRIZE { move = tempMove; species = tempSpecies; } } GIVEN { @@ -1175,18 +1546,27 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh SINGLE_BATTLE_TEST("Move Animations occur before their stat change animations - Singles (player to opponent)") { u32 j = ANIM_TEST_START_MOVE, move = 0, species = 0; + u32 k = 0, variation = 0, variationsNumber; + u32 friendship = 0, tempFriendship; u32 tempMove, tempSpecies; FORCE_MOVE_ANIM(TRUE); for (; j <= ANIM_TEST_END_MOVE; j++) { - ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies); - PARAMETRIZE { move = tempMove; species = tempSpecies; } + variationsNumber = GetVariationsNumber(j, FALSE); + for (k = 0; k < variationsNumber; k++) { + ParametrizeMovesAndSpecies(j, &tempMove, &tempSpecies, k); + tempFriendship = ParametrizeFriendship(j, k); + PARAMETRIZE { move = tempMove; species = tempSpecies; variation = k; friendship = tempFriendship;} + } } GIVEN { PLAYER(species) { - HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); + Level(GetParametrizedLevel(move, variation)); + HP(GetParametrizedHP(move, variation)); MaxHP(9999); Item(GetParametrizedItem(move, variation)); if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); + if (friendship) Friendship(friendship); + if (GetParametrizedShinyness(move, variation)) Shiny(TRUE); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND); @@ -1199,7 +1579,7 @@ SINGLE_BATTLE_TEST("Move Animations occur before their stat change animations - } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { - WhenSingles(move, player, opponent); + WhenSingles(move, player, opponent, variation); } SCENE { if (!(GetMoveEffect(move) == EFFECT_RECYCLE || GetMoveEffect(move) == EFFECT_BELCH diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index 8300c7b9c8..8862c49cff 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -92,7 +92,7 @@ DOUBLE_BATTLE_TEST("Ally Switch does not redirect the target of Snipe Shot") DOUBLE_BATTLE_TEST("Ally Switch does not redirect moves done by Pokémon with Stalwart and Propeller Tail") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_STALWART; } PARAMETRIZE { ability = ABILITY_PROPELLER_TAIL; } PARAMETRIZE { ability = ABILITY_TELEPATHY; } diff --git a/test/battle/move_effect/aurora_veil.c b/test/battle/move_effect/aurora_veil.c index b57c85df06..1b480ad1ed 100644 --- a/test/battle/move_effect/aurora_veil.c +++ b/test/battle/move_effect/aurora_veil.c @@ -25,6 +25,35 @@ SINGLE_BATTLE_TEST("Aurora Veil can only be used in Hail and Snow") } } +SINGLE_BATTLE_TEST("Aurora Veil will prevent Protean activation if it fails due to no Snow/Hail") +{ + GIVEN { + PLAYER(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_AURORA_VEIL); } + } SCENE { + MESSAGE("But it failed!"); + NOT ABILITY_POPUP(player, ABILITY_PROTEAN); + } +} + +SINGLE_BATTLE_TEST("Aurora Veil wont prevent Protean activation when it fails due to being set up already") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SNOWSCAPE); MOVE(player, MOVE_AURORA_VEIL); } + TURN { SWITCH(player, 1); } + TURN { MOVE(player, MOVE_AURORA_VEIL); } + } SCENE { + ABILITY_POPUP(player, ABILITY_PROTEAN); + MESSAGE("But it failed!"); + } +} + TO_DO_BATTLE_TEST("Aurora Veil reduces damage done to the user by half in singles") TO_DO_BATTLE_TEST("Aurora Veil reduces damage done to the user by roughly a third in doubles") TO_DO_BATTLE_TEST("Aurora Veil's damage reduction is ignored by Critical Hits") diff --git a/test/battle/move_effect/charge.c b/test/battle/move_effect/charge.c index 35f491254d..48b77d8bdc 100644 --- a/test/battle/move_effect/charge.c +++ b/test/battle/move_effect/charge.c @@ -75,7 +75,8 @@ SINGLE_BATTLE_TEST("Charge's effect is removed if the user fails using an Electr SINGLE_BATTLE_TEST("Charge's effect does not stack with Electromorphosis or Wind Power") { - u32 species, ability; + u32 species; + enum Ability ability; s16 damage[2]; PARAMETRIZE { species = SPECIES_WATTREL; ability = ABILITY_WIND_POWER; } @@ -130,7 +131,7 @@ SINGLE_BATTLE_TEST("Charge's effect is removed regardless if the next move is El } } -SINGLE_BATTLE_TEST("Charge will not expire if it flinches twice in a row") +SINGLE_BATTLE_TEST("Charge will expire if user flinches while using an electric move") { s16 damage[2]; GIVEN { @@ -150,9 +151,6 @@ SINGLE_BATTLE_TEST("Charge will not expire if it flinches twice in a row") ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player); HP_BAR(opponent, captureDamage: &damage[1]); } THEN { - if (B_CHARGE < GEN_9) - EXPECT_EQ(damage[0], damage[1]); - else - EXPECT_MUL_EQ(damage[0], Q_4_12(2.0), damage[1]); + EXPECT_EQ(damage[0], damage[1]); } } diff --git a/test/battle/move_effect/clangorous_soul.c b/test/battle/move_effect/clangorous_soul.c index 17e57d7dd5..a1a7ffa42a 100644 --- a/test/battle/move_effect/clangorous_soul.c +++ b/test/battle/move_effect/clangorous_soul.c @@ -1,11 +1,52 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Attack by 1 stage"); -TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Defense by 1 stage"); -TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Sp. Attack by 1 stage"); -TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Sp. Defense by 1 stage"); -TO_DO_BATTLE_TEST("Clangorous Soul raises the user's Speed by 1 stage"); -TO_DO_BATTLE_TEST("Clangorous Soul cuts the user's HP by 1/3"); +SINGLE_BATTLE_TEST("Clangorous Soul cuts the user's HP by 1/3") +{ + s16 dmg; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(300); MaxHP(300); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CLANGOROUS_SOUL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CLANGOROUS_SOUL, player); + HP_BAR(player, captureDamage: &dmg); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } THEN { + EXPECT_EQ(gBattleMons[0].maxHP / 3, dmg); + } +} + +SINGLE_BATTLE_TEST("Clangorous Soul raises the user's Atk, Def, Sp. Atk. Sp. Def and Speed by 1 stage") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(300); MaxHP(300); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CLANGOROUS_SOUL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CLANGOROUS_SOUL, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); + } +} + +SINGLE_BATTLE_TEST("Clangorous Soul fails if the user's HP is less or equal than 1/3") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(100); MaxHP(300); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CLANGOROUS_SOUL); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CLANGOROUS_SOUL, player); + } +} + TO_DO_BATTLE_TEST("Clangorous Soul fails if Attack, Defense, Sp. Attack, Sp. Defense and Speed are all maxed out"); -TO_DO_BATTLE_TEST("Clangorous Soul fails if the user's HP is less or equal than 1/3"); diff --git a/test/battle/move_effect/coaching.c b/test/battle/move_effect/coaching.c index 7245f8854b..642727de51 100644 --- a/test/battle/move_effect/coaching.c +++ b/test/battle/move_effect/coaching.c @@ -117,3 +117,23 @@ DOUBLE_BATTLE_TEST("Coaching fails if there's no ally") MESSAGE("But it failed!"); } } + +AI_DOUBLE_BATTLE_TEST("AI uses Coaching") +{ + u32 move; + PARAMETRIZE { move = MOVE_HEADBUTT; } + PARAMETRIZE { move = MOVE_DAZZLING_GLEAM; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_COACHING, MOVE_POUND); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(move); } + } WHEN { + if (move == MOVE_HEADBUTT) + TURN { EXPECT_MOVE(opponentLeft, MOVE_COACHING); } + else + TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_COACHING); } + } +} diff --git a/test/battle/move_effect/copycat.c b/test/battle/move_effect/copycat.c index da9e085ede..34f3551676 100644 --- a/test/battle/move_effect/copycat.c +++ b/test/battle/move_effect/copycat.c @@ -21,6 +21,27 @@ TO_DO_BATTLE_TEST("Copycat ignores the recharging turn of recharging moves (Gen TO_DO_BATTLE_TEST("Copycat can copy Bide on all turns"); TO_DO_BATTLE_TEST("Copycat copies moves called by other calling moves instead of the calling move (Gen 5+)"); +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_COPYCAT) == EFFECT_COPYCAT); +} + +SINGLE_BATTLE_TEST("Copycat deducts power points from itself, not the copied move") +{ + ASSUME(GetMovePP(MOVE_COPYCAT) == 20); + ASSUME(GetMovePP(MOVE_POUND) == 35); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_COPYCAT); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_POUND); } + } WHEN { + TURN { MOVE(opponent, MOVE_POUND); MOVE(player, MOVE_COPYCAT); } + } SCENE { + } THEN { + EXPECT_EQ(opponent->pp[0], 34); + EXPECT_EQ(player->pp[0], 19); + } +} + DOUBLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their base moves copied by Copycat") { GIVEN { diff --git a/test/battle/move_effect/destiny_bond.c b/test/battle/move_effect/destiny_bond.c index ddebc6bb1f..17cf658772 100644 --- a/test/battle/move_effect/destiny_bond.c +++ b/test/battle/move_effect/destiny_bond.c @@ -10,12 +10,18 @@ SINGLE_BATTLE_TEST("Destiny Bond faints the opposing mon if it fainted from the { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_DESTINY_BOND); MOVE(opponent, MOVE_SCRATCH); } + TURN { + MOVE(player, MOVE_DESTINY_BOND); + MOVE(opponent, MOVE_SCRATCH); + SEND_OUT(player, 1); + } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + MESSAGE("Wobbuffet fainted!"); MESSAGE("Wobbuffet took its attacker down with it!"); MESSAGE("The opposing Wobbuffet fainted!"); } diff --git a/test/battle/move_effect/doodle.c b/test/battle/move_effect/doodle.c index af144ecee5..3484dac6a0 100644 --- a/test/battle/move_effect/doodle.c +++ b/test/battle/move_effect/doodle.c @@ -84,7 +84,8 @@ DOUBLE_BATTLE_TEST("Doodle fails if partner has a banned Ability") DOUBLE_BATTLE_TEST("Doodle fails if ally's ability can't be suppressed") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } PARAMETRIZE { species = SPECIES_DARMANITAN; ability = ABILITY_ZEN_MODE; } diff --git a/test/battle/move_effect/dragon_darts.c b/test/battle/move_effect/dragon_darts.c index 40a9177589..97694909fe 100644 --- a/test/battle/move_effect/dragon_darts.c +++ b/test/battle/move_effect/dragon_darts.c @@ -97,7 +97,7 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if electrified and th { struct BattlePokemon *chosenTarget = NULL; struct BattlePokemon *finalTarget = NULL; - u32 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; abilityLeft = ABILITY_WATER_ABSORB; abilityRight = ABILITY_VOLT_ABSORB; } PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; abilityLeft = ABILITY_WATER_ABSORB; abilityRight = ABILITY_VOLT_ABSORB; } PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; abilityLeft = ABILITY_VOLT_ABSORB; abilityRight = ABILITY_WATER_ABSORB; } @@ -123,7 +123,7 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if electrified and th { struct BattlePokemon *chosenTarget = NULL; struct BattlePokemon *finalTarget = NULL; - u32 abilityLeft, abilityRight; + enum Ability abilityLeft, abilityRight; PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_MOTOR_DRIVE; } PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_MOTOR_DRIVE; } PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; abilityLeft = ABILITY_MOTOR_DRIVE; abilityRight = ABILITY_VITAL_SPIRIT; } diff --git a/test/battle/move_effect/fail_if_not_arg_type.c b/test/battle/move_effect/fail_if_not_arg_type.c index c1371d393d..b8b6eb3ae9 100644 --- a/test/battle/move_effect/fail_if_not_arg_type.c +++ b/test/battle/move_effect/fail_if_not_arg_type.c @@ -42,7 +42,6 @@ TO_DO_BATTLE_TEST("Burn Up doesn't thaw the user if it fails due to the user not SINGLE_BATTLE_TEST("Burn Up fails if the user has Protean/Libero and is not a Fire-type") { - KNOWN_FAILING; GIVEN { WITH_CONFIG(GEN_PROTEAN_LIBERO, GEN_6); PLAYER(SPECIES_REGIROCK); @@ -52,7 +51,10 @@ SINGLE_BATTLE_TEST("Burn Up fails if the user has Protean/Libero and is not a Fi TURN { MOVE(opponent, MOVE_BURN_UP); } } SCENE { MESSAGE("The opposing Kecleon used Burn Up!"); - NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); } + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_PROTEAN); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); + } MESSAGE("But it failed!"); } } diff --git a/test/battle/move_effect/fling.c b/test/battle/move_effect/fling.c index 635ca3d15f..2046ebe638 100644 --- a/test/battle/move_effect/fling.c +++ b/test/battle/move_effect/fling.c @@ -58,7 +58,7 @@ SINGLE_BATTLE_TEST("Fling fails if Pokémon is under the effects of Embargo or M SINGLE_BATTLE_TEST("Fling fails for Pokémon with Klutz ability") { - u16 ability; + enum Ability ability; PARAMETRIZE {ability = ABILITY_KLUTZ; } PARAMETRIZE {ability = ABILITY_RUN_AWAY; } @@ -180,6 +180,23 @@ SINGLE_BATTLE_TEST("Fling - Item is lost when target protects itself") } } +SINGLE_BATTLE_TEST("Fling - Item does not get blocked by Unnerve if it isn't a berry") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); + PLAYER(SPECIES_CALYREX) { Item(ITEM_MENTAL_HERB); Ability(ABILITY_UNNERVE); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_ORAN_BERRY); } + } WHEN { + TURN { MOVE(player, MOVE_TAUNT); MOVE(opponent, MOVE_SCRATCH); } + TURN { MOVE(player, MOVE_FLING); MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + MESSAGE("The opposing Wobbuffet's Taunt wore off!"); + } +} + SINGLE_BATTLE_TEST("Fling doesn't consume the item if Pokémon is asleep/frozen/paralyzed") { u32 status; @@ -509,3 +526,25 @@ SINGLE_BATTLE_TEST("Fling deals damage based on a TM's move power") EXPECT_EQ(damage[0], damage[1]); } } + +SINGLE_BATTLE_TEST("Fling deals damage based on a TM's move power") +{ + s16 damage[2]; + + GIVEN { + ASSUME(GetMovePower(MOVE_EARTHQUAKE) == GetMovePower(MOVE_EGG_BOMB)); + ASSUME(!IsSpeciesOfType(SPECIES_WOBBUFFET, TYPE_DARK)); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_TM_EARTHQUAKE); } + OPPONENT(SPECIES_HIPPOWDON); + } WHEN { + TURN { MOVE(player, MOVE_FLING); } + TURN { MOVE(player, MOVE_EGG_BOMB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EGG_BOMB, player); + HP_BAR(opponent, captureDamage: &damage[1]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + } +} diff --git a/test/battle/move_effect/flower_shield.c b/test/battle/move_effect/flower_shield.c index d690869fa3..4a72163855 100644 --- a/test/battle/move_effect/flower_shield.c +++ b/test/battle/move_effect/flower_shield.c @@ -71,3 +71,19 @@ DOUBLE_BATTLE_TEST("Flower Shield doesn't affect Grass-type Pokémon that are in } } } + +AI_DOUBLE_BATTLE_TEST("AI uses Flower Shield") +{ + GIVEN { + ASSUME(GetSpeciesType(SPECIES_TANGELA, 0) == TYPE_GRASS); + ASSUME(GetSpeciesType(SPECIES_WOBBUFFET, 0) != TYPE_GRASS); + ASSUME(GetSpeciesType(SPECIES_WOBBUFFET, 1) != TYPE_GRASS); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + OPPONENT(SPECIES_TANGELA) { Moves(MOVE_FLOWER_SHIELD, MOVE_POUND); } + OPPONENT(SPECIES_TANGELA); + } WHEN { + TURN { EXPECT_MOVE(opponentLeft, MOVE_FLOWER_SHIELD); } + } +} diff --git a/test/battle/move_effect/gastro_acid.c b/test/battle/move_effect/gastro_acid.c index 8cb0a7d4af..1bbc8c0d5b 100644 --- a/test/battle/move_effect/gastro_acid.c +++ b/test/battle/move_effect/gastro_acid.c @@ -8,7 +8,8 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Gastro Acid fails if target has a banned ability") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; } diff --git a/test/battle/move_effect/gear_up.c b/test/battle/move_effect/gear_up.c index 03aba9a395..051205a2ba 100644 --- a/test/battle/move_effect/gear_up.c +++ b/test/battle/move_effect/gear_up.c @@ -2,3 +2,16 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Gear Up (Move Effect) test titles") + +AI_DOUBLE_BATTLE_TEST("AI uses Gear Up") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + OPPONENT(SPECIES_KLINKLANG) { Ability(ABILITY_PLUS); Moves(MOVE_GEAR_UP, MOVE_WATER_GUN, MOVE_POUND); } + OPPONENT(SPECIES_KLINKLANG) { Ability(ABILITY_PLUS); Moves(MOVE_GEAR_UP, MOVE_WATER_GUN, MOVE_POUND); } + } WHEN { + TURN { EXPECT_MOVE(opponentLeft, MOVE_GEAR_UP); } + } +} diff --git a/test/battle/move_effect/gravity.c b/test/battle/move_effect/gravity.c index baac7a53ea..ec24917f6d 100644 --- a/test/battle/move_effect/gravity.c +++ b/test/battle/move_effect/gravity.c @@ -45,3 +45,36 @@ DOUBLE_BATTLE_TEST("Gravity cancels fly and sky drop if they are in the air") EXPECT_EQ(gLastMoves[0], MOVE_GRAVITY); } } + +AI_DOUBLE_BATTLE_TEST("AI uses Gravity") +{ + u32 move, friendItem, foeItem; + u64 aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; + + PARAMETRIZE { move = MOVE_THUNDER; friendItem = ITEM_NONE; foeItem = ITEM_NONE; } + PARAMETRIZE { move = MOVE_HEADBUTT; friendItem = ITEM_AIR_BALLOON; foeItem = ITEM_NONE; } + PARAMETRIZE { move = MOVE_HEADBUTT; friendItem = ITEM_AIR_BALLOON; foeItem = ITEM_AIR_BALLOON; } + PARAMETRIZE { move = MOVE_HEADBUTT; friendItem = ITEM_NONE; foeItem = ITEM_AIR_BALLOON; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + move = MOVE_THUNDER; friendItem = ITEM_NONE; foeItem = ITEM_NONE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + move = MOVE_HEADBUTT; friendItem = ITEM_AIR_BALLOON; foeItem = ITEM_NONE; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + move = MOVE_HEADBUTT; friendItem = ITEM_AIR_BALLOON; foeItem = ITEM_AIR_BALLOON; } + PARAMETRIZE { aiFlags |= AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION; + move = MOVE_HEADBUTT; friendItem = ITEM_NONE; foeItem = ITEM_AIR_BALLOON; } + + GIVEN { + AI_FLAGS(aiFlags); + PLAYER(SPECIES_WOBBUFFET) { Item(foeItem); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_GRAVITY, MOVE_HEADBUTT, MOVE_TAUNT); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(move, MOVE_EARTH_POWER); Item(friendItem); } + } WHEN { + if (move == MOVE_THUNDER || (foeItem == ITEM_AIR_BALLOON && friendItem != ITEM_AIR_BALLOON)) + TURN { EXPECT_MOVE(opponentLeft, MOVE_GRAVITY); } + else + TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_GRAVITY); } + } +} + diff --git a/test/battle/move_effect/grudge.c b/test/battle/move_effect/grudge.c index f0e0e53b6a..870d39c203 100644 --- a/test/battle/move_effect/grudge.c +++ b/test/battle/move_effect/grudge.c @@ -2,3 +2,52 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Grudge (Move Effect) test titles") + +SINGLE_BATTLE_TEST("Grudge depletes all pp of the move that fainted the target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_POUND, MOVE_SURF); }; + } WHEN { + TURN { + MOVE(player, MOVE_GRUDGE); + MOVE(opponent, MOVE_SCRATCH); + SEND_OUT(player, 1); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + MESSAGE("Wobbuffet fainted!"); + } THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_EQ(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge does not depletes pp of a z-move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_POUND, MOVE_SURF); }; + } WHEN { + TURN { + MOVE(player, MOVE_GRUDGE); + MOVE(opponent, MOVE_SCRATCH, gimmick: GIMMICK_Z_MOVE); + SEND_OUT(player, 1); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ZMOVE_ACTIVATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BREAKNECK_BLITZ, opponent); + MESSAGE("Wobbuffet fainted!"); + } THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} diff --git a/test/battle/move_effect/heal_bell.c b/test/battle/move_effect/heal_bell.c index 4c86fd11c0..2275677ceb 100644 --- a/test/battle/move_effect/heal_bell.c +++ b/test/battle/move_effect/heal_bell.c @@ -86,7 +86,8 @@ DOUBLE_BATTLE_TEST("Heal Bell/Aromatherapy cures the entire party of the user fr DOUBLE_BATTLE_TEST("Heal Bell does not cure Soundproof partners (Gen 4, Gen 6+)") { - u32 ability, config; + enum Ability ability; + u32 config; PARAMETRIZE { ability = ABILITY_SCRAPPY; config = GEN_4; } PARAMETRIZE { ability = ABILITY_SOUNDPROOF; config = GEN_4; } @@ -114,7 +115,8 @@ DOUBLE_BATTLE_TEST("Heal Bell does not cure Soundproof partners (Gen 4, Gen 6+)" SINGLE_BATTLE_TEST("Heal Bell cures inactive Soundproof Pokemon (Gen5+)") { - u32 config, ability; + u32 config; + enum Ability ability; PARAMETRIZE { config = GEN_4, ability = ABILITY_SCRAPPY; } PARAMETRIZE { config = GEN_4, ability = ABILITY_SOUNDPROOF; } diff --git a/test/battle/move_effect/hidden_power.c b/test/battle/move_effect/hidden_power.c index a04482eb29..9ac88e687f 100644 --- a/test/battle/move_effect/hidden_power.c +++ b/test/battle/move_effect/hidden_power.c @@ -31,7 +31,8 @@ ASSUMPTIONS // IV combinations sourced from https://www.smogon.com/forums/threads/hidden-power-iv-combinations.78083/ SINGLE_BATTLE_TEST("Hidden Power's type is determined by IVs") { - u32 type, j, foeType, foeSpecies, foeItem; + enum Type type, foeType, j; + u32 foeSpecies, foeItem; u32 hp, atk, def, spAtk, spDef, speed; bool32 hidden; diff --git a/test/battle/move_effect/ion_deluge.c b/test/battle/move_effect/ion_deluge.c index b806f9d8e1..4f74c6db72 100644 --- a/test/battle/move_effect/ion_deluge.c +++ b/test/battle/move_effect/ion_deluge.c @@ -27,7 +27,7 @@ WILD_BATTLE_TEST("Ion Deluge works the same way as always when used by a mon wit WILD_BATTLE_TEST("Ion Deluge works the same way as always when used by a mon with Lightning Rod / Motor Drive") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; } PARAMETRIZE { ability = ABILITY_MOTOR_DRIVE; } diff --git a/test/battle/move_effect/lash_out.c b/test/battle/move_effect/lash_out.c index 4ceb0c02a8..ed9465e915 100644 --- a/test/battle/move_effect/lash_out.c +++ b/test/battle/move_effect/lash_out.c @@ -118,7 +118,7 @@ SINGLE_BATTLE_TEST("Lash Out damage is boosted on turn 1 by switch in abilities" DOUBLE_BATTLE_TEST("Lash Out damage is boosted by Cotton Down activation in doubles") { s16 damage[2] = {0}; - u32 ability = ABILITY_NONE; + enum Ability ability = ABILITY_NONE; PARAMETRIZE { ability = ABILITY_REGENERATOR; } PARAMETRIZE { ability = ABILITY_COTTON_DOWN; } diff --git a/test/battle/move_effect/last_resort.c b/test/battle/move_effect/last_resort.c index c0b2380f27..089a723304 100644 --- a/test/battle/move_effect/last_resort.c +++ b/test/battle/move_effect/last_resort.c @@ -114,3 +114,43 @@ SINGLE_BATTLE_TEST("Last Resort works with Sleep Talk") HP_BAR(opponent); } } + +AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 2 moves") +{ + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_LAST_RESORT, MOVE_SCRATCH); } + } WHEN { + TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + TURN { EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 3 moves") +{ + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_LAST_RESORT, 5}, {MOVE_QUICK_ATTACK, 1}, {MOVE_SCRATCH, 35}); } + } WHEN { + TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + TURN { EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + } +} + +AI_SINGLE_BATTLE_TEST("AI uses Last Resort - 4 moves") +{ + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_LAST_RESORT, 5}, {MOVE_QUICK_ATTACK, 1}, {MOVE_SCRATCH, 1}, {MOVE_GUST, 35}); } + } WHEN { + TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + TURN { NOT_EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + TURN { EXPECT_MOVE(opponent, MOVE_LAST_RESORT); } + } +} + diff --git a/test/battle/move_effect/life_dew.c b/test/battle/move_effect/life_dew.c index 493c4c73e7..1969f3454c 100644 --- a/test/battle/move_effect/life_dew.c +++ b/test/battle/move_effect/life_dew.c @@ -84,3 +84,30 @@ DOUBLE_BATTLE_TEST("Life Dew only works on partner if user is at full hp") HP_BAR(playerRight); } } + +AI_SINGLE_BATTLE_TEST("AI uses Life Dew if it outheals your damage and outspeeds (singles)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SHOULD_RECOVER); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); Moves(MOVE_SCALD, MOVE_LIFE_DEW); HP(1); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_LIFE_DEW); } + } +} + +AI_DOUBLE_BATTLE_TEST("AI uses Life Dew if it outheals your damage and outspeeds (doubles)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SHOULD_RECOVER); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_TACKLE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(2); Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); Moves(MOVE_SCALD, MOVE_LIFE_DEW); HP(1); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); Moves(MOVE_SCALD); HP(1); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_TACKLE); MOVE(playerRight, MOVE_TACKLE); EXPECT_MOVE(opponentLeft, MOVE_LIFE_DEW); } + } +} + diff --git a/test/battle/move_effect/magic_room.c b/test/battle/move_effect/magic_room.c index cffd6034d7..02953f533d 100644 --- a/test/battle/move_effect/magic_room.c +++ b/test/battle/move_effect/magic_room.c @@ -36,4 +36,43 @@ DOUBLE_BATTLE_TEST("Magic Room prevents item hold effects") } } +SINGLE_BATTLE_TEST("Magic Room: An item that can activate will activate once Magic Room is over") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MAGIC_ROOM); MOVE(opponent, MOVE_GROWL); } + TURN {} + TURN {} + TURN {} + TURN {} + TURN {} + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_ROOM, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GROWL, opponent); + // Turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + // Turn 3 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + // Turn 4 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + // Turn 5 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } + + MESSAGE("Magic Room wore off, and held items' effects returned to normal!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + } +} + TO_DO_BATTLE_TEST("TODO: Write Magic Room (Move Effect) test titles") diff --git a/test/battle/move_effect/magnetic_flux.c b/test/battle/move_effect/magnetic_flux.c index f574db0089..6a23d2082f 100644 --- a/test/battle/move_effect/magnetic_flux.c +++ b/test/battle/move_effect/magnetic_flux.c @@ -2,3 +2,16 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Magnetic Flux (Move Effect) test titles") + +AI_DOUBLE_BATTLE_TEST("AI uses Magnetic Flux") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_POUND, MOVE_CELEBRATE); } + OPPONENT(SPECIES_KLINK) { Ability(ABILITY_PLUS); Moves(MOVE_MAGNETIC_FLUX, MOVE_POUND); } + OPPONENT(SPECIES_KLINK) { Ability(ABILITY_PLUS); Moves(MOVE_MAGNETIC_FLUX, MOVE_POUND); } + } WHEN { + TURN { EXPECT_MOVE(opponentLeft, MOVE_MAGNETIC_FLUX); } + } +} diff --git a/test/battle/move_effect/me_first.c b/test/battle/move_effect/me_first.c index f351c1a498..51f673ae5f 100644 --- a/test/battle/move_effect/me_first.c +++ b/test/battle/move_effect/me_first.c @@ -1,6 +1,11 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_ME_FIRST) == EFFECT_ME_FIRST); +} + SINGLE_BATTLE_TEST("Me First copies the move from the target and increases it's power by 1.5", s16 damage) { u32 move; @@ -77,4 +82,21 @@ SINGLE_BATTLE_TEST("Me First can be selected if users holds Assault Vest") } } +SINGLE_BATTLE_TEST("Me Frist deducts power points from itself, not the copied move") +{ + ASSUME(GetMovePP(MOVE_ME_FIRST) == 20); + ASSUME(GetMovePP(MOVE_POUND) == 35); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_ME_FIRST); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_POUND); } + } WHEN { + TURN { MOVE(player, MOVE_ME_FIRST); MOVE(opponent, MOVE_POUND); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ME_FIRST, player); + } THEN { + EXPECT_EQ(opponent->pp[0], 34); + EXPECT_EQ(player->pp[0], 19); + } +} + // TO_DO_BATTLE_TEST: Not everything has been tested diff --git a/test/battle/move_effect/mirror_move.c b/test/battle/move_effect/mirror_move.c index 2f3c65b827..677fc71a1a 100644 --- a/test/battle/move_effect/mirror_move.c +++ b/test/battle/move_effect/mirror_move.c @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Mirror Move fails if no move was used before") TURN { MOVE(player, MOVE_MIRROR_MOVE); MOVE(opponent, MOVE_SCRATCH); } } SCENE { MESSAGE("Wobbuffet used Mirror Move!"); - MESSAGE("The Mirror Move failed!"); + MESSAGE("But it failed!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); HP_BAR(player); } diff --git a/test/battle/move_effect/nature_power.c b/test/battle/move_effect/nature_power.c index 1e9692f88d..53aa68442d 100644 --- a/test/battle/move_effect/nature_power.c +++ b/test/battle/move_effect/nature_power.c @@ -1,4 +1,27 @@ #include "global.h" #include "test/battle.h" +#include "battle_environment.h" -TO_DO_BATTLE_TEST("TODO: Write Nature Power (Move Effect) test titles") +//TO_DO_BATTLE_TEST("TODO: Write Nature Power (Move Effect) test titles") + +SINGLE_BATTLE_TEST("Nature power plays a move correctly in any background") +{ + u32 environment = 0; + u32 move = MOVE_TRI_ATTACK; + for (u32 j = 0; j < BATTLE_ENVIRONMENT_COUNT; j++) + { + PARAMETRIZE {environment = i;} + } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + Environment(environment); + if (gBattleEnvironmentInfo[environment].naturePower) + move = gBattleEnvironmentInfo[environment].naturePower; + } WHEN { + TURN { MOVE(player, MOVE_NATURE_POWER); } + } SCENE { + NOT MESSAGE("Nature Power turned into Nature Power!"); + ANIMATION(ANIM_TYPE_MOVE, move, player); + } +} diff --git a/test/battle/move_effect/no_retreat.c b/test/battle/move_effect/no_retreat.c index bf2a15dfbf..fa944ab776 100644 --- a/test/battle/move_effect/no_retreat.c +++ b/test/battle/move_effect/no_retreat.c @@ -2,3 +2,60 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write No Retreat (Move Effect) test titles") + +SINGLE_BATTLE_TEST("No Retreat raises user's Atk/Def/Sp.Atk/Sp.Def/Speed unless No Retreat was already used by user") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_NO_RETREAT); } + TURN { MOVE(player, MOVE_NO_RETREAT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); + bool32 escapePrevention = gBattleMons[0].volatiles.escapePrevention; + EXPECT_EQ(escapePrevention, TRUE); + } +} + +// Question: If No Retreat is used is the mon blocking the switch out changed? +SINGLE_BATTLE_TEST("No Retreat won't fail if user is prevented from escaping") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_MEAN_LOOK); MOVE(player, MOVE_NO_RETREAT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEAN_LOOK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } +} + +SINGLE_BATTLE_TEST("No Retreat won't activate Protean if it fails due to already being used by the user") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + } WHEN { + TURN { MOVE(player, MOVE_NO_RETREAT); MOVE(opponent, MOVE_SKILL_SWAP); } + TURN { MOVE(player, MOVE_NO_RETREAT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_NO_RETREAT, player); + ABILITY_POPUP(player, ABILITY_PROTEAN); + } + } +} diff --git a/test/battle/move_effect/octolock.c b/test/battle/move_effect/octolock.c index 74e0b0fc4c..b98c17908d 100644 --- a/test/battle/move_effect/octolock.c +++ b/test/battle/move_effect/octolock.c @@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("Octolock decreases Defense and Sp. Def by at the end of the SINGLE_BATTLE_TEST("Octolock reduction is prevented by Clear Body, White Smoke and Full Metal Body") { u32 species; - u32 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_BELDUM; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE { species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } diff --git a/test/battle/move_effect/psychic_terrain.c b/test/battle/move_effect/psychic_terrain.c index 51fdb236ef..76e7bc7c82 100644 --- a/test/battle/move_effect/psychic_terrain.c +++ b/test/battle/move_effect/psychic_terrain.c @@ -11,7 +11,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority mov TURN { MOVE(player, MOVE_QUICK_ATTACK); MOVE(opponent, MOVE_QUICK_ATTACK); } } SCENE { MESSAGE("Claydol used Psychic Terrain!"); - MESSAGE("Claydol cannot use Quick Attack!"); + MESSAGE("The opposing Wobbuffet is protected by the Psychic Terrain!"); NOT { HP_BAR(opponent); } MESSAGE("The opposing Wobbuffet used Quick Attack!"); HP_BAR(player); @@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain increases power of Psychic-type moves by 30/ } } -SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target the user") +SINGLE_BATTLE_TEST("Psychic Terrain doesn't blocks priority moves that target the user") { GIVEN { PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); HP(1); } @@ -176,3 +176,37 @@ SINGLE_BATTLE_TEST("Psychic Terrain lasts for 5 turns") MESSAGE("The weirdness disappeared from the battlefield!"); } } + +DOUBLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority moves in doubles - Left") +{ + GIVEN { + PLAYER(SPECIES_CLAYDOL) { Ability(ABILITY_LEVITATE); } + PLAYER(SPECIES_TAPU_LELE) { Ability(ABILITY_PSYCHIC_SURGE); } + OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_COTTON_SPORE); } + } SCENE { + ABILITY_POPUP(playerRight, ABILITY_PSYCHIC_SURGE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_COTTON_SPORE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + } +} + +DOUBLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority moves in doubles - Right") +{ + GIVEN { + PLAYER(SPECIES_TAPU_LELE) { Ability(ABILITY_PSYCHIC_SURGE); } + PLAYER(SPECIES_CLAYDOL) { Ability(ABILITY_LEVITATE); } + OPPONENT(SPECIES_VOLBEAT) { Ability(ABILITY_PRANKSTER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_COTTON_SPORE); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_PSYCHIC_SURGE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_COTTON_SPORE, opponentLeft); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + } +} diff --git a/test/battle/move_effect/purify.c b/test/battle/move_effect/purify.c index 5f1651e96f..425d0a99a9 100644 --- a/test/battle/move_effect/purify.c +++ b/test/battle/move_effect/purify.c @@ -22,5 +22,45 @@ AI_DOUBLE_BATTLE_TEST("AI uses Purify") } } +AI_SINGLE_BATTLE_TEST("AI uses Purify to heal an enemy with Guts") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_GUTS; } + PARAMETRIZE { ability = ABILITY_BULLETPROOF; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_URSALUNA) { Ability(ability); Moves(MOVE_HEADLONG_RUSH, MOVE_CELEBRATE); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HEADBUTT, MOVE_PURIFY); } + } WHEN { + if (ability == ABILITY_GUTS) + TURN { EXPECT_MOVE(opponent, MOVE_PURIFY); } + else + TURN { NOT_EXPECT_MOVE(opponent, MOVE_PURIFY); } + } +} + +AI_DOUBLE_BATTLE_TEST("AI does not use Purify to heal an ally with Guts") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_GUTS; } + PARAMETRIZE { ability = ABILITY_BULLETPROOF; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_HEADBUTT, MOVE_PURIFY); } + OPPONENT(SPECIES_URSALUNA) { Ability(ability); Moves(MOVE_HEADLONG_RUSH); Status1(STATUS1_BURN); } + } WHEN { + if (ability == ABILITY_GUTS) + TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_PURIFY); } + else + TURN { EXPECT_MOVE(opponentLeft, MOVE_PURIFY, target: opponentRight); } + } +} + TO_DO_BATTLE_TEST("TODO: Write Purify (Move Effect) test titles") TO_DO_BATTLE_TEST("Purify doesn't heal HP if the target has Comatose") diff --git a/test/battle/move_effect/recoil_if_miss.c b/test/battle/move_effect/recoil_if_miss.c index a5dbfef178..0fc09a7fc4 100644 --- a/test/battle/move_effect/recoil_if_miss.c +++ b/test/battle/move_effect/recoil_if_miss.c @@ -134,7 +134,7 @@ SINGLE_BATTLE_TEST("Recoil if miss: Supercell Slam causes recoil if it is absorb SINGLE_BATTLE_TEST("Recoil if miss: Disguise doesn't prevent crash damage from Jump Kick into ghost types") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_EARLY_BIRD; } PARAMETRIZE { ability = ABILITY_SCRAPPY; } diff --git a/test/battle/move_effect/revival_blessing.c b/test/battle/move_effect/revival_blessing.c index f1a0ad74bc..eeb90d202d 100644 --- a/test/battle/move_effect/revival_blessing.c +++ b/test/battle/move_effect/revival_blessing.c @@ -49,29 +49,36 @@ SINGLE_BATTLE_TEST("Revival Blessing fails if no party members are fainted") } } -DOUBLE_BATTLE_TEST("Revival Blessing cannot revive a partner's party member") +// Can only be tested through AI test, else test fails due to trying to force illegal action +AI_MULTI_BATTLE_TEST("Revival Blessing cannot revive a partner's party member") { - KNOWN_FAILING; struct BattlePokemon *user = NULL; - gBattleTypeFlags |= BATTLE_TYPE_TWO_OPPONENTS; - PARAMETRIZE { user = opponentLeft; } - PARAMETRIZE { user = opponentRight; } + u32 move1, move2, move3; + PARAMETRIZE { user = opponentLeft, move1 = MOVE_REVIVAL_BLESSING, move2 = MOVE_CELEBRATE, move3 = MOVE_CELEBRATE; } + PARAMETRIZE { user = playerRight, move1 = MOVE_CELEBRATE, move2 = MOVE_REVIVAL_BLESSING, move3 = MOVE_CELEBRATE; } + PARAMETRIZE { user = opponentRight, move1 = MOVE_CELEBRATE, move2 = MOVE_CELEBRATE, move3 = MOVE_REVIVAL_BLESSING; } GIVEN { - ASSUME((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) != FALSE); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT); - OPPONENT(SPECIES_WYNAUT) { HP(0); } - OPPONENT(SPECIES_WYNAUT); + MULTI_PLAYER(SPECIES_CLEFABLE); + MULTI_PLAYER(SPECIES_CLEFABLE) { HP(0); } + MULTI_PLAYER(SPECIES_CLEFABLE); + MULTI_PARTNER(SPECIES_CLEFAIRY) { Moves(move2); } + MULTI_PARTNER(SPECIES_CLEFAIRY); + MULTI_PARTNER(SPECIES_CLEFAIRY); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { Moves(move1); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_A(SPECIES_WOBBUFFET); + MULTI_OPPONENT_B(SPECIES_WYNAUT) { Moves(move3); } + MULTI_OPPONENT_B(SPECIES_WYNAUT) { HP(0); } + MULTI_OPPONENT_B(SPECIES_WYNAUT); } WHEN { - TURN { MOVE(user, MOVE_REVIVAL_BLESSING, partyIndex:4); } + TURN { EXPECT_MOVE(playerRight, move2); } // EXPECT_MOVE makes battler2 AI-controlled } SCENE { if (user == opponentLeft) { MESSAGE("The opposing Wobbuffet used Revival Blessing!"); MESSAGE("But it failed!"); + } else if (user == playerRight) { + MESSAGE("Clefairy used Revival Blessing!"); + MESSAGE("But it failed!"); } else { MESSAGE("The opposing Wynaut used Revival Blessing!"); MESSAGE("Wynaut was revived and is ready to fight again!"); diff --git a/test/battle/move_effect/role_play.c b/test/battle/move_effect/role_play.c index 1a05f02d4a..ebd56bce2c 100644 --- a/test/battle/move_effect/role_play.c +++ b/test/battle/move_effect/role_play.c @@ -50,7 +50,8 @@ DOUBLE_BATTLE_TEST("Role Play copies target's current ability even if it changed SINGLE_BATTLE_TEST("Role Play and Doodle fail if target's ability can't be copied'") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_SHEDINJA; ability = ABILITY_WONDER_GUARD; } PARAMETRIZE { species = SPECIES_CASTFORM; ability = ABILITY_FORECAST; } @@ -90,7 +91,8 @@ SINGLE_BATTLE_TEST("Role Play and Doodle fail if target's ability can't be copie SINGLE_BATTLE_TEST("Role Play fails if user's ability can't be suppressed") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } if (B_UPDATED_ABILITY_DATA >= GEN_7) diff --git a/test/battle/move_effect/simple_beam.c b/test/battle/move_effect/simple_beam.c index 4250c8ce45..66d2a59fcc 100644 --- a/test/battle/move_effect/simple_beam.c +++ b/test/battle/move_effect/simple_beam.c @@ -3,7 +3,8 @@ ASSUMPTIONS { - ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_SIMPLE_BEAM); + ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_OVERWRITE_ABILITY); + ASSUME(GetMoveOverwriteAbility(MOVE_SIMPLE_BEAM) == ABILITY_SIMPLE); } SINGLE_BATTLE_TEST("Simple Beam replaces target's ability with Simple") @@ -18,7 +19,7 @@ SINGLE_BATTLE_TEST("Simple Beam replaces target's ability with Simple") ABILITY_POPUP(opponent, ABILITY_BLAZE); } THEN { EXPECT_EQ(opponent->ability, ABILITY_SIMPLE); - } + } } DOUBLE_BATTLE_TEST("Simple Beam fails if the target already has Simple") @@ -44,7 +45,8 @@ DOUBLE_BATTLE_TEST("Simple Beam fails if the target already has Simple") SINGLE_BATTLE_TEST("Simple Beam fails if target has an ability that can't be overwritten") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; } diff --git a/test/battle/move_effect/skill_swap.c b/test/battle/move_effect/skill_swap.c index c3c2ca91f4..59b023f5fa 100644 --- a/test/battle/move_effect/skill_swap.c +++ b/test/battle/move_effect/skill_swap.c @@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Skill Swap swaps user and target's abilities") } THEN { EXPECT_EQ(player->ability, ABILITY_BLAZE); EXPECT_EQ(opponent->ability, ABILITY_TELEPATHY); - } + } } DOUBLE_BATTLE_TEST("Skill Swap only swaps user's ability with target's ability") @@ -67,7 +67,8 @@ DOUBLE_BATTLE_TEST("Skill Swap doesn't display ability popups when swapping with SINGLE_BATTLE_TEST("Skill Swap fails if user or target has an ability that can't be swapped") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_SHEDINJA; ability = ABILITY_WONDER_GUARD; } PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } diff --git a/test/battle/move_effect/sleep_talk.c b/test/battle/move_effect/sleep_talk.c index 1f53530c46..2a2443c7ee 100644 --- a/test/battle/move_effect/sleep_talk.c +++ b/test/battle/move_effect/sleep_talk.c @@ -146,3 +146,21 @@ DOUBLE_BATTLE_TEST("Sleep Talk calls move and that move may be redirected by Sto ABILITY_POPUP(opponentRight, ABILITY_STORM_DRAIN); } } + +SINGLE_BATTLE_TEST("Sleep Talk deducts power points from itself, not the called move") +{ + ASSUME(GetMovePP(MOVE_SLEEP_TALK) == 10); + ASSUME(GetMovePP(MOVE_POUND) == 35); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_POUND); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SLEEP_TALK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SLEEP_TALK, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, player); + } THEN { + EXPECT_EQ(player->pp[0], 9); + EXPECT_EQ(player->pp[1], 35); + } +} diff --git a/test/battle/move_effect/solar_beam.c b/test/battle/move_effect/solar_beam.c index 309d950c50..6113b5c4ac 100644 --- a/test/battle/move_effect/solar_beam.c +++ b/test/battle/move_effect/solar_beam.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Solar Beam does not need a charging turn if Sun is up") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_DROUGHT; } PARAMETRIZE { ability = ABILITY_WHITE_SMOKE; } diff --git a/test/battle/move_effect/speed_down.c b/test/battle/move_effect/speed_down.c index 0be3daa90d..88d62f2f38 100644 --- a/test/battle/move_effect/speed_down.c +++ b/test/battle/move_effect/speed_down.c @@ -3,7 +3,7 @@ DOUBLE_BATTLE_TEST("Speed Down: Cotton Spore does not fail if it is blocked by one target") { - u32 abilityOne, abilityTwo; + enum Ability abilityOne, abilityTwo; PARAMETRIZE { abilityOne = ABILITY_OVERCOAT; abilityTwo = ABILITY_SKILL_LINK; } PARAMETRIZE { abilityOne = ABILITY_SKILL_LINK; abilityTwo = ABILITY_OVERCOAT; } diff --git a/test/battle/move_effect/speed_swap.c b/test/battle/move_effect/speed_swap.c index b5f9aaebaf..3405d510ca 100644 --- a/test/battle/move_effect/speed_swap.c +++ b/test/battle/move_effect/speed_swap.c @@ -24,12 +24,13 @@ SINGLE_BATTLE_TEST("Speed Swap swaps user and target's speed stats") } THEN { EXPECT_EQ(player->speed, 10); EXPECT_EQ(opponent->speed, 6); - } + } } SINGLE_BATTLE_TEST("Speed Swap doesn't swap user and target's speed modifiers") { - u32 species, ability, move; + u32 species, move; + enum Ability ability; PARAMETRIZE { species = SPECIES_WOBBUFFET; ability = ABILITY_TELEPATHY; move = MOVE_ROCK_POLISH; } // x2.0 PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_SWIFT_SWIM; move = MOVE_RAIN_DANCE; } // x2.0 GIVEN { @@ -54,5 +55,5 @@ SINGLE_BATTLE_TEST("Speed Swap doesn't swap user and target's speed modifiers") EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 2); } - } + } } diff --git a/test/battle/move_effect/spicy_extract.c b/test/battle/move_effect/spicy_extract.c index 7cf9eacb32..6dc2a77427 100644 --- a/test/battle/move_effect/spicy_extract.c +++ b/test/battle/move_effect/spicy_extract.c @@ -27,7 +27,7 @@ SINGLE_BATTLE_TEST("Spicy Extract raises target's Attack by 2 stages and lowers SINGLE_BATTLE_TEST("Spicy Extract is prevented by target's ability if it's Attack stat is maxed out") { - u16 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_CLEAR_BODY; } PARAMETRIZE { ability = ABILITY_LIGHT_METAL; } @@ -189,7 +189,7 @@ AI_DOUBLE_BATTLE_TEST("Spicy Extract user will use it if partner holds Clear Amu AI_DOUBLE_BATTLE_TEST("Spicy Extract user will not choose the move if it does not benefit partner") { u32 species; - u32 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_GHOLDENGO; ability = ABILITY_GOOD_AS_GOLD; } PARAMETRIZE { species = SPECIES_SNIVY; ability = ABILITY_CONTRARY; } diff --git a/test/battle/move_effect/stockpile.c b/test/battle/move_effect/stockpile.c index 907643a1bd..e18c97fc57 100644 --- a/test/battle/move_effect/stockpile.c +++ b/test/battle/move_effect/stockpile.c @@ -30,7 +30,7 @@ SINGLE_BATTLE_TEST("Stockpile's count can go up only to 3") MESSAGE("Wobbuffet stockpiled 3!"); NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player); - MESSAGE("Wobbuffet can't stockpile any more!"); + MESSAGE("But it failed!"); } } @@ -49,9 +49,9 @@ SINGLE_BATTLE_TEST("Spit Up and Swallow don't work if used without Stockpile") } SCENE { NOT ANIMATION(ANIM_TYPE_MOVE, move, player); if (move == MOVE_SWALLOW) - MESSAGE("But it failed to swallow a thing!"); + MESSAGE("But it failed!"); else - MESSAGE("But it failed to spit up a thing!"); + MESSAGE("But it failed!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_STOCKPILE, player); MESSAGE("Wobbuffet stockpiled 1!"); diff --git a/test/battle/move_effect/tera_blast.c b/test/battle/move_effect/tera_blast.c index 060e28802d..1e041dda97 100644 --- a/test/battle/move_effect/tera_blast.c +++ b/test/battle/move_effect/tera_blast.c @@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Tera Blast changes from Normal-type to the user's Tera Type" SINGLE_BATTLE_TEST("Tera Blast has correct effectiveness for every Tera Type") { u32 species; - u32 type; + enum Type type; PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_FLYING; } PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_POISON; } diff --git a/test/battle/move_effect/toxic.c b/test/battle/move_effect/toxic.c index a8134f9c66..045772db2b 100644 --- a/test/battle/move_effect/toxic.c +++ b/test/battle/move_effect/toxic.c @@ -75,7 +75,8 @@ SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type (Gen6+)") AI_SINGLE_BATTLE_TEST("AI avoids toxic when it can not poison target") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_SNORLAX; ability = ABILITY_IMMUNITY; } PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; } diff --git a/test/battle/move_effect/upper_hand.c b/test/battle/move_effect/upper_hand.c index facfaf4c2a..74cad10a89 100644 --- a/test/battle/move_effect/upper_hand.c +++ b/test/battle/move_effect/upper_hand.c @@ -156,3 +156,20 @@ DOUBLE_BATTLE_TEST("Upper Hand fails if the target has attempted to act even if NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_UPPER_HAND, playerLeft); } } + +SINGLE_BATTLE_TEST("Upper Hand failing will prevent Protean activation") +{ + GIVEN { + WITH_CONFIG(GEN_PROTEAN_LIBERO, GEN_6); + PLAYER(SPECIES_REGIROCK); + OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_UPPER_HAND); } + } SCENE { + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_PROTEAN); + ANIMATION(ANIM_TYPE_MOVE, MOVE_UPPER_HAND, player); + } + } +} diff --git a/test/battle/move_effect/worry_seed.c b/test/battle/move_effect/worry_seed.c index c4b18b7cab..a536802087 100644 --- a/test/battle/move_effect/worry_seed.c +++ b/test/battle/move_effect/worry_seed.c @@ -3,7 +3,8 @@ ASSUMPTIONS { - ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); + ASSUME(GetMoveOverwriteAbility(MOVE_WORRY_SEED) == ABILITY_INSOMNIA); } SINGLE_BATTLE_TEST("Worry Seed replaces target's ability with Insomnia") @@ -18,7 +19,7 @@ SINGLE_BATTLE_TEST("Worry Seed replaces target's ability with Insomnia") ABILITY_POPUP(opponent, ABILITY_BLAZE); } THEN { EXPECT_EQ(opponent->ability, ABILITY_INSOMNIA); - } + } } DOUBLE_BATTLE_TEST("Worry Seed fails if the target already has Insomnia") @@ -44,7 +45,8 @@ DOUBLE_BATTLE_TEST("Worry Seed fails if the target already has Insomnia") SINGLE_BATTLE_TEST("Worry Seed fails if target has an ability that can't be overwritten") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_ARCEUS; ability = ABILITY_MULTITYPE; } PARAMETRIZE { species = SPECIES_AEGISLASH; ability = ABILITY_STANCE_CHANGE; } diff --git a/test/battle/move_effect_secondary/dire_claw.c b/test/battle/move_effect_secondary/dire_claw.c index 6ad8e3dce9..f7606dd0c4 100644 --- a/test/battle/move_effect_secondary/dire_claw.c +++ b/test/battle/move_effect_secondary/dire_claw.c @@ -65,7 +65,8 @@ SINGLE_BATTLE_TEST("Dire Claw cannot poison/paralyze/cause to fall asleep Pokém { KNOWN_FAILING; u8 statusAnim; - u16 species, ability; + u16 species; + enum Ability ability; u32 rng; if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; } diff --git a/test/battle/move_effect_secondary/freeze.c b/test/battle/move_effect_secondary/freeze.c index 01a4b31c06..352845766d 100644 --- a/test/battle/move_effect_secondary/freeze.c +++ b/test/battle/move_effect_secondary/freeze.c @@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Powder Snow inflicts freeze") } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_POWDER_SNOW, player); HP_BAR(opponent); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + ANIMATION(ANIM_TYPE_STATUS, (B_USE_FROSTBITE ? B_ANIM_STATUS_FRB : B_ANIM_STATUS_FRZ), opponent); FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE); } } @@ -85,11 +85,11 @@ SINGLE_BATTLE_TEST("Freezing Glare shouldn't freeze Psychic-types") ANIMATION(ANIM_TYPE_MOVE, MOVE_FREEZING_GLARE, player); HP_BAR(opponent); #if B_STATUS_TYPE_IMMUNITY > GEN_1 - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + ANIMATION(ANIM_TYPE_STATUS, (B_USE_FROSTBITE ? B_ANIM_STATUS_FRB : B_ANIM_STATUS_FRZ), opponent); FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE); #else NONE_OF { - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + ANIMATION(ANIM_TYPE_STATUS, (B_USE_FROSTBITE ? B_ANIM_STATUS_FRB : B_ANIM_STATUS_FRZ), opponent); FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE); } #endif diff --git a/test/battle/move_effect_secondary/order_up.c b/test/battle/move_effect_secondary/order_up.c index ec6f1c51b5..bfabd6e3e3 100644 --- a/test/battle/move_effect_secondary/order_up.c +++ b/test/battle/move_effect_secondary/order_up.c @@ -140,7 +140,7 @@ DOUBLE_BATTLE_TEST("Order Up is boosted by Sheer Force without removing the stat DOUBLE_BATTLE_TEST("Order Up is always boosted by Sheer Force", s16 damage) { u32 move; - u32 ability; + enum Ability ability; PARAMETRIZE(move = MOVE_CELEBRATE, ability = ABILITY_STORM_DRAIN); PARAMETRIZE(move = MOVE_ENTRAINMENT, ability = ABILITY_STORM_DRAIN); PARAMETRIZE(move = MOVE_ENTRAINMENT, ability = ABILITY_COMMANDER); diff --git a/test/battle/move_effect_secondary/remove_status.c b/test/battle/move_effect_secondary/remove_status.c index 4e62ca55e9..f1219d7ed0 100644 --- a/test/battle/move_effect_secondary/remove_status.c +++ b/test/battle/move_effect_secondary/remove_status.c @@ -3,7 +3,7 @@ SINGLE_BATTLE_TEST("Smelling Salts does not cure paralyzed pokemons behind substitutes or get increased power") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_INNER_FOCUS; } PARAMETRIZE { ability = ABILITY_INFILTRATOR; } GIVEN { @@ -62,7 +62,7 @@ SINGLE_BATTLE_TEST("Smelling Salts get incread power vs. paralyzed targets") SINGLE_BATTLE_TEST("Wake-Up Slap does not cure paralyzed pokemons behind substitutes or get increased power") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_INNER_FOCUS; } PARAMETRIZE { ability = ABILITY_INFILTRATOR; } GIVEN { diff --git a/test/battle/move_effect_secondary/steal_item.c b/test/battle/move_effect_secondary/steal_item.c index 79c293757f..e83d5c5cb5 100644 --- a/test/battle/move_effect_secondary/steal_item.c +++ b/test/battle/move_effect_secondary/steal_item.c @@ -148,11 +148,12 @@ SINGLE_BATTLE_TEST("Thief and Covet can't steal target's held item if user faint } } -SINGLE_BATTLE_TEST("Thief and Covet: Berry activation happens before the item can be stolen") +SINGLE_BATTLE_TEST("Thief and Covet: Berries that activate on HP thresholds are stolen before they can activate") { u32 move; PARAMETRIZE { move = MOVE_THIEF; } PARAMETRIZE { move = MOVE_COVET; } + GIVEN { PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET) { MaxHP(200); HP(101); Item(ITEM_ORAN_BERRY); } @@ -161,6 +162,25 @@ SINGLE_BATTLE_TEST("Thief and Covet: Berry activation happens before the item ca } SCENE { ANIMATION(ANIM_TYPE_MOVE, move, player); HP_BAR(opponent); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); + } +} + +SINGLE_BATTLE_TEST("Thief and Covet: Berries that activate on a Status activate before the item can be stolen") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + + GIVEN { + PLAYER(SPECIES_TOXICROAK) { Ability(ABILITY_POISON_TOUCH); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LUM_BERRY); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + ABILITY_POPUP(player, ABILITY_POISON_TOUCH); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); } diff --git a/test/battle/move_effect_secondary/syrup_bomb.c b/test/battle/move_effect_secondary/syrup_bomb.c index 3bb52b6d70..4cf2172069 100644 --- a/test/battle/move_effect_secondary/syrup_bomb.c +++ b/test/battle/move_effect_secondary/syrup_bomb.c @@ -74,7 +74,7 @@ SINGLE_BATTLE_TEST("Syrup Bomb is prevented by Bulletproof") SINGLE_BATTLE_TEST("Sticky Syrup speed reduction is prevented by Clear Body, White Smoke or Full Metal Body") { u32 species; - u32 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_BELDUM; ability = ABILITY_CLEAR_BODY; } PARAMETRIZE { species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } diff --git a/test/battle/move_effect_secondary/tri_attack.c b/test/battle/move_effect_secondary/tri_attack.c index 4ec90f6f92..4ac69915e6 100644 --- a/test/battle/move_effect_secondary/tri_attack.c +++ b/test/battle/move_effect_secondary/tri_attack.c @@ -15,7 +15,7 @@ SINGLE_BATTLE_TEST("Tri Attack can inflict paralysis, burn or freeze") u8 statusAnim; PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; } PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; } - PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; } + PARAMETRIZE { statusAnim = (B_USE_FROSTBITE ? B_ANIM_STATUS_FRB : B_ANIM_STATUS_FRZ); } PASSES_RANDOMLY(1, 3, RNG_TRI_ATTACK); GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -29,7 +29,7 @@ SINGLE_BATTLE_TEST("Tri Attack can inflict paralysis, burn or freeze") ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponent); if (statusAnim == B_ANIM_STATUS_BRN) { STATUS_ICON(opponent, burn: TRUE); - } else if (statusAnim == B_ANIM_STATUS_FRZ) { + } else if (statusAnim == (B_USE_FROSTBITE ? B_ANIM_STATUS_FRB : B_ANIM_STATUS_FRZ)) { FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE); } else if (statusAnim == B_ANIM_STATUS_PRZ) { STATUS_ICON(opponent, paralysis: TRUE); @@ -79,7 +79,8 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze Pokémon with abiliti #endif { u8 statusAnim; - u16 species, ability; + u16 species; + enum Ability ability; u32 rng; PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_PERSIAN; ability = ABILITY_LIMBER; } PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; } diff --git a/test/battle/move_effects_combined/flinch_status.c b/test/battle/move_effects_combined/flinch_status.c index 75c9461880..0d37170726 100644 --- a/test/battle/move_effects_combined/flinch_status.c +++ b/test/battle/move_effects_combined/flinch_status.c @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Thunder, Ice and Fire Fang inflict status 10% of the time") ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); STATUS_ICON(opponent, paralysis: TRUE); } if (move == MOVE_ICE_FANG) { - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + ANIMATION(ANIM_TYPE_STATUS, (B_USE_FROSTBITE ? B_ANIM_STATUS_FRB : B_ANIM_STATUS_FRZ), opponent); FREEZE_OR_FROSTBURN_STATUS(opponent, TRUE); } if (move == MOVE_FIRE_FANG) { ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponent); diff --git a/test/battle/move_effects_combined/triple_arrows.c b/test/battle/move_effects_combined/triple_arrows.c index 70414e51c4..80318e823f 100644 --- a/test/battle/move_effects_combined/triple_arrows.c +++ b/test/battle/move_effects_combined/triple_arrows.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Triple Arrows may lower Defense by one stage") { - u32 ability; + enum Ability ability; u32 chance; PARAMETRIZE { ability = ABILITY_HUSTLE; chance = 50; } PARAMETRIZE { ability = ABILITY_SERENE_GRACE; chance = 100; } @@ -28,7 +28,7 @@ SINGLE_BATTLE_TEST("Triple Arrows may lower Defense by one stage") SINGLE_BATTLE_TEST("Triple Arrows makes the foe flinch 30% of the time") { - u32 ability; + enum Ability ability; u32 chance; PARAMETRIZE { ability = ABILITY_HUSTLE; chance = 30; } PARAMETRIZE { ability = ABILITY_SERENE_GRACE; chance = 60; } diff --git a/test/battle/move_flags/ignores_target_ability.c b/test/battle/move_flags/ignores_target_ability.c index 25e0f9a20f..4a533e7a08 100644 --- a/test/battle/move_flags/ignores_target_ability.c +++ b/test/battle/move_flags/ignores_target_ability.c @@ -10,7 +10,8 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("ignoresTargetAbility moves do not ignore the attacker's own ability", s16 damage) { - u32 ability, move; + enum Ability ability; + u32 move; PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_MAGIC_GUARD; } PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_UNAWARE; } @@ -47,7 +48,8 @@ SINGLE_BATTLE_TEST("ignoresTargetAbility moves do not ignore the attacker's own SINGLE_BATTLE_TEST("ignoresTargetAbility moves do ignore target's abilities", s16 damage) { - u32 ability, move; + enum Ability ability; + u32 move; PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_INNER_FOCUS; } PARAMETRIZE { move = MOVE_SUNSTEEL_STRIKE; ability = ABILITY_MULTISCALE; } @@ -76,7 +78,7 @@ SINGLE_BATTLE_TEST("ignoresTargetAbility moves do ignore target's abilities", s1 SINGLE_BATTLE_TEST("ignoresTargetAbility allows Pokémon with Battle Armor and Shell Armor to receive critical hits") { u32 species; - u32 ability; + enum Ability ability; PARAMETRIZE { species = SPECIES_KINGLER; ability = ABILITY_SHELL_ARMOR; } PARAMETRIZE { species = SPECIES_ARMALDO; ability = ABILITY_BATTLE_ARMOR; } diff --git a/test/battle/sleep_clause.c b/test/battle/sleep_clause.c index 3b8999f668..e45945a29f 100644 --- a/test/battle/sleep_clause.c +++ b/test/battle/sleep_clause.c @@ -1035,7 +1035,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mon is woken up by gaining the ability Insomnia / Vital Spirit") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { ability = ABILITY_INSOMNIA; } GIVEN { @@ -1072,7 +1072,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mon is sent out, has Trace, and Traces Insomnia / Vital spirit") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { ability = ABILITY_INSOMNIA; } @@ -1110,7 +1110,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mon is sent out and transforms into a mon with Insomnia / Vital spirit") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { ability = ABILITY_INSOMNIA; } KNOWN_FAILING; // Sleep Clause parts work, but Imposter seems broken with battle messages / targeting. Issue #5565 https://github.com/rh-hideout/pokeemerald-expansion/issues/5565 @@ -1404,7 +1404,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Waking up after Rest doesn't deactivate sleep SINGLE_BATTLE_TEST("Sleep Clause: Suppressing and then sleeping Vital Spirit / Insomnia and switching back in deactivates sleep clause") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { ability = ABILITY_INSOMNIA; } GIVEN { @@ -1435,7 +1435,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Suppressing and then sleeping Vital Spirit / I SINGLE_BATTLE_TEST("Sleep Clause: Mold Breaker Pokémon sleeping Vital Spirit / Insomnia activates sleep clause") { - u32 ability; + enum Ability ability; PARAMETRIZE { ability = ABILITY_VITAL_SPIRIT; } PARAMETRIZE { ability = ABILITY_INSOMNIA; } GIVEN { diff --git a/test/battle/status1/burn.c b/test/battle/status1/burn.c index 689338cce8..8ec9d05835 100644 --- a/test/battle/status1/burn.c +++ b/test/battle/status1/burn.c @@ -74,7 +74,8 @@ SINGLE_BATTLE_TEST("Will-O-Wisp can't burn a fire type") AI_SINGLE_BATTLE_TEST("AI avoids Will-o-Wisp when it can not burn target") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_BUIZEL; ability = ABILITY_WATER_VEIL; } PARAMETRIZE { species = SPECIES_DEWPIDER; ability = ABILITY_WATER_BUBBLE; } diff --git a/test/battle/status1/frostbite.c b/test/battle/status1/frostbite.c index 35503b00a3..e221a0eae3 100644 --- a/test/battle/status1/frostbite.c +++ b/test/battle/status1/frostbite.c @@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Frostbite deals 1/16th (Gen7+) or 1/8th damage to affected P TURN {} } SCENE { MESSAGE("The opposing Wobbuffet was hurt by its frostbite!"); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRB, opponent); HP_BAR(opponent, captureDamage: &frostbiteDamage); } THEN { EXPECT_EQ(frostbiteDamage, opponent->maxHP / ((B_BURN_DAMAGE >= GEN_7) ? 16 : 8)); } } @@ -86,11 +86,11 @@ SINGLE_BATTLE_TEST("Frostbite is healed when the user uses a thawing move") HP_BAR(opponent); if (move == MOVE_EMBER) { MESSAGE("Wobbuffet was hurt by its frostbite!"); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRB, player); } else { NONE_OF { MESSAGE("Wobbuffet was hurt by its frostbite!"); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRB, player); } } } diff --git a/test/battle/status1/paralysis.c b/test/battle/status1/paralysis.c index 1354c6490b..0be8cf1ef9 100644 --- a/test/battle/status1/paralysis.c +++ b/test/battle/status1/paralysis.c @@ -47,7 +47,8 @@ SINGLE_BATTLE_TEST("Paralysis has a 25% chance of skipping the turn") AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_HITMONLEE; ability = ABILITY_LIMBER; } PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; } diff --git a/test/battle/status1/sleep.c b/test/battle/status1/sleep.c index 7a9f60d5fe..a43daf8d65 100644 --- a/test/battle/status1/sleep.c +++ b/test/battle/status1/sleep.c @@ -52,7 +52,8 @@ SINGLE_BATTLE_TEST("Sleep: Spore doesn't affect grass types (Gen6+)") AI_SINGLE_BATTLE_TEST("AI avoids hypnosis when it can not put target to sleep") { - u32 species, ability; + u32 species; + enum Ability ability; PARAMETRIZE { species = SPECIES_HOOTHOOT; ability = ABILITY_INSOMNIA; } PARAMETRIZE { species = SPECIES_MANKEY; ability = ABILITY_VITAL_SPIRIT; } diff --git a/test/battle/switch_in_abilities.c b/test/battle/switch_in_abilities.c index c8a8c54dd3..4d125ddce8 100644 --- a/test/battle/switch_in_abilities.c +++ b/test/battle/switch_in_abilities.c @@ -126,3 +126,124 @@ DOUBLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO swi } } } + +MULTI_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - multibattle") +{ + u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2; + + PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; } + PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; } + PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; } + + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); } + MULTI_PARTNER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PARTNER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WEEZING_GALAR) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); } + MULTI_OPPONENT_B(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_B(SPECIES_VULPIX_ALOLA) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 1); SEND_OUT(opponentLeft, 1); SEND_OUT(playerRight, 4); SEND_OUT(opponentRight, 4); } + TURN { ; } + } SCENE { + MESSAGE("Wobbuffet used Explosion!"); + if (spdPlayer1 == 5) { + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } else if (spdOpponent2 == 5) { + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + } else { + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } + } +} + +TWO_VS_ONE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - 2v1") +{ + u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2; + + PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; } + PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; } + PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; } + + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); } + MULTI_PARTNER(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_PARTNER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WEEZING_GALAR) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); } + MULTI_OPPONENT_A(SPECIES_VULPIX_ALOLA) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 1); SEND_OUT(opponentLeft, 2); SEND_OUT(playerRight, 4); SEND_OUT(opponentRight, 3); } + } SCENE { + MESSAGE("Wobbuffet used Explosion!"); + if (spdPlayer1 == 5) { + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } else if (spdOpponent2 == 5) { + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + } else { + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } + } +} + +ONE_VS_TWO_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO switch - 1v2") +{ + u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2; + + PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; } + PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; } + PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; } + + GIVEN { + MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_PLAYER(SPECIES_TYRANITAR) { Speed(spdPlayer1); Ability(ABILITY_SAND_STREAM); } + MULTI_PLAYER(SPECIES_GYARADOS) { Speed(spdPlayer2); Ability(ABILITY_INTIMIDATE); } + MULTI_OPPONENT_A(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + MULTI_OPPONENT_A(SPECIES_WEEZING_GALAR) { Speed(spdOpponent1); Ability(ABILITY_MISTY_SURGE); } + MULTI_OPPONENT_B(SPECIES_WYNAUT) { HP(1); Speed(1); } + MULTI_OPPONENT_B(SPECIES_VULPIX_ALOLA) { Speed(spdOpponent2); Ability(ABILITY_SNOW_WARNING); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 1); SEND_OUT(playerRight, 3); SEND_OUT(opponentRight, 4); } + } SCENE { + MESSAGE("Wobbuffet used Explosion!"); + if (spdPlayer1 == 5) { + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } else if (spdOpponent2 == 5) { + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + } else { + ABILITY_POPUP(opponentLeft, ABILITY_MISTY_SURGE); + ABILITY_POPUP(playerLeft, ABILITY_SAND_STREAM); + ABILITY_POPUP(playerRight, ABILITY_INTIMIDATE); + ABILITY_POPUP(opponentRight, ABILITY_SNOW_WARNING); + } + } +} diff --git a/test/battle/weather/sandstorm.c b/test/battle/weather/sandstorm.c index 96a440a10e..d01bd72ce4 100644 --- a/test/battle/weather/sandstorm.c +++ b/test/battle/weather/sandstorm.c @@ -97,8 +97,8 @@ SINGLE_BATTLE_TEST("Sandstorm damage rounds properly when maxHP < 16") SINGLE_BATTLE_TEST("Sandstorm doesn't do damage when weather is negated") { - u32 type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); - u32 type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); + enum Type type1 = GetSpeciesType(SPECIES_STOUTLAND, 0); + enum Type type2 = GetSpeciesType(SPECIES_STOUTLAND, 1); GIVEN { ASSUME(type1 != TYPE_ROCK && type2 != TYPE_ROCK); ASSUME(type1 != TYPE_GROUND && type2 != TYPE_GROUND); diff --git a/test/daycare.c b/test/daycare.c index 1f142f1154..3792737030 100644 --- a/test/daycare.c +++ b/test/daycare.c @@ -51,7 +51,10 @@ TEST("(Daycare) Pokémon can breed with Ditto if they don't belong to the Ditto ZeroPlayerPartyMons(); for (j = 1; j < NUM_SPECIES; j++) - PARAMETRIZE { parentSpecies = j; } + { + if (IsSpeciesEnabled(j)) + PARAMETRIZE { parentSpecies = j; } + } VarSet(VAR_TEMP_C, parentSpecies); RUN_OVERWORLD_SCRIPT( givemon SPECIES_DITTO, 100; givemon VAR_TEMP_C, 100; diff --git a/test/pokemon.c b/test/pokemon.c index d6c0cb4d42..c902e56e45 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -5,6 +5,7 @@ #include "test/overworld_script.h" #include "test/test.h" #include "constants/characters.h" +#include "constants/move_relearner.h" TEST("Nature independent from Hidden Nature") { @@ -25,7 +26,8 @@ TEST("Nature independent from Hidden Nature") TEST("Terastallization type defaults to primary or secondary type") { - u32 i, teraType; + u32 i; + enum Type teraType; struct Pokemon mon; for (i = 0; i < 128; i++) PARAMETRIZE {} CreateMon(&mon, SPECIES_PIDGEY, 100, 0, FALSE, 0, OT_ID_PRESET, 0); @@ -36,7 +38,8 @@ TEST("Terastallization type defaults to primary or secondary type") TEST("Terastallization type can be set to any type except TYPE_NONE") { - u32 i, teraType; + u32 i; + enum Type teraType; struct Pokemon mon; for (i = 1; i < NUMBER_OF_MON_TYPES; i++) { @@ -49,7 +52,8 @@ TEST("Terastallization type can be set to any type except TYPE_NONE") TEST("Terastallization type is reset to the default types when setting Tera Type back to TYPE_NONE") { - u32 i, teraType, typeNone; + u32 i; + enum Type teraType, typeNone; struct Pokemon mon; for (i = 1; i < NUMBER_OF_MON_TYPES; i++) { diff --git a/test/species.c b/test/species.c index 06351f179e..c4d91e60e5 100644 --- a/test/species.c +++ b/test/species.c @@ -106,7 +106,7 @@ TEST("No species has two evolutions that use the evolution tracker") for (i = 0; i < NUM_SPECIES; i++) { - if (GetSpeciesEvolutions(i) != NULL) PARAMETRIZE { species = i; } + if (IsSpeciesEnabled(i) && GetSpeciesEvolutions(i) != NULL) PARAMETRIZE { species = i; } } evolutionTrackerEvolutions = 0; diff --git a/test/test_runner.c b/test/test_runner.c index ac4b20cd2c..ef12e8d5f1 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -10,6 +10,7 @@ #include "constants/characters.h" #include "test_runner.h" #include "test/test.h" +#include "test/battle.h" #define TIMEOUT_SECONDS 60 @@ -482,6 +483,7 @@ void Test_ExpectCrash(bool32 expectCrash) static void FunctionTest_SetUp(void *data) { (void)data; + ClearRiggedRng(); gFunctionTestRunnerState = AllocZeroed(sizeof(*gFunctionTestRunnerState)); SeedRng(0); } @@ -513,12 +515,84 @@ static bool32 FunctionTest_CheckProgress(void *data) return madeProgress; } +static u32 FunctionTest_RandomUniform(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) +{ + //rigged + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == tag) + { + if (reject && reject(gFunctionTestRunnerState->rngList[i].value)) + Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", gFunctionTestRunnerState->rngList[i].value); + return gFunctionTestRunnerState->rngList[i].value; + } + } + //trials + /* + if (tag == STATE->rngTag) + return RandomUniformTrials(tag, lo, hi, reject); + */ + + //default + return RandomUniformDefaultValue(tag, lo, hi, reject, caller); +} + +static u32 FunctionTest_RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller) +{ + //rigged + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == tag) + return gFunctionTestRunnerState->rngList[i].value; + } + + //trials + /* + if (tag == STATE->rngTag) + return RandomWeightedArrayTrials(tag, sum, n, weights); + */ + + //default + return RandomWeightedArrayDefaultValue(tag, n, weights, caller); +} + +static const void* FunctionTest_RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) +{ + //rigged + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == tag) + { + u32 element = 0; + for (u32 index = 0; index < count; index++) + { + memcpy(&element, (const u8 *)array + size * index, size); + if (element == gFunctionTestRunnerState->rngList[i].value) + return (const u8 *)array + size * index; + } + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, gFunctionTestRunnerState->rngList[i].value); + } + } + + //trials + /* + if (tag == STATE->rngTag) + return RandomElementTrials(tag, array, size, count); + */ + + //default + return RandomElementArrayDefaultValue(tag, array, size, count, caller); +} + const struct TestRunner gFunctionTestRunner = { .setUp = FunctionTest_SetUp, .run = FunctionTest_Run, .tearDown = FunctionTest_TearDown, .checkProgress = FunctionTest_CheckProgress, + .randomUniform = FunctionTest_RandomUniform, + .randomWeightedArray = FunctionTest_RandomWeightedArray, + .randomElementArray = FunctionTest_RandomElementArray, }; static void Assumptions_Run(void *data) @@ -826,3 +900,102 @@ u32 SourceLineOffset(u32 sourceLine) else return sourceLine - test->sourceLine; } + +u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomUniform) + return gTestRunnerState.test->runner->randomUniform(tag, lo, hi, NULL, caller); + else + return RandomUniformDefault(tag, lo, hi); +} + +u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32)) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomUniform) + return gTestRunnerState.test->runner->randomUniform(tag, lo, hi, reject, caller); + else + return RandomUniformExceptDefault(tag, lo, hi, reject); +} + +u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomWeightedArray) + return gTestRunnerState.test->runner->randomWeightedArray(tag, sum, n, weights, caller); + else + return RandomWeightedArrayDefault(tag, sum, n, weights); +} + +const void *RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count) +{ + void *caller = __builtin_extract_return_addr(__builtin_return_address(0)); + if (gTestRunnerState.test->runner->randomElementArray) + return gTestRunnerState.test->runner->randomElementArray(tag, array, size, count, caller); + else + return RandomElementArrayDefault(tag, array, size, count); +} + +u32 RandomUniformDefaultValue(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) +{ + u32 default_ = hi; + if (reject) + { + while (reject(default_)) + { + if (default_ == lo) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d rejected all values", caller, tag); + default_--; + } + } + return default_; +} + +u32 RandomWeightedArrayDefaultValue(enum RandomTag tag, u32 n, const u8 *weights, void *caller) +{ + while (weights[n-1] == 0) + { + if (n == 1) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called from %p with tag %d and all zero weights", caller, tag); + n--; + } + return n-1; +} + +const void *RandomElementArrayDefaultValue(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) +{ + return (const u8 *)array + size * (count - 1); +} + +void ClearRiggedRng(void) +{ + struct RiggedRNG zeroRng = {.tag = RNG_NONE, .value = 0}; + for (u32 i = 0; i < RIGGED_RNG_COUNT; i++) + memcpy(&gFunctionTestRunnerState->rngList[i], &zeroRng, sizeof(zeroRng)); +} + +void SetupRiggedRng(u32 sourceLine, enum RandomTag randomTag, u32 value) +{ + struct RiggedRNG rng = {.tag = randomTag, .value = value}; + u32 i; + for (i = 0; i < RIGGED_RNG_COUNT; i++) + { + if (gFunctionTestRunnerState->rngList[i].tag == randomTag) + { + memcpy(&gFunctionTestRunnerState->rngList[i], &rng, sizeof(rng)); + break; + } + else if (gFunctionTestRunnerState->rngList[i].tag > RNG_NONE) + { + continue; + } + else + { + memcpy(&gFunctionTestRunnerState->rngList[i], &rng, sizeof(rng)); + break; + } + } + if (i == RIGGED_RNG_COUNT) + Test_ExitWithResult(TEST_RESULT_FAIL, __LINE__, ":L%s:%d: Too many rigged RNGs to set up", gTestRunnerState.test->filename, sourceLine); +} diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 395381d1d2..a42b671552 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -3,6 +3,7 @@ #include "battle_ai_util.h" #include "battle_anim.h" #include "battle_controllers.h" +#include "battle_setup.h" #include "battle_gimmick.h" #include "battle_z_move.h" #include "event_data.h" @@ -10,11 +11,13 @@ #include "item_menu.h" #include "main.h" #include "malloc.h" +#include "party_menu.h" #include "random.h" #include "test/battle.h" #include "window.h" #include "constants/characters.h" #include "constants/trainers.h" +#include "constants/abilities.h" #if defined(__INTELLISENSE__) #undef TestRunner_Battle_RecordAbilityPopUp @@ -75,7 +78,7 @@ NAKED static void InvokeSingleTestFunctionWithStack(void *results, u32 i, struct .pool"); } -NAKED static void InvokeDoubleTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, SingleBattleTestFunction function, void *stack) +NAKED static void InvokeDoubleTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, DoubleBattleTestFunction function, void *stack) { asm("push {r4-r7,lr}\n\ ldr r4, [sp, #28] @ function\n\ @@ -99,6 +102,78 @@ NAKED static void InvokeDoubleTestFunctionWithStack(void *results, u32 i, struct .pool"); } +NAKED static void InvokeMultiTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, MultiBattleTestFunction function, void *stack) +{ + asm("push {r4-r7,lr}\n\ + ldr r4, [sp, #28] @ function\n\ + ldr r5, [sp, #32] @ stack\n\ + mov r6, sp\n\ + mov sp, r5\n\ + push {r6}\n\ + add r6, #20\n\ + ldmia r6, {r6, r7} @ playerRight, opponentRight\n\ + push {r6, r7}\n\ + ldr r6, =MultiRestoreSP + 1\n\ + mov lr, r6\n\ + bx r4\n\ + MultiRestoreSP:\n\ + add sp, #8\n\ + pop {r0}\n\ + mov sp, r0\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool"); +} + +NAKED static void InvokeTwoVsOneTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, TwoVsOneBattleTestFunction function, void *stack) +{ + asm("push {r4-r7,lr}\n\ + ldr r4, [sp, #28] @ function\n\ + ldr r5, [sp, #32] @ stack\n\ + mov r6, sp\n\ + mov sp, r5\n\ + push {r6}\n\ + add r6, #20\n\ + ldmia r6, {r6, r7} @ playerRight, opponentRight\n\ + push {r6, r7}\n\ + ldr r6, =TwoVsOneRestoreSP + 1\n\ + mov lr, r6\n\ + bx r4\n\ + TwoVsOneRestoreSP:\n\ + add sp, #8\n\ + pop {r0}\n\ + mov sp, r0\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool"); +} + +NAKED static void InvokeOneVsTwoTestFunctionWithStack(void *results, u32 i, struct BattlePokemon *playerLeft, struct BattlePokemon *opponentLeft, struct BattlePokemon *playerRight, struct BattlePokemon *opponentRight, OneVsTwoBattleTestFunction function, void *stack) +{ + asm("push {r4-r7,lr}\n\ + ldr r4, [sp, #28] @ function\n\ + ldr r5, [sp, #32] @ stack\n\ + mov r6, sp\n\ + mov sp, r5\n\ + push {r6}\n\ + add r6, #20\n\ + ldmia r6, {r6, r7} @ playerRight, opponentRight\n\ + push {r6, r7}\n\ + ldr r6, =OneVsTwoRestoreSP + 1\n\ + mov lr, r6\n\ + bx r4\n\ + OneVsTwoRestoreSP:\n\ + add sp, #8\n\ + pop {r0}\n\ + mov sp, r0\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0\n\ + .pool"); +} + // Calls test->function, but pointing its stack at DATA.stack so that // local variables are live after the function returns (and so can be // referenced by HP_BAR, or the next call, etc). @@ -117,7 +192,19 @@ static void InvokeTestFunction(const struct BattleTest *test) break; case BATTLE_TEST_DOUBLES: case BATTLE_TEST_AI_DOUBLES: - InvokeDoubleTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.singles, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + InvokeDoubleTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.doubles, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + break; + case BATTLE_TEST_MULTI: + case BATTLE_TEST_AI_MULTI: + InvokeMultiTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.multi, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + break; + case BATTLE_TEST_TWO_VS_ONE: + case BATTLE_TEST_AI_TWO_VS_ONE: + InvokeTwoVsOneTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.two_vs_one, &DATA.stack[BATTLE_TEST_STACK_SIZE]); + break; + case BATTLE_TEST_ONE_VS_TWO: + case BATTLE_TEST_AI_ONE_VS_TWO: + InvokeOneVsTwoTestFunctionWithStack(STATE->results, STATE->runParameter, &gBattleMons[B_POSITION_PLAYER_LEFT], &gBattleMons[B_POSITION_OPPONENT_LEFT], &gBattleMons[B_POSITION_PLAYER_RIGHT], &gBattleMons[B_POSITION_OPPONENT_RIGHT], test->function.one_vs_two, &DATA.stack[BATTLE_TEST_STACK_SIZE]); break; } } @@ -134,6 +221,9 @@ static bool32 IsAITest(void) { case BATTLE_TEST_AI_SINGLES: case BATTLE_TEST_AI_DOUBLES: + case BATTLE_TEST_AI_MULTI: + case BATTLE_TEST_AI_TWO_VS_ONE: + case BATTLE_TEST_AI_ONE_VS_TWO: return TRUE; } return FALSE; @@ -178,6 +268,12 @@ static void BattleTest_SetUp(void *data) break; case BATTLE_TEST_DOUBLES: case BATTLE_TEST_AI_DOUBLES: + case BATTLE_TEST_MULTI: + case BATTLE_TEST_AI_MULTI: + case BATTLE_TEST_TWO_VS_ONE: + case BATTLE_TEST_AI_TWO_VS_ONE: + case BATTLE_TEST_ONE_VS_TWO: + case BATTLE_TEST_AI_ONE_VS_TWO: STATE->battlersCount = 4; break; } @@ -262,26 +358,97 @@ static void BattleTest_Run(void *data) { case BATTLE_TEST_WILD: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; break; case BATTLE_TEST_AI_SINGLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER; DATA.recordedBattle.opponentA = TRAINER_LEAF; DATA.hasAI = TRUE; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; break; case BATTLE_TEST_AI_DOUBLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE; DATA.recordedBattle.opponentA = TRAINER_LEAF; + DATA.recordedBattle.opponentB = TRAINER_NONE; + DATA.hasAI = TRUE; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; + break; + case BATTLE_TEST_AI_MULTI: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_LEAF; DATA.recordedBattle.opponentB = TRAINER_RED; DATA.hasAI = TRUE; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon + break; + case BATTLE_TEST_AI_TWO_VS_ONE: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_LEAF; + DATA.recordedBattle.opponentB = 0xFFFF; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 1; // Opponent second mon + DATA.hasAI = TRUE; + break; + case BATTLE_TEST_AI_ONE_VS_TWO: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.opponentA = TRAINER_LEAF; + DATA.recordedBattle.opponentB = TRAINER_RED; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 1; // Player second mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon + DATA.hasAI = TRUE; break; case BATTLE_TEST_SINGLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER; DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; break; case BATTLE_TEST_DOUBLES: DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE; DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + DATA.recordedBattle.opponentB = TRAINER_NONE; + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; + break; + case BATTLE_TEST_MULTI: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; DATA.recordedBattle.opponentB = TRAINER_LINK_OPPONENT; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon + break; + case BATTLE_TEST_TWO_VS_ONE: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_MULTI; + DATA.recordedBattle.partnerId = TRAINER_PARTNER(PARTNER_STEVEN); + DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + DATA.recordedBattle.opponentB = 0xFFFF; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent first mon + DATA.currentMonIndexes[2] = 3; // Player partner first mon + DATA.currentMonIndexes[3] = 1; // Opponent second mon + break; + case BATTLE_TEST_ONE_VS_TWO: + DATA.recordedBattle.battleFlags = BATTLE_TYPE_IS_MASTER | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS; + DATA.recordedBattle.opponentA = TRAINER_LINK_OPPONENT; + DATA.recordedBattle.opponentB = TRAINER_LINK_OPPONENT; + DATA.currentMonIndexes[0] = 0; // Player first mon + DATA.currentMonIndexes[1] = 0; // Opponent A first mon + DATA.currentMonIndexes[2] = 1; // Player second mon + DATA.currentMonIndexes[3] = 3; // Opponent B first mon break; } @@ -293,9 +460,6 @@ static void BattleTest_Run(void *data) DATA.recordedBattle.playersBattlers[i] = i; } - for (i = 0; i < STATE->battlersCount; i++) - DATA.currentMonIndexes[i] = i / 2; - STATE->runRandomly = TRUE; STATE->runGiven = TRUE; STATE->runWhen = TRUE; @@ -325,10 +489,46 @@ static void BattleTest_Run(void *data) if (DATA.hasExplicitSpeeds) { - // TODO: If a battler is taking the default action maybe it - // should not require an explicit speed? - if (DATA.explicitSpeeds[B_SIDE_PLAYER] != (1 << DATA.playerPartySize) - 1 - || DATA.explicitSpeeds[B_SIDE_OPPONENT] != (1 << DATA.opponentPartySize) - 1) + u8 revisedPlayerExplicitSpeeds = 0; + u8 revisedPartnerExplicitSpeeds = 0; + u8 revisedOpponentAExplicitSpeeds = 0; + u8 revisedOpponentBExplicitSpeeds = 0; + + for (i = 0; i < 3; i++) + { + if(GetMonData(&DATA.recordedBattle.playerParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + revisedPlayerExplicitSpeeds |= 1 << i; + } + for (i = 3; i < PARTY_SIZE; i++) + { + if(GetMonData(&DATA.recordedBattle.playerParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + { + if(DATA.currentPosition == B_POSITION_PLAYER_LEFT) + revisedPlayerExplicitSpeeds |= 1 << i; + else + revisedPartnerExplicitSpeeds |= 1 << i; + } + } + + for (i = 0; i < 3; i++) + { + if(GetMonData(&DATA.recordedBattle.opponentParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + revisedOpponentAExplicitSpeeds |= 1 << i; + } + for (i = 3; i < PARTY_SIZE; i++) + { + if(GetMonData(&DATA.recordedBattle.opponentParty[i], MON_DATA_SPECIES, NULL) != SPECIES_NONE) + { + if(DATA.currentPosition == B_POSITION_OPPONENT_LEFT) + revisedOpponentAExplicitSpeeds |= 1 << i; + else + revisedOpponentBExplicitSpeeds |= 1 << i; + } + } + + if (((DATA.explicitSpeeds[B_POSITION_PLAYER_LEFT] + DATA.explicitSpeeds[B_POSITION_PLAYER_RIGHT]) != (revisedPlayerExplicitSpeeds + revisedPartnerExplicitSpeeds) + || (DATA.explicitSpeeds[B_POSITION_OPPONENT_LEFT] + DATA.explicitSpeeds[B_POSITION_OPPONENT_RIGHT]) != (revisedOpponentAExplicitSpeeds + revisedOpponentBExplicitSpeeds))) + { Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LSpeed required for all PLAYERs and OPPONENTs"); } @@ -354,96 +554,113 @@ static void BattleTest_Run(void *data) PrintTestName(); } -u32 RandomUniform(enum RandomTag tag, u32 lo, u32 hi) +u32 RandomUniformTrials(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) { - const struct BattlerTurn *turn = NULL; - - if (gCurrentTurnActionNumber < gBattlersCount) + STATE->didRunRandomly = TRUE; + if (STATE->trials == 1) { - u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; - if (turn && turn->rng.tag == tag) - return turn->rng.value; - } - - if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - u32 n = hi - lo + 1; - if (STATE->trials == 1) + u32 n = 0, i; + if (reject) { - STATE->trials = n; - PrintTestName(); - } - else if (STATE->trials != n) - { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, n); - } - STATE->trialRatio = Q_4_12(1) / STATE->trials; - return STATE->runTrial + lo; - } - - return hi; -} - -u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32)) -{ - const struct BattlerTurn *turn = NULL; - u32 default_; - - if (gCurrentTurnActionNumber < gBattlersCount) - { - u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; - if (turn && turn->rng.tag == tag) - { - if (reject(turn->rng.value)) - Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", turn->rng.value); - return turn->rng.value; - } - } - - if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - if (STATE->trials == 1) - { - u32 n = 0, i; for (i = lo; i <= hi; i++) if (!reject(i)) n++; STATE->trials = n; - PrintTestName(); } - STATE->trialRatio = Q_4_12(1) / STATE->trials; - - while (reject(STATE->runTrial + lo + STATE->rngTrialOffset)) - { - if (STATE->runTrial + lo + STATE->rngTrialOffset > hi) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d and inconsistent reject", __builtin_extract_return_addr(__builtin_return_address(0)), tag); - STATE->rngTrialOffset++; - } - - return STATE->runTrial + lo + STATE->rngTrialOffset; + else + STATE->trials = hi - lo + 1; + PrintTestName(); } + STATE->trialRatio = Q_4_12(1) / STATE->trials; - default_ = hi; - while (reject(default_)) + if (!reject) { - if (default_ == lo) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d rejected all values", __builtin_extract_return_addr(__builtin_return_address(0)), tag); - default_--; + if (STATE->trials != (hi - lo + 1)) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniform called from %p with tag %d and inconsistent trials %d and %d", caller, tag, STATE->trials, hi - lo + 1); + return STATE->runTrial + lo; } - return default_; + + while (reject(STATE->runTrial + lo + STATE->rngTrialOffset)) + { + if (STATE->runTrial + lo + STATE->rngTrialOffset > hi) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomUniformExcept called from %p with tag %d and inconsistent reject", caller, tag); + STATE->rngTrialOffset++; + } + + return STATE->runTrial + lo + STATE->rngTrialOffset; + } -u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) +u32 RandomWeightedArrayTrials(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller) { + //Detect inconsistent sum + u32 weightSum = 0; + if (STATE->runTrial == 0) + { + for (u32 i = 0; i < n; i++) + weightSum += weights[i]; + if (weightSum != sum) + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called from %p has weights not matching its sum", caller); + } + + STATE->didRunRandomly = TRUE; + if (STATE->trials == 1) + { + STATE->trials = n; + PrintTestName(); + } + else if (STATE->trials != n) + { + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called from %p with tag %d and inconsistent trials %d and %d", caller, tag, STATE->trials, n); + } + + STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum; + return STATE->runTrial; +} + +const void *RandomElementArrayTrials(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) +{ + STATE->didRunRandomly = TRUE; + if (STATE->trials == 1) + { + STATE->trials = count; + PrintTestName(); + } + else if (STATE->trials != count) + { + Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called from %p with tag %d and inconsistent trials %d and %d", caller, tag, STATE->trials, count); + } + STATE->trialRatio = Q_4_12(1) / count; + return (const u8 *)array + size * STATE->runTrial; +} + +static u32 BattleTest_RandomUniform(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32), void *caller) +{ + //rigged const struct BattlerTurn *turn = NULL; + if (gCurrentTurnActionNumber < gBattlersCount) + { + u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; + turn = &DATA.battleRecordTurns[gBattleResults.battleTurnCounter][battlerId]; + if (turn && turn->rng.tag == tag) + { + if (reject && reject(turn->rng.value)) + Test_ExitWithResult(TEST_RESULT_INVALID, SourceLine(0), ":LWITH_RNG specified a rejected value (%d)", turn->rng.value); + return turn->rng.value; + } + } + //trials + if (tag == STATE->rngTag) + return RandomUniformTrials(tag, lo, hi, reject, caller); - if (sum == 0) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called with zero sum"); + //default + return RandomUniformDefaultValue(tag, lo, hi, reject, caller); +} +static u32 BattleTest_RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights, void *caller) +{ + //rigged + const struct BattlerTurn *turn = NULL; if (gCurrentTurnActionNumber < gBattlersCount || tag == RNG_SHELL_SIDE_ARM) { u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; @@ -452,23 +669,11 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) return turn->rng.value; } + //trials if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - if (STATE->trials == 1) - { - STATE->trials = n; - PrintTestName(); - } - else if (STATE->trials != n) - { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeighted called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, n); - } - // TODO: Detect inconsistent sum. - STATE->trialRatio = Q_4_12(weights[STATE->runTrial]) / sum; - return STATE->runTrial; - } + return RandomWeightedArrayTrials(tag, sum, n, weights, caller); + //default switch (tag) { case RNG_ACCURACY: @@ -493,21 +698,14 @@ u32 RandomWeightedArray(enum RandomTag tag, u32 sum, u32 n, const u8 *weights) return TRUE; default: - while (weights[n-1] == 0) - { - if (n == 1) - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomWeightedArray called from %p with tag %d and all zero weights", __builtin_extract_return_addr(__builtin_return_address(0)), tag); - n--; - } - return n-1; + return RandomWeightedArrayDefaultValue(tag, n, weights, caller); } } -const void *RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count) +static const void *BattleTest_RandomElementArray(enum RandomTag tag, const void *array, size_t size, size_t count, void *caller) { + //rigged const struct BattlerTurn *turn = NULL; - u32 index = count-1; - if (gCurrentTurnActionNumber < gBattlersCount) { u32 battlerId = gBattlerByTurnOrder[gCurrentTurnActionNumber]; @@ -515,36 +713,26 @@ const void *RandomElementArray(enum RandomTag tag, const void *array, size_t siz if (turn && turn->rng.tag == tag) { u32 element = 0; - for (index = 0; index < count; index++) + for (u32 index = 0; index < count; index++) { memcpy(&element, (const u8 *)array + size * index, size); if (element == turn->rng.value) return (const u8 *)array + size * index; } - // TODO: Incorporate the line number. Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":L%s: RandomElement illegal value requested: %d", gTestRunnerState.test->filename, turn->rng.value); } } + + //trials if (tag == STATE->rngTag) - { - STATE->didRunRandomly = TRUE; - if (STATE->trials == 1) - { - STATE->trials = count; - PrintTestName(); - } - else if (STATE->trials != count) - { - Test_ExitWithResult(TEST_RESULT_ERROR, SourceLine(0), ":LRandomElement called from %p with tag %d and inconsistent trials %d and %d", __builtin_extract_return_addr(__builtin_return_address(0)), tag, STATE->trials, count); - } - STATE->trialRatio = Q_4_12(1) / count; - return (const u8 *)array + size * STATE->runTrial; - } - return (const u8 *)array + size * index; + return RandomElementArrayTrials(tag, array, size, count, caller); + + //default + return RandomElementArrayDefaultValue(tag, array, size, count, caller); } -static s32 TryAbilityPopUp(s32 i, s32 n, u32 battlerId, u32 ability) +static s32 TryAbilityPopUp(s32 i, s32 n, u32 battlerId, enum Ability ability) { struct QueuedAbilityEvent *event; s32 iMax = i + n; @@ -562,7 +750,7 @@ static s32 TryAbilityPopUp(s32 i, s32 n, u32 battlerId, u32 ability) return -1; } -void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, u32 ability) +void TestRunner_Battle_RecordAbilityPopUp(u32 battlerId, enum Ability ability) { s32 queuedEvent; s32 match; @@ -765,6 +953,16 @@ static const char *const sBattleActionNames[] = [B_ACTION_SWITCH] = "SWITCH", }; +static const char *const sGimmickIdentifiers[GIMMICKS_COUNT] = +{ + [GIMMICK_NONE] = "N/A", + [GIMMICK_MEGA] = "Mega Evolution", + [GIMMICK_ULTRA_BURST] = "Ultra Burst", + [GIMMICK_Z_MOVE] = "Z-Move", + [GIMMICK_DYNAMAX] = "Dynamax", + [GIMMICK_TERA] = "Terastallize", +}; + static u32 CountAiExpectMoves(struct ExpectedAIAction *expectedAction, u32 battlerId, bool32 printLog) { u32 i, countExpected = 0; @@ -780,7 +978,7 @@ static u32 CountAiExpectMoves(struct ExpectedAIAction *expectedAction, u32 battl return countExpected; } -void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target) +void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target, enum Gimmick gimmick) { const char *filename = gTestRunnerState.test->filename; u32 id = DATA.trial.aiActionsPlayed[battlerId]; @@ -802,6 +1000,9 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target) if (expectedAction->explicitTarget && expectedAction->target != target) Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected target %s, got %s", filename, expectedAction->sourceLine, BattlerIdentifier(expectedAction->target), BattlerIdentifier(target)); + if (expectedAction->gimmick != GIMMICKS_COUNT && expectedAction->gimmick != gimmick) + Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Expected gimmick %s, got %s", filename, expectedAction->sourceLine, sGimmickIdentifiers[expectedAction->gimmick], sGimmickIdentifiers[gimmick]); + for (i = 0; i < MAX_MON_MOVES; i++) { if ((1u << i) & expectedAction->moveSlots) @@ -1496,14 +1697,24 @@ void RNGSeed_(u32 sourceLine, rng_value_t seed) void AIFlags_(u32 sourceLine, u64 flags) { - INVALID_IF(!IsAITest(), "AI_FLAGS is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); - DATA.recordedBattle.AI_scripts = flags; + INVALID_IF(!IsAITest(), "AI_FLAGS is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); + for (u32 i = 0; i < MAX_BATTLERS_COUNT; i++) + { + DATA.recordedBattle.AI_scripts[i] = flags; + } + DATA.hasAI = TRUE; +} + +void BattlerAIFlags_(u32 sourceLine, u32 battler, u64 flags) +{ + INVALID_IF(!IsAITest(), "AI_FLAGS is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); + DATA.recordedBattle.AI_scripts[battler] |= flags; DATA.hasAI = TRUE; } void AILogScores(u32 sourceLine) { - INVALID_IF(!IsAITest(), "AI_LOG is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "AI_LOG is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); DATA.logAI = TRUE; } @@ -1515,6 +1726,9 @@ const struct TestRunner gBattleTestRunner = .tearDown = BattleTest_TearDown, .checkProgress = BattleTest_CheckProgress, .handleExitWithResult = BattleTest_HandleExitWithResult, + .randomUniform = BattleTest_RandomUniform, + .randomWeightedArray = BattleTest_RandomWeightedArray, + .randomElementArray = BattleTest_RandomElementArray, }; void SetFlagForTest(u32 sourceLine, u16 flagId) @@ -1539,14 +1753,14 @@ void ClearFlagAfterTest(void) } } -void OpenPokemon(u32 sourceLine, u32 side, u32 species) +void OpenPokemon(u32 sourceLine, enum BattlerPosition position, u32 species) { s32 i, data; u8 *partySize; struct Pokemon *party; INVALID_IF(species >= SPECIES_EGG, "Invalid species: %d", species); ASSUMPTION_FAIL_IF(!IsSpeciesEnabled(species), "Species disabled: %d", species); - if (side == B_SIDE_PLAYER) + if ((position & BIT_SIDE) == B_SIDE_PLAYER) { partySize = &DATA.playerPartySize; party = DATA.recordedBattle.playerParty; @@ -1557,13 +1771,67 @@ void OpenPokemon(u32 sourceLine, u32 side, u32 species) party = DATA.recordedBattle.opponentParty; } INVALID_IF(*partySize >= PARTY_SIZE, "Too many Pokemon in party"); - DATA.currentSide = side; + DATA.currentPosition = position; DATA.currentPartyIndex = *partySize; DATA.currentMon = &party[DATA.currentPartyIndex]; DATA.gender = 0xFF; // Male DATA.nature = NATURE_HARDY; (*partySize)++; + CreateMon(DATA.currentMon, species, 100, 0, TRUE, 0, OT_ID_PRESET, 0); + data = MOVE_NONE; + for (i = 0; i < MAX_MON_MOVES; i++) + SetMonData(DATA.currentMon, MON_DATA_MOVE1 + i, &data); + data = 0; + if (B_FRIENDSHIP_BOOST) + { + // This way, we avoid the boost affecting tests unless explicitly stated. + SetMonData(DATA.currentMon, MON_DATA_FRIENDSHIP, &data); + CalculateMonStats(DATA.currentMon); + } +} + +void OpenPokemonMulti(u32 sourceLine, enum BattlerPosition position, u32 species) +{ + + s32 i, data; + u8 *partySize; + struct Pokemon *party; + INVALID_IF(species >= SPECIES_EGG, "Invalid species: %d", species); + ASSUMPTION_FAIL_IF(!IsSpeciesEnabled(species), "Species disabled: %d", species); + if (position == B_POSITION_PLAYER_LEFT) // MULTI_PLAYER + { + partySize = &DATA.playerPartySize; + party = DATA.recordedBattle.playerParty; + } + else if (position == B_POSITION_PLAYER_RIGHT) // MULTI_PARTNER + { + partySize = &DATA.playerPartySize; + if ((*partySize == 0) || (*partySize == 1) || (*partySize == 2)) + *partySize = 3; + party = DATA.recordedBattle.playerParty; + } + else if (position == B_POSITION_OPPONENT_LEFT) // MULTI_OPPONENT_A + { + partySize = &DATA.opponentPartySize; + party = DATA.recordedBattle.opponentParty; + } + else // MULTI_OPPONENT_B + { + partySize = &DATA.opponentPartySize; + if ((*partySize == 0) || (*partySize == 1) || (*partySize == 2)) + *partySize = 3; + party = DATA.recordedBattle.opponentParty; + } + INVALID_IF(*partySize >= PARTY_SIZE, "Too many Pokemon in party"); + DATA.currentPosition = position; + DATA.currentPartyIndex = *partySize; + DATA.currentMon = &party[DATA.currentPartyIndex]; + DATA.gender = 0xFF; // Male + DATA.nature = NATURE_HARDY; + DATA.isShiny = FALSE; + (*partySize)++; + CreateMon(DATA.currentMon, species, 100, 0, TRUE, 0, OT_ID_PRESET, 0); // Reset move IDs, but force PP to be non-zero. This is a safeguard against test species that only learn 1 move having test moves with 0 PP for (i = 0; i < MAX_MON_MOVES; i++) @@ -1607,21 +1875,32 @@ void ClosePokemon(u32 sourceLine) { s32 i; u32 data; - INVALID_IF(DATA.hasExplicitSpeeds && !(DATA.explicitSpeeds[DATA.currentSide] & (1 << DATA.currentPartyIndex)), "Speed required"); + INVALID_IF(DATA.hasExplicitSpeeds && !(DATA.explicitSpeeds[DATA.currentPosition] & (1 << DATA.currentPartyIndex)), "Speed required"); for (i = 0; i < STATE->battlersCount; i++) { - if ((i & BIT_SIDE) == DATA.currentSide + if (i == DATA.currentPosition && DATA.currentMonIndexes[i] == DATA.currentPartyIndex) { INVALID_IF(GetMonData(DATA.currentMon, MON_DATA_HP) == 0, "Battlers cannot be fainted"); } } - data = FALSE; - SetMonData(DATA.currentMon, MON_DATA_IS_SHINY, &data); UpdateMonPersonality(&DATA.currentMon->box, GenerateNature(DATA.nature, DATA.gender % NUM_NATURES) | DATA.gender); + data = DATA.isShiny; + SetMonData(DATA.currentMon, MON_DATA_IS_SHINY, &data); DATA.currentMon = NULL; } +static void SetGimmick(u32 sourceLine, u32 side, u32 partyIndex, enum Gimmick gimmick) +{ + enum Gimmick currentGimmick = DATA.chosenGimmick[side][partyIndex]; + if (!((currentGimmick == GIMMICK_ULTRA_BURST && gimmick == GIMMICK_Z_MOVE) + || (currentGimmick == GIMMICK_Z_MOVE && gimmick == GIMMICK_ULTRA_BURST))) + { + INVALID_IF(currentGimmick != GIMMICK_NONE && currentGimmick != gimmick, "Cannot set %s because %s already set", sGimmickIdentifiers[gimmick], sGimmickIdentifiers[currentGimmick]); + } + DATA.chosenGimmick[side][partyIndex] = gimmick; +} + void Gender_(u32 sourceLine, u32 gender) { const struct SpeciesInfo *info; @@ -1650,7 +1929,7 @@ void Nature_(u32 sourceLine, u32 nature) DATA.nature = nature; } -void Ability_(u32 sourceLine, u32 ability) +void Ability_(u32 sourceLine, enum Ability ability) { s32 i; u32 species; @@ -1670,7 +1949,7 @@ void Ability_(u32 sourceLine, u32 ability) // Store forced ability to be set when the battle starts if invalid. if (i == NUM_ABILITY_SLOTS) { - DATA.forcedAbilities[DATA.currentSide][DATA.currentPartyIndex] = ability; + DATA.forcedAbilities[DATA.currentPosition][DATA.currentPartyIndex] = ability; } } @@ -1748,7 +2027,7 @@ void Speed_(u32 sourceLine, u32 speed) bool32 hyperTrainingFlag = TRUE; SetMonData(DATA.currentMon, MON_DATA_HYPER_TRAINED_SPEED, &hyperTrainingFlag); DATA.hasExplicitSpeeds = TRUE; - DATA.explicitSpeeds[DATA.currentSide] |= 1 << DATA.currentPartyIndex; + DATA.explicitSpeeds[DATA.currentPosition] |= 1 << DATA.currentPartyIndex; } void HPIV_(u32 sourceLine, u32 hpIV) @@ -1798,6 +2077,17 @@ void Item_(u32 sourceLine, u32 item) INVALID_IF(!DATA.currentMon, "Item outside of PLAYER/OPPONENT"); INVALID_IF(item >= ITEMS_COUNT, "Illegal item: %d", item); SetMonData(DATA.currentMon, MON_DATA_HELD_ITEM, &item); + switch (GetItemHoldEffect(item)) + { + case HOLD_EFFECT_MEGA_STONE: + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_MEGA); + break; + case HOLD_EFFECT_Z_CRYSTAL: + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_Z_MOVE); + break; + default: + break; + } } void Moves_(u32 sourceLine, u16 moves[MAX_MON_MOVES]) @@ -1813,7 +2103,7 @@ void Moves_(u32 sourceLine, u16 moves[MAX_MON_MOVES]) u32 pp = GetMovePP(moves[i]); SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &pp); } - DATA.explicitMoves[DATA.currentSide] |= 1 << DATA.currentPartyIndex; + DATA.explicitMoves[DATA.currentPosition] |= 1 << DATA.currentPartyIndex; } void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]) @@ -1828,7 +2118,7 @@ void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]) SetMonData(DATA.currentMon, MON_DATA_MOVE1 + i, &moveWithPP[i].moveId); SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &moveWithPP[i].pp); } - DATA.explicitMoves[DATA.currentSide] |= 1 << DATA.currentPartyIndex; + DATA.explicitMoves[DATA.currentPosition] |= 1 << DATA.currentPartyIndex; } void Friendship_(u32 sourceLine, u32 friendship) @@ -1854,18 +2144,21 @@ void DynamaxLevel_(u32 sourceLine, u32 dynamaxLevel) { INVALID_IF(!DATA.currentMon, "DynamaxLevel outside of PLAYER/OPPONENT"); SetMonData(DATA.currentMon, MON_DATA_DYNAMAX_LEVEL, &dynamaxLevel); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_DYNAMAX); } void GigantamaxFactor_(u32 sourceLine, bool32 gigantamaxFactor) { INVALID_IF(!DATA.currentMon, "GigantamaxFactor outside of PLAYER/OPPONENT"); SetMonData(DATA.currentMon, MON_DATA_GIGANTAMAX_FACTOR, &gigantamaxFactor); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_DYNAMAX); } -void TeraType_(u32 sourceLine, u32 teraType) +void TeraType_(u32 sourceLine, enum Type teraType) { INVALID_IF(!DATA.currentMon, "TeraType outside of PLAYER/OPPONENT"); SetMonData(DATA.currentMon, MON_DATA_TERA_TYPE, &teraType); + SetGimmick(sourceLine, DATA.currentPosition, DATA.currentPartyIndex, GIMMICK_TERA); } void Shadow_(u32 sourceLine, bool32 isShadow) @@ -1874,6 +2167,19 @@ void Shadow_(u32 sourceLine, bool32 isShadow) SetMonData(DATA.currentMon, MON_DATA_IS_SHADOW, &isShadow); } +void Shiny_(u32 sourceLine, bool32 isShiny) +{ + INVALID_IF(!DATA.currentMon, "Shiny outside of PLAYER/OPPONENT"); + DATA.isShiny = isShiny; +} + +void Environment_(u32 sourceLine, u32 environment) +{ + INVALID_IF(DATA.forcedEnvironment, "Environment is already set"); + INVALID_IF(environment >= BATTLE_ENVIRONMENT_COUNT, "Illegal environment: %d", environment); + DATA.forcedEnvironment = environment + 1; +} + static const char *const sBattlerIdentifiersSingles[] = { "player", @@ -1899,7 +2205,13 @@ static const char *BattlerIdentifier(s32 battlerId) return sBattlerIdentifiersSingles[battlerId]; case BATTLE_TEST_DOUBLES: case BATTLE_TEST_AI_DOUBLES: - return sBattlerIdentifiersDoubles[battlerId]; + case BATTLE_TEST_MULTI: + case BATTLE_TEST_AI_MULTI: + case BATTLE_TEST_TWO_VS_ONE: + case BATTLE_TEST_AI_TWO_VS_ONE: + case BATTLE_TEST_ONE_VS_TWO: + case BATTLE_TEST_AI_ONE_VS_TWO: + return sBattlerIdentifiersDoubles[battlerId]; } return ""; } @@ -2039,7 +2351,7 @@ void CloseTurn(u32 sourceLine) for (i = 0; i < STATE->battlersCount; i++) { if (!(DATA.actionBattlers & (1 << i))) - { + { // Multi test partner trainers want setting to RecordedPartner controller if no move set in this case. if (IsAITest() && (i & BIT_SIDE) == B_SIDE_OPPONENT) // If Move was not specified, allow any move used. SetAiActionToPass(sourceLine, i); else @@ -2053,7 +2365,7 @@ void CloseTurn(u32 sourceLine) static struct Pokemon *CurrentMon(s32 battlerId) { struct Pokemon *party; - if ((battlerId & BIT_SIDE) == B_SIDE_PLAYER) + if (battlerId == B_POSITION_PLAYER_LEFT || battlerId == B_POSITION_PLAYER_RIGHT) party = DATA.recordedBattle.playerParty; else party = DATA.recordedBattle.opponentParty; @@ -2152,7 +2464,7 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 * if (ctx->explicitGimmick && ctx->gimmick != GIMMICK_NONE) { u32 item = GetMonData(mon, MON_DATA_HELD_ITEM); - enum ItemHoldEffect holdEffect = GetItemHoldEffect(item); + enum HoldEffect holdEffect = GetItemHoldEffect(item); u32 species = GetMonData(mon, MON_DATA_SPECIES); u32 side = battlerId & BIT_SIDE; @@ -2167,11 +2479,7 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 * INVALID_IF(ctx->gimmick != GIMMICK_Z_MOVE && ctx->gimmick != GIMMICK_ULTRA_BURST && holdEffect == HOLD_EFFECT_Z_CRYSTAL, "Cannot use another gimmick while holding a Z-Crystal"); // Check multiple gimmick use. - INVALID_IF(DATA.chosenGimmick[side][DATA.currentMonIndexes[battlerId]] != GIMMICK_NONE - && !(DATA.chosenGimmick[side][DATA.currentMonIndexes[battlerId]] == GIMMICK_ULTRA_BURST - && ctx->gimmick == GIMMICK_Z_MOVE), "Cannot use multiple gimmicks on the same battler"); - - DATA.chosenGimmick[side][DATA.currentMonIndexes[battlerId]] = ctx->gimmick; + SetGimmick(sourceLine, side, DATA.currentMonIndexes[battlerId], ctx->gimmick); *moveSlot |= RET_GIMMICK; } } @@ -2295,17 +2603,18 @@ static void TryMarkExpectMove(u32 sourceLine, struct BattlePokemon *battler, str s32 target; INVALID_IF(DATA.turnState == TURN_CLOSED, "EXPECT_MOVE outside TURN"); - INVALID_IF(!IsAITest(), "EXPECT_MOVE is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "EXPECT_MOVE is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, and AI_TWO_VS_ONE_TEST"); MoveGetIdAndSlot(battlerId, ctx, &moveId, &moveSlot, sourceLine); target = MoveGetTarget(battlerId, moveId, ctx, sourceLine); id = DATA.expectedAiActionIndex[battlerId]; DATA.expectedAiActions[battlerId][id].type = B_ACTION_USE_MOVE; - DATA.expectedAiActions[battlerId][id].moveSlots |= 1 << moveSlot; + DATA.expectedAiActions[battlerId][id].moveSlots |= 1 << (moveSlot & ~RET_GIMMICK); DATA.expectedAiActions[battlerId][id].target = target; DATA.expectedAiActions[battlerId][id].explicitTarget = ctx->explicitTarget; DATA.expectedAiActions[battlerId][id].sourceLine = sourceLine; DATA.expectedAiActions[battlerId][id].actionSet = TRUE; + DATA.expectedAiActions[battlerId][id].gimmick = ctx->explicitGimmick ? ctx->gimmick : GIMMICKS_COUNT; if (ctx->explicitNotExpected) DATA.expectedAiActions[battlerId][id].notMove = ctx->notExpected; @@ -2325,7 +2634,7 @@ void ExpectSendOut(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex s32 i, id; s32 battlerId = battler - gBattleMons; INVALID_IF(DATA.turnState == TURN_CLOSED, "EXPECT_SEND_OUT outside TURN"); - INVALID_IF(!IsAITest(), "EXPECT_SEND_OUT is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "EXPECT_SEND_OUT is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, AI_TWO_VS_ONE_TEST, and AI_ONE_VS_TWO_TEST"); INVALID_IF(partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), "EXPECT_SEND_OUT to invalid party index"); for (i = 0; i < STATE->battlersCount; i++) { @@ -2333,8 +2642,9 @@ void ExpectSendOut(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex INVALID_IF(DATA.currentMonIndexes[i] == partyIndex, "EXPECT_SEND_OUT to battler"); } if (!(DATA.actionBattlers & (1 << battlerId))) - { - if (IsAITest() && (battlerId & BIT_SIDE) == B_SIDE_OPPONENT) // If Move was not specified, allow any move used. + { // Multi test partner trainers want setting to PlayerPartner controller even if no move set in this case. + if (IsAITest() && (((battlerId & BIT_SIDE) == B_SIDE_OPPONENT) // If Move was not specified, allow any move used. + || (IsMultibattleTest() && battlerId == B_POSITION_PLAYER_RIGHT))) SetAiActionToPass(sourceLine, battlerId); else Move(sourceLine, battler, (struct MoveContext) { move: MOVE_CELEBRATE, explicitMove: TRUE }); @@ -2377,7 +2687,7 @@ void Score(u32 sourceLine, struct BattlePokemon *battler, u32 cmp, bool32 toValu s32 battlerId = battler - gBattleMons; s32 turn = DATA.turns; - INVALID_IF(!IsAITest(), "SCORE_%s%s is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST", sCmpToStringTable[cmp], (toValue == TRUE) ? "_VAL" : ""); + INVALID_IF(!IsAITest(), "SCORE_%s%s is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, & AI_TWO_VS_ONE_TEST", sCmpToStringTable[cmp], (toValue == TRUE) ? "_VAL" : ""); for (i = 0; i < MAX_AI_SCORE_COMPARISION_PER_TURN; i++) { @@ -2461,7 +2771,7 @@ void ExpectSwitch(u32 sourceLine, struct BattlePokemon *battler, u32 partyIndex) s32 i, id; s32 battlerId = battler - gBattleMons; INVALID_IF(DATA.turnState == TURN_CLOSED, "EXPECT_SWITCH outside TURN"); - INVALID_IF(!IsAITest(), "EXPECT_SWITCH is usable only in AI_SINGLE_BATTLE_TEST & AI_DOUBLE_BATTLE_TEST"); + INVALID_IF(!IsAITest(), "EXPECT_SWITCH is usable only in AI_SINGLE_BATTLE_TEST, AI_DOUBLE_BATTLE_TEST, AI_MULTI_BATTLE_TEST, AI_TWO_VS_ONE_TEST, and AI_ONE_VS_TWO_TEST"); INVALID_IF(DATA.actionBattlers & (1 << battlerId), "Multiple battler actions"); INVALID_IF(partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), "EXPECT_SWITCH to invalid party index"); @@ -2583,7 +2893,6 @@ void CloseQueueGroup(u32 sourceLine) void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityEventContext ctx) { -#if B_ABILITY_POP_UP s32 battlerId = battler - gBattleMons; INVALID_IF(!STATE->runScene, "ABILITY_POPUP outside of SCENE"); if (DATA.queuedEventsCount == MAX_QUEUED_EVENTS) @@ -2598,7 +2907,6 @@ void QueueAbility(u32 sourceLine, struct BattlePokemon *battler, struct AbilityE .ability = ctx.ability, }}, }; -#endif } void QueueAnimation(u32 sourceLine, u32 type, u32 id, struct AnimationEventContext ctx) @@ -2795,6 +3103,11 @@ u32 TestRunner_Battle_GetForcedAbility(u32 side, u32 partyIndex) return DATA.forcedAbilities[side][partyIndex]; } +u32 TestRunner_Battle_GetForcedEnvironment(void) +{ + return DATA.forcedEnvironment; +} + u32 TestRunner_Battle_GetChosenGimmick(u32 side, u32 partyIndex) { return DATA.chosenGimmick[side][partyIndex]; diff --git a/test/text.c b/test/text.c index cb5b82ca46..05e9ca1ffd 100644 --- a/test/text.c +++ b/test/text.c @@ -499,7 +499,7 @@ TEST("Ability names fit on Pokemon Summary Screen") { u32 i; const u32 fontId = FONT_NORMAL, widthPx = 144; - u32 ability = ABILITY_NONE; + enum Ability ability = ABILITY_NONE; for (i = 1; i < ABILITIES_COUNT; i++) { PARAMETRIZE_LABEL("%S", gAbilitiesInfo[i].name) { ability = i; } @@ -511,7 +511,7 @@ TEST("Ability names fit on Ability Pop-Up") { u32 i; const u32 fontId = FONT_SMALL_NARROWER, widthPx = 76; - u32 ability = ABILITY_NONE; + enum Ability ability = ABILITY_NONE; for (i = 1; i < ABILITIES_COUNT; i++) { PARAMETRIZE_LABEL("%S", gAbilitiesInfo[i].name) { ability = i; } @@ -523,7 +523,7 @@ TEST("Ability descriptions fit on Pokemon Summary Screen") { u32 i; const u32 fontId = FONT_NORMAL, widthPx = 146; - u32 ability = ABILITY_NONE; + enum Ability ability = ABILITY_NONE; for (i = 1; i < ABILITIES_COUNT; i++) { PARAMETRIZE_LABEL("%S", gAbilitiesInfo[i].description) { ability = i; } @@ -535,7 +535,7 @@ TEST("Type names fit on Battle Screen") { u32 i; const u32 fontId = FONT_NARROWER, widthPx = 39; - u32 type = TYPE_NORMAL; + enum Type type = TYPE_NORMAL; for (i = 0; i < NUMBER_OF_MON_TYPES; i++) { PARAMETRIZE_LABEL("%S", gTypesInfo[i].name) { type = i; } @@ -547,7 +547,7 @@ TEST("Type names fit on Pokedex Search Screen") { u32 i; const u32 fontId = FONT_NARROWER, widthPx = 38; - u32 type = TYPE_NORMAL; + enum Type type = TYPE_NORMAL; for (i = 0; i < NUMBER_OF_MON_TYPES; i++) { PARAMETRIZE_LABEL("%S", gTypesInfo[i].name) { type = i; } @@ -570,9 +570,9 @@ TEST("Battle strings fit on the battle message window") s32 sixDigitNines = 999999; // 36 pixels. u8 nickname[POKEMON_NAME_LENGTH + 1] = _("MMMMMMMMMMMM"); // 72 pixels. u32 longMoveID = MOVE_NATURES_MADNESS; // 89 pixels. - u32 longAbilityID = ABILITY_SUPERSWEET_SYRUP; // 91 pixels. + enum Ability longAbilityID = ABILITY_SUPERSWEET_SYRUP; // 91 pixels. u32 longStatName = STAT_EVASION; // 40 pixels. - u32 longTypeName = TYPE_ELECTRIC; // 43 pixels. + enum Type longTypeName = TYPE_ELECTRIC; // 43 pixels. u32 longSpeciesName = SPECIES_SANDY_SHOCKS; // 47 pixels. u32 longItemName = ITEM_UNREMARKABLE_TEACUP; // 73 pixels. u8 boxName[9] = _("MMMMMMMM"); // 54 pixels. @@ -663,8 +663,6 @@ TEST("Battle strings fit on the battle message window") break; // Buffer Move name to B_BUFF1 case STRINGID_PKMNLEARNEDMOVE2: - case STRINGID_TEAMSTOPPEDWORKING: // Unused - case STRINGID_FOESTOPPEDWORKING: // Unused case STRINGID_PKMNHURTBY: case STRINGID_PKMNFREEDFROM: case STRINGID_PKMNMOVEWASDISABLED: @@ -715,8 +713,6 @@ TEST("Battle strings fit on the battle message window") case STRINGID_ATTACKERABILITYSTATRAISE: case STRINGID_TARGETABILITYSTATLOWER: case STRINGID_SCRIPTINGABILITYSTATRAISE: - case STRINGID_BATTLERABILITYRAISEDSTAT: - case STRINGID_ABILITYRAISEDSTATDRASTICALLY: case STRINGID_STATWASHEIGHTENED: StringCopy(gBattleTextBuff1, gStatNamesTable[longStatName]); break; @@ -758,7 +754,6 @@ TEST("Battle strings fit on the battle message window") case STRINGID_PKMNCURIOUSABOUTX: case STRINGID_PKMNENTHRALLEDBYX: case STRINGID_PKMNIGNOREDX: - case STRINGID_PREVENTEDFROMWORKING: case STRINGID_PKMNOBTAINEDX: case STRINGID_ABOUTTOUSEPOLTERGEIST: PREPARE_ITEM_BUFFER(gBattleTextBuff1, longItemName); diff --git a/tools/learnset_helpers/make_teachables.py b/tools/learnset_helpers/make_teachables.py index 6f3b186b68..a0e94124f7 100644 --- a/tools/learnset_helpers/make_teachables.py +++ b/tools/learnset_helpers/make_teachables.py @@ -150,6 +150,7 @@ def create_tutor_moves_array(tutors: list[str]) -> None: header = dedent("""\ // DO NOT MODIFY THIS FILE! It is auto-generated by tools/learnset_helpers/make_teachables.py // Set the config P_TUTOR_MOVES_ARRAY in include/config/pokemon.h to TRUE to enable this array! + // Also need by tutor moves relearner! const u16 gTutorMoves[] = { """) diff --git a/tools/learnset_helpers/porymoves_files/za.json b/tools/learnset_helpers/porymoves_files/za.json new file mode 100644 index 0000000000..cda070084f --- /dev/null +++ b/tools/learnset_helpers/porymoves_files/za.json @@ -0,0 +1,19086 @@ +{ + "BULBASAUR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "3", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_GROWTH" + }, + { + "Level": "9", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "15", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "15", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "25", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "30", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "35", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "40", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "42", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "45", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "55", + "Move": "MOVE_SOLAR_BEAM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SAFEGUARD", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "IVYSAUR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "3", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_GROWTH" + }, + { + "Level": "9", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "15", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "15", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "25", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "30", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "35", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "40", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "42", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "45", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "55", + "Move": "MOVE_SOLAR_BEAM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SAFEGUARD", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "VENUSAUR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "3", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_GROWTH" + }, + { + "Level": "9", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "15", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "15", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "25", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "30", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "35", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "40", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "42", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "45", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "55", + "Move": "MOVE_SOLAR_BEAM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SAFEGUARD", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC", + "MOVE_WORK_UP" + ], + "TutorMoves": [ + "MOVE_POWER_WHIP" + ], + "EggMoves": [] + }, + "CHARMANDER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "4", + "Move": "MOVE_EMBER" + }, + { + "Level": "8", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "17", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "30", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "42", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "54", + "Move": "MOVE_FLARE_BLITZ" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_CRUNCH", + "MOVE_DIG", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_HEAT_WAVE", + "MOVE_IRON_TAIL", + "MOVE_OUTRAGE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_PUNCH", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CHARMELEON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "4", + "Move": "MOVE_EMBER" + }, + { + "Level": "8", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "17", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "30", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "42", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "54", + "Move": "MOVE_FLARE_BLITZ" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_CRUNCH", + "MOVE_DIG", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_HEAT_WAVE", + "MOVE_IRON_TAIL", + "MOVE_OUTRAGE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_PUNCH", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CHARIZARD": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "4", + "Move": "MOVE_EMBER" + }, + { + "Level": "8", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "17", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "30", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "42", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "54", + "Move": "MOVE_FLARE_BLITZ" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_CRUNCH", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLY", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_HYPER_BEAM", + "MOVE_IRON_TAIL", + "MOVE_OUTRAGE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_PUNCH", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [ + "MOVE_AIR_SLASH", + "MOVE_FIRE_BLAST" + ], + "EggMoves": [] + }, + "SQUIRTLE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "3", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "12", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "20", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "30", + "Move": "MOVE_AQUA_RING" + }, + { + "Level": "35", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "40", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "45", + "Move": "MOVE_LIQUIDATION" + } + ], + "TMMoves": [ + "MOVE_AURA_SPHERE", + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_HEADBUTT", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_HEAD", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "WARTORTLE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "3", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "12", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "20", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "30", + "Move": "MOVE_AQUA_RING" + }, + { + "Level": "35", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "40", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "45", + "Move": "MOVE_LIQUIDATION" + } + ], + "TMMoves": [ + "MOVE_AURA_SPHERE", + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_HEADBUTT", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_HEAD", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BLASTOISE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "3", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "12", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "20", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "30", + "Move": "MOVE_AQUA_RING" + }, + { + "Level": "35", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "40", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "45", + "Move": "MOVE_LIQUIDATION" + } + ], + "TMMoves": [ + "MOVE_AURA_SPHERE", + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_CRUNCH", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_HEAD", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_FLASH_CANNON", + "MOVE_HYDRO_PUMP" + ], + "EggMoves": [] + }, + "WEEDLE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_STRING_SHOT" + } + ], + "TMMoves": [ + "MOVE_ELECTROWEB" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "KAKUNA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "7", + "Move": "MOVE_HARDEN" + } + ], + "TMMoves": [ + "MOVE_ELECTROWEB", + "MOVE_IRON_DEFENSE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BEEDRILL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "7", + "Move": "MOVE_HARDEN" + }, + { + "Level": "15", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "20", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "25", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "27", + "Move": "MOVE_BUG_BUZZ" + }, + { + "Level": "29", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "33", + "Move": "MOVE_LUNGE" + }, + { + "Level": "35", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "40", + "Move": "MOVE_DRILL_RUN" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_SMASH", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC", + "MOVE_U_TURN" + ], + "TutorMoves": [ + "MOVE_PIN_MISSILE" + ], + "EggMoves": [] + }, + "PIDGEY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "9", + "Move": "MOVE_GUST" + }, + { + "Level": "13", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "17", + "Move": "MOVE_TWISTER" + }, + { + "Level": "21", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "25", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "29", + "Move": "MOVE_AGILITY" + }, + { + "Level": "33", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "45", + "Move": "MOVE_HURRICANE" + }, + { + "Level": "50", + "Move": "MOVE_BRAVE_BIRD" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_U_TURN", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PIDGEOTTO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "9", + "Move": "MOVE_GUST" + }, + { + "Level": "13", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "17", + "Move": "MOVE_TWISTER" + }, + { + "Level": "21", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "25", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "29", + "Move": "MOVE_AGILITY" + }, + { + "Level": "33", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "45", + "Move": "MOVE_HURRICANE" + }, + { + "Level": "50", + "Move": "MOVE_BRAVE_BIRD" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_U_TURN", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PIDGEOT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "9", + "Move": "MOVE_GUST" + }, + { + "Level": "13", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "17", + "Move": "MOVE_TWISTER" + }, + { + "Level": "21", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "25", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "29", + "Move": "MOVE_AGILITY" + }, + { + "Level": "33", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "45", + "Move": "MOVE_HURRICANE" + }, + { + "Level": "50", + "Move": "MOVE_BRAVE_BIRD" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_U_TURN", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "EKANS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "4", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "9", + "Move": "MOVE_BITE" + }, + { + "Level": "12", + "Move": "MOVE_GLARE" + }, + { + "Level": "15", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "17", + "Move": "MOVE_SCREECH" + }, + { + "Level": "25", + "Move": "MOVE_TOXIC" + }, + { + "Level": "33", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "36", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "41", + "Move": "MOVE_HAZE" + }, + { + "Level": "49", + "Move": "MOVE_GUNK_SHOT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_GIGA_DRAIN", + "MOVE_ICE_FANG", + "MOVE_IRON_TAIL", + "MOVE_KNOCK_OFF", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ARBOK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "4", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "9", + "Move": "MOVE_BITE" + }, + { + "Level": "12", + "Move": "MOVE_GLARE" + }, + { + "Level": "15", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "17", + "Move": "MOVE_SCREECH" + }, + { + "Level": "25", + "Move": "MOVE_TOXIC" + }, + { + "Level": "33", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "36", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "41", + "Move": "MOVE_HAZE" + }, + { + "Level": "49", + "Move": "MOVE_GUNK_SHOT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_FANG", + "MOVE_IRON_TAIL", + "MOVE_KNOCK_OFF", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [ + "MOVE_CRUNCH" + ], + "EggMoves": [] + }, + "PIKACHU": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "4", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "12", + "Move": "MOVE_NUZZLE" + }, + { + "Level": "16", + "Move": "MOVE_SPARK" + }, + { + "Level": "20", + "Move": "MOVE_CHARM" + }, + { + "Level": "25", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "30", + "Move": "MOVE_CHARGE" + }, + { + "Level": "35", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "40", + "Move": "MOVE_THUNDER" + }, + { + "Level": "99", + "Move": "MOVE_VOLT_TACKLE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_IRON_TAIL", + "MOVE_NASTY_PLOT", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "RAICHU": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "4", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "12", + "Move": "MOVE_NUZZLE" + }, + { + "Level": "16", + "Move": "MOVE_SPARK" + }, + { + "Level": "20", + "Move": "MOVE_CHARM" + }, + { + "Level": "25", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "30", + "Move": "MOVE_CHARGE" + }, + { + "Level": "35", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "40", + "Move": "MOVE_THUNDER" + }, + { + "Level": "99", + "Move": "MOVE_VOLT_TACKLE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_TAIL", + "MOVE_NASTY_PLOT", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [ + "MOVE_EERIE_IMPULSE", + "MOVE_THUNDER_PUNCH" + ], + "EggMoves": [] + }, + "RAICHU_ALOLA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "4", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "12", + "Move": "MOVE_NUZZLE" + }, + { + "Level": "16", + "Move": "MOVE_SPARK" + }, + { + "Level": "20", + "Move": "MOVE_CHARM" + }, + { + "Level": "25", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "30", + "Move": "MOVE_CHARGE" + }, + { + "Level": "35", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "40", + "Move": "MOVE_THUNDER" + }, + { + "Level": "99", + "Move": "MOVE_VOLT_TACKLE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_TAIL", + "MOVE_NASTY_PLOT", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [ + "MOVE_EERIE_IMPULSE", + "MOVE_PSYCHIC" + ], + "EggMoves": [] + }, + "CLEFAIRY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "5", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "8", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "13", + "Move": "MOVE_CHARM" + }, + { + "Level": "16", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "18", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "20", + "Move": "MOVE_METRONOME" + }, + { + "Level": "22", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "24", + "Move": "MOVE_MOONLIGHT" + }, + { + "Level": "28", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "32", + "Move": "MOVE_DAZZLING_GLEAM" + }, + { + "Level": "42", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "48", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "55", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_HEADBUTT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CLEFABLE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "5", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "8", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "13", + "Move": "MOVE_CHARM" + }, + { + "Level": "16", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "18", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "20", + "Move": "MOVE_METRONOME" + }, + { + "Level": "22", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "24", + "Move": "MOVE_MOONLIGHT" + }, + { + "Level": "28", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "32", + "Move": "MOVE_DAZZLING_GLEAM" + }, + { + "Level": "42", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "48", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "52", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "55", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ABRA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TELEPORT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "KADABRA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "1", + "Move": "MOVE_TELEPORT" + }, + { + "Level": "10", + "Move": "MOVE_REFLECT" + }, + { + "Level": "20", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "25", + "Move": "MOVE_RECOVER" + }, + { + "Level": "30", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "35", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "40", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "45", + "Move": "MOVE_FUTURE_SIGHT" + }, + { + "Level": "50", + "Move": "MOVE_CALM_MIND" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_CONFUSION" + ], + "EggMoves": [] + }, + "ALAKAZAM": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "1", + "Move": "MOVE_TELEPORT" + }, + { + "Level": "10", + "Move": "MOVE_REFLECT" + }, + { + "Level": "20", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "25", + "Move": "MOVE_RECOVER" + }, + { + "Level": "30", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "35", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "40", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "45", + "Move": "MOVE_FUTURE_SIGHT" + }, + { + "Level": "50", + "Move": "MOVE_CALM_MIND" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_CONFUSION" + ], + "EggMoves": [] + }, + "MACHOP": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "4", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "12", + "Move": "MOVE_POWER_UP_PUNCH" + }, + { + "Level": "14", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "16", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "18", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "20", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "25", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "30", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "36", + "Move": "MOVE_DETECT" + }, + { + "Level": "44", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "54", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CLOSE_COMBAT", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_PUNCH", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MACHOKE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "4", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "12", + "Move": "MOVE_POWER_UP_PUNCH" + }, + { + "Level": "14", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "16", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "18", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "20", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "25", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "30", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "36", + "Move": "MOVE_DETECT" + }, + { + "Level": "44", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "54", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CLOSE_COMBAT", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_PUNCH", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MACHAMP": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "4", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "12", + "Move": "MOVE_POWER_UP_PUNCH" + }, + { + "Level": "14", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "16", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "18", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "20", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "25", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "30", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "36", + "Move": "MOVE_DETECT" + }, + { + "Level": "40", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "44", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "54", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CLOSE_COMBAT", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_PUNCH", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BELLSPROUT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "8", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "10", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "13", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "15", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "17", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "19", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "23", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "26", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "30", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "33", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "40", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "44", + "Move": "MOVE_POWER_WHIP" + }, + { + "Level": "48", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BULLET_SEED", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "WEEPINBELL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "8", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "10", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "13", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "15", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "17", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "19", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "23", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "26", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "30", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "33", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "40", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "44", + "Move": "MOVE_POWER_WHIP" + }, + { + "Level": "48", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BULLET_SEED", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC" + ], + "TutorMoves": [ + "MOVE_LUNGE" + ], + "EggMoves": [] + }, + "VICTREEBEL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "1", + "Move": "MOVE_LUNGE" + }, + { + "Level": "8", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "10", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "13", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "15", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "17", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "19", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "23", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "26", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "30", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "33", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "40", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "44", + "Move": "MOVE_POWER_WHIP" + }, + { + "Level": "48", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BULLET_SEED", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC" + ], + "TutorMoves": [ + "MOVE_SLUDGE_BOMB" + ], + "EggMoves": [] + }, + "SLOWPOKE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "1", + "Move": "MOVE_CURSE" + }, + { + "Level": "3", + "Move": "MOVE_GROWL" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "14", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "18", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "21", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "24", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "27", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "36", + "Move": "MOVE_SURF" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHIC" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_LIQUIDATION", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_WAVE", + "MOVE_WATERFALL", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SLOWBRO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "1", + "Move": "MOVE_CURSE" + }, + { + "Level": "3", + "Move": "MOVE_GROWL" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "14", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "18", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "21", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "24", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "27", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "36", + "Move": "MOVE_SURF" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "45", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_LIQUIDATION", + "MOVE_METRONOME", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_POWER_GEM", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_WAVE", + "MOVE_WATERFALL", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SLOWBRO_GALAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "1", + "Move": "MOVE_CURSE" + }, + { + "Level": "3", + "Move": "MOVE_GROWL" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "14", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "18", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "21", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "24", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "27", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "33", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "36", + "Move": "MOVE_SURF" + }, + { + "Level": "40", + "Move": "MOVE_SLUDGE_BOMB" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "45", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HEAL_BLOCK", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_LIQUIDATION", + "MOVE_METRONOME", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC", + "MOVE_TOXIC_SPIKES", + "MOVE_WATERFALL", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GASTLY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "1", + "Move": "MOVE_LICK" + }, + { + "Level": "4", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "12", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "20", + "Move": "MOVE_CURSE" + }, + { + "Level": "24", + "Move": "MOVE_HAZE" + }, + { + "Level": "28", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "36", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "40", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "50", + "Move": "MOVE_PERISH_SONG" + } + ], + "TMMoves": [ + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_GUNK_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SELF_DESTRUCT", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_TOXIC", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HAUNTER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "1", + "Move": "MOVE_LICK" + }, + { + "Level": "4", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "12", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "16", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "20", + "Move": "MOVE_CURSE" + }, + { + "Level": "24", + "Move": "MOVE_HAZE" + }, + { + "Level": "28", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "36", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "40", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "48", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "50", + "Move": "MOVE_PERISH_SONG" + }, + { + "Level": "55", + "Move": "MOVE_PHANTOM_FORCE" + } + ], + "TMMoves": [ + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_GIGA_DRAIN", + "MOVE_GUNK_SHOT", + "MOVE_ICE_PUNCH", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SELF_DESTRUCT", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_TOXIC", + "MOVE_TOXIC_SPIKES", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GENGAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "1", + "Move": "MOVE_LICK" + }, + { + "Level": "4", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "12", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "16", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "20", + "Move": "MOVE_CURSE" + }, + { + "Level": "24", + "Move": "MOVE_HAZE" + }, + { + "Level": "28", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "36", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "40", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "48", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "50", + "Move": "MOVE_PERISH_SONG" + }, + { + "Level": "55", + "Move": "MOVE_PHANTOM_FORCE" + } + ], + "TMMoves": [ + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SELF_DESTRUCT", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC", + "MOVE_TOXIC_SPIKES", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ONIX": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "16", + "Move": "MOVE_CURSE" + }, + { + "Level": "20", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "22", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "24", + "Move": "MOVE_SCREECH" + }, + { + "Level": "28", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "32", + "Move": "MOVE_STEALTH_ROCK" + }, + { + "Level": "44", + "Move": "MOVE_DIG" + }, + { + "Level": "48", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "52", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "56", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "62", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROCK_BLAST", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "KANGASKHAN": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "4", + "Move": "MOVE_GROWL" + }, + { + "Level": "12", + "Move": "MOVE_BITE" + }, + { + "Level": "20", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "24", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "32", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "40", + "Move": "MOVE_ENDURE" + }, + { + "Level": "48", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "54", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTHQUAKE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_WHIRLPOOL", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "STARYU": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "12", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "16", + "Move": "MOVE_SWIFT" + }, + { + "Level": "20", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "24", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "32", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "36", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "40", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "44", + "Move": "MOVE_SURF" + }, + { + "Level": "48", + "Move": "MOVE_RECOVER" + }, + { + "Level": "56", + "Move": "MOVE_HYDRO_PUMP" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_FLIP_TURN", + "MOVE_ICE_BEAM", + "MOVE_ICY_WIND", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SELF_DESTRUCT", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "STARMIE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "12", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "16", + "Move": "MOVE_SWIFT" + }, + { + "Level": "20", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "24", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "32", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "36", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "40", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "42", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "44", + "Move": "MOVE_SURF" + }, + { + "Level": "48", + "Move": "MOVE_RECOVER" + }, + { + "Level": "56", + "Move": "MOVE_HYDRO_PUMP" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BLIZZARD", + "MOVE_BULK_UP", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_FLIP_TURN", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICY_WIND", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SELF_DESTRUCT", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SCYTHER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "12", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "16", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "20", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "28", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "32", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "34", + "Move": "MOVE_BUG_BUZZ" + }, + { + "Level": "36", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "42", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "46", + "Move": "MOVE_LUNGE" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_CLOSE_COMBAT", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_KNOCK_OFF", + "MOVE_LIGHT_SCREEN", + "MOVE_NIGHT_SLASH", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_U_TURN" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PINSIR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "8", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "16", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "20", + "Move": "MOVE_DETECT" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "32", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "36", + "Move": "MOVE_LUNGE" + }, + { + "Level": "40", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "50", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MAGIKARP": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "15", + "Move": "MOVE_TACKLE" + } + ], + "TMMoves": [ + "MOVE_HYDRO_PUMP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GYARADOS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "1", + "Move": "MOVE_TWISTER" + }, + { + "Level": "24", + "Move": "MOVE_WATERFALL" + }, + { + "Level": "30", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "33", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "40", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "44", + "Move": "MOVE_HURRICANE" + }, + { + "Level": "45", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "50", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "55", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [ + "MOVE_BITE", + "MOVE_WATER_GUN", + "MOVE_WHIRLPOOL" + ], + "EggMoves": [] + }, + "EEVEE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "20", + "Move": "MOVE_SWIFT" + }, + { + "Level": "25", + "Move": "MOVE_BITE" + }, + { + "Level": "30", + "Move": "MOVE_WISH" + }, + { + "Level": "40", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "45", + "Move": "MOVE_CHARM" + }, + { + "Level": "50", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "VAPOREON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "20", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "25", + "Move": "MOVE_HAZE" + }, + { + "Level": "30", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "35", + "Move": "MOVE_AQUA_RING" + }, + { + "Level": "40", + "Move": "MOVE_SURF" + }, + { + "Level": "45", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "50", + "Move": "MOVE_HYDRO_PUMP" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_IRON_TAIL", + "MOVE_LIQUIDATION", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_DOUBLE_EDGE", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_WATER_GUN", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "JOLTEON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "20", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "25", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "30", + "Move": "MOVE_THUNDER_FANG" + }, + { + "Level": "35", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "40", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "45", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "50", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_DOUBLE_EDGE", + "MOVE_EERIE_IMPULSE", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_THUNDER_SHOCK", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "FLAREON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "20", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "25", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "30", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "35", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "40", + "Move": "MOVE_LAVA_PLUME" + }, + { + "Level": "50", + "Move": "MOVE_FLARE_BLITZ" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TAUNT", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_DOUBLE_EDGE", + "MOVE_EMBER", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "AERODACTYL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_STEEL_WING" + }, + { + "Level": "5", + "Move": "MOVE_SUPERSONIC" + }, + { + "Level": "10", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "20", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "25", + "Move": "MOVE_ROAR" + }, + { + "Level": "30", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "35", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "40", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "45", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "55", + "Move": "MOVE_HYPER_BEAM" + }, + { + "Level": "60", + "Move": "MOVE_GIGA_IMPACT" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FLAMETHROWER", + "MOVE_FLY", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_ICE_FANG", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG", + "MOVE_WHIRLWIND" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DRATINI": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "5", + "Move": "MOVE_TWISTER" + }, + { + "Level": "10", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "15", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "20", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "25", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "40", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "50", + "Move": "MOVE_EXTREME_SPEED" + }, + { + "Level": "55", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "60", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BLIZZARD", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_IRON_HEAD", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DRAGONAIR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "5", + "Move": "MOVE_TWISTER" + }, + { + "Level": "10", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "15", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "20", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "25", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "40", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "50", + "Move": "MOVE_EXTREME_SPEED" + }, + { + "Level": "55", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "60", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BLIZZARD", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_IRON_HEAD", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DRAGONITE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "5", + "Move": "MOVE_TWISTER" + }, + { + "Level": "10", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "15", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "20", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "25", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "40", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "50", + "Move": "MOVE_EXTREME_SPEED" + }, + { + "Level": "55", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "60", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_FLY", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_HEAD", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_WHIRLWIND" + ], + "TutorMoves": [ + "MOVE_FIRE_PUNCH", + "MOVE_HURRICANE", + "MOVE_THUNDER_PUNCH", + "MOVE_WING_ATTACK" + ], + "EggMoves": [] + }, + "MEWTWO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "1", + "Move": "MOVE_SWIFT" + }, + { + "Level": "12", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "16", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "24", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "32", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "40", + "Move": "MOVE_AURA_SPHERE" + }, + { + "Level": "48", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "64", + "Move": "MOVE_MIST" + }, + { + "Level": "72", + "Move": "MOVE_PSYSTRIKE" + }, + { + "Level": "80", + "Move": "MOVE_RECOVER" + }, + { + "Level": "88", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DISCHARGE", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HURRICANE", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_POWER_GEM", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAKE_DOWN", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC", + "MOVE_WILL_O_WISP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CHIKORITA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_LEAFAGE" + }, + { + "Level": "9", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "14", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "22", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "27", + "Move": "MOVE_REFLECT" + }, + { + "Level": "36", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "40", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "45", + "Move": "MOVE_SOLAR_BEAM" + }, + { + "Level": "50", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "56", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BULLDOZE", + "MOVE_BULLET_SEED", + "MOVE_CURSE", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_HEADBUTT", + "MOVE_IRON_TAIL", + "MOVE_KNOCK_OFF", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BAYLEEF": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_LEAFAGE" + }, + { + "Level": "9", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "14", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "22", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "27", + "Move": "MOVE_REFLECT" + }, + { + "Level": "36", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "40", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "45", + "Move": "MOVE_SOLAR_BEAM" + }, + { + "Level": "50", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "56", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BULLDOZE", + "MOVE_BULLET_SEED", + "MOVE_CURSE", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_HEADBUTT", + "MOVE_IRON_TAIL", + "MOVE_KNOCK_OFF", + "MOVE_PROTECT", + "MOVE_ROCK_SMASH", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_WORK_UP" + ], + "TutorMoves": [ + "MOVE_GIGA_DRAIN" + ], + "EggMoves": [] + }, + "MEGANIUM": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_LEAFAGE" + }, + { + "Level": "9", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "14", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "22", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "27", + "Move": "MOVE_REFLECT" + }, + { + "Level": "36", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "40", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "45", + "Move": "MOVE_SOLAR_BEAM" + }, + { + "Level": "50", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "56", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BULLDOZE", + "MOVE_BULLET_SEED", + "MOVE_CURSE", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_TAIL", + "MOVE_KNOCK_OFF", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_SMASH", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_WORK_UP" + ], + "TutorMoves": [ + "MOVE_GIGA_DRAIN", + "MOVE_LEAF_BLADE" + ], + "EggMoves": [] + }, + "TOTODILE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "10", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "21", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "26", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "35", + "Move": "MOVE_SCREECH" + }, + { + "Level": "40", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "50", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "56", + "Move": "MOVE_OUTRAGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_DOUBLE_TEAM", + "MOVE_DRAGON_CLAW", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICY_WIND", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CROCONAW": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "10", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "21", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "26", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "35", + "Move": "MOVE_SCREECH" + }, + { + "Level": "40", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "50", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "56", + "Move": "MOVE_OUTRAGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_DOUBLE_TEAM", + "MOVE_DRAGON_CLAW", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICY_WIND", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_WORK_UP" + ], + "TutorMoves": [ + "MOVE_SLASH" + ], + "EggMoves": [] + }, + "FERALIGATR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_SLASH" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "10", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "21", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "26", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "35", + "Move": "MOVE_SCREECH" + }, + { + "Level": "40", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "50", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "56", + "Move": "MOVE_OUTRAGE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICY_WIND", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE", + "MOVE_WHIRLPOOL", + "MOVE_WORK_UP" + ], + "TutorMoves": [ + "MOVE_CRUNCH" + ], + "EggMoves": [] + }, + "SPINARAK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "5", + "Move": "MOVE_ABSORB" + }, + { + "Level": "8", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "12", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "16", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "21", + "Move": "MOVE_SCREECH" + }, + { + "Level": "24", + "Move": "MOVE_STICKY_WEB" + }, + { + "Level": "27", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "30", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "33", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "35", + "Move": "MOVE_BUG_BUZZ" + }, + { + "Level": "37", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "40", + "Move": "MOVE_LUNGE" + }, + { + "Level": "44", + "Move": "MOVE_MEGAHORN" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_DIG", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_HEADBUTT", + "MOVE_KNOCK_OFF", + "MOVE_PROTECT", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TOXIC", + "MOVE_TOXIC_SPIKES" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ARIADOS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "1", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "5", + "Move": "MOVE_ABSORB" + }, + { + "Level": "8", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "12", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "16", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "21", + "Move": "MOVE_SCREECH" + }, + { + "Level": "24", + "Move": "MOVE_STICKY_WEB" + }, + { + "Level": "27", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "30", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "33", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "35", + "Move": "MOVE_BUG_BUZZ" + }, + { + "Level": "37", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "40", + "Move": "MOVE_LUNGE" + }, + { + "Level": "44", + "Move": "MOVE_MEGAHORN" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_DIG", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_KNOCK_OFF", + "MOVE_PROTECT", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TOXIC", + "MOVE_TOXIC_SPIKES" + ], + "TutorMoves": [ + "MOVE_SWORDS_DANCE" + ], + "EggMoves": [] + }, + "PICHU": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "4", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "12", + "Move": "MOVE_NUZZLE" + }, + { + "Level": "16", + "Move": "MOVE_SPARK" + }, + { + "Level": "20", + "Move": "MOVE_CHARM" + }, + { + "Level": "25", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "30", + "Move": "MOVE_CHARGE" + }, + { + "Level": "35", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "40", + "Move": "MOVE_THUNDER" + }, + { + "Level": "99", + "Move": "MOVE_VOLT_TACKLE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_IRON_TAIL", + "MOVE_NASTY_PLOT", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CLEFFA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "5", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "8", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "13", + "Move": "MOVE_CHARM" + }, + { + "Level": "16", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "18", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "20", + "Move": "MOVE_METRONOME" + }, + { + "Level": "22", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "24", + "Move": "MOVE_MOONLIGHT" + }, + { + "Level": "28", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "42", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "48", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "55", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_HEADBUTT", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MAREEP": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "4", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "8", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "15", + "Move": "MOVE_CHARGE" + }, + { + "Level": "17", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "28", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "32", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "36", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "40", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "45", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "FLAAFFY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "4", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "8", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "15", + "Move": "MOVE_CHARGE" + }, + { + "Level": "17", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "28", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "32", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "36", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "40", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "45", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_ICE_PUNCH", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AMPHAROS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "4", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "8", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "15", + "Move": "MOVE_CHARGE" + }, + { + "Level": "17", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "28", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "32", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "36", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "40", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "42", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "45", + "Move": "MOVE_THUNDER" + }, + { + "Level": "50", + "Move": "MOVE_ZAP_CANNON" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_PULSE", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLASH_CANNON", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_VOLT_SWITCH", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [ + "MOVE_EERIE_IMPULSE", + "MOVE_THUNDER_PUNCH" + ], + "EggMoves": [] + }, + "ESPEON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "25", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "30", + "Move": "MOVE_MORNING_SUN" + }, + { + "Level": "35", + "Move": "MOVE_HEAL_BLOCK" + }, + { + "Level": "40", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "45", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "55", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_POWER_GEM", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_WAVE" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_CONFUSION", + "MOVE_DOUBLE_EDGE", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "UMBREON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "20", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "30", + "Move": "MOVE_MOONLIGHT" + }, + { + "Level": "35", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "40", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "45", + "Move": "MOVE_SCREECH" + }, + { + "Level": "50", + "Move": "MOVE_CRUNCH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_DOUBLE_EDGE", + "MOVE_SNARL", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "SLOWKING": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CURSE" + }, + { + "Level": "1", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "1", + "Move": "MOVE_NASTY_PLOT" + }, + { + "Level": "3", + "Move": "MOVE_GROWL" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "14", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "18", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "21", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "24", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "27", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "36", + "Move": "MOVE_SURF" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "45", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_LIQUIDATION", + "MOVE_METRONOME", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_WAVE", + "MOVE_WATERFALL", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [ + "MOVE_CONFUSION" + ], + "EggMoves": [] + }, + "SLOWKING_GALAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CURSE" + }, + { + "Level": "1", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "1", + "Move": "MOVE_NASTY_PLOT" + }, + { + "Level": "3", + "Move": "MOVE_GROWL" + }, + { + "Level": "6", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "14", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "18", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "21", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "24", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "27", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "36", + "Move": "MOVE_SURF" + }, + { + "Level": "36", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "45", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HEAL_BLOCK", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_LIQUIDATION", + "MOVE_METRONOME", + "MOVE_MUD_SHOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC_SPIKES", + "MOVE_WATERFALL", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [ + "MOVE_CONFUSION", + "MOVE_TOXIC" + ], + "EggMoves": [] + }, + "STEELIX": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "1", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "16", + "Move": "MOVE_CURSE" + }, + { + "Level": "20", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "22", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "24", + "Move": "MOVE_SCREECH" + }, + { + "Level": "28", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "32", + "Move": "MOVE_STEALTH_ROCK" + }, + { + "Level": "36", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "44", + "Move": "MOVE_DIG" + }, + { + "Level": "52", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "56", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "62", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DARK_PULSE", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_FANG", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROCK_BLAST", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [ + "MOVE_IRON_TAIL" + ], + "EggMoves": [] + }, + "SCIZOR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "12", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "16", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "18", + "Move": "MOVE_STEEL_WING" + }, + { + "Level": "20", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "28", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "32", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "34", + "Move": "MOVE_BUG_BUZZ" + }, + { + "Level": "36", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "42", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "46", + "Move": "MOVE_LUNGE" + }, + { + "Level": "48", + "Move": "MOVE_IRON_HEAD" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_CLOSE_COMBAT", + "MOVE_CURSE", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_KNOCK_OFF", + "MOVE_LIGHT_SCREEN", + "MOVE_NIGHT_SLASH", + "MOVE_PROTECT", + "MOVE_SAFEGUARD", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_U_TURN" + ], + "TutorMoves": [ + "MOVE_BULLET_PUNCH" + ], + "EggMoves": [] + }, + "HERACROSS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "5", + "Move": "MOVE_ENDURE" + }, + { + "Level": "10", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "13", + "Move": "MOVE_DETECT" + }, + { + "Level": "15", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "20", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "24", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "28", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "30", + "Move": "MOVE_BUG_BUZZ" + }, + { + "Level": "32", + "Move": "MOVE_LUNGE" + }, + { + "Level": "38", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "45", + "Move": "MOVE_MEGAHORN" + }, + { + "Level": "50", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULK_UP", + "MOVE_BULLDOZE", + "MOVE_BULLET_SEED", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_KNOCK_OFF", + "MOVE_MUD_SHOT", + "MOVE_NIGHT_SLASH", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SPIKES", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DELIBIRD": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "15", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "18", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "25", + "Move": "MOVE_ICE_SHARD" + }, + { + "Level": "28", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "32", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "35", + "Move": "MOVE_ICE_PUNCH" + }, + { + "Level": "37", + "Move": "MOVE_FREEZE_DRY" + }, + { + "Level": "40", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_PROTECT", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SKARMORY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "12", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "16", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "20", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "28", + "Move": "MOVE_STEEL_WING" + }, + { + "Level": "34", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "38", + "Move": "MOVE_DRILL_RUN" + }, + { + "Level": "42", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "46", + "Move": "MOVE_SPIKES" + }, + { + "Level": "50", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "56", + "Move": "MOVE_BRAVE_BIRD" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_FLY", + "MOVE_GIGA_IMPACT", + "MOVE_HURRICANE", + "MOVE_HYPER_BEAM", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_TAUNT", + "MOVE_WHIRLWIND", + "MOVE_X_SCISSOR" + ], + "TutorMoves": [ + "MOVE_AIR_SLASH" + ], + "EggMoves": [] + }, + "HOUNDOUR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "6", + "Move": "MOVE_TACKLE" + }, + { + "Level": "13", + "Move": "MOVE_ROAR" + }, + { + "Level": "16", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "28", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "44", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "49", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "52", + "Move": "MOVE_NASTY_PLOT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLARE_BLITZ", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_VOICE", + "MOVE_MUD_SHOT", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HOUNDOOM": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "1", + "Move": "MOVE_NASTY_PLOT" + }, + { + "Level": "6", + "Move": "MOVE_TACKLE" + }, + { + "Level": "13", + "Move": "MOVE_ROAR" + }, + { + "Level": "16", + "Move": "MOVE_BITE" + }, + { + "Level": "21", + "Move": "MOVE_SNARL" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "28", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "34", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "44", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "49", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "55", + "Move": "MOVE_OVERHEAT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLARE_BLITZ", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG", + "MOVE_TOXIC", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "LARVITAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "3", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "9", + "Move": "MOVE_BITE" + }, + { + "Level": "12", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "15", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "21", + "Move": "MOVE_SCREECH" + }, + { + "Level": "27", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "33", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "37", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "40", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "48", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_MUD_SHOT", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PUPITAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "3", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "9", + "Move": "MOVE_BITE" + }, + { + "Level": "12", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "15", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "21", + "Move": "MOVE_SCREECH" + }, + { + "Level": "27", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "33", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "37", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "40", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "48", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_IRON_HEAD", + "MOVE_MUD_SHOT", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [ + "MOVE_IRON_DEFENSE" + ], + "EggMoves": [] + }, + "TYRANITAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "3", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "9", + "Move": "MOVE_BITE" + }, + { + "Level": "12", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "15", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "21", + "Move": "MOVE_SCREECH" + }, + { + "Level": "27", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "33", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "37", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "40", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "48", + "Move": "MOVE_HYPER_BEAM" + }, + { + "Level": "53", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_GIGA_IMPACT" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_HEADBUTT", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICE_PUNCH", + "MOVE_IRON_HEAD", + "MOVE_KNOCK_OFF", + "MOVE_MUD_SHOT", + "MOVE_OUTRAGE", + "MOVE_POWER_GEM", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_FANG", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE" + ], + "TutorMoves": [ + "MOVE_DARK_PULSE", + "MOVE_IRON_DEFENSE" + ], + "EggMoves": [] + }, + "RALTS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "6", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "9", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "12", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "15", + "Move": "MOVE_TELEPORT" + }, + { + "Level": "18", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "20", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "24", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "28", + "Move": "MOVE_CHARM" + }, + { + "Level": "30", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "35", + "Move": "MOVE_CALM_MIND" + }, + { + "Level": "38", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "44", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "58", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_HYPER_VOICE", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WILL_O_WISP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "KIRLIA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "6", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "9", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "12", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "15", + "Move": "MOVE_TELEPORT" + }, + { + "Level": "18", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "20", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "24", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "28", + "Move": "MOVE_CHARM" + }, + { + "Level": "30", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "35", + "Move": "MOVE_CALM_MIND" + }, + { + "Level": "38", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "44", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "58", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WILL_O_WISP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GARDEVOIR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "6", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "9", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "12", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "15", + "Move": "MOVE_TELEPORT" + }, + { + "Level": "18", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "20", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "24", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "28", + "Move": "MOVE_CHARM" + }, + { + "Level": "30", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "32", + "Move": "MOVE_WISH" + }, + { + "Level": "35", + "Move": "MOVE_CALM_MIND" + }, + { + "Level": "38", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "44", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "49", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "58", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_AURA_SPHERE", + "MOVE_BODY_SLAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WILL_O_WISP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_DAZZLING_GLEAM" + ], + "EggMoves": [] + }, + "SABLEYE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "9", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "15", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "18", + "Move": "MOVE_DETECT" + }, + { + "Level": "20", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "22", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "25", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "28", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "33", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "39", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "42", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "45", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "50", + "Move": "MOVE_RECOVER" + }, + { + "Level": "53", + "Move": "MOVE_PARTING_SHOT" + }, + { + "Level": "56", + "Move": "MOVE_PHANTOM_FORCE" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WILL_O_WISP", + "MOVE_X_SCISSOR" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MAWILE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "5", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "16", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "20", + "Move": "MOVE_CHARM" + }, + { + "Level": "22", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "24", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "28", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "40", + "Move": "MOVE_TAUNT" + }, + { + "Level": "48", + "Move": "MOVE_PLAY_ROUGH" + }, + { + "Level": "55", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DARK_PULSE", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FLAMETHROWER", + "MOVE_FLASH_CANNON", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICE_PUNCH", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_FANG", + "MOVE_THUNDER_PUNCH" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ARON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "8", + "Move": "MOVE_ROCK_TOMB" + }, + { + "Level": "12", + "Move": "MOVE_ROAR" + }, + { + "Level": "16", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "20", + "Move": "MOVE_PROTECT" + }, + { + "Level": "24", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "28", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "33", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "44", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "48", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "52", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "66", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_MUD_SHOT", + "MOVE_SHADOW_CLAW", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "LAIRON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "8", + "Move": "MOVE_ROCK_TOMB" + }, + { + "Level": "12", + "Move": "MOVE_ROAR" + }, + { + "Level": "16", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "20", + "Move": "MOVE_PROTECT" + }, + { + "Level": "24", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "28", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "33", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "44", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "48", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "52", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "66", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_MUD_SHOT", + "MOVE_SHADOW_CLAW", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AGGRON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "8", + "Move": "MOVE_ROCK_TOMB" + }, + { + "Level": "12", + "Move": "MOVE_ROAR" + }, + { + "Level": "16", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "20", + "Move": "MOVE_PROTECT" + }, + { + "Level": "24", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "28", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "33", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "44", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "48", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "52", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "66", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CRUNCH", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_MUD_SHOT", + "MOVE_OUTRAGE", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WHIRLPOOL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MEDITITE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "9", + "Move": "MOVE_DETECT" + }, + { + "Level": "12", + "Move": "MOVE_ENDURE" + }, + { + "Level": "14", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "16", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "20", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "23", + "Move": "MOVE_CALM_MIND" + }, + { + "Level": "25", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "30", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "41", + "Move": "MOVE_RECOVER" + }, + { + "Level": "52", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_CLOSE_COMBAT", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_POISON_JAB", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MEDICHAM": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "9", + "Move": "MOVE_DETECT" + }, + { + "Level": "12", + "Move": "MOVE_ENDURE" + }, + { + "Level": "14", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "16", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "20", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "23", + "Move": "MOVE_CALM_MIND" + }, + { + "Level": "25", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "30", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "34", + "Move": "MOVE_AGILITY" + }, + { + "Level": "41", + "Move": "MOVE_RECOVER" + }, + { + "Level": "52", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_CLOSE_COMBAT", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_POISON_JAB", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT" + ], + "TutorMoves": [ + "MOVE_FIRE_PUNCH", + "MOVE_ICE_PUNCH", + "MOVE_THUNDER_PUNCH" + ], + "EggMoves": [] + }, + "ELECTRIKE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "8", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "12", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "16", + "Move": "MOVE_SPARK" + }, + { + "Level": "20", + "Move": "MOVE_BITE" + }, + { + "Level": "22", + "Move": "MOVE_EERIE_IMPULSE" + }, + { + "Level": "24", + "Move": "MOVE_THUNDER_FANG" + }, + { + "Level": "28", + "Move": "MOVE_ROAR" + }, + { + "Level": "30", + "Move": "MOVE_SNARL" + }, + { + "Level": "36", + "Move": "MOVE_CHARGE" + }, + { + "Level": "40", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "44", + "Move": "MOVE_WILD_CHARGE" + }, + { + "Level": "50", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_CRUNCH", + "MOVE_CURSE", + "MOVE_DISCHARGE", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_FLAMETHROWER", + "MOVE_HEADBUTT", + "MOVE_ICE_FANG", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_VOLT_SWITCH" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MANECTRIC": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "1", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "8", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "12", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "16", + "Move": "MOVE_SPARK" + }, + { + "Level": "20", + "Move": "MOVE_BITE" + }, + { + "Level": "22", + "Move": "MOVE_EERIE_IMPULSE" + }, + { + "Level": "24", + "Move": "MOVE_THUNDER_FANG" + }, + { + "Level": "28", + "Move": "MOVE_ROAR" + }, + { + "Level": "30", + "Move": "MOVE_SNARL" + }, + { + "Level": "36", + "Move": "MOVE_CHARGE" + }, + { + "Level": "40", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "44", + "Move": "MOVE_WILD_CHARGE" + }, + { + "Level": "50", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_CRUNCH", + "MOVE_CURSE", + "MOVE_DISCHARGE", + "MOVE_ENDURE", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_FANG", + "MOVE_LIGHT_SCREEN", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_VOLT_SWITCH" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ROSELIA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "1", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "1", + "Move": "MOVE_CHARM" + }, + { + "Level": "5", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "8", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "10", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "15", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "18", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "22", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "30", + "Move": "MOVE_GIGA_DRAIN" + }, + { + "Level": "33", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "37", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "44", + "Move": "MOVE_TOXIC" + }, + { + "Level": "55", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE" + ], + "TutorMoves": [ + "MOVE_POISON_STING" + ], + "EggMoves": [] + }, + "CARVANHA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "8", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "16", + "Move": "MOVE_BITE" + }, + { + "Level": "20", + "Move": "MOVE_FLIP_TURN" + }, + { + "Level": "24", + "Move": "MOVE_SCREECH" + }, + { + "Level": "32", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "40", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "44", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "51", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "54", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BLIZZARD", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_HYDRO_PUMP", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICY_WIND", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_WATERFALL", + "MOVE_WHIRLPOOL", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SHARPEDO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "1", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "8", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "16", + "Move": "MOVE_BITE" + }, + { + "Level": "20", + "Move": "MOVE_FLIP_TURN" + }, + { + "Level": "24", + "Move": "MOVE_SCREECH" + }, + { + "Level": "32", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_AGILITY" + }, + { + "Level": "40", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "44", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "51", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "54", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_CLOSE_COMBAT", + "MOVE_DARK_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_FANG", + "MOVE_ICY_WIND", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_WATERFALL", + "MOVE_WHIRLPOOL", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_SLASH" + ], + "EggMoves": [] + }, + "NUMEL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_EMBER" + }, + { + "Level": "8", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "12", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "19", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "22", + "Move": "MOVE_LAVA_PLUME" + }, + { + "Level": "26", + "Move": "MOVE_EARTH_POWER" + }, + { + "Level": "29", + "Move": "MOVE_CURSE" + }, + { + "Level": "31", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "40", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "46", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "51", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "55", + "Move": "MOVE_HEAT_CRASH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLARE_BLITZ", + "MOVE_FLASH_CANNON", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_IRON_HEAD", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_WILL_O_WISP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CAMERUPT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_EMBER" + }, + { + "Level": "8", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "12", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "19", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "22", + "Move": "MOVE_LAVA_PLUME" + }, + { + "Level": "26", + "Move": "MOVE_EARTH_POWER" + }, + { + "Level": "29", + "Move": "MOVE_CURSE" + }, + { + "Level": "31", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "40", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "46", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "51", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "55", + "Move": "MOVE_HEAT_CRASH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLARE_BLITZ", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_IRON_HEAD", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_WILL_O_WISP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_ROCK_SLIDE" + ], + "EggMoves": [] + }, + "SWABLU": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "4", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "8", + "Move": "MOVE_MIST" + }, + { + "Level": "20", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "24", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "32", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "35", + "Move": "MOVE_TWISTER" + }, + { + "Level": "37", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "40", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "44", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "50", + "Move": "MOVE_BRAVE_BIRD" + }, + { + "Level": "55", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "60", + "Move": "MOVE_PERISH_SONG" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_DAZZLING_GLEAM", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_OUTRAGE", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ALTARIA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "4", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "8", + "Move": "MOVE_MIST" + }, + { + "Level": "20", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "24", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "32", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "35", + "Move": "MOVE_TWISTER" + }, + { + "Level": "37", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "40", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "44", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "50", + "Move": "MOVE_BRAVE_BIRD" + }, + { + "Level": "55", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "60", + "Move": "MOVE_PERISH_SONG" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_DAZZLING_GLEAM", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_FLY", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_OUTRAGE", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [ + "MOVE_DRAGON_PULSE" + ], + "EggMoves": [] + }, + "SHUPPET": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "1", + "Move": "MOVE_LICK" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "12", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "16", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "19", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "23", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "26", + "Move": "MOVE_CURSE" + }, + { + "Level": "30", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "34", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "42", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "48", + "Move": "MOVE_GUNK_SHOT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_HEADBUTT", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BANETTE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "1", + "Move": "MOVE_LICK" + }, + { + "Level": "1", + "Move": "MOVE_SLASH" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "12", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "16", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "19", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "23", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "26", + "Move": "MOVE_CURSE" + }, + { + "Level": "30", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "34", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "42", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "48", + "Move": "MOVE_GUNK_SHOT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ABSOL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "10", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "15", + "Move": "MOVE_DETECT" + }, + { + "Level": "20", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "23", + "Move": "MOVE_SLASH" + }, + { + "Level": "27", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "32", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "36", + "Move": "MOVE_TAUNT" + }, + { + "Level": "40", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "43", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "46", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "48", + "Move": "MOVE_FUTURE_SIGHT" + }, + { + "Level": "54", + "Move": "MOVE_PERISH_SONG" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_CLOSE_COMBAT", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_BALL", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WILL_O_WISP", + "MOVE_X_SCISSOR", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SNORUNT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "10", + "Move": "MOVE_ICE_SHARD" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "20", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "25", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "30", + "Move": "MOVE_ICE_FANG" + }, + { + "Level": "35", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "40", + "Move": "MOVE_ICICLE_CRASH" + }, + { + "Level": "45", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "50", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_ENDURE", + "MOVE_ICE_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_SHADOW_BALL", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GLALIE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "10", + "Move": "MOVE_ICE_SHARD" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "20", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "25", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "30", + "Move": "MOVE_ICE_FANG" + }, + { + "Level": "35", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "40", + "Move": "MOVE_ICICLE_CRASH" + }, + { + "Level": "45", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "50", + "Move": "MOVE_BLIZZARD" + }, + { + "Level": "55", + "Move": "MOVE_EXPLOSION" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DARK_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_IRON_HEAD", + "MOVE_LIGHT_SCREEN", + "MOVE_SELF_DESTRUCT", + "MOVE_SHADOW_BALL", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [ + "MOVE_FREEZE_DRY" + ], + "EggMoves": [] + }, + "BAGON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "25", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "35", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "40", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "45", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "50", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "55", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FIRE_SPIN", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SHELGON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "25", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "35", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "40", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "45", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "50", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "55", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FIRE_SPIN", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [ + "MOVE_PROTECT" + ], + "EggMoves": [] + }, + "SALAMENCE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "1", + "Move": "MOVE_PROTECT" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "25", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "35", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "40", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "45", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "50", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "55", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "60", + "Move": "MOVE_AIR_SLASH" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FIRE_SPIN", + "MOVE_GIGA_IMPACT", + "MOVE_HURRICANE", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [ + "MOVE_FLY" + ], + "EggMoves": [] + }, + "BELDUM": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_HEADBUTT", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "METANG": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "6", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "18", + "Move": "MOVE_FLASH_CANNON" + }, + { + "Level": "26", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "34", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "50", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "54", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "58", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_HEADBUTT", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH" + ], + "TutorMoves": [ + "MOVE_CONFUSION", + "MOVE_METAL_CLAW" + ], + "EggMoves": [] + }, + "METAGROSS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "1", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "1", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "6", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "18", + "Move": "MOVE_FLASH_CANNON" + }, + { + "Level": "26", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "34", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "46", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "50", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "54", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "58", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_ICE_PUNCH", + "MOVE_KNOCK_OFF", + "MOVE_LIGHT_SCREEN", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH" + ], + "TutorMoves": [ + "MOVE_EXPLOSION", + "MOVE_HEAVY_SLAM" + ], + "EggMoves": [] + }, + "BUDEW": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "1", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "1", + "Move": "MOVE_CHARM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ROSERADE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "1", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "1", + "Move": "MOVE_CHARM" + }, + { + "Level": "5", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "8", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "10", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "15", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "18", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "22", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "30", + "Move": "MOVE_GIGA_DRAIN" + }, + { + "Level": "34", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "37", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "44", + "Move": "MOVE_TOXIC" + }, + { + "Level": "55", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE" + ], + "TutorMoves": [ + "MOVE_POISON_STING" + ], + "EggMoves": [] + }, + "BUNEARY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "14", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "16", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "20", + "Move": "MOVE_AGILITY" + }, + { + "Level": "24", + "Move": "MOVE_CHARM" + }, + { + "Level": "28", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "32", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "42", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "48", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "52", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_CLOSE_COMBAT", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_PLAY_ROUGH", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "LOPUNNY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "6", + "Move": "MOVE_POWER_UP_PUNCH" + }, + { + "Level": "9", + "Move": "MOVE_MACH_PUNCH" + }, + { + "Level": "12", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "14", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "16", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "20", + "Move": "MOVE_AGILITY" + }, + { + "Level": "24", + "Move": "MOVE_CHARM" + }, + { + "Level": "28", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "32", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "36", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "42", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "48", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "52", + "Move": "MOVE_DYNAMIC_PUNCH" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_CLOSE_COMBAT", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_U_TURN", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GIBLE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "18", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "25", + "Move": "MOVE_BITE" + }, + { + "Level": "30", + "Move": "MOVE_SLASH" + }, + { + "Level": "36", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "42", + "Move": "MOVE_DIG" + }, + { + "Level": "54", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "60", + "Move": "MOVE_DRAGON_RUSH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FLAMETHROWER", + "MOVE_IRON_HEAD", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GABITE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "18", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "25", + "Move": "MOVE_BITE" + }, + { + "Level": "30", + "Move": "MOVE_SLASH" + }, + { + "Level": "36", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "42", + "Move": "MOVE_DIG" + }, + { + "Level": "54", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "60", + "Move": "MOVE_DRAGON_RUSH" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_CRUNCH", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FLAMETHROWER", + "MOVE_IRON_HEAD", + "MOVE_OUTRAGE", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SPIKES", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GARCHOMP": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "12", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "18", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "25", + "Move": "MOVE_BITE" + }, + { + "Level": "30", + "Move": "MOVE_SLASH" + }, + { + "Level": "36", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "42", + "Move": "MOVE_DIG" + }, + { + "Level": "54", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "60", + "Move": "MOVE_DRAGON_RUSH" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_HEAD", + "MOVE_IRON_TAIL", + "MOVE_LIQUIDATION", + "MOVE_OUTRAGE", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SPIKES", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [ + "MOVE_CRUNCH" + ], + "EggMoves": [] + }, + "RIOLU": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "1", + "Move": "MOVE_ENDURE" + }, + { + "Level": "1", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "8", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "16", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "20", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "24", + "Move": "MOVE_SCREECH" + }, + { + "Level": "24", + "Move": "MOVE_DETECT" + }, + { + "Level": "28", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "35", + "Move": "MOVE_SWORDS_DANCE" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_CLOSE_COMBAT", + "MOVE_CRUNCH", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_FOCUS_BLAST", + "MOVE_ICE_PUNCH", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "LUCARIO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "1", + "Move": "MOVE_PROTECT" + }, + { + "Level": "1", + "Move": "MOVE_ENDURE" + }, + { + "Level": "1", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "8", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "16", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "20", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "24", + "Move": "MOVE_SCREECH" + }, + { + "Level": "25", + "Move": "MOVE_AURA_SPHERE" + }, + { + "Level": "28", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "32", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "35", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "38", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "45", + "Move": "MOVE_EXTREME_SPEED" + }, + { + "Level": "54", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_CALM_MIND", + "MOVE_CRUNCH", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_FLASH_CANNON", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_TAIL", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_POWER_UP_PUNCH", + "MOVE_PSYCHIC", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_WATER_PULSE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_DETECT" + ], + "EggMoves": [] + }, + "HIPPOPOTAS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "4", + "Move": "MOVE_BITE" + }, + { + "Level": "8", + "Move": "MOVE_CURSE" + }, + { + "Level": "12", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "16", + "Move": "MOVE_DIG" + }, + { + "Level": "20", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "24", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "28", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "32", + "Move": "MOVE_ROAR" + }, + { + "Level": "40", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "44", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_ICE_FANG", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG", + "MOVE_WHIRLWIND" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HIPPOWDON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "12", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "16", + "Move": "MOVE_DIG" + }, + { + "Level": "20", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "24", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "28", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "32", + "Move": "MOVE_ROAR" + }, + { + "Level": "36", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "40", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "44", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CURSE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_FANG", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG", + "MOVE_WHIRLWIND" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SNOVER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_LEAFAGE" + }, + { + "Level": "10", + "Move": "MOVE_MIST" + }, + { + "Level": "15", + "Move": "MOVE_ICE_SHARD" + }, + { + "Level": "20", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "25", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "30", + "Move": "MOVE_GROWTH" + }, + { + "Level": "35", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "41", + "Move": "MOVE_WOOD_HAMMER" + }, + { + "Level": "45", + "Move": "MOVE_BLIZZARD" + }, + { + "Level": "53", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_MAGICAL_LEAF", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ABOMASNOW": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_LEAFAGE" + }, + { + "Level": "10", + "Move": "MOVE_MIST" + }, + { + "Level": "15", + "Move": "MOVE_ICE_SHARD" + }, + { + "Level": "20", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "25", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "30", + "Move": "MOVE_GROWTH" + }, + { + "Level": "35", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "41", + "Move": "MOVE_WOOD_HAMMER" + }, + { + "Level": "45", + "Move": "MOVE_BLIZZARD" + }, + { + "Level": "53", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLET_SEED", + "MOVE_CURSE", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_MAGICAL_LEAF", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [ + "MOVE_ICE_PUNCH" + ], + "EggMoves": [] + }, + "LEAFEON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "20", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "25", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "30", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "35", + "Move": "MOVE_LEAF_BLADE" + }, + { + "Level": "40", + "Move": "MOVE_GIGA_DRAIN" + }, + { + "Level": "45", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "50", + "Move": "MOVE_LEAF_STORM" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_X_SCISSOR" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_DOUBLE_EDGE", + "MOVE_RAZOR_LEAF", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "GLACEON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "18", + "Move": "MOVE_MIST" + }, + { + "Level": "23", + "Move": "MOVE_ICE_SHARD" + }, + { + "Level": "27", + "Move": "MOVE_ICE_FANG" + }, + { + "Level": "36", + "Move": "MOVE_ICE_BEAM" + }, + { + "Level": "40", + "Move": "MOVE_FREEZE_DRY" + }, + { + "Level": "50", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_DOUBLE_EDGE", + "MOVE_ICY_WIND", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "GALLADE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "1", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "1", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "6", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "15", + "Move": "MOVE_TELEPORT" + }, + { + "Level": "18", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "28", + "Move": "MOVE_PROTECT" + }, + { + "Level": "30", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "35", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "42", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "50", + "Move": "MOVE_LEAF_BLADE" + }, + { + "Level": "58", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_AURA_SPHERE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_DAZZLING_GLEAM", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_KNOCK_OFF", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WILL_O_WISP", + "MOVE_X_SCISSOR", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_CALM_MIND", + "MOVE_CHARM", + "MOVE_CONFUSE_RAY", + "MOVE_DRAINING_KISS", + "MOVE_FUTURE_SIGHT", + "MOVE_MAGICAL_LEAF", + "MOVE_MYSTICAL_FIRE", + "MOVE_NIGHT_SLASH", + "MOVE_PSYCHIC", + "MOVE_SLASH" + ], + "EggMoves": [] + }, + "FROSLASS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "10", + "Move": "MOVE_ICE_SHARD" + }, + { + "Level": "15", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "20", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "25", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "30", + "Move": "MOVE_HAZE" + }, + { + "Level": "35", + "Move": "MOVE_ICE_BEAM" + }, + { + "Level": "40", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "45", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "50", + "Move": "MOVE_BLIZZARD" + }, + { + "Level": "55", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "60", + "Move": "MOVE_CURSE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_NASTY_PLOT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [ + "MOVE_CRUNCH", + "MOVE_DRAINING_KISS", + "MOVE_ICE_FANG", + "MOVE_ICICLE_CRASH", + "MOVE_PROTECT" + ], + "EggMoves": [] + }, + "TEPIG": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_EMBER" + }, + { + "Level": "10", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "13", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "15", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "24", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "29", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "32", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "50", + "Move": "MOVE_FLARE_BLITZ" + }, + { + "Level": "56", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_DIG", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_WILD_CHARGE", + "MOVE_WILL_O_WISP", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PIGNITE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_EMBER" + }, + { + "Level": "10", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "13", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "15", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "24", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "29", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "32", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "36", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "50", + "Move": "MOVE_FLARE_BLITZ" + }, + { + "Level": "56", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_KNOCK_OFF", + "MOVE_OVERHEAT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_WILD_CHARGE", + "MOVE_WILL_O_WISP", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_POWER_UP_PUNCH" + ], + "EggMoves": [] + }, + "EMBOAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "6", + "Move": "MOVE_EMBER" + }, + { + "Level": "10", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "13", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "15", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "24", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "29", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "32", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "36", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "45", + "Move": "MOVE_CLOSE_COMBAT" + }, + { + "Level": "50", + "Move": "MOVE_FLARE_BLITZ" + }, + { + "Level": "56", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_IRON_HEAD", + "MOVE_KNOCK_OFF", + "MOVE_OVERHEAT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_WILD_CHARGE", + "MOVE_WILL_O_WISP", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_HEAT_CRASH", + "MOVE_POWER_UP_PUNCH" + ], + "EggMoves": [] + }, + "PATRAT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "3", + "Move": "MOVE_LEER" + }, + { + "Level": "6", + "Move": "MOVE_BITE" + }, + { + "Level": "11", + "Move": "MOVE_DETECT" + }, + { + "Level": "16", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "18", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "21", + "Move": "MOVE_SUPER_FANG" + }, + { + "Level": "26", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "28", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "33", + "Move": "MOVE_NASTY_PLOT" + } + ], + "TMMoves": [ + "MOVE_BULLET_SEED", + "MOVE_DIG", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_GUNK_SHOT", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDERBOLT", + "MOVE_TOXIC", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "WATCHOG": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "3", + "Move": "MOVE_LEER" + }, + { + "Level": "6", + "Move": "MOVE_BITE" + }, + { + "Level": "11", + "Move": "MOVE_DETECT" + }, + { + "Level": "16", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "18", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "21", + "Move": "MOVE_SUPER_FANG" + }, + { + "Level": "26", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "28", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "33", + "Move": "MOVE_NASTY_PLOT" + }, + { + "Level": "40", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "46", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "50", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BULLET_SEED", + "MOVE_DIG", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_LIGHT_SCREEN", + "MOVE_MUD_SHOT", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SMASH", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_CONFUSE_RAY" + ], + "EggMoves": [] + }, + "PANSAGE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "4", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_LICK" + }, + { + "Level": "10", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "16", + "Move": "MOVE_BULLET_SEED" + }, + { + "Level": "19", + "Move": "MOVE_BITE" + }, + { + "Level": "22", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "28", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "32", + "Move": "MOVE_LEAF_STORM" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "43", + "Move": "MOVE_FOCUS_BLAST" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_GUNK_SHOT", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_TOXIC" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SIMISAGE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "4", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_LICK" + }, + { + "Level": "10", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "16", + "Move": "MOVE_BULLET_SEED" + }, + { + "Level": "19", + "Move": "MOVE_BITE" + }, + { + "Level": "22", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "28", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "32", + "Move": "MOVE_LEAF_STORM" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "43", + "Move": "MOVE_FOCUS_BLAST" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_TOXIC" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PANSEAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "4", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_LICK" + }, + { + "Level": "10", + "Move": "MOVE_EMBER" + }, + { + "Level": "16", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "19", + "Move": "MOVE_BITE" + }, + { + "Level": "25", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "28", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "32", + "Move": "MOVE_FIRE_BLAST" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "43", + "Move": "MOVE_FOCUS_BLAST" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FLARE_BLITZ", + "MOVE_GUNK_SHOT", + "MOVE_HEAT_WAVE", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_OVERHEAT", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SIMISEAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "4", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_LICK" + }, + { + "Level": "10", + "Move": "MOVE_EMBER" + }, + { + "Level": "16", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "19", + "Move": "MOVE_BITE" + }, + { + "Level": "25", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "28", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "32", + "Move": "MOVE_FIRE_BLAST" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "43", + "Move": "MOVE_FOCUS_BLAST" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FLARE_BLITZ", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_OVERHEAT", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PANPOUR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_AQUA_RING" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "4", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_LICK" + }, + { + "Level": "10", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "16", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "19", + "Move": "MOVE_BITE" + }, + { + "Level": "25", + "Move": "MOVE_TAUNT" + }, + { + "Level": "28", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "32", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "43", + "Move": "MOVE_FOCUS_BLAST" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_GUNK_SHOT", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_WATERFALL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SIMIPOUR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_AQUA_RING" + }, + { + "Level": "1", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "4", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_LICK" + }, + { + "Level": "10", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "16", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "19", + "Move": "MOVE_BITE" + }, + { + "Level": "25", + "Move": "MOVE_TAUNT" + }, + { + "Level": "28", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "32", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "43", + "Move": "MOVE_FOCUS_BLAST" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_IRON_TAIL", + "MOVE_LIQUIDATION", + "MOVE_MUD_SHOT", + "MOVE_NASTY_PLOT", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_WATERFALL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DRILBUR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "7", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "13", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "18", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "28", + "Move": "MOVE_DIG" + }, + { + "Level": "32", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "36", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "40", + "Move": "MOVE_DRILL_RUN" + }, + { + "Level": "46", + "Move": "MOVE_EARTHQUAKE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_IRON_DEFENSE", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_X_SCISSOR" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "EXCADRILL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "7", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "13", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "16", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "18", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "26", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "28", + "Move": "MOVE_DIG" + }, + { + "Level": "32", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "36", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "40", + "Move": "MOVE_DRILL_RUN" + }, + { + "Level": "46", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "50", + "Move": "MOVE_MEGAHORN" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [ + "MOVE_METAL_SOUND" + ], + "EggMoves": [] + }, + "AUDINO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "4", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "8", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "16", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "20", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "24", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "32", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "36", + "Move": "MOVE_WISH" + }, + { + "Level": "40", + "Move": "MOVE_HYPER_VOICE" + }, + { + "Level": "48", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_WILD_CHARGE", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "VENIPEDE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "4", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "8", + "Move": "MOVE_PROTECT" + }, + { + "Level": "12", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "16", + "Move": "MOVE_SCREECH" + }, + { + "Level": "20", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "28", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "36", + "Move": "MOVE_TOXIC" + }, + { + "Level": "48", + "Move": "MOVE_AGILITY" + }, + { + "Level": "52", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_IRON_DEFENSE", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_TOXIC_SPIKES" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "WHIRLIPEDE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "4", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "8", + "Move": "MOVE_PROTECT" + }, + { + "Level": "12", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "16", + "Move": "MOVE_SCREECH" + }, + { + "Level": "20", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "28", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "36", + "Move": "MOVE_TOXIC" + }, + { + "Level": "48", + "Move": "MOVE_AGILITY" + }, + { + "Level": "52", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_IRON_DEFENSE", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_TOXIC_SPIKES" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SCOLIPEDE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_STING" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "4", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "8", + "Move": "MOVE_PROTECT" + }, + { + "Level": "12", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "16", + "Move": "MOVE_SCREECH" + }, + { + "Level": "20", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "28", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "36", + "Move": "MOVE_TOXIC" + }, + { + "Level": "40", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "44", + "Move": "MOVE_X_SCISSOR" + }, + { + "Level": "48", + "Move": "MOVE_AGILITY" + }, + { + "Level": "52", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "56", + "Move": "MOVE_MEGAHORN" + } + ], + "TMMoves": [ + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TOXIC_SPIKES", + "MOVE_U_TURN" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SANDILE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "9", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "15", + "Move": "MOVE_BITE" + }, + { + "Level": "21", + "Move": "MOVE_DIG" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "27", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "42", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "50", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_DARK_PULSE", + "MOVE_DRAGON_CLAW", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "KROKOROK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "9", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "15", + "Move": "MOVE_BITE" + }, + { + "Level": "21", + "Move": "MOVE_DIG" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "27", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "42", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "50", + "Move": "MOVE_DOUBLE_EDGE" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_DRAGON_CLAW", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_KNOCK_OFF", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "KROOKODILE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "9", + "Move": "MOVE_SAND_TOMB" + }, + { + "Level": "15", + "Move": "MOVE_BITE" + }, + { + "Level": "21", + "Move": "MOVE_DIG" + }, + { + "Level": "24", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "27", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "42", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "50", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "58", + "Move": "MOVE_OUTRAGE" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_BULLDOZE", + "MOVE_CLOSE_COMBAT", + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_DRAGON_CLAW", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_HEAD", + "MOVE_KNOCK_OFF", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG" + ], + "TutorMoves": [ + "MOVE_BREAKING_SWIPE" + ], + "EggMoves": [] + }, + "SCRAGGY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "8", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "12", + "Move": "MOVE_POWER_UP_PUNCH" + }, + { + "Level": "16", + "Move": "MOVE_ROCK_TOMB" + }, + { + "Level": "20", + "Move": "MOVE_PROTECT" + }, + { + "Level": "26", + "Move": "MOVE_PARTING_SHOT" + }, + { + "Level": "32", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "35", + "Move": "MOVE_DETECT" + }, + { + "Level": "40", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "44", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "48", + "Move": "MOVE_DYNAMIC_PUNCH" + }, + { + "Level": "52", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BULK_UP", + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_ICE_PUNCH", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_POISON_JAB", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_SLUDGE_BOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SCRAFTY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "8", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "12", + "Move": "MOVE_POWER_UP_PUNCH" + }, + { + "Level": "16", + "Move": "MOVE_ROCK_TOMB" + }, + { + "Level": "20", + "Move": "MOVE_PROTECT" + }, + { + "Level": "26", + "Move": "MOVE_PARTING_SHOT" + }, + { + "Level": "32", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "35", + "Move": "MOVE_DETECT" + }, + { + "Level": "40", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "44", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "48", + "Move": "MOVE_DYNAMIC_PUNCH" + }, + { + "Level": "52", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BULK_UP", + "MOVE_CLOSE_COMBAT", + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_KNOCK_OFF", + "MOVE_METRONOME", + "MOVE_OUTRAGE", + "MOVE_POISON_JAB", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_SLUDGE_BOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_TAUNT", + "MOVE_THUNDER_PUNCH", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "TRUBBISH": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "9", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "12", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "15", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "18", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "20", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "24", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "27", + "Move": "MOVE_SLUDGE_BOMB" + }, + { + "Level": "30", + "Move": "MOVE_TOXIC" + }, + { + "Level": "34", + "Move": "MOVE_SELF_DESTRUCT" + }, + { + "Level": "39", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "44", + "Move": "MOVE_GUNK_SHOT" + }, + { + "Level": "53", + "Move": "MOVE_EXPLOSION" + } + ], + "TMMoves": [ + "MOVE_BULLET_SEED", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_ROCK_BLAST", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GARBODOR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "1", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "9", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "12", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "15", + "Move": "MOVE_TOXIC_SPIKES" + }, + { + "Level": "18", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "20", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "24", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "27", + "Move": "MOVE_SLUDGE_BOMB" + }, + { + "Level": "30", + "Move": "MOVE_TOXIC" + }, + { + "Level": "34", + "Move": "MOVE_SELF_DESTRUCT" + }, + { + "Level": "39", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "44", + "Move": "MOVE_GUNK_SHOT" + }, + { + "Level": "53", + "Move": "MOVE_EXPLOSION" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLET_SEED", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_MUD_SHOT", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_ROCK_BLAST", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_THUNDERBOLT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "VANILLITE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_TAUNT" + }, + { + "Level": "8", + "Move": "MOVE_MIST" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "20", + "Move": "MOVE_SELF_DESTRUCT" + }, + { + "Level": "24", + "Move": "MOVE_ICICLE_CRASH" + }, + { + "Level": "32", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "35", + "Move": "MOVE_ICE_BEAM" + }, + { + "Level": "46", + "Move": "MOVE_EXPLOSION" + }, + { + "Level": "58", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "VANILLISH": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "4", + "Move": "MOVE_TAUNT" + }, + { + "Level": "8", + "Move": "MOVE_MIST" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "20", + "Move": "MOVE_SELF_DESTRUCT" + }, + { + "Level": "24", + "Move": "MOVE_ICICLE_CRASH" + }, + { + "Level": "32", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "35", + "Move": "MOVE_ICE_BEAM" + }, + { + "Level": "46", + "Move": "MOVE_EXPLOSION" + }, + { + "Level": "58", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "VANILLUXE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "1", + "Move": "MOVE_FREEZE_DRY" + }, + { + "Level": "4", + "Move": "MOVE_TAUNT" + }, + { + "Level": "8", + "Move": "MOVE_MIST" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "20", + "Move": "MOVE_SELF_DESTRUCT" + }, + { + "Level": "24", + "Move": "MOVE_ICICLE_CRASH" + }, + { + "Level": "32", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "35", + "Move": "MOVE_ICE_BEAM" + }, + { + "Level": "46", + "Move": "MOVE_EXPLOSION" + }, + { + "Level": "58", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "EMOLGA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_NUZZLE" + }, + { + "Level": "5", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "7", + "Move": "MOVE_CHARM" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "20", + "Move": "MOVE_CHARGE" + }, + { + "Level": "22", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "25", + "Move": "MOVE_EERIE_IMPULSE" + }, + { + "Level": "29", + "Move": "MOVE_SPARK" + }, + { + "Level": "35", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_VOLT_SWITCH" + }, + { + "Level": "44", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "52", + "Move": "MOVE_DISCHARGE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "TYNAMO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "1", + "Move": "MOVE_SPARK" + } + ], + "TMMoves": [ + "MOVE_PROTECT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "EELEKTRIK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "1", + "Move": "MOVE_SPARK" + }, + { + "Level": "18", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "29", + "Move": "MOVE_DISCHARGE" + }, + { + "Level": "33", + "Move": "MOVE_EERIE_IMPULSE" + }, + { + "Level": "39", + "Move": "MOVE_CHARGE" + }, + { + "Level": "44", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "46", + "Move": "MOVE_WILD_CHARGE" + }, + { + "Level": "48", + "Move": "MOVE_ZAP_CANNON" + }, + { + "Level": "50", + "Move": "MOVE_SUPER_FANG" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_DRAIN", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDER_FANG", + "MOVE_U_TURN", + "MOVE_VOLT_SWITCH" + ], + "TutorMoves": [ + "MOVE_CRUNCH" + ], + "EggMoves": [] + }, + "EELEKTROSS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SPARK" + }, + { + "Level": "1", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "18", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "21", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "29", + "Move": "MOVE_DISCHARGE" + }, + { + "Level": "33", + "Move": "MOVE_EERIE_IMPULSE" + }, + { + "Level": "36", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "39", + "Move": "MOVE_CHARGE" + }, + { + "Level": "44", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "46", + "Move": "MOVE_WILD_CHARGE" + }, + { + "Level": "48", + "Move": "MOVE_ZAP_CANNON" + }, + { + "Level": "50", + "Move": "MOVE_SUPER_FANG" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULK_UP", + "MOVE_BULLDOZE", + "MOVE_CLOSE_COMBAT", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDER_FANG", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_U_TURN", + "MOVE_VOLT_SWITCH", + "MOVE_WATERFALL", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "LITWICK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "1", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "10", + "Move": "MOVE_HAZE" + }, + { + "Level": "12", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "16", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "20", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "24", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "28", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "32", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "38", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "44", + "Move": "MOVE_CURSE" + }, + { + "Level": "48", + "Move": "MOVE_HEAL_BLOCK" + }, + { + "Level": "52", + "Move": "MOVE_OVERHEAT" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_BLAST", + "MOVE_HEAT_WAVE", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SAFEGUARD", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "LAMPENT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "1", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "10", + "Move": "MOVE_HAZE" + }, + { + "Level": "12", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "16", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "20", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "24", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "28", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "32", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "38", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "44", + "Move": "MOVE_CURSE" + }, + { + "Level": "48", + "Move": "MOVE_HEAL_BLOCK" + }, + { + "Level": "52", + "Move": "MOVE_OVERHEAT" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_BLAST", + "MOVE_HEAT_WAVE", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SAFEGUARD", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CHANDELURE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "1", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "10", + "Move": "MOVE_HAZE" + }, + { + "Level": "12", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "16", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "20", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "24", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "28", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "32", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "38", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "44", + "Move": "MOVE_CURSE" + }, + { + "Level": "48", + "Move": "MOVE_HEAL_BLOCK" + }, + { + "Level": "52", + "Move": "MOVE_OVERHEAT" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_BLAST", + "MOVE_FLARE_BLITZ", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SAFEGUARD", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "STUNFISK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "5", + "Move": "MOVE_ENDURE" + }, + { + "Level": "10", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "15", + "Move": "MOVE_ROCK_TOMB" + }, + { + "Level": "20", + "Move": "MOVE_CHARGE" + }, + { + "Level": "25", + "Move": "MOVE_SPARK" + }, + { + "Level": "30", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "35", + "Move": "MOVE_DISCHARGE" + }, + { + "Level": "40", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "45", + "Move": "MOVE_EERIE_IMPULSE" + }, + { + "Level": "50", + "Move": "MOVE_SLUDGE_WAVE" + } + ], + "TMMoves": [ + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_EARTH_POWER", + "MOVE_ELECTROWEB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "STUNFISK_GALAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "1", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "5", + "Move": "MOVE_ENDURE" + }, + { + "Level": "10", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "15", + "Move": "MOVE_ROCK_TOMB" + }, + { + "Level": "20", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "25", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "30", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "35", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "40", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "45", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "50", + "Move": "MOVE_STEALTH_ROCK" + } + ], + "TMMoves": [ + "MOVE_BULLDOZE", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_EARTH_POWER", + "MOVE_FLASH_CANNON", + "MOVE_ICE_FANG", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_SLUDGE_BOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CHESPIN": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_GROWTH" + }, + { + "Level": "8", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "11", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "18", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "27", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "35", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "42", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "48", + "Move": "MOVE_WOOD_HAMMER" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BULLDOZE", + "MOVE_BULLET_SEED", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_HEADBUTT", + "MOVE_IRON_HEAD", + "MOVE_MUD_SHOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "QUILLADIN": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_GROWTH" + }, + { + "Level": "8", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "11", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "18", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "27", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "35", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "42", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "48", + "Move": "MOVE_WOOD_HAMMER" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BULK_UP", + "MOVE_BULLDOZE", + "MOVE_BULLET_SEED", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_HEADBUTT", + "MOVE_IRON_HEAD", + "MOVE_MUD_SHOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CHESNAUGHT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_GROWTH" + }, + { + "Level": "8", + "Move": "MOVE_ROLLOUT" + }, + { + "Level": "11", + "Move": "MOVE_BITE" + }, + { + "Level": "15", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "18", + "Move": "MOVE_PIN_MISSILE" + }, + { + "Level": "27", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "35", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "38", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "42", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "45", + "Move": "MOVE_CLOSE_COMBAT" + }, + { + "Level": "48", + "Move": "MOVE_WOOD_HAMMER" + }, + { + "Level": "55", + "Move": "MOVE_GIGA_IMPACT" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BULLDOZE", + "MOVE_BULLET_SEED", + "MOVE_CRUNCH", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_KNOCK_OFF", + "MOVE_MUD_SHOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SPIKES", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_PUNCH", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_SPIKY_SHIELD" + ], + "EggMoves": [] + }, + "FENNEKIN": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "5", + "Move": "MOVE_EMBER" + }, + { + "Level": "14", + "Move": "MOVE_CHARM" + }, + { + "Level": "17", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "25", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "31", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "35", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "38", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "41", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "54", + "Move": "MOVE_FIRE_BLAST" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_CALM_MIND", + "MOVE_ENDURE", + "MOVE_FLARE_BLITZ", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BRAIXEN": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "5", + "Move": "MOVE_EMBER" + }, + { + "Level": "14", + "Move": "MOVE_CHARM" + }, + { + "Level": "17", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "25", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "31", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "35", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "38", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "41", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "46", + "Move": "MOVE_AGILITY" + }, + { + "Level": "54", + "Move": "MOVE_FIRE_BLAST" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLARE_BLITZ", + "MOVE_HEAT_WAVE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DELPHOX": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "5", + "Move": "MOVE_EMBER" + }, + { + "Level": "14", + "Move": "MOVE_CHARM" + }, + { + "Level": "17", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "20", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "25", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "31", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "35", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "38", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "41", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "46", + "Move": "MOVE_AGILITY" + }, + { + "Level": "54", + "Move": "MOVE_FIRE_BLAST" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLARE_BLITZ", + "MOVE_FOCUS_BLAST", + "MOVE_HEAL_BLOCK", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SAFEGUARD", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_FUTURE_SIGHT", + "MOVE_MYSTICAL_FIRE", + "MOVE_SHADOW_BALL" + ], + "EggMoves": [] + }, + "FROAKIE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "10", + "Move": "MOVE_LICK" + }, + { + "Level": "14", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "18", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "35", + "Move": "MOVE_SUBSTITUTE" + }, + { + "Level": "38", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "43", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "51", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "57", + "Move": "MOVE_HYDRO_PUMP" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BLIZZARD", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ICE_BEAM", + "MOVE_ICY_WIND", + "MOVE_LIQUIDATION", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SPIKES", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_TOXIC_SPIKES", + "MOVE_U_TURN", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "FROGADIER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "10", + "Move": "MOVE_LICK" + }, + { + "Level": "14", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "18", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "23", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "28", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "35", + "Move": "MOVE_SUBSTITUTE" + }, + { + "Level": "38", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "43", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "51", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "57", + "Move": "MOVE_HYDRO_PUMP" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_GUNK_SHOT", + "MOVE_HEADBUTT", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_LIQUIDATION", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SPIKES", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_TAUNT", + "MOVE_TOXIC_SPIKES", + "MOVE_U_TURN", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GRENINJA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "10", + "Move": "MOVE_LICK" + }, + { + "Level": "14", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "18", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "23", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "28", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "35", + "Move": "MOVE_SUBSTITUTE" + }, + { + "Level": "38", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "43", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "51", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "57", + "Move": "MOVE_HYDRO_PUMP" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_ICY_WIND", + "MOVE_LIQUIDATION", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SPIKES", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_TAUNT", + "MOVE_TOXIC_SPIKES", + "MOVE_U_TURN", + "MOVE_WATERFALL", + "MOVE_WATER_PULSE" + ], + "TutorMoves": [ + "MOVE_WATER_SHURIKEN" + ], + "EggMoves": [] + }, + "BUNNELBY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "14", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "24", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "28", + "Move": "MOVE_DIG" + }, + { + "Level": "32", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "40", + "Move": "MOVE_SUPER_FANG" + }, + { + "Level": "44", + "Move": "MOVE_EARTHQUAKE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_BULLDOZE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_HEADBUTT", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SPIKES", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DIGGERSBY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "7", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "14", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "24", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "28", + "Move": "MOVE_DIG" + }, + { + "Level": "32", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "40", + "Move": "MOVE_SUPER_FANG" + }, + { + "Level": "44", + "Move": "MOVE_EARTHQUAKE" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULK_UP", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SPIKES", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_PUNCH", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [ + "MOVE_BULLDOZE" + ], + "EggMoves": [] + }, + "FLETCHLING": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "8", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "12", + "Move": "MOVE_EMBER" + }, + { + "Level": "16", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "20", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "25", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "30", + "Move": "MOVE_STEEL_WING" + }, + { + "Level": "35", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_AGILITY" + }, + { + "Level": "45", + "Move": "MOVE_FLARE_BLITZ" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_U_TURN", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "FLETCHINDER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "8", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "12", + "Move": "MOVE_EMBER" + }, + { + "Level": "16", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "20", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "25", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "30", + "Move": "MOVE_STEEL_WING" + }, + { + "Level": "35", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_AGILITY" + }, + { + "Level": "45", + "Move": "MOVE_FLARE_BLITZ" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_FLY", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_U_TURN", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [ + "MOVE_WING_ATTACK" + ], + "EggMoves": [] + }, + "TALONFLAME": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "8", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "12", + "Move": "MOVE_EMBER" + }, + { + "Level": "16", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "20", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "25", + "Move": "MOVE_FLAME_WHEEL" + }, + { + "Level": "30", + "Move": "MOVE_STEEL_WING" + }, + { + "Level": "35", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_AGILITY" + }, + { + "Level": "45", + "Move": "MOVE_FLARE_BLITZ" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_BULK_UP", + "MOVE_DOUBLE_EDGE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_FLY", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_HYPER_BEAM", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_SWORDS_DANCE", + "MOVE_U_TURN", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [ + "MOVE_BRAVE_BIRD" + ], + "EggMoves": [] + }, + "SCATTERBUG": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "7", + "Move": "MOVE_STUN_SPORE" + } + ], + "TMMoves": [ + "MOVE_PROTECT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SPEWPA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "1", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "7", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "10", + "Move": "MOVE_INFESTATION" + } + ], + "TMMoves": [ + "MOVE_IRON_DEFENSE" + ], + "TutorMoves": [ + "MOVE_PROTECT" + ], + "EggMoves": [] + }, + "VIVILLON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_POISON_POWDER" + }, + { + "Level": "1", + "Move": "MOVE_STUN_SPORE" + }, + { + "Level": "1", + "Move": "MOVE_SLEEP_POWDER" + }, + { + "Level": "10", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "12", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "15", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "17", + "Move": "MOVE_SUPERSONIC" + }, + { + "Level": "21", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "25", + "Move": "MOVE_U_TURN" + }, + { + "Level": "28", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "35", + "Move": "MOVE_BUG_BUZZ" + }, + { + "Level": "40", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "40", + "Move": "MOVE_HURRICANE" + }, + { + "Level": "45", + "Move": "MOVE_WHIRLWIND" + } + ], + "TMMoves": [ + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_PSYCHIC", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [ + "MOVE_GUST", + "MOVE_HARDEN", + "MOVE_PROTECT", + "MOVE_STRING_SHOT", + "MOVE_TACKLE" + ], + "EggMoves": [] + }, + "LITLEO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "5", + "Move": "MOVE_EMBER" + }, + { + "Level": "6", + "Move": "MOVE_ROAR" + }, + { + "Level": "8", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "11", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "16", + "Move": "MOVE_SNARL" + }, + { + "Level": "20", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "23", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "28", + "Move": "MOVE_EARTH_POWER" + }, + { + "Level": "32", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "42", + "Move": "MOVE_HYPER_VOICE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLARE_BLITZ", + "MOVE_HEAT_WAVE", + "MOVE_OVERHEAT", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG", + "MOVE_WILD_CHARGE", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PYROAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_EMBER" + }, + { + "Level": "6", + "Move": "MOVE_ROAR" + }, + { + "Level": "8", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "11", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "16", + "Move": "MOVE_SNARL" + }, + { + "Level": "20", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "23", + "Move": "MOVE_FIRE_FANG" + }, + { + "Level": "28", + "Move": "MOVE_EARTH_POWER" + }, + { + "Level": "32", + "Move": "MOVE_FLAMETHROWER" + }, + { + "Level": "36", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "42", + "Move": "MOVE_HYPER_VOICE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_EDGE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLARE_BLITZ", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_PROTECT", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG", + "MOVE_WILD_CHARGE", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [ + "MOVE_HYPER_BEAM", + "MOVE_OVERHEAT" + ], + "EggMoves": [] + }, + "FLAB\u00c9B\u00c9": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "6", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "10", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "15", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "18", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "20", + "Move": "MOVE_WISH" + }, + { + "Level": "22", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "26", + "Move": "MOVE_CHARM" + }, + { + "Level": "33", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "40", + "Move": "MOVE_ENERGY_BALL" + }, + { + "Level": "54", + "Move": "MOVE_SOLAR_BEAM" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "FLOETTE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "10", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "15", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "18", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "20", + "Move": "MOVE_WISH" + }, + { + "Level": "22", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "26", + "Move": "MOVE_CHARM" + }, + { + "Level": "33", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "40", + "Move": "MOVE_ENERGY_BALL" + }, + { + "Level": "54", + "Move": "MOVE_SOLAR_BEAM" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [ + "MOVE_MOONBLAST" + ], + "EggMoves": [] + }, + "FLOETTE_ETERNAL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "10", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "15", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "18", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "20", + "Move": "MOVE_WISH" + }, + { + "Level": "22", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "26", + "Move": "MOVE_CHARM" + }, + { + "Level": "33", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "40", + "Move": "MOVE_ENERGY_BALL" + }, + { + "Level": "50", + "Move": "MOVE_LIGHT_OF_RUIN" + }, + { + "Level": "54", + "Move": "MOVE_SOLAR_BEAM" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [ + "MOVE_MOONBLAST" + ], + "EggMoves": [] + }, + "FLORGES": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "1", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "10", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "15", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "18", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "20", + "Move": "MOVE_WISH" + }, + { + "Level": "22", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "26", + "Move": "MOVE_CHARM" + }, + { + "Level": "33", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "40", + "Move": "MOVE_ENERGY_BALL" + }, + { + "Level": "54", + "Move": "MOVE_SOLAR_BEAM" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_GIGA_DRAIN", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [ + "MOVE_DISARMING_VOICE" + ], + "EggMoves": [] + }, + "SKIDDO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "7", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "9", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "12", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "13", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "16", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "20", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "22", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "26", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "34", + "Move": "MOVE_HORN_LEECH" + }, + { + "Level": "38", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "42", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "45", + "Move": "MOVE_LEAF_BLADE" + }, + { + "Level": "50", + "Move": "MOVE_MEGAHORN" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLET_SEED", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_LEAF_STORM", + "MOVE_MAGICAL_LEAF", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_WILD_CHARGE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GOGOAT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWTH" + }, + { + "Level": "7", + "Move": "MOVE_VINE_WHIP" + }, + { + "Level": "9", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "12", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "13", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "16", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "20", + "Move": "MOVE_SYNTHESIS" + }, + { + "Level": "22", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "26", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "34", + "Move": "MOVE_HORN_LEECH" + }, + { + "Level": "38", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "42", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "45", + "Move": "MOVE_LEAF_BLADE" + }, + { + "Level": "50", + "Move": "MOVE_MEGAHORN" + }, + { + "Level": "55", + "Move": "MOVE_EARTHQUAKE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLET_SEED", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LEAF_STORM", + "MOVE_MAGICAL_LEAF", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_WILD_CHARGE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_AERIAL_ACE" + ], + "EggMoves": [] + }, + "PANCHAM": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "8", + "Move": "MOVE_TAUNT" + }, + { + "Level": "15", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "20", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "28", + "Move": "MOVE_DETECT" + }, + { + "Level": "30", + "Move": "MOVE_PARTING_SHOT" + }, + { + "Level": "34", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "44", + "Move": "MOVE_BODY_SLAM" + } + ], + "TMMoves": [ + "MOVE_BULK_UP", + "MOVE_BULLDOZE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_HYPER_VOICE", + "MOVE_ICE_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_PUNCH" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PANGORO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_TAUNT" + }, + { + "Level": "1", + "Move": "MOVE_BULLET_PUNCH" + }, + { + "Level": "15", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "20", + "Move": "MOVE_WORK_UP" + }, + { + "Level": "24", + "Move": "MOVE_SLASH" + }, + { + "Level": "28", + "Move": "MOVE_DETECT" + }, + { + "Level": "30", + "Move": "MOVE_PARTING_SHOT" + }, + { + "Level": "34", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "38", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "44", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "50", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "54", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "58", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_BULK_UP", + "MOVE_BULLDOZE", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_PUNCH", + "MOVE_IRON_HEAD", + "MOVE_KNOCK_OFF", + "MOVE_POISON_JAB", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_SMASH", + "MOVE_ROCK_TOMB", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDER_PUNCH", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_NIGHT_SLASH" + ], + "EggMoves": [] + }, + "FURFROU": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "8", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "13", + "Move": "MOVE_BITE" + }, + { + "Level": "16", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "20", + "Move": "MOVE_ROAR" + }, + { + "Level": "22", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "25", + "Move": "MOVE_CHARM" + }, + { + "Level": "28", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "30", + "Move": "MOVE_SNARL" + }, + { + "Level": "36", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "43", + "Move": "MOVE_HYPER_VOICE" + } + ], + "TMMoves": [ + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_FANG", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_ROCK_SMASH", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDER_FANG", + "MOVE_THUNDER_WAVE", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ESPURR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "6", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "9", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "13", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "15", + "Move": "MOVE_SWIFT" + }, + { + "Level": "21", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "30", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "30", + "Move": "MOVE_REFLECT" + }, + { + "Level": "36", + "Move": "MOVE_PSYSHOCK" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_NASTY_PLOT", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MEOWSTIC_M": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "6", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "9", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "13", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "15", + "Move": "MOVE_SWIFT" + }, + { + "Level": "18", + "Move": "MOVE_CHARM" + }, + { + "Level": "21", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "30", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "30", + "Move": "MOVE_REFLECT" + }, + { + "Level": "36", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "44", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "46", + "Move": "MOVE_HEAL_BLOCK" + }, + { + "Level": "50", + "Move": "MOVE_WISH" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_NASTY_PLOT", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SPIKES", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_TOXIC_SPIKES", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MEOWSTIC_F": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_MAGICAL_LEAF" + }, + { + "Level": "1", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "9", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "13", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "15", + "Move": "MOVE_SWIFT" + }, + { + "Level": "21", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "24", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "30", + "Move": "MOVE_REFLECT" + }, + { + "Level": "36", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "40", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "44", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "50", + "Move": "MOVE_FUTURE_SIGHT" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DIG", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_NASTY_PLOT", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_SAFEGUARD", + "MOVE_SUBSTITUTE", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WATER_PULSE", + "MOVE_WORK_UP", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HONEDGE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "4", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "12", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "16", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "20", + "Move": "MOVE_SLASH" + }, + { + "Level": "22", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "24", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "32", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "38", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "44", + "Move": "MOVE_SWORDS_DANCE" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_CLOSE_COMBAT", + "MOVE_FLASH_CANNON", + "MOVE_HEADBUTT", + "MOVE_NIGHT_SLASH", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DOUBLADE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "4", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "12", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "16", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "20", + "Move": "MOVE_SLASH" + }, + { + "Level": "22", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "24", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "32", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "38", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "44", + "Move": "MOVE_SWORDS_DANCE" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_CLOSE_COMBAT", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_HEADBUTT", + "MOVE_NIGHT_SLASH", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_SUBSTITUTE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AEGISLASH": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "4", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "12", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "16", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "20", + "Move": "MOVE_SLASH" + }, + { + "Level": "22", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "24", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "32", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "38", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "44", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "50", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_CLOSE_COMBAT", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HYPER_BEAM", + "MOVE_NIGHT_SLASH", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [ + "MOVE_KINGS_SHIELD" + ], + "EggMoves": [] + }, + "SPRITZEE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "8", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "10", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "15", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "22", + "Move": "MOVE_WISH" + }, + { + "Level": "24", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "27", + "Move": "MOVE_DAZZLING_GLEAM" + }, + { + "Level": "30", + "Move": "MOVE_CHARM" + }, + { + "Level": "33", + "Move": "MOVE_CALM_MIND" + }, + { + "Level": "36", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "40", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "44", + "Move": "MOVE_HEAL_BLOCK" + }, + { + "Level": "48", + "Move": "MOVE_HYPNOSIS" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FLASH_CANNON", + "MOVE_LIGHT_SCREEN", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_THUNDERBOLT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AROMATISSE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "8", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "10", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "15", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "22", + "Move": "MOVE_WISH" + }, + { + "Level": "24", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "27", + "Move": "MOVE_DAZZLING_GLEAM" + }, + { + "Level": "30", + "Move": "MOVE_CHARM" + }, + { + "Level": "33", + "Move": "MOVE_CALM_MIND" + }, + { + "Level": "36", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "40", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "44", + "Move": "MOVE_HEAL_BLOCK" + }, + { + "Level": "48", + "Move": "MOVE_HYPNOSIS" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SUBSTITUTE", + "MOVE_THUNDERBOLT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SWIRLIX": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CHARM" + }, + { + "Level": "6", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "12", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "15", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "18", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "21", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "24", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "27", + "Move": "MOVE_ENERGY_BALL" + }, + { + "Level": "32", + "Move": "MOVE_WISH" + }, + { + "Level": "36", + "Move": "MOVE_PLAY_ROUGH" + }, + { + "Level": "40", + "Move": "MOVE_STICKY_WEB" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_FLAMETHROWER", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SAFEGUARD", + "MOVE_SELF_DESTRUCT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDERBOLT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SLURPUFF": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_CHARM" + }, + { + "Level": "6", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "12", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "15", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "18", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "21", + "Move": "MOVE_STRING_SHOT" + }, + { + "Level": "24", + "Move": "MOVE_COTTON_GUARD" + }, + { + "Level": "27", + "Move": "MOVE_ENERGY_BALL" + }, + { + "Level": "32", + "Move": "MOVE_WISH" + }, + { + "Level": "36", + "Move": "MOVE_PLAY_ROUGH" + }, + { + "Level": "40", + "Move": "MOVE_STICKY_WEB" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_METRONOME", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SAFEGUARD", + "MOVE_SELF_DESTRUCT", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_THUNDERBOLT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "INKAY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "3", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "6", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "14", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "15", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "21", + "Move": "MOVE_SLASH" + }, + { + "Level": "24", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "33", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "37", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "42", + "Move": "MOVE_TOPSY_TURVY" + }, + { + "Level": "54", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_FLAMETHROWER", + "MOVE_FUTURE_SIGHT", + "MOVE_HEADBUTT", + "MOVE_LIGHT_SCREEN", + "MOVE_LIQUIDATION", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "MALAMAR": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_PECK" + }, + { + "Level": "3", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "6", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "14", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "15", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "21", + "Move": "MOVE_SLASH" + }, + { + "Level": "24", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "33", + "Move": "MOVE_PSYCHO_CUT" + }, + { + "Level": "37", + "Move": "MOVE_PSYSHOCK" + }, + { + "Level": "42", + "Move": "MOVE_TOPSY_TURVY" + }, + { + "Level": "54", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_BULK_UP", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FLAMETHROWER", + "MOVE_FUTURE_SIGHT", + "MOVE_GIGA_IMPACT", + "MOVE_HEADBUTT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_LIQUIDATION", + "MOVE_NASTY_PLOT", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BINACLE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "9", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "12", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "14", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "16", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "18", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "23", + "Move": "MOVE_SLASH" + }, + { + "Level": "35", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "40", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "45", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "50", + "Move": "MOVE_STONE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_ICE_BEAM", + "MOVE_MUD_SHOT", + "MOVE_POISON_JAB", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_TAUNT", + "MOVE_WATERFALL", + "MOVE_X_SCISSOR" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BARBARACLE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_SCREECH" + }, + { + "Level": "9", + "Move": "MOVE_INFESTATION" + }, + { + "Level": "12", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "14", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "16", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "18", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "23", + "Move": "MOVE_SLASH" + }, + { + "Level": "35", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "40", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "43", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "45", + "Move": "MOVE_LIQUIDATION" + }, + { + "Level": "50", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "54", + "Move": "MOVE_CLOSE_COMBAT" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BULK_UP", + "MOVE_DIG", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_MUD_SHOT", + "MOVE_POISON_JAB", + "MOVE_POWER_UP_PUNCH", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWORDS_DANCE", + "MOVE_TAUNT", + "MOVE_WATERFALL", + "MOVE_X_SCISSOR" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SKRELP": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "5", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "10", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "22", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "25", + "Move": "MOVE_TOXIC" + }, + { + "Level": "30", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "32", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "36", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "40", + "Move": "MOVE_SLUDGE_BOMB" + }, + { + "Level": "46", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "52", + "Move": "MOVE_SLUDGE_WAVE" + } + ], + "TMMoves": [ + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_GUNK_SHOT", + "MOVE_LIQUIDATION", + "MOVE_OUTRAGE", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDERBOLT", + "MOVE_TOXIC_SPIKES", + "MOVE_WATERFALL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DRAGALGE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_SMOKESCREEN" + }, + { + "Level": "5", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "10", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "15", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "22", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "25", + "Move": "MOVE_TOXIC" + }, + { + "Level": "30", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "32", + "Move": "MOVE_POISON_JAB" + }, + { + "Level": "36", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "40", + "Move": "MOVE_SLUDGE_BOMB" + }, + { + "Level": "46", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "52", + "Move": "MOVE_SLUDGE_WAVE" + } + ], + "TMMoves": [ + "MOVE_DRACO_METEOR", + "MOVE_ENDURE", + "MOVE_FLIP_TURN", + "MOVE_FOCUS_BLAST", + "MOVE_GUNK_SHOT", + "MOVE_HYPER_BEAM", + "MOVE_LIQUIDATION", + "MOVE_OUTRAGE", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDERBOLT", + "MOVE_TOXIC_SPIKES", + "MOVE_WATERFALL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CLAUNCHER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "10", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "13", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "16", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "24", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "34", + "Move": "MOVE_AURA_SPHERE" + }, + { + "Level": "40", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "45", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "48", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "52", + "Move": "MOVE_HYDRO_PUMP" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_FLIP_TURN", + "MOVE_ICE_BEAM", + "MOVE_LIQUIDATION", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_U_TURN", + "MOVE_WATERFALL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CLAWITZER": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_SPLASH" + }, + { + "Level": "10", + "Move": "MOVE_BUBBLE_BEAM" + }, + { + "Level": "13", + "Move": "MOVE_AQUA_JET" + }, + { + "Level": "16", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "24", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "34", + "Move": "MOVE_AURA_SPHERE" + }, + { + "Level": "40", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "45", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "48", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "52", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "55", + "Move": "MOVE_FOCUS_BLAST" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_FLIP_TURN", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_LIQUIDATION", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_U_TURN", + "MOVE_WATERFALL" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HELIOPTILE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "12", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_SWIFT" + }, + { + "Level": "20", + "Move": "MOVE_PARABOLIC_CHARGE" + }, + { + "Level": "24", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "28", + "Move": "MOVE_VOLT_SWITCH" + }, + { + "Level": "30", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "32", + "Move": "MOVE_MORNING_SUN" + }, + { + "Level": "36", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "42", + "Move": "MOVE_CHARGE" + }, + { + "Level": "50", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HELIOLISK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "12", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_SWIFT" + }, + { + "Level": "20", + "Move": "MOVE_PARABOLIC_CHARGE" + }, + { + "Level": "24", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "28", + "Move": "MOVE_VOLT_SWITCH" + }, + { + "Level": "30", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "32", + "Move": "MOVE_MORNING_SUN" + }, + { + "Level": "36", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "42", + "Move": "MOVE_CHARGE" + }, + { + "Level": "50", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_DRAGON_PULSE", + "MOVE_ELECTROWEB", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_THUNDER_PUNCH", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "TYRUNT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "4", + "Move": "MOVE_ROAR" + }, + { + "Level": "8", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "12", + "Move": "MOVE_CHARM" + }, + { + "Level": "16", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "28", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "32", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "44", + "Move": "MOVE_EARTHQUAKE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CLOSE_COMBAT", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_HYPER_VOICE", + "MOVE_ICE_FANG", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_OUTRAGE", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "TYRANTRUM": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "4", + "Move": "MOVE_ROAR" + }, + { + "Level": "8", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "12", + "Move": "MOVE_CHARM" + }, + { + "Level": "16", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "28", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "32", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_DRAGON_CLAW" + }, + { + "Level": "44", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "52", + "Move": "MOVE_GIGA_IMPACT" + }, + { + "Level": "58", + "Move": "MOVE_HEAD_SMASH" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_BULLDOZE", + "MOVE_CLOSE_COMBAT", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_PULSE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_FANG", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_ICE_FANG", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_IRON_TAIL", + "MOVE_OUTRAGE", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER_FANG", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AMAURA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "16", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "20", + "Move": "MOVE_MIST" + }, + { + "Level": "24", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "28", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "36", + "Move": "MOVE_FREEZE_DRY" + }, + { + "Level": "40", + "Move": "MOVE_ICE_BEAM" + }, + { + "Level": "44", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "52", + "Move": "MOVE_BLIZZARD" + }, + { + "Level": "56", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_THUNDERBOLT", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AURORUS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "16", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "20", + "Move": "MOVE_MIST" + }, + { + "Level": "24", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "28", + "Move": "MOVE_THUNDER_WAVE" + }, + { + "Level": "36", + "Move": "MOVE_FREEZE_DRY" + }, + { + "Level": "40", + "Move": "MOVE_ICE_BEAM" + }, + { + "Level": "44", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "52", + "Move": "MOVE_BLIZZARD" + }, + { + "Level": "56", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_VOICE", + "MOVE_IRON_DEFENSE", + "MOVE_IRON_HEAD", + "MOVE_IRON_TAIL", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_STEALTH_ROCK", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SYLVEON": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_GROWL" + }, + { + "Level": "10", + "Move": "MOVE_QUICK_ATTACK" + }, + { + "Level": "15", + "Move": "MOVE_DISARMING_VOICE" + }, + { + "Level": "25", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "30", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "35", + "Move": "MOVE_DAZZLING_GLEAM" + }, + { + "Level": "40", + "Move": "MOVE_HYPER_VOICE" + }, + { + "Level": "45", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "50", + "Move": "MOVE_MOONBLAST" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_CURSE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_TAIL", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROAR", + "MOVE_SHADOW_BALL", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT" + ], + "TutorMoves": [ + "MOVE_CHARM", + "MOVE_DOUBLE_EDGE", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_WISH" + ], + "EggMoves": [] + }, + "HAWLUCHA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "4", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "8", + "Move": "MOVE_DETECT" + }, + { + "Level": "12", + "Move": "MOVE_AERIAL_ACE" + }, + { + "Level": "20", + "Move": "MOVE_FEATHER_DANCE" + }, + { + "Level": "24", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "26", + "Move": "MOVE_LUNGE" + }, + { + "Level": "28", + "Move": "MOVE_BOUNCE" + }, + { + "Level": "32", + "Move": "MOVE_TAUNT" + }, + { + "Level": "36", + "Move": "MOVE_FLYING_PRESS" + }, + { + "Level": "40", + "Move": "MOVE_SWORDS_DANCE" + }, + { + "Level": "44", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "52", + "Move": "MOVE_BRAVE_BIRD" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BULK_UP", + "MOVE_CLOSE_COMBAT", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_FIRE_PUNCH", + "MOVE_FLY", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_HEAD", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_U_TURN", + "MOVE_X_SCISSOR", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DEDENNE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TAIL_WHIP" + }, + { + "Level": "1", + "Move": "MOVE_THUNDER_SHOCK" + }, + { + "Level": "1", + "Move": "MOVE_NUZZLE" + }, + { + "Level": "5", + "Move": "MOVE_CHARGE" + }, + { + "Level": "10", + "Move": "MOVE_CHARM" + }, + { + "Level": "15", + "Move": "MOVE_PARABOLIC_CHARGE" + }, + { + "Level": "20", + "Move": "MOVE_EERIE_IMPULSE" + }, + { + "Level": "25", + "Move": "MOVE_VOLT_SWITCH" + }, + { + "Level": "30", + "Move": "MOVE_PLAY_ROUGH" + }, + { + "Level": "35", + "Move": "MOVE_THUNDERBOLT" + }, + { + "Level": "40", + "Move": "MOVE_SUPER_FANG" + }, + { + "Level": "50", + "Move": "MOVE_THUNDER" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_DAZZLING_GLEAM", + "MOVE_DIG", + "MOVE_DISCHARGE", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "CARBINK": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "12", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "15", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "23", + "Move": "MOVE_DAZZLING_GLEAM" + }, + { + "Level": "25", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "28", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "30", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "32", + "Move": "MOVE_FLASH_CANNON" + }, + { + "Level": "35", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "38", + "Move": "MOVE_STEALTH_ROCK" + }, + { + "Level": "45", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "52", + "Move": "MOVE_STONE_EDGE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DOUBLE_EDGE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROCK_BLAST", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GOOMY": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_CHARM" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "18", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "25", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "35", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "41", + "Move": "MOVE_CURSE" + }, + { + "Level": "45", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_SURF" + } + ], + "TMMoves": [ + "MOVE_DRACO_METEOR", + "MOVE_ENDURE", + "MOVE_OUTRAGE", + "MOVE_ROCK_SLIDE", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDERBOLT", + "MOVE_TOXIC" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SLIGGOO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_CHARM" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "18", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "25", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "35", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "41", + "Move": "MOVE_CURSE" + }, + { + "Level": "45", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_SURF" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_DRACO_METEOR", + "MOVE_ENDURE", + "MOVE_ICE_BEAM", + "MOVE_OUTRAGE", + "MOVE_ROCK_SLIDE", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_TOXIC" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "SLIGGOO_HISUI": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_CHARM" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "18", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "25", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "35", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "41", + "Move": "MOVE_CURSE" + }, + { + "Level": "45", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_SURF" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_DRACO_METEOR", + "MOVE_ENDURE", + "MOVE_ICE_BEAM", + "MOVE_IRON_HEAD", + "MOVE_OUTRAGE", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_TOXIC" + ], + "TutorMoves": [ + "MOVE_IRON_DEFENSE" + ], + "EggMoves": [] + }, + "GOODRA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "1", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_CHARM" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "18", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "25", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "35", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "41", + "Move": "MOVE_CURSE" + }, + { + "Level": "45", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_SURF" + }, + { + "Level": "58", + "Move": "MOVE_POWER_WHIP" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BULLDOZE", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_KNOCK_OFF", + "MOVE_OUTRAGE", + "MOVE_ROCK_SLIDE", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_TOXIC" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GOODRA_HISUI": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_ACID_ARMOR" + }, + { + "Level": "1", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "5", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "8", + "Move": "MOVE_CHARM" + }, + { + "Level": "10", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "18", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "25", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "35", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "41", + "Move": "MOVE_CURSE" + }, + { + "Level": "44", + "Move": "MOVE_IRON_TAIL" + }, + { + "Level": "45", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "55", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "56", + "Move": "MOVE_SURF" + }, + { + "Level": "58", + "Move": "MOVE_SLUDGE_WAVE" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_BULLDOZE", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_PUNCH", + "MOVE_FLAMETHROWER", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_IRON_HEAD", + "MOVE_KNOCK_OFF", + "MOVE_OUTRAGE", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SLUDGE_BOMB", + "MOVE_SUBSTITUTE", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_TOXIC" + ], + "TutorMoves": [ + "MOVE_BREAKING_SWIPE" + ], + "EggMoves": [] + }, + "KLEFKI": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "8", + "Move": "MOVE_FAIRY_WIND" + }, + { + "Level": "13", + "Move": "MOVE_METAL_CLAW" + }, + { + "Level": "20", + "Move": "MOVE_METAL_SOUND" + }, + { + "Level": "24", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "36", + "Move": "MOVE_FLASH_CANNON" + }, + { + "Level": "40", + "Move": "MOVE_PLAY_ROUGH" + }, + { + "Level": "44", + "Move": "MOVE_DAZZLING_GLEAM" + }, + { + "Level": "52", + "Move": "MOVE_HEAL_BLOCK" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DOUBLE_TEAM", + "MOVE_ENDURE", + "MOVE_FUTURE_SIGHT", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER_WAVE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PHANTUMP": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "8", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "12", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "16", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "24", + "Move": "MOVE_GROWTH" + }, + { + "Level": "28", + "Move": "MOVE_HORN_LEECH" + }, + { + "Level": "32", + "Move": "MOVE_FORESTS_CURSE" + }, + { + "Level": "36", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "44", + "Move": "MOVE_WOOD_HAMMER" + }, + { + "Level": "50", + "Move": "MOVE_CURSE" + } + ], + "TMMoves": [ + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_GIGA_DRAIN", + "MOVE_HEAL_BLOCK", + "MOVE_MAGICAL_LEAF", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "TREVENANT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "8", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "12", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "16", + "Move": "MOVE_WILL_O_WISP" + }, + { + "Level": "24", + "Move": "MOVE_GROWTH" + }, + { + "Level": "28", + "Move": "MOVE_HORN_LEECH" + }, + { + "Level": "30", + "Move": "MOVE_SHADOW_CLAW" + }, + { + "Level": "32", + "Move": "MOVE_FORESTS_CURSE" + }, + { + "Level": "36", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "44", + "Move": "MOVE_WOOD_HAMMER" + }, + { + "Level": "50", + "Move": "MOVE_CURSE" + } + ], + "TMMoves": [ + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_MAGICAL_LEAF", + "MOVE_POISON_JAB", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_SAFEGUARD", + "MOVE_SHADOW_BALL", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_X_SCISSOR" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "PUMPKABOO": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TRICK_OR_TREAT" + }, + { + "Level": "4", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "16", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "20", + "Move": "MOVE_BULLET_SEED" + }, + { + "Level": "24", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "27", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "36", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "40", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "46", + "Move": "MOVE_POWER_WHIP" + } + ], + "TMMoves": [ + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_DRAIN", + "MOVE_LIGHT_SCREEN", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_ROCK_SLIDE", + "MOVE_SAFEGUARD", + "MOVE_SELF_DESTRUCT", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "GOURGEIST": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_TRICK_OR_TREAT" + }, + { + "Level": "1", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "4", + "Move": "MOVE_SHADOW_SNEAK" + }, + { + "Level": "8", + "Move": "MOVE_CONFUSE_RAY" + }, + { + "Level": "12", + "Move": "MOVE_RAZOR_LEAF" + }, + { + "Level": "16", + "Move": "MOVE_LEECH_SEED" + }, + { + "Level": "20", + "Move": "MOVE_BULLET_SEED" + }, + { + "Level": "24", + "Move": "MOVE_BRUTAL_SWING" + }, + { + "Level": "27", + "Move": "MOVE_HYPNOSIS" + }, + { + "Level": "36", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "40", + "Move": "MOVE_MYSTICAL_FIRE" + }, + { + "Level": "44", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "46", + "Move": "MOVE_POWER_WHIP" + }, + { + "Level": "52", + "Move": "MOVE_EXPLOSION" + } + ], + "TMMoves": [ + "MOVE_CURSE", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_SPIN", + "MOVE_FLAMETHROWER", + "MOVE_GIGA_DRAIN", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_LIGHT_SCREEN", + "MOVE_NASTY_PLOT", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_ROCK_SLIDE", + "MOVE_SAFEGUARD", + "MOVE_SELF_DESTRUCT", + "MOVE_SHADOW_CLAW", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "BERGMITE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "3", + "Move": "MOVE_TACKLE" + }, + { + "Level": "9", + "Move": "MOVE_CURSE" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "21", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_ICE_FANG" + }, + { + "Level": "27", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "30", + "Move": "MOVE_RECOVER" + }, + { + "Level": "33", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "42", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "54", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_ENDURE", + "MOVE_ICE_BEAM", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AVALUGG": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "1", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "3", + "Move": "MOVE_TACKLE" + }, + { + "Level": "9", + "Move": "MOVE_CURSE" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "21", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_ICE_FANG" + }, + { + "Level": "27", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "30", + "Move": "MOVE_RECOVER" + }, + { + "Level": "33", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "39", + "Move": "MOVE_ICICLE_CRASH" + }, + { + "Level": "42", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "54", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SURF" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "AVALUGG_HISUI": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "1", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "3", + "Move": "MOVE_TACKLE" + }, + { + "Level": "9", + "Move": "MOVE_CURSE" + }, + { + "Level": "12", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "15", + "Move": "MOVE_PROTECT" + }, + { + "Level": "21", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_ICE_FANG" + }, + { + "Level": "27", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "30", + "Move": "MOVE_RECOVER" + }, + { + "Level": "33", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "36", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "39", + "Move": "MOVE_ROCK_BLAST" + }, + { + "Level": "42", + "Move": "MOVE_DOUBLE_EDGE" + }, + { + "Level": "46", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "48", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "54", + "Move": "MOVE_BLIZZARD" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BULLDOZE", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_STEALTH_ROCK", + "MOVE_SUBSTITUTE", + "MOVE_SURF" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "NOIBAT": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "4", + "Move": "MOVE_GUST" + }, + { + "Level": "8", + "Move": "MOVE_SUPERSONIC" + }, + { + "Level": "12", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "16", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "20", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "28", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "32", + "Move": "MOVE_SUPER_FANG" + }, + { + "Level": "36", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_SCREECH" + }, + { + "Level": "44", + "Move": "MOVE_HURRICANE" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BRICK_BREAK", + "MOVE_DARK_PULSE", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_CLAW", + "MOVE_DRAGON_PULSE", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_VOICE", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_U_TURN", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "NOIVERN": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ABSORB" + }, + { + "Level": "1", + "Move": "MOVE_MOONLIGHT" + }, + { + "Level": "4", + "Move": "MOVE_GUST" + }, + { + "Level": "8", + "Move": "MOVE_SUPERSONIC" + }, + { + "Level": "12", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "16", + "Move": "MOVE_WING_ATTACK" + }, + { + "Level": "20", + "Move": "MOVE_BITE" + }, + { + "Level": "24", + "Move": "MOVE_LEECH_LIFE" + }, + { + "Level": "28", + "Move": "MOVE_WHIRLWIND" + }, + { + "Level": "32", + "Move": "MOVE_SUPER_FANG" + }, + { + "Level": "36", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_SCREECH" + }, + { + "Level": "44", + "Move": "MOVE_HURRICANE" + }, + { + "Level": "52", + "Move": "MOVE_BOOMBURST" + } + ], + "TMMoves": [ + "MOVE_AERIAL_ACE", + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DARK_PULSE", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_CLAW", + "MOVE_ENDURE", + "MOVE_FLAMETHROWER", + "MOVE_FLY", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_TAIL", + "MOVE_OUTRAGE", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAUNT", + "MOVE_U_TURN", + "MOVE_WATER_PULSE", + "MOVE_WILD_CHARGE" + ], + "TutorMoves": [ + "MOVE_DRAGON_PULSE" + ], + "EggMoves": [] + }, + "XERNEAS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "5", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "20", + "Move": "MOVE_NIGHT_SLASH" + }, + { + "Level": "35", + "Move": "MOVE_HORN_LEECH" + }, + { + "Level": "50", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "55", + "Move": "MOVE_GEOMANCY" + }, + { + "Level": "60", + "Move": "MOVE_MOONBLAST" + }, + { + "Level": "70", + "Move": "MOVE_MEGAHORN" + }, + { + "Level": "75", + "Move": "MOVE_CLOSE_COMBAT" + }, + { + "Level": "80", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "85", + "Move": "MOVE_GIGA_IMPACT" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_FOCUS_BLAST", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_SLIDE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "YVELTAL": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_GUST" + }, + { + "Level": "1", + "Move": "MOVE_DOUBLE_TEAM" + }, + { + "Level": "5", + "Move": "MOVE_TAUNT" + }, + { + "Level": "10", + "Move": "MOVE_SNARL" + }, + { + "Level": "35", + "Move": "MOVE_AIR_SLASH" + }, + { + "Level": "40", + "Move": "MOVE_DARK_PULSE" + }, + { + "Level": "45", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "55", + "Move": "MOVE_OBLIVION_WING" + }, + { + "Level": "60", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "65", + "Move": "MOVE_DRAGON_RUSH" + }, + { + "Level": "70", + "Move": "MOVE_HURRICANE" + }, + { + "Level": "75", + "Move": "MOVE_FOCUS_BLAST" + }, + { + "Level": "85", + "Move": "MOVE_HYPER_BEAM" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_DRAGON_CLAW", + "MOVE_ENDURE", + "MOVE_FLY", + "MOVE_GIGA_IMPACT", + "MOVE_HEAL_BLOCK", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_VOICE", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_U_TURN", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "ZYGARDE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_BITE" + }, + { + "Level": "1", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "1", + "Move": "MOVE_BULLDOZE" + }, + { + "Level": "1", + "Move": "MOVE_THOUSAND_ARROWS" + }, + { + "Level": "1", + "Move": "MOVE_THOUSAND_WAVES" + }, + { + "Level": "1", + "Move": "MOVE_LANDS_WRATH" + }, + { + "Level": "1", + "Move": "MOVE_CORE_ENFORCER" + }, + { + "Level": "8", + "Move": "MOVE_HAZE" + }, + { + "Level": "16", + "Move": "MOVE_DIG" + }, + { + "Level": "24", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "32", + "Move": "MOVE_CRUNCH" + }, + { + "Level": "40", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "44", + "Move": "MOVE_BREAKING_SWIPE" + }, + { + "Level": "56", + "Move": "MOVE_GLARE" + }, + { + "Level": "60", + "Move": "MOVE_SLUDGE_WAVE" + }, + { + "Level": "70", + "Move": "MOVE_EXTREME_SPEED" + }, + { + "Level": "80", + "Move": "MOVE_EARTHQUAKE" + }, + { + "Level": "88", + "Move": "MOVE_OUTRAGE" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DRACO_METEOR", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_HYPER_VOICE", + "MOVE_IRON_HEAD", + "MOVE_PROTECT", + "MOVE_ROCK_SLIDE", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DIANCIE": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_ROCK_THROW" + }, + { + "Level": "1", + "Move": "MOVE_HARDEN" + }, + { + "Level": "1", + "Move": "MOVE_DIAMOND_STORM" + }, + { + "Level": "7", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "14", + "Move": "MOVE_FAKE_TEARS" + }, + { + "Level": "21", + "Move": "MOVE_DRAINING_KISS" + }, + { + "Level": "33", + "Move": "MOVE_ROCK_SLIDE" + }, + { + "Level": "42", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "44", + "Move": "MOVE_POWER_GEM" + }, + { + "Level": "46", + "Move": "MOVE_STEALTH_ROCK" + }, + { + "Level": "50", + "Move": "MOVE_STONE_EDGE" + }, + { + "Level": "54", + "Move": "MOVE_MOONBLAST" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_CALM_MIND", + "MOVE_DAZZLING_GLEAM", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FLASH_CANNON", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_IRON_DEFENSE", + "MOVE_METRONOME", + "MOVE_PLAY_ROUGH", + "MOVE_PROTECT", + "MOVE_PSYCHIC", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_TOMB", + "MOVE_SAFEGUARD", + "MOVE_SPIKES", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HOOPA_CONFINED": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "15", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "19", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "22", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "35", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "38", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "42", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "45", + "Move": "MOVE_NASTY_PLOT" + }, + { + "Level": "52", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "60", + "Move": "MOVE_HYPERSPACE_HOLE" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_FUTURE_SIGHT", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "HOOPA_UNBOUND": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_CONFUSION" + }, + { + "Level": "15", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "19", + "Move": "MOVE_PSYBEAM" + }, + { + "Level": "22", + "Move": "MOVE_KNOCK_OFF" + }, + { + "Level": "35", + "Move": "MOVE_PHANTOM_FORCE" + }, + { + "Level": "38", + "Move": "MOVE_ZEN_HEADBUTT" + }, + { + "Level": "42", + "Move": "MOVE_SHADOW_BALL" + }, + { + "Level": "45", + "Move": "MOVE_NASTY_PLOT" + }, + { + "Level": "52", + "Move": "MOVE_PSYCHIC" + }, + { + "Level": "60", + "Move": "MOVE_HYPERSPACE_FURY" + } + ], + "TMMoves": [ + "MOVE_BRICK_BREAK", + "MOVE_CALM_MIND", + "MOVE_DARK_PULSE", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_PUNCH", + "MOVE_FOCUS_BLAST", + "MOVE_FUTURE_SIGHT", + "MOVE_GIGA_IMPACT", + "MOVE_GUNK_SHOT", + "MOVE_HEAL_BLOCK", + "MOVE_HYPER_BEAM", + "MOVE_ICE_PUNCH", + "MOVE_PROTECT", + "MOVE_PSYSHOCK", + "MOVE_REFLECT", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SWIFT", + "MOVE_TAKE_DOWN", + "MOVE_TAUNT", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_PUNCH", + "MOVE_THUNDER_WAVE" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "VOLCANION": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_WATER_GUN" + }, + { + "Level": "1", + "Move": "MOVE_FIRE_SPIN" + }, + { + "Level": "1", + "Move": "MOVE_STEAM_ERUPTION" + }, + { + "Level": "6", + "Move": "MOVE_LEER" + }, + { + "Level": "18", + "Move": "MOVE_MUD_SHOT" + }, + { + "Level": "24", + "Move": "MOVE_WATER_PULSE" + }, + { + "Level": "30", + "Move": "MOVE_HEAT_CRASH" + }, + { + "Level": "33", + "Move": "MOVE_TAKE_DOWN" + }, + { + "Level": "40", + "Move": "MOVE_MIST" + }, + { + "Level": "40", + "Move": "MOVE_HAZE" + }, + { + "Level": "42", + "Move": "MOVE_HEAVY_SLAM" + }, + { + "Level": "46", + "Move": "MOVE_HYDRO_PUMP" + }, + { + "Level": "50", + "Move": "MOVE_FLARE_BLITZ" + }, + { + "Level": "54", + "Move": "MOVE_OVERHEAT" + }, + { + "Level": "60", + "Move": "MOVE_EXPLOSION" + } + ], + "TMMoves": [ + "MOVE_BODY_SLAM", + "MOVE_BRICK_BREAK", + "MOVE_DIG", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_FIRE_BLAST", + "MOVE_FIRE_FANG", + "MOVE_FLAMETHROWER", + "MOVE_FLASH_CANNON", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HYPER_BEAM", + "MOVE_LIQUIDATION", + "MOVE_PROTECT", + "MOVE_ROAR", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SELF_DESTRUCT", + "MOVE_SLUDGE_BOMB", + "MOVE_SOLAR_BEAM", + "MOVE_STONE_EDGE", + "MOVE_SUBSTITUTE", + "MOVE_TAUNT", + "MOVE_THUNDER_FANG", + "MOVE_WILD_CHARGE", + "MOVE_WILL_O_WISP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "DRAMPA": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_LEER" + }, + { + "Level": "1", + "Move": "MOVE_TWISTER" + }, + { + "Level": "5", + "Move": "MOVE_PROTECT" + }, + { + "Level": "10", + "Move": "MOVE_GLARE" + }, + { + "Level": "15", + "Move": "MOVE_SAFEGUARD" + }, + { + "Level": "20", + "Move": "MOVE_DRAGON_BREATH" + }, + { + "Level": "25", + "Move": "MOVE_ICY_WIND" + }, + { + "Level": "28", + "Move": "MOVE_BODY_SLAM" + }, + { + "Level": "32", + "Move": "MOVE_AMNESIA" + }, + { + "Level": "35", + "Move": "MOVE_DRAGON_PULSE" + }, + { + "Level": "40", + "Move": "MOVE_LIGHT_SCREEN" + }, + { + "Level": "44", + "Move": "MOVE_FLY" + }, + { + "Level": "50", + "Move": "MOVE_HYPER_VOICE" + }, + { + "Level": "54", + "Move": "MOVE_OUTRAGE" + }, + { + "Level": "56", + "Move": "MOVE_DRAGON_RUSH" + } + ], + "TMMoves": [ + "MOVE_BLIZZARD", + "MOVE_CALM_MIND", + "MOVE_DRACO_METEOR", + "MOVE_DRAGON_CLAW", + "MOVE_EARTHQUAKE", + "MOVE_EARTH_POWER", + "MOVE_ENDURE", + "MOVE_ENERGY_BALL", + "MOVE_FIRE_BLAST", + "MOVE_FLAMETHROWER", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HEAT_WAVE", + "MOVE_HURRICANE", + "MOVE_HYDRO_PUMP", + "MOVE_HYPER_BEAM", + "MOVE_ICE_BEAM", + "MOVE_PLAY_ROUGH", + "MOVE_ROCK_SLIDE", + "MOVE_SHADOW_BALL", + "MOVE_SHADOW_CLAW", + "MOVE_SOLAR_BEAM", + "MOVE_SUBSTITUTE", + "MOVE_SURF", + "MOVE_SWIFT", + "MOVE_THUNDER", + "MOVE_THUNDERBOLT", + "MOVE_THUNDER_WAVE", + "MOVE_WHIRLWIND", + "MOVE_WORK_UP" + ], + "TutorMoves": [], + "EggMoves": [] + }, + "FALINKS": { + "LevelMoves": [ + { + "Level": "1", + "Move": "MOVE_TACKLE" + }, + { + "Level": "1", + "Move": "MOVE_PROTECT" + }, + { + "Level": "5", + "Move": "MOVE_ROCK_SMASH" + }, + { + "Level": "10", + "Move": "MOVE_FOCUS_ENERGY" + }, + { + "Level": "15", + "Move": "MOVE_HEADBUTT" + }, + { + "Level": "20", + "Move": "MOVE_BULK_UP" + }, + { + "Level": "25", + "Move": "MOVE_ENDURE" + }, + { + "Level": "32", + "Move": "MOVE_IRON_HEAD" + }, + { + "Level": "36", + "Move": "MOVE_BRICK_BREAK" + }, + { + "Level": "40", + "Move": "MOVE_NO_RETREAT" + }, + { + "Level": "43", + "Move": "MOVE_IRON_DEFENSE" + }, + { + "Level": "48", + "Move": "MOVE_CLOSE_COMBAT" + }, + { + "Level": "52", + "Move": "MOVE_MEGAHORN" + } + ], + "TMMoves": [ + "MOVE_AGILITY", + "MOVE_BODY_SLAM", + "MOVE_FOCUS_BLAST", + "MOVE_GIGA_IMPACT", + "MOVE_HYPER_BEAM", + "MOVE_KNOCK_OFF", + "MOVE_POISON_JAB", + "MOVE_ROCK_SLIDE", + "MOVE_ROCK_TOMB", + "MOVE_SUBSTITUTE", + "MOVE_SWORDS_DANCE", + "MOVE_ZEN_HEADBUTT" + ], + "TutorMoves": [], + "EggMoves": [] + } +} \ No newline at end of file diff --git a/tools/wild_encounters/wild_encounters_to_header.py b/tools/wild_encounters/wild_encounters_to_header.py index 375dda3ecf..2fca4623e7 100644 --- a/tools/wild_encounters/wild_encounters_to_header.py +++ b/tools/wild_encounters/wild_encounters_to_header.py @@ -1,720 +1,277 @@ import json import re -import os - -IS_ENABLED = False -DEXNAV_ENABLED = False - -# C string vars -define = "#define" -ENCOUNTER_CHANCE = "ENCOUNTER_CHANCE" -SLOT = "SLOT" -TOTAL = "TOTAL" -NULL = "NULL" -UNDEFINED = "UNDEFINED" -MAP_UNDEFINED = "MAP_UNDEFINED" - -# encounter group header types, filled out programmatically -MON_HEADERS = [] - -# mon encounter group types -fieldData = [] -fieldInfoStrings = [] -fieldStrings = [] - -# time of day encounter data -TIME_DEFAULT = "" -TIME_DEFAULT_LABEL = "TIME_OF_DAY_DEFAULT" -TIME_DEFAULT_INDEX = 0 -TIMES_OF_DAY_COUNT = TIME_DEFAULT_INDEX + 1 - -# struct building blocks -baseStruct = "const struct WildPokemon" -structLabel = "" -structMonType = "" -structTime = "" -structMap = "" - -structInfo = "Info" -structHeader = "Header" -structArrayAssign = "[] =" - -baseStructLabel = "" -baseStructContent = [] -infoStructString = "" -infoStructRate = 0 -infoStructContent = [] -headerStructLabel = "" -headerStructContent = {} -headerStructTable = {} -headerIndex = 0 - -# map header data variables -hLabel = "" -hForMaps = True -headersArray = [headerIndex] - -# debug output control -mainSwitch = True -printWarningAndInclude = mainSwitch -printEncounterHeaders = mainSwitch -printEncounterRateMacros = mainSwitch -printEncounterStructsInfoString = mainSwitch -printEncounterStructs = mainSwitch - - -class TimeOfDay(): - def __init__(self): - self.vals = [] - self.lvals = [] - self.fvals = [] - self.count = 0 - - def __len__(self): - return self.count - - # for debugging purposes - def __str__(self): - return str([self.vals, self.lvals, self.fvals, self.count]) - - def add(self, val): - self.vals.append(val) - self.lvals.append(val.lower()) - self.fvals.append(GetTimeLabelFromString(val).capitalize()) - self.count += 1 - - def indexOf(self, val): - tempArr = [self.vals, self.lvals, self.fvals] - - for tvals in tempArr: - i = 0 - for time in tvals: - if val in time: - return i - - i += 1 - # return -1 here so it returns a consistent type and can be checked against < 0 - return -1 - - -def ImportWildEncounterFile(): - # make sure we're in the right directory before anything else - if not os.path.exists("Makefile"): - print("Please run this script from the project's root folder.") - quit() - - global MON_HEADERS - - global TIME_OF_DAY - TIME_OF_DAY = SetupUserTimeEnum(TimeOfDay()) - - global IS_ENABLED - global TIMES_OF_DAY_COUNT - if IsConfigEnabled(): - IS_ENABLED = True - TIMES_OF_DAY_COUNT = len(TIME_OF_DAY) - - global DEXNAV_ENABLED - DEXNAV_ENABLED = IsDexnavEnabled() - - global fieldInfoStrings - global fieldStrings - global structLabel - global structMonType - global structTime - global structMap - global baseStructLabel - global baseStructContent - global infoStructString - global infoStructRate - global headerStructLabel - global headerStructContent - global hLabel - global headersArray - global encounterTotalCount - global encounterCount - global headerIndex - global fieldData - global tabStr - tabStr = " " - - wFile = open("src/data/wild_encounters.json") - wData = json.load(wFile) - - encounterTotalCount = [] - encounterCount = [] - groupCount = 0 - while groupCount < len(wData["wild_encounter_groups"]): - encounterTotalCount.append(0) - encounterCount.append(0) - groupCount += 1 - - for data in wData["wild_encounter_groups"]: - wEncounters = wData["wild_encounter_groups"][headerIndex]["encounters"] - headerSuffix = structHeader + "s" - - if data["label"]: - hLabel = wData["wild_encounter_groups"][headerIndex]["label"] - if headerSuffix in hLabel: - hLabel = hLabel[:len(hLabel) - len(headerSuffix)] - MON_HEADERS.append(hLabel) - - if data["for_maps"]: - hForMaps = wData["wild_encounter_groups"][headerIndex]["for_maps"] - - if headerIndex == 0: - wFields = wData["wild_encounter_groups"][headerIndex]["fields"] - fieldCounter = 0 - for field in wFields: - if not CheckFieldDataDupes(field["type"]): - AddFieldData(fieldCounter, field["type"], field["encounter_rates"]) - - if "groups" in field: - fieldData[fieldCounter]["groups"] = field["groups"] - - """ - hidden mons need a special bit of logic since they're not in the vanilla - wild_encounters.json file, but the code expects them to be there - """ - hidden_mons = "hidden_mons" - if (fieldCounter == len(wFields) - 1) and not CheckFieldDataDupes(hidden_mons): - hidden_dummy_rates = [1, 0] - AddFieldData(fieldCounter + 1, hidden_mons, hidden_dummy_rates) - - fieldCounter += 1 - - if printWarningAndInclude: - PrintGeneratedWarningText() - print('#include "rtc.h"') - print("\n") - - PrintEncounterRateMacros() - - for encounter in wEncounters: - if "map" in encounter: - structMap = encounter["map"] - else: - structMap = encounter["base_label"] - - structLabel = encounter["base_label"] - - if encounterTotalCount[headerIndex] != len(wEncounters): - encounterTotalCount[headerIndex] = len(wEncounters) - - encounterCount[headerIndex] += 1 - headersArray = [] - - structTime = TIME_DEFAULT_INDEX - if IS_ENABLED: - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - tempfTime = f"_{TIME_OF_DAY.fvals[timeCounter]}" - tempTime = TIME_OF_DAY.vals[timeCounter] - if tempfTime in structLabel or tempTime in structLabel: - structTime = timeCounter - - timeCounter += 1 - - fieldCounter = 0 - fieldInfoStrings = [] - while fieldCounter < len(fieldData): - fieldInfoStrings.append("") - fieldStrings.append("") - fieldCounter += 1 - - fieldCounter = 0 - while fieldCounter < len(fieldData): - for areaTable in encounter: - if fieldData[fieldCounter]["name"] in areaTable: - structMonType = fieldData[fieldCounter]["pascalName"] - if f"_{TIME_OF_DAY.fvals[structTime]}" in structLabel: - fieldInfoStrings[fieldCounter] = f"{structLabel}_{structMonType}{structInfo}" - fieldStrings[fieldCounter] = f"{structLabel}_{structMonType}" - else: - fieldInfoStrings[fieldCounter] = f"{structLabel}_{TIME_OF_DAY.fvals[structTime]}_{structMonType}{structInfo}" - fieldStrings[fieldCounter] = f"{structLabel}_{TIME_OF_DAY.fvals[structTime]}_{structMonType}" - else: - structMonType = "" - continue - - baseStructContent = [] - for group in encounter[areaTable]: - if "mons" in group: - for mon in encounter[areaTable][group]: - baseStructContent.append(list(mon.values())) - - if "encounter_rate" in group: - infoStructRate = encounter[areaTable][group] - - baseStructLabel = f"{baseStruct} {fieldStrings[fieldCounter]}{structArrayAssign}" - if printEncounterStructs: - print() - print(baseStructLabel) - print("{") - PrintStructContent(baseStructContent) - print("};") - - if printEncounterStructsInfoString: - infoStructString = f"{baseStruct}{structInfo} {fieldInfoStrings[fieldCounter]} = {{ {infoStructRate}, {fieldStrings[fieldCounter]} }};" - print(infoStructString) - - fieldCounter += 1 - AssembleMonHeaderContent() - headerIndex += 1 - PrintWildMonHeadersContent() - - -def PrintStructContent(contentList): - for monList in contentList: - print(f"{tabStr}{{ {monList[0]}, {monList[1]}, {monList[2]} }},") - return - - -def GetStructLabelWithoutTime(label): - labelLength = len(label) - timeLength = 0 - - if not IS_ENABLED: - return label - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - tempTime = TIME_OF_DAY.fvals[timeCounter] - if tempTime in label: - timeLength = len(tempTime) - return label[:(labelLength - (timeLength + 1))] - - timeCounter += 1 - return label - - -def GetStructTimeWithoutLabel(label): - if not IS_ENABLED: - return TIME_DEFAULT_INDEX - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - tempTime = f"_{TIME_OF_DAY.fvals[timeCounter]}" - if tempTime in label: - return timeCounter - - timeCounter += 1 - return TIME_DEFAULT_INDEX - - -def AssembleMonHeaderContent(): - SetupMonInfoVars() - - tempHeaderLabel = GetWildMonHeadersLabel() - tempHeaderTimeIndex = GetStructTimeWithoutLabel(structLabel) - structLabelNoTime = GetStructLabelWithoutTime(structLabel) - - if tempHeaderLabel not in headerStructTable: - headerStructTable[tempHeaderLabel] = {} - headerStructTable[tempHeaderLabel]["groupNum"] = headerIndex - - if structLabelNoTime not in headerStructTable[tempHeaderLabel]: - headerStructTable[tempHeaderLabel][structLabelNoTime] = {} - headerStructTable[tempHeaderLabel][structLabelNoTime]["headerType"] = GetWildMonHeadersLabel() - headerStructTable[tempHeaderLabel][structLabelNoTime]["mapGroup"] = structMap - headerStructTable[tempHeaderLabel][structLabelNoTime]["mapNum"] = structMap - headerStructTable[tempHeaderLabel][structLabelNoTime]["encounterTotalCount"] = encounterTotalCount[headerIndex] - headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"] = [] - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"].append([]) - timeCounter += 1 - - fieldCounter = 0 - while fieldCounter < len(fieldData): - headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(fieldInfoStrings[fieldCounter]) - fieldCounter += 1 - - -def SetupMonInfoVars(): - i = 0 - while i < len(fieldData): - fieldData[i]["infoStringBase"] = "." + fieldData[i]["snakeName"] + structInfo - if CheckEmpty(fieldInfoStrings[i]): - fieldInfoStrings[i] = NULL - else: - fieldInfoStrings[i] = "&" + fieldInfoStrings[i] - - i += 1 - - -def PrintWildMonHeadersContent(): - groupCount = 0 - for group in headerStructTable: - labelCount = 0 - for label in headerStructTable[group]: - if label != "groupNum": - if labelCount == 0: - PrintEncounterHeaders("\n") - PrintEncounterHeaders(headerStructTable[group][label]["headerType"]) - - PrintEncounterHeaders(tabStr + "{") - - for stat in headerStructTable[group][label]: - mapData = headerStructTable[group][label][stat] - - if stat == "mapGroup": - PrintEncounterHeaders(f"{TabStr(2)}.mapGroup = {GetMapGroupEnum(mapData)},") - elif stat == "mapNum": - PrintEncounterHeaders(f"{TabStr(2)}.mapNum = {GetMapGroupEnum(mapData, labelCount + 1)},") - - if type(headerStructTable[group][label][stat]) == list: - PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =") - PrintEncounterHeaders(TabStr(2) + "{") - - timeCounter = 0 - while timeCounter < TIMES_OF_DAY_COUNT: - monInfo = headerStructTable[group][label][stat][timeCounter] - PrintEncounterHeaders(f"{TabStr(3)}[{TIME_OF_DAY.vals[timeCounter]}] = ") - - infoIndex = 0 - while infoIndex < len(fieldData): - if infoIndex == 0: - PrintEncounterHeaders(TabStr(3) + "{") - - if len(monInfo) == 0: - PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(infoIndex)} = NULL,") - else: - PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(infoIndex)} = {monInfo[infoIndex]},") - - if infoIndex == len(fieldData) - 1: - PrintEncounterHeaders(TabStr(3) + "},") - - infoIndex += 1 - timeCounter += 1 - PrintEncounterHeaders(TabStr(2) + "},") - PrintEncounterHeaders(tabStr + "},") - labelCount += 1 - PrintEncounterHeaders(tabStr + "{") - PrintEncounterHeaders(f"{TabStr(2)}.mapGroup = {GetMapGroupEnum(MAP_UNDEFINED)},") - PrintEncounterHeaders(f"{TabStr(2)}.mapNum = {GetMapGroupEnum(MAP_UNDEFINED, labelCount + 1)},") - - nullCount = 0 - while nullCount < TIMES_OF_DAY_COUNT: - if nullCount == 0: - PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =") - PrintEncounterHeaders(TabStr(2)+ "{") - - PrintEncounterHeaders(f"{TabStr(3)}[{TIME_OF_DAY.vals[nullCount]}] = ") - - nullIndex = 0 - while nullIndex <= len(fieldData) - 1: - if nullIndex == 0: - PrintEncounterHeaders(TabStr(3) + "{") - - PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(nullIndex)} = NULL,") - - if nullIndex == len(fieldData) - 1: - PrintEncounterHeaders(TabStr(3) + "},") - - nullIndex += 1 - nullCount += 1 - PrintEncounterHeaders(TabStr(2) + "},") - PrintEncounterHeaders(tabStr + "},") - groupCount += 1 - PrintEncounterHeaders("};") - - -def GetWildMonHeadersLabel(): - return f"{baseStruct}{structHeader} {MON_HEADERS[headerIndex]}{structHeader}s{structArrayAssign}" + "\n{" - - -def PrintEncounterHeaders(content): - if printEncounterHeaders: - print(content) - - -def PrintEncounterRateMacros(): - if not printEncounterRateMacros: - return - - fieldCounter = 0 - while fieldCounter < len(fieldData): - tempName = fieldData[fieldCounter]["name"].upper() - if "groups" not in fieldData[fieldCounter]: - rateCount = 0 - if fieldData[fieldCounter]["encounter_rates"]: - for percent in fieldData[fieldCounter]["encounter_rates"]: - if not DEXNAV_ENABLED and tempName == "HIDDEN_MONS": - break - - if rateCount == 0: - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount} {percent}") - else: - print( - f"{define} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount - 1} + {percent}" - ) - - if rateCount + 1 == len(fieldData[fieldCounter]["encounter_rates"]): - print( - f"{define} {ENCOUNTER_CHANCE}_{tempName}_{TOTAL} ({ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount})" - ) - - rateCount += 1 - else: - rates = fieldData[fieldCounter]["encounter_rates"] - groups = fieldData[fieldCounter]["groups"] - - for method in groups: - method_indices = groups[method] - if not method_indices: +class Config: + def __init__(self, config_file_name, rtc_constants_file_name, encounters_json_data): + self.times_of_day = None + self.mon_types = None + self.time_encounters = None + self.disable_time_fallback = None + self.time_fallback = None + + self.ParseTimeEnum(rtc_constants_file_name) + if self.times_of_day == None: + raise Exception(f"Failed to parse 'enum TimeOfDay' in '{rtc_constants_file_name}'") + + self.ParseMonTypes(encounters_json_data) + if self.mon_types == None: + raise Exception("No fields defined in 'wild_encounters.json'") + + with open(config_file_name, 'r') as config_file: + lines = config_file.readlines() + for line in lines: + self.ParseTimeConfig(line) + + if self.time_encounters == None: + raise Exception("OW_TIME_OF_DAY_ENCOUNTERS not defined.") + if self.disable_time_fallback == None: + raise Exception("OW_TIME_OF_DAY_DISABLE_FALLBACK not defined.") + if self.time_fallback == None: + raise Exception("OW_TIME_OF_DAY_FALLBACK not defined.") + + def ParseTimeEnum(self, rtc_constants_file_name): + with open(rtc_constants_file_name, 'r') as rtc_constants_file: + DEFAULT_TIME_PAT = re.compile(r"enum\s+TimeOfDay\s*\{(?P[\s*\w+,\=\d*]+)\s*\}\s*\;") + file = rtc_constants_file.read() + + m = DEFAULT_TIME_PAT.search(file) + if m: + txt = m.group('rtc_val') + values = re.findall(r'TIME_\w+', txt) + self.times_of_day = {} + for value in values: + self.times_of_day[value] = value.title().replace("Time_", "").replace("_", "") + + def ParseMonTypes(self, encounters_json_data): + for group in encounters_json_data["wild_encounter_groups"]: + if "fields" in group: + for field in group["fields"]: + field_type = field["type"] + if not self.mon_types: + self.mon_types = [] + self.mon_types.append(field_type) + + def ParseTimeConfig(self, line): + m = re.search(r'#define OW_TIME_OF_DAY_ENCOUNTERS\s+(\w+)', line) + if m: + self.time_encounters = m.group(1) == "TRUE" + + m = re.search(r'#define OW_TIME_OF_DAY_DISABLE_FALLBACK\s+(\w+)', line) + if m: + self.disable_time_fallback = m.group(1) == "TRUE" + + m = re.search(r'#define OW_TIME_OF_DAY_FALLBACK\s+(\w+)', line) + if m: + self.time_fallback = m.group(1) + + +class WildEncounterAssembler: + def __init__(self, output_file, json_data, config): + self.output_file = output_file + self.json_data = json_data + self.config = config + + def WriteLine(self, line="", indents = 0): + self.output_file.write(4 * indents * " " + line + "\n") + + def WriteHeader(self): + self.WriteLine("//") + self.WriteLine("// DO NOT MODIFY THIS FILE! It is auto-generated by tools/wild_encounters/wild_encounters_to_header.py") + self.WriteLine("//") + self.output_file.write("\n\n") + + def WriteMacro(self, macro, value): + self.output_file.write("#define " + macro + " " + value + "\n") + + def WriteMacros(self): + wild_encounter_groups = self.json_data["wild_encounter_groups"] + for wild_encounter_group in wild_encounter_groups: + if "fields" in wild_encounter_group: + fields = wild_encounter_group["fields"] + for field in fields: + field_type = field["type"] + macro_base = "ENCOUNTER_CHANCE_" + field_type.upper() + previous_group = None + previous_macro = None + encounter_rates = field["encounter_rates"] + + group_name_mapping = len(encounter_rates) * [""] + if "groups" in field: + groups = field["groups"] + for group_name, indices in groups.items(): + for index in indices: + group_name_mapping[index] = "_" + group_name.upper() + + for idx, rate in enumerate(encounter_rates): + macro_name = macro_base + group_name_mapping[idx] + "_SLOT_" + str(idx) + macro_value = str(rate) + if previous_group == group_name_mapping[idx]: + macro_value = "(" + previous_macro + " + " + macro_value + ")" + elif idx > 0: + macro_total_name = macro_base + group_name_mapping[idx - 1] + "_TOTAL" + self.WriteMacro(macro_total_name, "(" + previous_macro + ")") + self.WriteMacro(macro_name, macro_value) + previous_group = group_name_mapping[idx] + previous_macro = macro_name + if idx == len(encounter_rates) - 1: + macro_total_name = macro_base + group_name_mapping[idx] + "_TOTAL" + self.WriteMacro(macro_total_name, "(" + previous_macro + ")") + macro_total_name = macro_base + group_name_mapping[-1] + "_TOTAL" + self.WriteLine() + + def WriteMonInfos(self, name, mons, encounter_rate): + info_name = name + "Info" + self.WriteLine(f"const struct WildPokemon {name}[] =") + self.WriteLine("{") + for mon in mons: + species = mon["species"] + min_level = 2 if "min_level" not in mon else mon["min_level"] + max_level = 100 if "max_level" not in mon else mon["max_level"] + self.WriteLine(f"{{ {min_level}, {max_level}, {species} }},", 1) + + self.WriteLine("};") + self.WriteLine() + self.WriteLine(f"const struct WildPokemonInfo {info_name} = {{ {encounter_rate}, {name} }};") + self.WriteLine() + + def WriteTerminator(self): + self.WriteLine("{", 1) + self.WriteLine(".mapGroup = MAP_GROUP(MAP_UNDEFINED),", 2) + self.WriteLine(".mapNum = MAP_NUM(MAP_UNDEFINED),", 2) + self.WriteLine(".encounterTypes =", 2) + self.WriteLine("{", 2) + for time in self.config.times_of_day: + if not self.config.time_encounters and time != self.config.time_fallback: + continue + self.WriteLine(f"[{time}] =", 3) + self.WriteLine("{", 3) + for mon_type in self.config.mon_types: + member_name = mon_type.title().replace("_", "") + member_name = member_name[0].lower() + member_name[1:] + "Info" + self.WriteLine(f".{member_name} = NULL,", 4) + self.WriteLine("},", 3) + self.WriteLine("},", 2) + self.WriteLine("},", 1) + + def WritePokemonHeaders(self, headers): + label = headers["label"] + self.WriteLine(f"const struct WildPokemonHeader {label}[] =") + self.WriteLine("{") + for shared_label in headers["data"]: + self.WriteLine() + map_data = headers["data"][shared_label] + encounter_data = map_data + map_group = map_data["mapGroup"] + map_num = map_data["mapNum"] + version = "EMERALD" + if "FireRed" in shared_label: + version = "FIRERED" + elif "LeafGreen" in shared_label: + version = "LEAFGREEN" + + self.WriteLine(f"#ifdef {version}") + + self.WriteLine("{", 1) + self.WriteLine(f".mapGroup = {map_group},", 2) + self.WriteLine(f".mapNum = {map_num},", 2) + self.WriteLine(".encounterTypes =", 2) + self.WriteLine("{", 2) + for time in self.config.times_of_day: + if not self.config.time_encounters and time != self.config.time_fallback: continue + self.WriteLine(f"[{time}] =", 3) + self.WriteLine("{", 3) + for mon_type in self.config.mon_types: + member_name = mon_type.title().replace("_", "") + member_name = member_name[0].lower() + member_name[1:] + "Info" + value = "NULL" + if time in encounter_data and mon_type in encounter_data[time]: + value = encounter_data[time][mon_type] + if value != "NULL": + value = "&" + value + self.WriteLine(f".{member_name} = {value},", 4) - for i, methodPercentIndex in enumerate(method_indices): - if methodPercentIndex < 0 or methodPercentIndex >= len(rates): - print(f"#error Invalid fishing encounter rate index {methodPercentIndex} for {method.upper()}") + self.WriteLine("},", 3) + + self.WriteLine("},", 2) + self.WriteLine("},", 1) + self.WriteLine(f"#endif") + self.WriteTerminator() + self.WriteLine("};") + + + def WriteEncounters(self): + wild_encounter_groups = self.json_data["wild_encounter_groups"] + for wild_encounter_group in wild_encounter_groups: + headers = {} + headers["label"] = wild_encounter_group["label"] + headers["data"] = {} + for_maps = False + map_num_counter = 1 + if "for_maps" in wild_encounter_group: + for_maps = wild_encounter_group["for_maps"] + encounters = wild_encounter_group["encounters"] + + for map_encounters in encounters: + map_group = "0" + map_num = str(map_num_counter) + if for_maps: + map_name = map_encounters["map"] + map_group = f"MAP_GROUP({map_name})" + map_num = f"MAP_NUM({map_name})" + map_num_counter += 1 + base_label = map_encounters["base_label"] + shared_label = base_label + time = self.config.time_fallback + + for time_ident in self.config.times_of_day: + if self.config.times_of_day[time_ident] in base_label: + time = time_ident + shared_label = shared_label.replace('_' + self.config.times_of_day[time_ident], '') + + if shared_label not in headers["data"]: + headers["data"][shared_label] = {} + if time not in headers["data"][shared_label]: + headers["data"][shared_label][time] = {} + headers["data"][shared_label]["mapGroup"] = map_group + headers["data"][shared_label]["mapNum"] = map_num + + version = "EMERALD" + if "FireRed" in shared_label: + version = "FIRERED" + elif "LeafGreen" in shared_label: + version = "LEAFGREEN" + self.WriteLine(f"#ifdef {version}") + for mon_type in self.config.mon_types: + if mon_type not in map_encounters: + headers["data"][shared_label][mon_type] = "NULL" continue - rate_value = rates[methodPercentIndex] - if i == 0: - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex} {rate_value}") - else: - previous_method_index = method_indices[i - 1] - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{previous_method_index} + {rate_value}") + mons_entry = map_encounters[mon_type] + encounter_rate = mons_entry["encounter_rate"] + mons = mons_entry["mons"] - if i == len(method_indices) - 1: - print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex})") + mon_array_name = base_label + "_" + mon_type.title().replace("_", "") + self.WriteMonInfos(mon_array_name, mons, encounter_rate) + headers["data"][shared_label][time][mon_type] = mon_array_name + "Info" + self.WriteLine(f"#endif") - fieldCounter += 1 - print() + self.WritePokemonHeaders(headers) -def GetTimeLabelFromString(string): - time = "TIME" - time_ = "TIME_" - - if string == "TIMES_OF_DAY_COUNT": - return string - - if time_ in string.upper(): - return string[len(time_):len(string)] - elif time in string.upper(): - return string[len(time):len(string)] - return string - - -def GetIMonInfoStringFromIndex(index): - return fieldData[index]["infoStringBase"] - - -def GetMapGroupEnum(string, index = 0): - if "MAP_" in string and index == 0: - return "MAP_GROUP(" + string + ")" - elif "MAP_" in string and index != 0: - return "MAP_NUM(" + string + ")" - return index - - -""" -get copied lhea :^ ) -- next four functions copied almost verbatim from @lhearachel's python scripts in tools/learnset_helpers -""" -def PrintGeneratedWarningText(): - print("//") - print("// DO NOT MODIFY THIS FILE! It is auto-generated by tools/wild_encounters/wild_encounters_to_header.py") - print("//") - print("\n") - - -def IsConfigEnabled(): - CONFIG_ENABLED_PAT = re.compile(r"#define OW_TIME_OF_DAY_ENCOUNTERS\s+(?P[^ ]*)") - - with open("./include/config/overworld.h", "r") as overworld_config_file: - config_overworld = overworld_config_file.read() - config_setting = CONFIG_ENABLED_PAT.search(config_overworld) - return config_setting is not None and config_setting.group("cfg_val") in ("TRUE", "1") - - -def IsDexnavEnabled(): - CONFIG_ENABLED_PAT = re.compile(r"#define DEXNAV_ENABLED\s+(?P[^ ]*)") - - with open("./include/config/dexnav.h", "r") as overworld_config_file: - config_overworld = overworld_config_file.read() - config_setting = CONFIG_ENABLED_PAT.search(config_overworld) - return config_setting is not None and config_setting.group("cfg_val") in ("TRUE", "1") - - -def GetTimeEnum(): - DEFAULT_TIME_PAT = re.compile(r"enum\s+TimeOfDay\s*\{(?P[\s*\w+,\=\d*]+)\s*\}\s*\;") - - with open("./include/constants/rtc.h", "r") as rtc_include_file: - include_rtc = rtc_include_file.read() - include_enum = DEFAULT_TIME_PAT.search(include_rtc) - return include_enum.group("rtc_val") - - -def CheckEmpty(string): - return string == "" or string.isspace() or string == "\n" - - -def SetupUserTimeEnum(timeOfDay): - enum_string = GetTimeEnum() - enum_string = enum_string.split(",") - - # check for extra element from trailing comma - if CheckEmpty(enum_string[-1]): - enum_string.pop(-1) - - # we don't need the `TIMES_OF_DAY_COUNT` value, so - 1 from the value of len(enum_string) - strCount = 0 - while strCount < len(enum_string) - 1: - tempStr = enum_string[strCount].strip("\n ") - - """ - we need to ignore any value assignments, as the times will need to correspond - with the elements in the array. - """ - if "=" in tempStr: - tempStr = tempStr[0:tempStr.index("=")] - tempStr = tempStr.strip(" ") - - #double check we didn't catch any empty values - if not CheckEmpty(enum_string[strCount]): - timeOfDay.add(tempStr) - - strCount += 1 - return timeOfDay - - -def TabStr(amount): - return tabStr * amount - - -def GetPascalCase(string): - stringArray = string.split("_") - pascalString = "" - - for string in stringArray: - pascalString += string.capitalize() - return pascalString - - -def GetSnakeCase(string): - stringArray = string.split("_") - snakeString = "" - - i = 0 - for string in stringArray: - if i == 0: - snakeString += string - else: - snakeString += string.capitalize() - - i += 1 - return snakeString - - -def CheckFieldDataDupes(name): - for field in fieldData: - if field["name"] == name: - return True - return False - - -def AddFieldData(index, fieldType, fieldRates): - fieldData.append({}) - fieldData[index]["name"] = fieldType - fieldData[index]["pascalName"] = GetPascalCase(fieldType) - fieldData[index]["snakeName"] = GetSnakeCase(fieldType) - fieldData[index]["encounter_rates"] = fieldRates - +def ConvertToHeaderFile(json_data): + with open('src/data/wild_encounters.h', 'w') as output_file: + config = Config('include/config/overworld.h', 'include/constants/rtc.h', json_data) + assembler = WildEncounterAssembler(output_file, json_data, config) + assembler.WriteHeader() + assembler.WriteMacros() + assembler.WriteEncounters() def main(): - pass + with open('src/data/wild_encounters.json', 'r') as json_file: + json_data = json.load(json_file) + ConvertToHeaderFile(json_data) -if __name__ == "__main__": - ImportWildEncounterFile() - - -""" -!!!! EXAMPLE OUTPUT !!!! -- when OW_TIME_OF DAY_ENCOUNTERS is FALSE in configoverworld.h - -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 20 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 + 20 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 + 10 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 + 10 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 + 10 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 + 10 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 + 5 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 + 5 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 + 4 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 + 4 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_10 ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 + 1 -#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_11 ENCOUNTER_CHANCE_LAND_MONS_SLOT_10 + 1 -#define ENCOUNTER_CHANCE_LAND_MONS_TOTAL (ENCOUNTER_CHANCE_LAND_MONS_SLOT_11) -#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 60 -#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 + 30 -#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 + 5 -#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_3 ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 + 4 -#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_4 ENCOUNTER_CHANCE_WATER_MONS_SLOT_3 + 1 -#define ENCOUNTER_CHANCE_WATER_MONS_TOTAL (ENCOUNTER_CHANCE_WATER_MONS_SLOT_4) -#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_0 60 -#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_1 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_0 + 30 -#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_2 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_1 + 5 -#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_3 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_2 + 4 -#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_4 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_3 + 1 -#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_TOTAL (ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_4) -#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2 60 -#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2 + 20 -#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4 ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 + 20 -#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4) -#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_0 70 -#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_1 ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_0 + 30 -#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_1) -#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5 40 -#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5 + 40 -#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6 + 15 -#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7 + 4 -#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 + 1 -#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9) - -- if DEXNAV_ENABLED is TRUE -- these macros are 1 and 0, respectively if hidden_mons isn't in the encounter - rate list at the top of wild_encounters.json -#define ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_0 1 -#define ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_1 ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_0 + 0 -#define ENCOUNTER_CHANCE_HIDDEN_MONS_TOTAL (ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_1) - -const struct WildPokemon gRoute101_LandMons_Day[] = -{ - { 2, 2, SPECIES_WURMPLE }, - { 2, 2, SPECIES_POOCHYENA }, - { 2, 2, SPECIES_WURMPLE }, - { 3, 3, SPECIES_WURMPLE }, - { 3, 3, SPECIES_POOCHYENA }, - { 3, 3, SPECIES_POOCHYENA }, - { 3, 3, SPECIES_WURMPLE }, - { 3, 3, SPECIES_POOCHYENA }, - { 2, 2, SPECIES_ZIGZAGOON }, - { 2, 2, SPECIES_ZIGZAGOON }, - { 3, 3, SPECIES_ZIGZAGOON }, - { 3, 3, SPECIES_ZIGZAGOON }, -}; - -const struct WildPokemonInfo gRoute101_Day_LandMonsInfo= { 20, gRoute101_Day_LandMons }; -const struct WildPokemonHeader gWildMonHeaders[] = -{ - { - .mapGroup = MAP(ROUTE101), - .mapNum = MAP_NUM(ROUTE101), - .encounterTypes = - [OW_TIME_OF_DAY_DEFAULT] = - { - .landMonsInfo = &gRoute101_LandMonsInfo, - .waterMonsInfo = NULL, - .rockSmashMonsInfo = NULL, - .fishingMonsInfo = NULL, - .hiddenMonsInfo = NULL, - } - }, -} -""" +if __name__ == '__main__': + main()