Merge branch '_RHH/master' into _RHH/upcoming
This commit is contained in:
commit
5d4ab8cc7e
8 changed files with 125 additions and 42 deletions
15
Makefile
15
Makefile
|
@ -372,6 +372,13 @@ ifneq ($(NODEP),1)
|
|||
-include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d))
|
||||
endif
|
||||
|
||||
$(TEST_BUILDDIR)/%.o: $(TEST_SUBDIR)/%.c
|
||||
@echo "$(CC1) <flags> -o $@ $<"
|
||||
@$(CPP) $(CPPFLAGS) $< | $(PREPROC) -i $< charmap.txt | $(CC1) $(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $(AS) $(ASFLAGS) -o $@ -
|
||||
|
||||
$(TEST_BUILDDIR)/%.d: $(TEST_SUBDIR)/%.c
|
||||
$(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) -I tools/agbcc/include $<
|
||||
|
||||
$(ASM_BUILDDIR)/%.o: $(ASM_SUBDIR)/%.s
|
||||
$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
||||
|
@ -415,14 +422,6 @@ $(OBJ_DIR)/sym_ewram.ld: sym_ewram.txt
|
|||
$(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h: $(DATA_ASM_BUILDDIR)/event_scripts.o
|
||||
python3 $(TOOLS_DIR)/learnset_helpers/teachable.py
|
||||
|
||||
# NOTE: Based on C_DEP above, but without NODEP and KEEP_TEMPS handling.
|
||||
define TEST_DEP
|
||||
$1: $2 $$(shell $(SCANINC) -I include -I $(TOOLS_DIR)/agbcc/include $2)
|
||||
@echo "$$(CC1) <flags> -o $$@ $$<"
|
||||
@$$(CPP) $$(CPPFLAGS) $$< | $$(PREPROC) -i $$< charmap.txt | $$(CC1) $$(CFLAGS) -o - - | cat - <(echo -e ".text\n\t.align\t2, 0") | $$(AS) $$(ASFLAGS) -o $$@ -
|
||||
endef
|
||||
$(foreach src, $(TEST_SRCS), $(eval $(call TEST_DEP,$(patsubst $(TEST_SUBDIR)/%.c,$(TEST_BUILDDIR)/%.o,$(src)),$(src),$(patsubst $(TEST_SUBDIR)/%.c,%,$(src)))))
|
||||
|
||||
# Linker script
|
||||
LD_SCRIPT := ld_script_modern.ld
|
||||
LD_SCRIPT_DEPS :=
|
||||
|
|
|
@ -931,7 +931,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
|
|||
|
||||
if (GetBattlerSide(battlerAtk) == B_SIDE_PLAYER)
|
||||
{
|
||||
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality)
|
||||
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality && !megaEvo)
|
||||
{
|
||||
personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_PERSONALITY);
|
||||
isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_IS_SHINY);
|
||||
|
@ -949,7 +949,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
|
|||
}
|
||||
else
|
||||
{
|
||||
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality)
|
||||
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality && !megaEvo)
|
||||
{
|
||||
personalityValue = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_PERSONALITY);
|
||||
isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_IS_SHINY);
|
||||
|
|
|
@ -2297,14 +2297,14 @@ s32 GetDrainedBigRootHp(u32 battler, s32 hp)
|
|||
return hp * -1;
|
||||
}
|
||||
|
||||
#define MAGIC_GUARD_CHECK \
|
||||
if (ability == ABILITY_MAGIC_GUARD) \
|
||||
{\
|
||||
RecordAbilityBattle(battler, ability);\
|
||||
gBattleStruct->turnEffectsTracker++;\
|
||||
break;\
|
||||
}
|
||||
static inline bool32 IsBattlerProtectedByMagicGuard(u32 battler, u32 ability)
|
||||
{
|
||||
if (ability != ABILITY_MAGIC_GUARD)
|
||||
return FALSE;
|
||||
|
||||
RecordAbilityBattle(battler, ability);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u8 DoBattlerEndTurnEffects(void)
|
||||
{
|
||||
|
@ -2432,10 +2432,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
case ENDTURN_LEECH_SEED: // leech seed
|
||||
if ((gStatuses3[battler] & STATUS3_LEECHSEED)
|
||||
&& IsBattlerAlive(gStatuses3[battler] & STATUS3_LEECHSEED_BATTLER)
|
||||
&& IsBattlerAlive(battler))
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
|
||||
gBattlerTarget = gStatuses3[battler] & STATUS3_LEECHSEED_BATTLER; // Notice gBattlerTarget is actually the HP receiver.
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8;
|
||||
if (gBattleMoveDamage == 0)
|
||||
|
@ -2449,10 +2448,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
break;
|
||||
case ENDTURN_POISON: // poison
|
||||
if ((gBattleMons[battler].status1 & STATUS1_POISON)
|
||||
&& IsBattlerAlive(battler))
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
|
||||
if (ability == ABILITY_POISON_HEAL)
|
||||
{
|
||||
if (!BATTLER_MAX_HP(battler) && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK))
|
||||
|
@ -2478,10 +2476,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
break;
|
||||
case ENDTURN_BAD_POISON: // toxic poison
|
||||
if ((gBattleMons[battler].status1 & STATUS1_TOXIC_POISON)
|
||||
&& IsBattlerAlive(battler))
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
|
||||
if (ability == ABILITY_POISON_HEAL)
|
||||
{
|
||||
if (!BATTLER_MAX_HP(battler) && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK))
|
||||
|
@ -2510,9 +2507,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
break;
|
||||
case ENDTURN_BURN: // burn
|
||||
if ((gBattleMons[battler].status1 & STATUS1_BURN)
|
||||
&& IsBattlerAlive(battler))
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8);
|
||||
if (ability == ABILITY_HEATPROOF)
|
||||
{
|
||||
|
@ -2529,9 +2526,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
break;
|
||||
case ENDTURN_FROSTBITE: // burn
|
||||
if ((gBattleMons[battler].status1 & STATUS1_FROSTBITE)
|
||||
&& IsBattlerAlive(battler))
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / (B_BURN_DAMAGE >= GEN_7 ? 16 : 8);
|
||||
if (gBattleMoveDamage == 0)
|
||||
gBattleMoveDamage = 1;
|
||||
|
@ -2542,9 +2539,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
break;
|
||||
case ENDTURN_NIGHTMARES: // spooky nightmares
|
||||
if ((gBattleMons[battler].status2 & STATUS2_NIGHTMARE)
|
||||
&& IsBattlerAlive(battler))
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
// R/S does not perform this sleep check, which causes the nightmare effect to
|
||||
// persist even after the affected Pokémon has been awakened by Shed Skin.
|
||||
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
|
||||
|
@ -2564,9 +2561,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
break;
|
||||
case ENDTURN_CURSE: // curse
|
||||
if ((gBattleMons[battler].status2 & STATUS2_CURSED)
|
||||
&& IsBattlerAlive(battler))
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 4;
|
||||
if (gBattleMoveDamage == 0)
|
||||
gBattleMoveDamage = 1;
|
||||
|
@ -2580,7 +2577,11 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
{
|
||||
if (--gDisableStructs[battler].wrapTurns != 0) // damaged by wrap
|
||||
{
|
||||
MAGIC_GUARD_CHECK;
|
||||
if (IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
gBattleStruct->turnEffectsTracker++;
|
||||
break;
|
||||
}
|
||||
|
||||
gBattleScripting.animArg1 = gBattleStruct->wrappedMove[battler];
|
||||
gBattleScripting.animArg2 = gBattleStruct->wrappedMove[battler] >> 8;
|
||||
|
@ -2884,7 +2885,9 @@ u8 DoBattlerEndTurnEffects(void)
|
|||
gBattleStruct->turnEffectsTracker++;
|
||||
break;
|
||||
case ENDTURN_SALT_CURE:
|
||||
if (gStatuses4[battler] & STATUS4_SALT_CURE && IsBattlerAlive(battler))
|
||||
if (gStatuses4[battler] & STATUS4_SALT_CURE
|
||||
&& IsBattlerAlive(battler)
|
||||
&& !IsBattlerProtectedByMagicGuard(battler, ability))
|
||||
{
|
||||
gBattlerTarget = battler;
|
||||
if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_STEEL) || IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_WATER))
|
||||
|
|
41
test/battle/move_effect/fixed_damage_arg.c
Normal file
41
test/battle/move_effect/fixed_damage_arg.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_SONIC_BOOM].effect == EFFECT_FIXED_DAMAGE_ARG);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sonic Boom deals fixed damage", s16 damage)
|
||||
{
|
||||
u16 mon;
|
||||
PARAMETRIZE { mon = SPECIES_RATTATA; }
|
||||
PARAMETRIZE { mon = SPECIES_ARON; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SONIC_BOOM].argument == 20);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(mon);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SONIC_BOOM); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SONIC_BOOM, player);
|
||||
HP_BAR(opponent, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT(results[0].damage == 20);
|
||||
EXPECT(results[1].damage == 20);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sonic Boom doesn't affect ghost types")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTLY);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SONIC_BOOM); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SONIC_BOOM, player);
|
||||
MESSAGE("It doesn't affect the opposing Gastly…");
|
||||
}
|
||||
}
|
|
@ -99,3 +99,21 @@ SINGLE_BATTLE_TEST("Salt Cure does not get applied if hitting a Substitute")
|
|||
NOT MESSAGE("The opposing Wobbuffet is being salt cured!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Salt Cure residual damage does not inflict any damage against Magic Guard")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CLEFABLE) { Ability(ABILITY_MAGIC_GUARD); };
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SALT_CURE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SALT_CURE, player);
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SALT_CURE_DAMAGE, opponent);
|
||||
HP_BAR(opponent);
|
||||
MESSAGE("The opposing Clefable is hurt by Salt Cure!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ SINGLE_BATTLE_TEST("Terrain started after the one which started the battle lasts
|
|||
VarSet(B_VAR_STARTING_STATUS_TIMER, 0);
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Ability(viaMove == TRUE ? ABILITY_SHADOW_TAG : ABILITY_GRASSY_SURGE); }
|
||||
PLAYER(SPECIES_TAPU_BULU) { Ability(viaMove == TRUE ? ABILITY_TELEPATHY : ABILITY_GRASSY_SURGE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
// More than 5 turns
|
||||
|
@ -84,7 +84,7 @@ SINGLE_BATTLE_TEST("Terrain started after the one which started the battle lasts
|
|||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_RESTORE_BG);
|
||||
// Player uses Grassy Terrain
|
||||
if (viaMove) {
|
||||
MESSAGE("Wobbuffet used GrssyTerrain!");
|
||||
MESSAGE("Tapu Bulu used Grassy Terrain!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GRASSY_TERRAIN, player);
|
||||
MESSAGE("Grass grew to cover the battlefield!");
|
||||
} else {
|
||||
|
@ -94,13 +94,13 @@ SINGLE_BATTLE_TEST("Terrain started after the one which started the battle lasts
|
|||
}
|
||||
|
||||
// 5 turns
|
||||
MESSAGE("Wobbuffet used Celebrate!");
|
||||
MESSAGE("Tapu Bulu used Celebrate!");
|
||||
MESSAGE("The opposing Wobbuffet used Celebrate!");
|
||||
|
||||
MESSAGE("Wobbuffet used Celebrate!");
|
||||
MESSAGE("Tapu Bulu used Celebrate!");
|
||||
MESSAGE("The opposing Wobbuffet used Celebrate!");
|
||||
|
||||
MESSAGE("Wobbuffet used Celebrate!");
|
||||
MESSAGE("Tapu Bulu used Celebrate!");
|
||||
MESSAGE("The opposing Wobbuffet used Celebrate!");
|
||||
|
||||
MESSAGE("The grass disappeared from the battlefield.");
|
||||
|
|
|
@ -12,7 +12,7 @@ all: mgba-rom-test-hydra$(EXE)
|
|||
@:
|
||||
|
||||
mgba-rom-test-hydra$(EXE): $(SRCS)
|
||||
$(CC) $(SRCS) -o $@ -lm $(LDFLAGS)
|
||||
$(CC) $(SRCS) -Werror=implicit-function-declaration -o $@ -lm $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) mgba-rom-test-hydra$(EXE)
|
||||
|
|
|
@ -106,6 +106,28 @@ static const struct Symbol *lookup_address(uint32_t address)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
// Very naive implementation of 'memmem' for systems which don't make it
|
||||
// available by default.
|
||||
void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
|
||||
{
|
||||
const char *haystack_ = haystack;
|
||||
const char *needle_ = needle;
|
||||
for (size_t i = 0; i < haystacklen - needlelen; i++)
|
||||
{
|
||||
size_t j;
|
||||
for (j = 0; j < needlelen; j++)
|
||||
{
|
||||
if (haystack_[i+j] != needle_[j])
|
||||
break;
|
||||
}
|
||||
if (j == needlelen)
|
||||
return (void *)&haystack_[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Similar to 'fwrite(buffer, 1, size, f)' except that anything which
|
||||
// looks like the output of '%p' (i.e. '<0x\d{7}>') is translated into
|
||||
// the name of a symbol (if it represents one).
|
||||
|
|
Loading…
Reference in a new issue