Merge branch 'master' of https://github.com/rh-hideout-chinese/pokeemerald-expansion
This commit is contained in:
commit
25d0c0c066
6
.github/README.md
vendored
6
.github/README.md
vendored
@ -64,14 +64,14 @@ pokeemerald-expansion是基于pret的[pokeemerald](https://github.com/pret/pokee
|
||||
- 检查你的当前版本。
|
||||
- 你可以在调试菜单的`Utilities -> Expansion Version`选项中检查。
|
||||
- 如果该选项不可用,你可能拥有的是1.6.2或更早的版本。在那种情况下,请查看[更改日志](docs/CHANGELOG.md)以确定你的版本,基于你仓库中可用的功能。
|
||||
- ***重要提示***:如果你落后了几个版本,我们建议你一次更新一个小版本,而不是直接跳到最新的补丁版本(例如,1.5.3 -> 1.6.2 -> 1.7.4等等。查看在线文档网站](https://rh-hideout.github.io/pokeemerald-expansion/CHANGELOG.html)以查看每个步骤的最新版本。)
|
||||
- ***重要提示***:如果你落后了几个版本,我们建议你一次更新一个小版本,而不是直接跳到最新的补丁版本(例如,1.5.3 -> 1.6.2 -> 1.7.4等等。[查看在线文档网站](https://rh-hideout.github.io/pokeemerald-expansion/CHANGELOG.html)以查看每个步骤的最新版本。)
|
||||
- 一旦你设置了远程仓库,请运行命令`git pull RHH expansion/X.Y.Z`,将X、Y和Z替换为你想要更新到的相应版本的数字(例如,要更新到1.11.1,请使用`git pull RHH expansion/1.11.1`)。
|
||||
- ***重要提示***:如果你落后了几个版本,我们建议你一次更新一个小版本,而不是直接跳到最新的补丁版本(例如,1.5.3 -> 1.6.2 -> 1.7.4等等)
|
||||
- 另外,你可以更新到扩展的未发布版本。
|
||||
- ***master(稳定版)***:它包含将在下一个补丁版本中发布的***bug修复***。要合并,请使用`git pull RHH master`。
|
||||
- ***upcoming(不稳定版,可能存在bug)***:它包含将在下一个小版本中发布的***功能***。要合并,请使用`git pull RHH upcoming`。
|
||||
|
||||
### 请考虑在你的项目中归功于整个贡献者名单](https://github.com/rh-hideout/pokeemerald-expansion/wiki/Credits),因为他们都为开发这个项目付出了辛勤的努力 :)
|
||||
### 请考虑在你的项目中归功于整个[贡献者名单](https://github.com/rh-hideout/pokeemerald-expansion/wiki/Credits),因为他们都为开发这个项目付出了辛勤的努力 :)
|
||||
|
||||
## 谁在维护这个项目?
|
||||
|
||||
@ -246,4 +246,4 @@ pokeemerald-expansion是基于pret的[pokeemerald](https://github.com/pret/pokee
|
||||
- 《黑2/白2》及以后的驱虫喷雾系统,也支持《Let's Go!皮卡丘/伊布》中的香水。
|
||||
- 第六世代及以后的努力值上限。
|
||||
- 包含了pret的所有错误修复。
|
||||
- 修复了地图上的下雪天气效果。
|
||||
- 修复了地图上的下雪天气效果。
|
||||
|
||||
8
Makefile
8
Makefile
@ -50,6 +50,7 @@ endif
|
||||
PREFIX := arm-none-eabi-
|
||||
OBJCOPY := $(PREFIX)objcopy
|
||||
OBJDUMP := $(PREFIX)objdump
|
||||
READELF := $(PREFIX)readelf
|
||||
AS := $(PREFIX)as
|
||||
LD := $(PREFIX)ld
|
||||
|
||||
@ -86,6 +87,7 @@ endif
|
||||
ELF := $(ROM:.gba=.elf)
|
||||
MAP := $(ROM:.gba=.map)
|
||||
SYM := $(ROM:.gba=.sym)
|
||||
NOCASHSYM := $(ROM:.gba=.sym)
|
||||
|
||||
# Commonly used directories
|
||||
C_SUBDIR = src
|
||||
@ -294,6 +296,8 @@ endif
|
||||
|
||||
syms: $(SYM)
|
||||
|
||||
nosyms: $(NOCASHSYM)
|
||||
|
||||
clean: tidy clean-tools clean-check-tools clean-generated clean-assets
|
||||
@$(MAKE) clean -C libagbsyscall
|
||||
|
||||
@ -465,3 +469,7 @@ $(ROM): $(ELF)
|
||||
# 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' > $@
|
||||
|
||||
# Symbol file (`make nosyms)
|
||||
$(NOCASHSYM): $(ELF)
|
||||
$(READELF) -Ws $< | tail -n +4 | awk '$$4 !~/(FILE|NOTYPE)/ && $$8 !~/^(\$$|\.)/ {print $$2,$$8}' | sort -k 1 | awk '!seen[$$1]++' > $@
|
||||
|
||||
@ -8399,7 +8399,7 @@ BattleScript_BattlerAbilityStatRaiseOnSwitchIn::
|
||||
BattleScript_ScriptingAbilityStatRaise::
|
||||
copybyte gBattlerAbility, sBATTLER
|
||||
call BattleScript_AbilityPopUp
|
||||
copybyte sSAVED_DMG, gBattlerAttacker
|
||||
saveattacker
|
||||
copybyte gBattlerAttacker, sBATTLER
|
||||
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_NOT_PROTECT_AFFECTED | MOVE_EFFECT_CERTAIN, NULL
|
||||
setgraphicalstatchangevalues
|
||||
@ -8407,7 +8407,7 @@ BattleScript_ScriptingAbilityStatRaise::
|
||||
waitanimation
|
||||
printstring STRINGID_ATTACKERABILITYSTATRAISE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
copybyte gBattlerAttacker, sSAVED_DMG
|
||||
restoreattacker
|
||||
return
|
||||
|
||||
BattleScript_WeakArmorActivates::
|
||||
|
||||
@ -265,13 +265,12 @@ BattleScript_ActionWallyThrow:
|
||||
end2
|
||||
|
||||
BattleScript_TrainerASlideMsgRet::
|
||||
handletrainerslidemsg BS_SCRIPTING, 0
|
||||
trainerslidein BS_OPPONENT1
|
||||
handletrainerslidemsg BS_SCRIPTING, 1
|
||||
handletrainerslidemsg BS_SCRIPTING, PRINT_SLIDE_MESSAGE
|
||||
waitstate
|
||||
trainerslideout BS_OPPONENT1
|
||||
waitstate
|
||||
handletrainerslidemsg BS_SCRIPTING, 2
|
||||
handletrainerslidemsg BS_SCRIPTING, RESTORE_BATTLER_SLIDE_CONTROL
|
||||
return
|
||||
|
||||
BattleScript_TrainerASlideMsgEnd2::
|
||||
@ -279,13 +278,12 @@ BattleScript_TrainerASlideMsgEnd2::
|
||||
end2
|
||||
|
||||
BattleScript_TrainerBSlideMsgRet::
|
||||
handletrainerslidemsg BS_SCRIPTING, 0
|
||||
trainerslidein BS_OPPONENT2
|
||||
handletrainerslidemsg BS_SCRIPTING, 1
|
||||
handletrainerslidemsg BS_SCRIPTING, PRINT_SLIDE_MESSAGE
|
||||
waitstate
|
||||
trainerslideout BS_OPPONENT2
|
||||
waitstate
|
||||
handletrainerslidemsg BS_SCRIPTING, 2
|
||||
handletrainerslidemsg BS_SCRIPTING, RESTORE_BATTLER_SLIDE_CONTROL
|
||||
return
|
||||
|
||||
BattleScript_TrainerBSlideMsgEnd2::
|
||||
|
||||
@ -113,4 +113,40 @@ mkdir decomps
|
||||
|
||||
```bash
|
||||
cd ~/decomps
|
||||
```
|
||||
|
||||
## WSL更新或安装依赖时错误解决
|
||||
|
||||
<b>更新WSL</b>或<b>安装依赖项</b>时如果出现以下错误提示
|
||||
|
||||
```console
|
||||
E: Sub-process /usr/bin/dpkg returned an error code (1)
|
||||
```
|
||||
|
||||
可先执行以下命令
|
||||
|
||||
```bash
|
||||
sudo mv /var/lib/dpkg/info /var/lib/dpkg/info_old
|
||||
sudo mkdir /var/lib/dpkg/info
|
||||
```
|
||||
|
||||
<b>等待命令执行完毕</b>后再次运行<b>更新WSL</b>或<b>安装依赖项</b>命令。<b>更新或安装完毕后</b>运行以下命令以恢复pkg信息
|
||||
|
||||
```bash
|
||||
sudo mv /var/lib/dpkg/info_old/* /var/lib/dpkg/info/
|
||||
sudo rmdir /var/lib/dpkg/info_old
|
||||
```
|
||||
|
||||
如果出现以下提示,并列出可移除的包名(以libllvm17t64为例)
|
||||
|
||||
```console
|
||||
The following package was automatically installed and is no longer required:
|
||||
libllvm17t64
|
||||
```
|
||||
|
||||
可执行以下命令解决该提示
|
||||
|
||||
```bash
|
||||
sudo apt autoremove
|
||||
sudo apt install libllvm17t64
|
||||
```
|
||||
@ -736,19 +736,19 @@ struct BattleStruct
|
||||
u8 debugBattler;
|
||||
u8 magnitudeBasePower;
|
||||
u8 presentBasePower;
|
||||
u8 roostTypes[MAX_BATTLERS_COUNT][2];
|
||||
u8 roostTypes[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES];
|
||||
u8 savedBattlerTarget[5];
|
||||
u8 savedBattlerAttacker[5];
|
||||
u8 savedTargetCount:4;
|
||||
u8 savedAttackerCount:4;
|
||||
bool8 ateBoost[MAX_BATTLERS_COUNT];
|
||||
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler
|
||||
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES]; // two per battler
|
||||
struct ZMoveData zmove;
|
||||
struct DynamaxData dynamax;
|
||||
struct BattleGimmickData gimmick;
|
||||
const u8 *trainerSlideMsg;
|
||||
enum BattleIntroStates introState:8;
|
||||
u8 ateBerry[2]; // array id determined by side, each party pokemon as bit
|
||||
u8 ateBerry[NUM_BATTLE_SIDES]; // array id determined by side, each party pokemon as bit
|
||||
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];
|
||||
@ -804,13 +804,14 @@ struct BattleStruct
|
||||
u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side
|
||||
u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party
|
||||
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
|
||||
s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg
|
||||
u8 cheekPouchActivated:1;
|
||||
u8 padding2:3;
|
||||
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
|
||||
s32 moveDamage[MAX_BATTLERS_COUNT];
|
||||
s32 critChance[MAX_BATTLERS_COUNT];
|
||||
s16 moveDamage[MAX_BATTLERS_COUNT];
|
||||
s16 critChance[MAX_BATTLERS_COUNT];
|
||||
u16 moveResultFlags[MAX_BATTLERS_COUNT];
|
||||
u8 missStringId[MAX_BATTLERS_COUNT];
|
||||
u8 noResultString[MAX_BATTLERS_COUNT];
|
||||
@ -821,7 +822,6 @@ struct BattleStruct
|
||||
u8 numSpreadTargets:2;
|
||||
u8 bypassMoldBreakerChecks:1; // for ABILITYEFFECT_IMMUNITY
|
||||
u8 noTargetPresent:1;
|
||||
u8 usedEjectItem;
|
||||
u8 usedMicleBerry;
|
||||
struct MessageStatus slideMessageStatus;
|
||||
u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT];
|
||||
|
||||
@ -605,4 +605,10 @@ enum StartingStatus
|
||||
STARTING_STATUS_SWAMP_OPPONENT,
|
||||
};
|
||||
|
||||
enum SlideMsgStates
|
||||
{
|
||||
PRINT_SLIDE_MESSAGE,
|
||||
RESTORE_BATTLER_SLIDE_CONTROL,
|
||||
};
|
||||
|
||||
#endif // GUARD_CONSTANTS_BATTLE_H
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/python python3
|
||||
# 原始字符串
|
||||
text = "全副武装的样子。\n即使是极巨化宝可梦的\n攻击也能轻易抵挡。"
|
||||
|
||||
|
||||
@ -1,9 +1,19 @@
|
||||
#!/usr/bin/python python3
|
||||
import os
|
||||
import openpyxl
|
||||
import re
|
||||
|
||||
# 获取py文件所在文件夹绝对路径
|
||||
pydir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
#获取excel相对py文件路径
|
||||
excel_path = os.path.join(pydir, "src", "精灵跟随.xlsx")
|
||||
|
||||
# 获取C文件所在文件夹相对py文件路径
|
||||
cdir = os.path.join(os.path.dirname(pydir), "src")
|
||||
|
||||
# 文件路径
|
||||
excel_path = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\python_tools\src\精灵跟随.xlsx"
|
||||
c_file_path = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\src\follower_helper.c"
|
||||
c_file_path = os.path.join(cdir, "follower_helper.c")
|
||||
|
||||
# 读取 Excel 文件
|
||||
wb = openpyxl.load_workbook(excel_path)
|
||||
|
||||
@ -1,8 +1,16 @@
|
||||
#!/usr/bin/python python3
|
||||
import os
|
||||
import re
|
||||
|
||||
# 获取py文件所在文件夹绝对路径
|
||||
pydir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# 获取C文件所在文件夹相对py文件路径
|
||||
cdir = os.path.join(os.path.dirname(pydir), "src")
|
||||
|
||||
# 文件路径
|
||||
input_file = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\src\strings.c"
|
||||
output_file = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\extracted_strings.txt"
|
||||
input_file = os.path.join(cdir, "strings.c")
|
||||
output_file = os.path.join(os.path.dirname(pydir), "extracted_strings.txt")
|
||||
|
||||
# 正则表达式匹配变量名和 _("...") 之间的内容
|
||||
pattern = re.compile(r'const\s+u8\s+(\w+)\[\]\s*=\s*_\("([^"]*)"\)')
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
#!/usr/bin/python python3
|
||||
import re
|
||||
import os
|
||||
from openpyxl import load_workbook
|
||||
|
||||
pydir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# 文件路径
|
||||
c_file_path = os.path.dirname(os.path.abspath(__file__))+"/../src/battle_message.c"
|
||||
xlsx_file_path = os.path.dirname(os.path.abspath(__file__))+"/src/战斗文本.xlsx"
|
||||
c_file_path = os.path.join(os.path.dirname(pydir), "src", "battle_message.c")
|
||||
xlsx_file_path = os.path.join(pydir, "src", "战斗文本.xlsx")
|
||||
|
||||
# 读取 xlsx 文件并解析为字典
|
||||
def load_translations(xlsx_file_path):
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/python python3
|
||||
import re
|
||||
import openpyxl
|
||||
import os
|
||||
@ -45,8 +46,8 @@ def replace_in_c_file(c_file, replacement_dict):
|
||||
# 主函数
|
||||
def main():
|
||||
current_folder = os.path.dirname(os.path.abspath(__file__))
|
||||
xlsx_file = current_folder+"/src/debug文本.xlsx" # Excel 文件路径
|
||||
c_file = current_folder+"/../src/battle_debug.c" # C 文件路径
|
||||
xlsx_file = os.path.join(current_folder, "src", "debug文本.xlsx") # Excel 文件路径
|
||||
c_file = os.path.join(os.path.dirname(current_folder), "src", "battle_debug.c") # C 文件路径
|
||||
|
||||
# 加载替换字典
|
||||
replacement_dict = load_replacement_dict(xlsx_file)
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
#!/usr/bin/python python3
|
||||
import openpyxl
|
||||
import re
|
||||
import os
|
||||
|
||||
# 文件路径
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
h_file_path = os.path.join(base_dir, "../src/data/decoration/header.h")
|
||||
xlsx_path = os.path.join(base_dir, "src/装饰物品.xlsx")
|
||||
h_file_path = os.path.join(os.path.dirname(base_dir), "src", "data", "decoration", "header.h")
|
||||
xlsx_path = os.path.join(base_dir, "src", "装饰物品.xlsx")
|
||||
|
||||
# 加载Excel文件
|
||||
wb = openpyxl.load_workbook(xlsx_path)
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/python python3
|
||||
import openpyxl
|
||||
import re
|
||||
import os
|
||||
|
||||
# 文件路径
|
||||
h_file_path = os.path.dirname(os.path.abspath(__file__))+"/../src/data/decoration/description.h"
|
||||
xlsx_path = os.path.dirname(os.path.abspath(__file__))+"/src/装饰物品.xlsx"
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
h_file_path = os.path.join(os.path.dirname(base_dir), "src", "data", "decoration", "description.h")
|
||||
xlsx_path = os.path.join(base_dir, "src", "装饰物品.xlsx")
|
||||
|
||||
# 加载Excel文件
|
||||
wb = openpyxl.load_workbook(xlsx_path)
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/python python3
|
||||
import os
|
||||
import re
|
||||
import pandas as pd
|
||||
@ -60,13 +61,13 @@ def replace_item_info(content, df):
|
||||
return content
|
||||
|
||||
def log(message):
|
||||
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
|
||||
with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file:
|
||||
log_file.write(message + "\n")
|
||||
print(message)
|
||||
|
||||
if __name__ == "__main__":
|
||||
work_file = current_folder +"\..\src\data\items.h"
|
||||
df = pd.read_excel(current_folder +r'\src\道具.xlsx')
|
||||
work_file = os.path.join(os.path.dirname(current_folder), "src", "data", "items.h")
|
||||
df = pd.read_excel(os.path.join(current_folder, "src", "道具.xlsx"))
|
||||
df.set_index('道具', inplace=True)
|
||||
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/python python3
|
||||
import os
|
||||
import re
|
||||
import pandas as pd
|
||||
@ -56,14 +57,13 @@ def replace_species_info(content, df):
|
||||
return content
|
||||
|
||||
def log(message):
|
||||
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
|
||||
with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file:
|
||||
log_file.write(message + "\n")
|
||||
print(message)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
work_folder = current_folder +"\..\src\data\pokemon\species_info"
|
||||
df = pd.read_excel(current_folder +r'\src\图鉴.xlsx')
|
||||
work_folder = os.path.join(os.path.dirname(current_folder), "src", "data", "pokemon", "species_info")
|
||||
df = pd.read_excel(os.path.join(current_folder, "src", "图鉴.xlsx"))
|
||||
df.set_index('name', inplace=True)
|
||||
|
||||
for filename in os.listdir(work_folder):
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/python python3
|
||||
import os
|
||||
import re
|
||||
import pandas as pd
|
||||
@ -60,14 +61,13 @@ def replace_move_info(content, df):
|
||||
return content
|
||||
|
||||
def log(message):
|
||||
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
|
||||
with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file:
|
||||
log_file.write(message + "\n")
|
||||
print(message)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
work_file = current_folder +"\..\src\data\moves_info.h"
|
||||
df = pd.read_excel(current_folder +r'\src\招式.xlsx')
|
||||
work_file = os.path.join(os.path.dirname(current_folder), "src", "data", "moves_info.h")
|
||||
df = pd.read_excel(os.path.join(current_folder, "src", "招式.xlsx"))
|
||||
df.set_index('招式', inplace=True)
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
|
||||
#!/usr/bin/python python3
|
||||
import os
|
||||
import re
|
||||
import pandas as pd
|
||||
@ -44,13 +44,12 @@ def replace_move_info(content, df):
|
||||
return content
|
||||
|
||||
def log(message):
|
||||
with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file:
|
||||
with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file:
|
||||
log_file.write(message + "\n")
|
||||
print(message)
|
||||
if __name__ == "__main__":
|
||||
|
||||
work_file = current_folder +"\..\src\strings.c"
|
||||
df = pd.read_excel(current_folder + r'\src\文本.xlsx')
|
||||
work_file = os.path.join(os.path.dirname(current_folder), "src", "strings.c")
|
||||
df = pd.read_excel(os.path.join(current_folder, "src", "文本.xlsx"))
|
||||
|
||||
# 检查并清理重复的“变量名”
|
||||
df = df.drop_duplicates(subset='变量名', keep='first')
|
||||
|
||||
@ -1677,6 +1677,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
|
||||
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
|
||||
|
||||
if (effect == EFFECT_DRAGON_DARTS
|
||||
&& !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(battlerDef), gCurrentMove)
|
||||
&& !recalcDragonDarts // So we don't jump back and forth between targets
|
||||
&& CanTargetPartner(gBattlerAttacker, battlerDef)
|
||||
&& !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(battlerDef)))
|
||||
@ -6496,8 +6497,7 @@ static void Cmd_moveend(void)
|
||||
else if (moveRecoil > 0
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget))
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleScripting.savedDmg * max(1, moveRecoil) / 100);
|
||||
BattleScriptPushCursor();
|
||||
@ -7006,6 +7006,7 @@ static void Cmd_moveend(void)
|
||||
else
|
||||
{
|
||||
if (moveEffect == EFFECT_DRAGON_DARTS
|
||||
&& !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(gBattlerTarget), gCurrentMove)
|
||||
&& !(gBattleStruct->moveResultFlags[BATTLE_PARTNER(gBattlerTarget)] & MOVE_RESULT_MISSED) // didn't miss the other target
|
||||
&& CanTargetPartner(gBattlerAttacker, gBattlerTarget)
|
||||
&& !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(gBattlerTarget)))
|
||||
@ -7157,6 +7158,10 @@ 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;
|
||||
|
||||
@ -9048,7 +9053,7 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId)
|
||||
&& !IsBattlerAtMaxHp(battler))
|
||||
{
|
||||
gBattleStruct->cheekPouchActivated = TRUE;
|
||||
gBattleScripting.savedDmg = gBattleStruct->moveDamage[battler];
|
||||
gBattleStruct->savedcheekPouchDamage = gBattleStruct->moveDamage[battler];
|
||||
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 3;
|
||||
if (gBattleStruct->moveDamage[battler] == 0)
|
||||
gBattleStruct->moveDamage[battler] = 1;
|
||||
@ -9066,7 +9071,7 @@ static void TryRestoreDamageAfterCheeckPouch(u32 battler)
|
||||
{
|
||||
if (gBattleStruct->cheekPouchActivated)
|
||||
{
|
||||
gBattleStruct->moveDamage[battler] = gBattleScripting.savedDmg;
|
||||
gBattleStruct->moveDamage[battler] = gBattleStruct->savedcheekPouchDamage;
|
||||
gBattleStruct->cheekPouchActivated = FALSE;
|
||||
}
|
||||
}
|
||||
@ -10602,6 +10607,7 @@ static void Cmd_various(void)
|
||||
if ((battlerAbility == ABILITY_MOXIE
|
||||
|| battlerAbility == ABILITY_CHILLING_NEIGH
|
||||
|| battlerAbility == ABILITY_AS_ONE_ICE_RIDER)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& HasAttackerFaintedTarget()
|
||||
&& !NoAliveMonsForEitherParty()
|
||||
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
@ -10625,6 +10631,7 @@ static void Cmd_various(void)
|
||||
|
||||
if ((battlerAbility == ABILITY_GRIM_NEIGH
|
||||
|| battlerAbility == ABILITY_AS_ONE_SHADOW_RIDER)
|
||||
&& IsBattlerAlive(battler)
|
||||
&& HasAttackerFaintedTarget()
|
||||
&& !NoAliveMonsForEitherParty()
|
||||
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
@ -10663,7 +10670,8 @@ static void Cmd_various(void)
|
||||
VARIOUS_ARGS();
|
||||
|
||||
i = GetHighestStatId(battler);
|
||||
if (GetBattlerAbility(battler) == ABILITY_BEAST_BOOST
|
||||
if (IsBattlerAlive(battler)
|
||||
&& GetBattlerAbility(battler) == ABILITY_BEAST_BOOST
|
||||
&& HasAttackerFaintedTarget()
|
||||
&& !NoAliveMonsForEitherParty()
|
||||
&& CompareStat(gBattlerAttacker, i, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
@ -10701,6 +10709,7 @@ static void Cmd_various(void)
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_FELL_STINGER
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& HasAttackerFaintedTarget()
|
||||
&& !NoAliveMonsForEitherParty()
|
||||
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
@ -11119,21 +11128,13 @@ static void Cmd_various(void)
|
||||
case VARIOUS_HANDLE_TRAINER_SLIDE_MSG:
|
||||
{
|
||||
VARIOUS_ARGS(u8 case_);
|
||||
if (cmd->case_ == 0)
|
||||
{
|
||||
// Save sprite IDs, because trainer slide in will overwrite gBattlerSpriteIds variable.
|
||||
gBattleScripting.savedDmg = (gBattlerSpriteIds[battler] & 0xFF) | (gBattlerSpriteIds[BATTLE_PARTNER(battler)] << 8);
|
||||
}
|
||||
else if (cmd->case_ == 1)
|
||||
if (cmd->case_ == PRINT_SLIDE_MESSAGE)
|
||||
{
|
||||
BtlController_EmitPrintString(battler, BUFFER_A, STRINGID_TRAINERSLIDE);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
}
|
||||
else
|
||||
else if (cmd->case_ == RESTORE_BATTLER_SLIDE_CONTROL)
|
||||
{
|
||||
gBattlerSpriteIds[BATTLE_PARTNER(battler)] = gBattleScripting.savedDmg >> 8;
|
||||
gBattlerSpriteIds[battler] = gBattleScripting.savedDmg & 0xFF;
|
||||
gBattleScripting.savedDmg = 0;
|
||||
if (IsBattlerAlive(battler))
|
||||
{
|
||||
SetBattlerShadowSpriteCallback(battler, gBattleMons[battler].species);
|
||||
|
||||
@ -227,15 +227,28 @@ static bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef, u32 a
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline bool32 IsDragonDartsSecondHit(u32 effect)
|
||||
{
|
||||
if (effect != EFFECT_DRAGON_DARTS)
|
||||
return FALSE;
|
||||
|
||||
if (gMultiHitCounter == 1)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move)
|
||||
{
|
||||
u32 ability = GetBattlerAbility(battlerAtk);
|
||||
u32 effect = GetMoveEffect(move);
|
||||
|
||||
if (gSideTimers[defSide].followmeTimer == 0
|
||||
|| !IsBattlerAlive(gSideTimers[defSide].followmeTarget)
|
||||
|| effect == EFFECT_SNIPE_SHOT || effect == EFFECT_SKY_DROP
|
||||
|| ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART)
|
||||
|| (!IsBattlerAlive(gSideTimers[defSide].followmeTarget) && !IsDragonDartsSecondHit(effect))
|
||||
|| effect == EFFECT_SNIPE_SHOT
|
||||
|| effect == EFFECT_SKY_DROP
|
||||
|| ability == ABILITY_PROPELLER_TAIL
|
||||
|| ability == ABILITY_STALWART)
|
||||
return FALSE;
|
||||
|
||||
if (effect == EFFECT_PURSUIT && IsPursuitTargetSet())
|
||||
@ -3582,6 +3595,9 @@ static void CancellerWeatherPrimal(u32 *effect)
|
||||
}
|
||||
if (*effect == 1)
|
||||
{
|
||||
gBattleScripting.moveEffect = 0;
|
||||
gProtectStructs[gBattlerAttacker].chargingTurn = FALSE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove;
|
||||
@ -3696,6 +3712,7 @@ static void CancellerMultihitMoves(u32 *effect)
|
||||
gMultiHitCounter = GetMoveStrikeCount(gCurrentMove);
|
||||
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_DRAGON_DARTS
|
||||
&& !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(gBattlerTarget), gCurrentMove)
|
||||
&& CanTargetPartner(gBattlerAttacker, gBattlerTarget)
|
||||
&& TargetFullyImmuneToCurrMove(gBattlerAttacker, gBattlerTarget))
|
||||
gBattlerTarget = BATTLE_PARTNER(gBattlerTarget);
|
||||
@ -7355,6 +7372,7 @@ u32 RestoreWhiteHerbStats(u32 battler)
|
||||
}
|
||||
if (effect != 0)
|
||||
{
|
||||
gLastUsedItem = gBattleMons[battler].item;
|
||||
gBattleScripting.battler = battler;
|
||||
gPotentialItemEffectBattler = battler;
|
||||
}
|
||||
@ -7679,10 +7697,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
|
||||
case HOLD_EFFECT_RESTORE_STATS:
|
||||
effect = RestoreWhiteHerbStats(battler);
|
||||
if (effect != 0)
|
||||
{
|
||||
gBattlerAttacker = battler;
|
||||
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_CONFUSE_SPICY:
|
||||
if (B_BERRIES_INSTANT >= GEN_4)
|
||||
@ -7898,10 +7913,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
|
||||
case HOLD_EFFECT_RESTORE_STATS:
|
||||
effect = RestoreWhiteHerbStats(battler);
|
||||
if (effect != 0)
|
||||
{
|
||||
gBattlerAttacker = battler;
|
||||
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON))
|
||||
@ -8190,7 +8202,8 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
|
||||
break;
|
||||
case HOLD_EFFECT_LIFE_ORB:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveDamage[gBattlerTarget]) // Needs the second check in case of Substitute
|
||||
&& !IsBattleMoveStatus(gCurrentMove)
|
||||
&& (IsBattlerTurnDamaged(gBattlerTarget) || !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Needs the second check in case of Substitute
|
||||
&& !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove))
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD
|
||||
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
|
||||
@ -8311,7 +8324,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
|
||||
effect = TrySetEnigmaBerry(battler);
|
||||
break;
|
||||
case HOLD_EFFECT_JABOCA_BERRY: // consume and damage attacker if used physical move
|
||||
if (IsBattlerAlive(battler)
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
|
||||
&& IsBattleMovePhysical(gCurrentMove)
|
||||
@ -8331,7 +8344,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn)
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_ROWAP_BERRY: // consume and damage attacker if used special move
|
||||
if (IsBattlerAlive(battler)
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
|
||||
&& IsBattleMoveSpecial(gCurrentMove)
|
||||
|
||||
@ -4278,6 +4278,13 @@ static const u16 sBasculinEggMoveLearnset[] = {
|
||||
MOVE_HEAD_SMASH,
|
||||
MOVE_UNAVAILABLE,
|
||||
};
|
||||
#if P_HISUIAN_FORMS
|
||||
static const u16 sBasculinWhiteStripedEggMoveLearnset[] = {
|
||||
MOVE_ENDEAVOR,
|
||||
MOVE_LAST_RESPECTS,
|
||||
MOVE_UNAVAILABLE,
|
||||
};
|
||||
#endif //P_HISUIAN_FORMS
|
||||
#endif //P_FAMILY_BASCULIN
|
||||
|
||||
#if P_FAMILY_SANDILE
|
||||
|
||||
@ -4377,6 +4377,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] =
|
||||
)
|
||||
.levelUpLearnset = sBasculinWhiteStripedLevelUpLearnset,
|
||||
.teachableLearnset = sBasculinWhiteStripedTeachableLearnset,
|
||||
.eggMoveLearnset = sBasculinWhiteStripedEggMoveLearnset,
|
||||
.formSpeciesIdTable = sBasculinFormSpeciesIdTable,
|
||||
.evolutions = EVOLUTION({EVO_RECOIL_DAMAGE_MALE, 294, SPECIES_BASCULEGION_M},
|
||||
{EVO_RECOIL_DAMAGE_FEMALE, 294, SPECIES_BASCULEGION_F}),
|
||||
|
||||
@ -36,3 +36,23 @@ SINGLE_BATTLE_TEST("Beast Boost boosts the most proficient stat when knocking ou
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Beast Boost doesn't trigger if user is fainted")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND);
|
||||
ASSUME(GetMovePower(MOVE_SCRATCH) > 0);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_KARTANA) { Ability(ABILITY_BEAST_BOOST); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DESTINY_BOND); MOVE(opponent, MOVE_SCRATCH); SEND_OUT(player, 1); SEND_OUT(opponent, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent);
|
||||
NOT ABILITY_POPUP(opponent, ABILITY_BEAST_BOOST);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,3 +65,21 @@ SINGLE_BATTLE_TEST("Desolate Land does not block a move if pokemon is asleep and
|
||||
MESSAGE("The opposing Wobbuffet is fast asleep.");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Desolate Land will not create a softlock when move in semi invulnerable position is blocked")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DIVE); }
|
||||
TURN { SWITCH(opponent, 1); SKIP_TURN(player); }
|
||||
TURN { MOVE(player, MOVE_CELEBRATE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DIVE, player);
|
||||
ABILITY_POPUP(opponent, ABILITY_DESOLATE_LAND);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DIVE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,3 +58,18 @@ SINGLE_BATTLE_TEST("Jaboca Berry tirggers before Bug Bite can steal it")
|
||||
NOT MESSAGE("Wynaut stole and ate the opposing Wobbuffet's Jaboca Berry!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Jaboca Berry is triggered even if berry user dies")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_JABOCA_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
HP_BAR(player);
|
||||
MESSAGE("Wobbuffet was hurt by the opposing Wobbuffet's Jaboca Berry!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Life Orb activates if it hits a Substitute")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_TACKLE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
|
||||
HP_BAR(player);
|
||||
MESSAGE("Wobbuffet was hurt by the Life Orb!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Life Orb does not activate if using a status move")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_GROWL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GROWL, player);
|
||||
NONE_OF {
|
||||
HP_BAR(player);
|
||||
MESSAGE("Wobbuffet was hurt by the Life Orb!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,3 +217,21 @@ SINGLE_BATTLE_TEST("White Herb has correct interactions with Intimidate triggere
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("White Herb is correctly displayed")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT) { Item(ITEM_WHITE_HERB); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_SUPERPOWER, target: opponentRight); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerRight);
|
||||
MESSAGE("Wynaut returned its stats to normal using its White Herb!");
|
||||
} THEN {
|
||||
EXPECT(playerLeft->item == ITEM_NONE);
|
||||
EXPECT(playerLeft->statStages[STAT_DEF] = DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,3 +57,18 @@ SINGLE_BATTLE_TEST("Rowap Berry is not triggered by a physical move")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Rowap Berry is triggered even if berry user dies")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_ROWAP_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SWIFT); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWIFT, player);
|
||||
HP_BAR(player);
|
||||
MESSAGE("Wobbuffet was hurt by the opposing Wobbuffet's Rowap Berry!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,7 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is F
|
||||
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; }
|
||||
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
@ -252,3 +253,61 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if one strike misses")
|
||||
MESSAGE("The Pokémon was hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts strikes will be both redirected to Follow Me user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
MESSAGE("The Pokémon was hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a fairy type follow me user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CLEFAIRY);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
MESSAGE("The Pokémon was hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts fails to strike the second target if first target fainted and follow me was active")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
HP_BAR(opponentRight);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft);
|
||||
MESSAGE("The Pokémon was hit 2 time(s)!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,3 +179,19 @@ SINGLE_BATTLE_TEST("Hit Escape: Electric Seed boost is received by the right pok
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Hit Escape: U-turn triggers before Eject Pack")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); };
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_GOODRA_HISUI) { Ability(ABILITY_GOOEY); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_U_TURN); SEND_OUT(player, 1); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
|
||||
HP_BAR(opponent);
|
||||
SEND_IN_MESSAGE("Wynaut");
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
|
||||
namespace json11 {
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user