added trainer see double battle and more overworld configs

This commit is contained in:
cawtds
2024-07-28 12:47:27 +02:00
parent 2d09a14b02
commit 55b67e23ee
48 changed files with 892 additions and 285 deletions

View File

@@ -1741,6 +1741,17 @@
.2byte \quantity
.endm
@ Sets the selected object to the id of the currently approaching trainer.
.macro selectapproachingtrainer
.byte 0xd5
.endm
@ Freezes all objects immediately except the player and the approaching trainers.
@ The player and trainers are frozen once their movement is finished.
.macro lockfortrainer
.byte 0xd6
.endm
.macro _dynmultichoice left:req, top:req, ignoreBPress:req, maxBeforeScroll:req, shouldSort:req, initialSelected:req, callbacks:req argv:vararg
.byte 0xe3
.2byte \left

View File

@@ -23,12 +23,23 @@
.align 2
BattleScript_LocalTrainerBattleWon::
jumpifbattletype BATTLE_TYPE_TWO_OPPONENTS, BattleScript_LocalTwoTrainersDefeated
printstring STRINGID_PLAYERDEFEATEDTRAINER1
goto BattleScript_LocalBattleWonLoseTexts
BattleScript_LocalTwoTrainersDefeated::
printstring STRINGID_TWOENEMIESDEFEATED
BattleScript_LocalBattleWonLoseTexts::
trainerslidein BS_ATTACKER
waitstate
printstring STRINGID_TRAINER1LOSETEXT
getmoneyreward
jumpifnotbattletype BATTLE_TYPE_TWO_OPPONENTS, BattleScript_LocalTrainerBattleWonGotMoney
trainerslideout B_POSITION_OPPONENT_LEFT
waitstate
trainerslidein BS_FAINTED
waitstate
printstring STRINGID_TRAINER2LOSETEXT
BattleScript_LocalTrainerBattleWonGotMoney::
getmoneyreward
printstring STRINGID_PLAYERGOTMONEY
waitmessage B_WAIT_TIME_LONG
BattleScript_PayDayMoneyAndPickUpItems::

View File

@@ -886,10 +886,6 @@ Text_GiveNicknameToReceivedMon::
.string "Want to give a nickname to the\n"
.string "{STR_VAR_2} you received?$"
gText_PkmnFainted3::
.string "{STR_VAR_1} fainted…\p"
.string "$"
Text_WelcomeWantToHealPkmn::
.string "Welcome to our POKéMON CENTER!\p"
.string "Would you like me to heal your\n"

View File

@@ -214,6 +214,8 @@ gScriptCmdTable::
.4byte ScrCmd_setmonmetlocation @ 0xd2
.4byte ScrCmd_getbraillestringwidth @ 0xd3
.4byte ScrCmd_bufferitemnameplural @ 0xd4
.4byte ScrCmd_selectapproachingtrainer @ 0xd5
.4byte ScrCmd_lockfortrainer @ 0xd6
gScriptCmdTableEnd::
.4byte ScrCmd_nop

View File

@@ -1,9 +1,11 @@
EventScript_DoTrainerBattleFromApproach::
lock
selectapproachingtrainer
lockfortrainer
EventScript_TrainerApproach::
special PlayTrainerEncounterMusic
special EndTrainerApproach
waitstate
goto EventScript_DoTrainerBattle
goto EventScript_ShowTrainerIntroMsg
EventScript_TryDoNormalTrainerBattle::
lock
@@ -16,7 +18,7 @@ EventScript_TryDoNormalTrainerBattle::
goto_if_ne VAR_RESULT, FALSE, EventScript_NoTrainerBattle
special PlayTrainerEncounterMusic
special SetUpTrainerMovement
goto EventScript_DoTrainerBattle
goto EventScript_ShowTrainerIntroMsg
EventScript_NoTrainerBattle::
gotopostbattlescript
@@ -31,7 +33,7 @@ EventScript_TryDoDoubleTrainerBattle::
goto_if_ne VAR_RESULT, PLAYER_HAS_TWO_USABLE_MONS, EventScript_NotEnoughMonsForDoubleBattle
special PlayTrainerEncounterMusic
special SetUpTrainerMovement
goto EventScript_DoTrainerBattle
goto EventScript_ShowTrainerIntroMsg
EventScript_NotEnoughMonsForDoubleBattle::
special ShowTrainerCantBattleSpeech
@@ -112,10 +114,15 @@ Movement_RevealTrainer::
reveal_trainer
step_end
EventScript_DoTrainerBattle::
EventScript_ShowTrainerIntroMsg::
special ShowTrainerIntroSpeech
waitmessage
waitbuttonpress
special TryPrepareSecondApproachingTrainer
goto_if_eq VAR_RESULT, TRUE, EventScript_TrainerApproach
goto EventScript_DoTrainerBattle
EventScript_DoTrainerBattle::
goto_if_questlog EventScript_EndQuestLogBattle
dotrainerbattle
specialvar VAR_RESULT, GetTrainerBattleMode

View File

@@ -456,4 +456,5 @@ gSpecials::
def_special GetSprayId
def_special GetLastUsedSprayType
def_special TrySkyBattle
def_special TryPrepareSecondApproachingTrainer
gSpecialsEnd::

View File

@@ -995,8 +995,6 @@ extern u8 gBattleOutcome;
extern u16 gLastUsedItem;
extern u32 gBattleTypeFlags;
extern struct MonSpritesGfx *gMonSpritesGfxPtr;
extern u16 gTrainerBattleOpponent_A;
extern u16 gTrainerBattleOpponent_B;
extern u16 gMoveToLearn;
extern u16 gBattleMovePower;
extern struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT];

View File

@@ -266,7 +266,7 @@ void BattleControllerComplete(u32 battler); // Can be used for all the controlle
void BtlController_Empty(u32 battler); // Empty command, does nothing, only completes the execution.
void BtlController_TerminatorNop(u32 battler); // Dummy function at the end of the table.
void BattleControllerDummy(u32 battler);
void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit);
void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit, bool32 doSlideIn);
void Controller_WaitForString(u32 battler);
// handlers

View File

@@ -38,15 +38,11 @@ enum
#define TAG_HEALTHBOX_PALS_1 55049
#define TAG_HEALTHBOX_PALS_2 55050
#define TAG_HEALTHBOX_SAFARI_TILE 55051
#define TAG_PARTY_SUMMARY_BAR_PLAYER_TILE 55052
#define TAG_PARTY_SUMMARY_BAR_OPPONENT_TILE 55053
#define TAG_PARTY_SUMMARY_BAR_TILE 55052
#define TAG_PARTY_SUMMARY_BAR_PLAYER_PAL 55056
#define TAG_PARTY_SUMMARY_BAR_OPPONENT_PAL 55057
#define TAG_PARTY_SUMMARY_BALL_PLAYER_PAL 55058
#define TAG_PARTY_SUMMARY_BALL_OPPONENT_PAL 55059
#define TAG_PARTY_SUMMARY_BALL_PLAYER_TILE 55060
#define TAG_PARTY_SUMMARY_BALL_OPPONENT_TILE 55061
#define TAG_PARTY_SUMMARY_BAR_PAL 55056
#define TAG_PARTY_SUMMARY_BALL_PAL 55058
#define TAG_PARTY_SUMMARY_BALL_TILE 55060
#define TAG_HEALTHBOX_PAL TAG_HEALTHBOX_PLAYER1_TILE
#define TAG_HEALTHBAR_PAL TAG_HEALTHBAR_PLAYER1_TILE

View File

@@ -92,6 +92,7 @@ void SpriteCB_FaintSlideAnim(struct Sprite *sprite);
void DoBounceEffect(u8 battler, u8 which, s8 delta, s8 amplitude);
void EndBounceEffect(u8 battler, u8 which);
void SpriteCB_PlayerMonFromBall(struct Sprite *sprite);
void SpriteCB_PlayerMonSlideIn(struct Sprite *sprite);
void SpriteCB_PlayerThrowInit(struct Sprite *sprite);
void UpdatePlayerPosInThrowAnim(struct Sprite *sprite);
void BeginBattleIntroDummy(void);

View File

@@ -1,8 +1,8 @@
#ifndef GUARD_BATTLE_SETUP_H
#define GUARD_BATTLE_SETUP_H
#include "global.h"
extern u16 gTrainerBattleOpponent_A;
extern u16 gTrainerBattleOpponent_B;
extern u16 gPartnerTrainerId;
void StartWildBattle(void);
@@ -17,8 +17,11 @@ void StartGroudonKyogreBattle(void);
void StartRegiBattle(void);
u8 BattleSetup_GetTerrainId(void);
u8 BattleSetup_GetBattleTowerBattleTransition(void);
void ResetTrainerOpponentIds(void);
const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data);
void ConfigureAndSetUpOneTrainerBattle(u8 trainerEventObjId, const u8 *trainerScript);
void ConfigureTwoTrainersBattle(u8 trainerObjEventId, const u8 *trainerScript);
void SetUpTwoTrainersBattle(void);
bool32 GetTrainerFlagFromScriptPointer(const u8 *data);
void SetUpTrainerMovement(void);
u8 GetTrainerBattleMode(void);
@@ -27,7 +30,7 @@ void SetBattledTrainerFlag(void);
bool8 HasTrainerBeenFought(u16 trainerId);
void SetTrainerFlag(u16 trainerId);
void ClearTrainerFlag(u16 trainerId);
void StartTrainerBattle(void);
void BattleSetup_StartTrainerBattle(void);
void StartRematchBattle(void);
void ShowTrainerIntroSpeech(void);
const u8 *BattleSetup_GetScriptAddrAfterBattle(void);
@@ -35,6 +38,7 @@ const u8 *BattleSetup_GetTrainerPostBattleScript(void);
void ShowTrainerCantBattleSpeech(void);
void PlayTrainerEncounterMusic(void);
const u8 *GetTrainerALoseText(void);
const u8 *GetTrainerBLoseText(void);
const u8 *GetTrainerWonSpeech(void);
void BattleSetup_StartTrainerBattle_Debug(void);

View File

@@ -29,7 +29,7 @@ extern const u16 gBattleTowerBannedSpecies[];
void ClearEReaderTrainer(struct BattleTowerEReaderTrainer *);
void ValidateEReaderTrainer(void);
u8 GetBattleTowerTrainerFrontSpriteId(void);
u8 GetBattleTowerTrainerFrontSpriteId(u16 trainerId);
u8 GetEreaderTrainerFrontSpriteId(void);
void CopyEReaderTrainerName5(u8 *dest);
void GetBattleTowerTrainerName(u8 *text);

View File

@@ -6,7 +6,6 @@
// Other settings
#define OW_POISON_DAMAGE GEN_LATEST // In Gen4, Pokémon no longer faint from Poison in the overworld. In Gen5+, they no longer take damage at all.
#define OW_TIMES_OF_DAY GEN_LATEST // Different generations have the times of day change at different times.
#define OW_DOUBLE_APPROACH_WITH_ONE_MON FALSE // If enabled, you can be spotted by two trainers at the same time even if you only have one eligible Pokémon in your party.
#define OW_HIDE_REPEAT_MAP_POPUP FALSE // If enabled, map popups will not appear if entering a map with the same Map Section Id as the last.
@@ -44,7 +43,7 @@
// (You should not use 48x48 sprites/tables for compressed gfx)
// 16x32, 32x32, 64x64 etc are fine
// Follower Pokémon
#define OW_FOLLOWERS_ENABLED TRUE // Enables follower Pokémon, HGSS style. Requires OW_POKEMON_OBJECT_EVENTS.
#define OW_FOLLOWERS_ENABLED FALSE // Enables follower Pokémon, HGSS style. Requires OW_POKEMON_OBJECT_EVENTS. Note that additional scripting may be required for them to be fully supported!
#define OW_FOLLOWERS_BOBBING TRUE // If true, follower pokemon will bob up and down during their idle & walking animations
#define OW_FOLLOWERS_POKEBALLS TRUE // Followers will emerge from the pokeball they are stored in, instead of a normal pokeball
@@ -59,9 +58,18 @@
#define OW_STORM_DRAIN GEN_LATEST // In Gen8+, if a Pokémon with Storm Drain is leading the party, there is a 50% chance to encounter a Water-type Pokémon.
#define OW_FLASH_FIRE GEN_LATEST // In Gen8+, if a Pokémon with Flash Fire is leading the party, there is a 50% chance to encounter a Fire-type Pokémon.
// These generational defines only make a distinction for OW_ALTERED_TIME_RATIO
#define GEN_8_PLA GEN_LATEST + 2
//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. This has no effect if OW_USE_FAKE_RTC is FALSE.
// Overworld flags
// 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 OW_FLAG_PAUSE_TIME 0 // If this flag is set and OW_USE_FAKE_RTC is enabled, seconds on the in-game clock will not advance.
#define OW_FLAG_NO_ENCOUNTER 0 // If this flag is set, wild encounters will be disabled.
#define OW_FLAG_NO_TRAINER_SEE 0 // If this flag is set, trainers will not battle the player unless they're talked to.
#define OW_FLAG_NO_COLLISION 0 // If this flag is set, the player will be able to walk over tiles with collision. Mainly intended for debugging purposes.
@@ -82,8 +90,11 @@
#define OW_POPUP_BW_COLOR_WHITE 1 // White pop-up from W2
// Configuration
#define OW_POPUP_BW_COLOR OW_POPUP_BW_COLOR_BLACK // B2W2 use different colors for their map pop-ups.
#define OW_POPUP_BW_COLOR OW_POPUP_BW_COLOR_BLACK // B2W2 use different colors for their map pop-ups.
#define OW_POPUP_BW_TIME_MODE OW_POPUP_BW_TIME_NONE // Determines what type of time is shown.
#define OW_POPUP_BW_ALPHA_BLEND FALSE // Enables alpha blending/transparency for the pop-ups. Mainly intended to be used with the black color option.
// Pokémon Center
#define OW_IGNORE_EGGS_ON_HEAL GEN_LATEST // In Gen 4+, the nurse in the Pokémon Center does not heal Eggs on healing machine.
#endif // GUARD_CONFIG_OVERWORLD_H

View File

@@ -7,8 +7,9 @@ bool8 IsFreezePlayerFinished(void);
void FreezeObjects_WaitForPlayer(void);
bool8 IsFreezeSelectedObjectAndPlayerFinished(void);
void FreezeObjects_WaitForPlayerAndSelected(void);
void FreezeForApproachingTrainers(void);
void ClearPlayerHeldMovementAndUnfreezeObjectEvents(void);
bool8 walkrun_is_standing_still(void);
bool8 IsPlayerStandingStill(void);
void UnionRoom_UnlockPlayerAndChatPartner(void);
#endif // GUARD_EVENT_OBJECT_LOCK_H

View File

@@ -1,6 +1,10 @@
#ifndef GUARD_EVENT_OBJECT_MOVEMENT_H
#define GUARD_EVENT_OBJECT_MOVEMENT_H
#if OW_POKEMON_OBJECT_EVENTS == FALSE && OW_FOLLOWERS_ENABLED == TRUE
#error "OW_POKEMON_OBJECT_EVENTS needs to be TRUE in order for OW_FOLLOWERS_ENABLED to work."
#endif
// Palette slots for overworld NPCs.
// The same standard set of palettes for overworld objects are normally always loaded at the same
// time while walking around the overworld. The only exceptions are the palettes for the player and
@@ -108,7 +112,7 @@ struct ObjectEvent *GetFollowerObject(void);
u8 CreateVirtualObject(u16 graphicsId, u8 virtualObjId, s16 x, s16 y, u8 elevation, u8 direction);
u8 CreateObjectGraphicsSprite(u16 graphicsId, SpriteCallback callback, s16 x, s16 y, u8 subpriority);
u8 TrySpawnObjectEvent(u8 localId, u8 mapNum, u8 mapGroup);
int SpawnSpecialObjectEventParameterized(u16 graphicsId, u8 movementBehavior, u8 localId, s16 x, s16 y, u8 elevation);
u32 SpawnSpecialObjectEventParameterized(u16 graphicsId, u8 movementBehavior, u8 localId, s16 x, s16 y, u8 elevation);
u8 SpawnSpecialObjectEvent(struct ObjectEventTemplate *);
void CameraObjectReset1(void);
void CameraObjectReset2(void);
@@ -178,6 +182,7 @@ void FreezeObjectEvents(void);
bool8 FreezeObjectEvent(struct ObjectEvent *);
void UnfreezeObjectEvent(struct ObjectEvent *);
void FreezeObjectEventsExceptOne(u8 objEventId);
void FreezeObjectEventsExceptTwo(u8 objectEventId1, u8 objectEventId2);
void SetVirtualObjectGraphics(u8 virtualObjId, u16 graphicsId);
void SetVirtualObjectInvisibility(u8 virtualObjId, bool32 invisible);
bool32 IsVirtualObjectInvisible(u8 virtualObjId);

View File

@@ -50,6 +50,7 @@ extern const struct SpriteTemplate gBallSpriteTemplates[];
#define POKEBALL_PLAYER_SENDOUT 0xFF
#define POKEBALL_OPPONENT_SENDOUT 0xFE
#define POKEBALL_PLAYER_SLIDEIN 0xFD
u8 DoPokeballSendOutAnimation(u32 battler, s16 pan, u8 kindOfThrow);
void CreatePokeballSpriteToReleaseMon(u8 monSpriteId, u8 monPalNum, u8 x, u8 y, u8 oamPriority, u8 subpriortiy, u8 delay, u32 fadePalettes);

View File

@@ -762,6 +762,7 @@ u8 GiveMonToPlayer(struct Pokemon *mon);
u8 CalculatePlayerPartyCount(void);
u8 CalculateEnemyPartyCount(void);
u8 GetMonsStateToDoubles(void);
u8 GetMonsStateToDoubles_2(void);
u16 GetAbilityBySpecies(u16 species, u8 abilityNum);
u16 GetMonAbility(struct Pokemon *mon);
u8 GetSecretBaseTrainerPicIndex(void);

View File

@@ -64,7 +64,6 @@ void RecordedBattle_ClearBattlerAction(u8 battlerId, u8 bytesToClear);
u8 RecordedBattle_GetBattlerAction(u32 actionType, u8 battlerId);
u8 RecordedBattle_BufferNewBattlerData(u8 *dst);
void RecordedBattle_RecordAllBattlerData(u8 *data);
bool32 MoveRecordedBattleToSaveData(void);
void SetPartiesFromRecordedSave(struct RecordedBattleSave *src);
void SetVariablesForRecordedBattle(struct RecordedBattleSave *);
void RecordedBattle_SaveParties(void);

View File

@@ -72,6 +72,9 @@ bool8 CanWalkAwayToCancelMsgBox(void);
void SetWalkingIntoSignVars(void);
bool8 IsMsgBoxWalkawayDisabled(void);
// srccmd.h
void SetMovingNpcId(u16 npcId);
extern const u8 *gRamScriptRetAddr;
extern u8 gWalkAwayFromSignInhibitTimer;

View File

@@ -83,7 +83,7 @@ extern const u8 gText_RegisteredDataDeleted[];
extern const u8 gText_Confirm3[];
extern const u8 gText_Cancel4[];
extern const u8 gText_IsThisTheCorrectTime[];
extern const u8 gText_PkmnFainted3[];
extern const u8 gText_PkmnFainted_FldPsn[];
extern const u8 gText_Coins[];
extern const u8 gText_EggNickname[];
extern const u8 gText_MenuPokemon[];

View File

@@ -1,10 +1,19 @@
#ifndef GUARD_TRAINER_SEE_H
#define GUARD_TRAINER_SEE_H
#include "global.h"
struct ApproachingTrainer
{
u8 objectEventId;
u8 radius; // plus 1
const u8 *trainerScriptPtr;
u8 taskId;
};
extern u16 gWhichTrainerToFaceAfterBattle;
extern struct ApproachingTrainer gApproachingTrainers[2];
extern u8 gNoOfApproachingTrainers;
extern bool8 gTrainerApproachedPlayer;
extern u8 gApproachingTrainerId;
bool8 CheckForTrainersWantingBattle(void);
void MovementAction_RevealTrainer_RunTrainerSeeFuncList(struct ObjectEvent *var);
@@ -13,5 +22,8 @@ u8 FldEff_DoubleExclMarkIcon(void);
u8 FldEff_XIcon(void);
u8 FldEff_SmileyFaceIcon(void);
u8 FldEff_QuestionMarkIcon(void);
u8 GetCurrentApproachingTrainerObjectEventId(void);
u8 GetChosenApproachingTrainerObjectEventId(u8 arrayId);
void TryPrepareSecondApproachingTrainer(void);
#endif //GUARD_TRAINER_SEE_H

View File

@@ -4,6 +4,7 @@
#include "battle_anim.h"
#include "battle_bg.h"
#include "battle_message.h"
#include "battle_setup.h"
#include "battle_terrain.h"
#include "decompress.h"
#include "graphics.h"

View File

@@ -4,6 +4,7 @@
#include "battle_controllers.h"
#include "battle_interface.h"
#include "battle_message.h"
#include "battle_setup.h"
#include "gflib.h"
#include "data.h"
#include "link.h"

View File

@@ -8,14 +8,15 @@
#include "random.h"
#include "battle.h"
#include "battle_ai_main.h"
#include "battle_ai_switch_items.h"
#include "battle_ai_util.h"
#include "battle_anim.h"
#include "battle_controllers.h"
#include "battle_message.h"
#include "battle_interface.h"
#include "battle_tower.h"
#include "battle_gfx_sfx_util.h"
#include "battle_ai_switch_items.h"
#include "battle_interface.h"
#include "battle_message.h"
#include "battle_setup.h"
#include "battle_tower.h"
#include "battle_z_move.h"
#include "link.h"
#include "party_menu.h"
@@ -136,32 +137,60 @@ static void Intro_DelayAndEnd(u32 battler)
static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
{
bool8 var = FALSE;
bool8 healthboxAnimDone = FALSE;
bool8 twoMons;
if (!IsDoubleBattle() || ((IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI))))
twoMons = TwoOpponentIntroMons(battler);
if (!twoMons || ((twoMons && (gBattleTypeFlags & BATTLE_TYPE_MULTI) && !BATTLE_TWO_VS_ONE_OPPONENT) || (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)))
{
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
var = TRUE;
healthboxAnimDone = TRUE;
twoMons = FALSE;
}
else if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == gSprites[gHealthboxSpriteIds[battler]].callback)
else
{
var = TRUE;
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
healthboxAnimDone = TRUE;
twoMons = TRUE;
}
if (IsCryPlayingOrClearCrySongs())
var = FALSE;
if (var && gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim && gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
if (healthboxAnimDone)
{
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
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);
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
m4aMPlayContinue(&gMPlayInfo_BGM);
if (twoMons == TRUE)
{
if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim
&& gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
{
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
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);
}
else
return;
}
else if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
{
if (GetBattlerPosition(battler) == 3)
{
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
{
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
}
else
return;
}
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
}
else
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 256);
return;
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3;
gBattlerControllerFuncs[battler] = Intro_DelayAndEnd;
}
@@ -169,30 +198,93 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
static void Intro_TryShinyAnimShowHealthbox(u32 battler)
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim && !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
bool32 bgmRestored = FALSE;
bool32 battlerAnimsDone = FALSE;
bool32 twoMons;
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim)
TryShinyAnimation(battler, &gEnemyParty[gBattlerPartyIndexes[battler]]);
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
twoMons = TwoOpponentIntroMons(battler);
if (!(gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
&& (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT)
&& twoMons
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
TryShinyAnimation(BATTLE_PARTNER(battler), &gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]);
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
{
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
if (!gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted)
{
if (twoMons && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT))
{
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], &gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], HEALTHBOX_ALL);
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
}
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gEnemyParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
}
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = TRUE;
}
if (!gBattleSpritesDataPtr->healthBoxesData[battler].waitForCry
&& gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].waitForCry
&& !IsCryPlayingOrClearCrySongs())
{
if (!gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored)
{
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
{
if (GetBattlerPosition(battler) == 1)
m4aMPlayContinue(&gMPlayInfo_BGM);
}
else
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
}
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = TRUE;
bgmRestored = TRUE;
}
if (!twoMons || (twoMons && gBattleTypeFlags & BATTLE_TYPE_MULTI && !BATTLE_TWO_VS_ONE_OPPONENT))
{
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)
{
battlerAnimsDone = TRUE;
}
}
else
{
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy
&& gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy
&& gSprites[gBattlerSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
{
battlerAnimsDone = TRUE;
}
}
if (bgmRestored && battlerAnimsDone)
{
if (twoMons && (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) || BATTLE_TWO_VS_ONE_OPPONENT))
{
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)],
&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]],
HEALTHBOX_ALL);
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
SetBattlerShadowSpriteCallback(BATTLE_PARTNER(battler), GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], MON_DATA_SPECIES));
}
DestroySprite(&gSprites[gBattleControllerData[battler]]);
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler],
&gEnemyParty[gBattlerPartyIndexes[battler]],
HEALTHBOX_ALL);
StartHealthboxSlideIn(battler);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
SetBattlerShadowSpriteCallback(battler, GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES));
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = FALSE;
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = FALSE;
gBattlerControllerFuncs[battler] = Intro_WaitForShinyAnimAndHealthbox;
}
}
@@ -298,11 +390,30 @@ static u32 OpponentGetTrainerPicId(u32 battlerId) // TODO: trainer refactoring
u32 trainerPicId;
if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
trainerPicId = GetBattleTowerTrainerFrontSpriteId();
{
if (gBattleTypeFlags & (BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_TOWER_LINK_MULTI))
{
if (battlerId == 1)
trainerPicId = GetBattleTowerTrainerFrontSpriteId(gTrainerBattleOpponent_A);
else
trainerPicId = GetBattleTowerTrainerFrontSpriteId(gTrainerBattleOpponent_B);
}
else
{
trainerPicId = GetBattleTowerTrainerFrontSpriteId(gTrainerBattleOpponent_A);
}
}
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER)
trainerPicId = GetTrainerTowerTrainerFrontSpriteId();
else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER)
trainerPicId = GetEreaderTrainerFrontSpriteId();
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
if (battlerId != 1)
trainerPicId = GetTrainerPicFromId(gTrainerBattleOpponent_B);
else
trainerPicId = GetTrainerPicFromId(gTrainerBattleOpponent_A);
}
else
trainerPicId = GetTrainerPicFromId(gTrainerBattleOpponent_A);
@@ -336,7 +447,7 @@ static void OpponentHandleTrainerSlide(u32 battler)
}
static void OpponentHandleTrainerSlideBack(u32 battler)
{
{
BtlController_HandleTrainerSlideBack(battler, 35, FALSE);
}

View File

@@ -396,7 +396,10 @@ static void RecordedOpponentHandleDrawTrainerPic(u32 battler)
if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
{
trainerPicId = GetBattleTowerTrainerFrontSpriteId();
if (battler == B_POSITION_OPPONENT_LEFT)
trainerPicId = GetBattleTowerTrainerFrontSpriteId(gTrainerBattleOpponent_A);
else
trainerPicId = GetBattleTowerTrainerFrontSpriteId(gTrainerBattleOpponent_B);
}
else
{

View File

@@ -6,7 +6,9 @@
#include "battle_controllers.h"
#include "battle_interface.h"
#include "battle_message.h"
#include "battle_setup.h"
#include "cable_club.h"
#include "event_object_movement.h"
#include "link.h"
#include "link_rfu.h"
#include "palette.h"
@@ -19,9 +21,9 @@
#include "test_runner.h"
#include "text.h"
#include "util.h"
#include "constants/abilities.h"
#include "constants/songs.h"
#include "constants/sound.h"
#include "constants/abilities.h"
static EWRAM_DATA u8 sLinkSendTaskId = 0;
static EWRAM_DATA u8 sLinkReceiveTaskId = 0;
@@ -1834,7 +1836,22 @@ static void SetBattlerMonData(u32 battler, struct Pokemon *party, u32 monId)
HandleLowHpMusicChange(&party[gBattlerPartyIndexes[battler]], battler);
}
void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit)
// In normal singles, if follower pokemon is out, have it slide in instead of being thrown
static bool8 ShouldDoSlideInAnim(void)
{
struct ObjectEvent *followerObj = GetFollowerObject();
if (!followerObj || followerObj->invisible)
return FALSE;
if (gBattleTypeFlags & (
BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_FIRST_BATTLE |
BATTLE_TYPE_SAFARI | BATTLE_TYPE_OLD_MAN_TUTORIAL | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TWO_OPPONENTS |
BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED | BATTLE_TYPE_POKEDUDE | BATTLE_TYPE_TRAINER_TOWER)
)
return FALSE;
return TRUE;
}
void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit, bool32 doSlideIn)
{
u16 species;
u32 side = GetBattlerSide(battler);
@@ -1865,7 +1882,7 @@ void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit)
gSprites[gBattleControllerData[battler]].data[1] = gBattlerSpriteIds[battler];
gSprites[gBattleControllerData[battler]].data[2] = battler;
gSprites[gBattleControllerData[battler]].data[0] = DoPokeballSendOutAnimation(battler, 0, (side == B_SIDE_OPPONENT) ? POKEBALL_OPPONENT_SENDOUT : POKEBALL_PLAYER_SENDOUT);
gSprites[gBattleControllerData[battler]].data[0] = DoPokeballSendOutAnimation(battler, 0, (side == B_SIDE_OPPONENT) ? POKEBALL_OPPONENT_SENDOUT : (doSlideIn ? POKEBALL_PLAYER_SLIDEIN : POKEBALL_PLAYER_SENDOUT));
}
static void FreeMonSprite(u32 battler)
@@ -2213,7 +2230,7 @@ void BtlController_HandleSwitchInAnim(u32 battler, bool32 isPlayerSide, void (*c
gBattlerPartyIndexes[battler] = gBattleResources->bufferA[battler][1];
if (isPlayerSide)
BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battler]], battler);
StartSendOutAnim(battler, gBattleResources->bufferA[battler][2]);
StartSendOutAnim(battler, gBattleResources->bufferA[battler][2], FALSE);
gBattlerControllerFuncs[battler] = controllerCallback;
}
@@ -2719,17 +2736,17 @@ static void Task_StartSendOutAnim(u8 taskId)
if (TwoMonsAtSendOut(battler))
{
gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler];
StartSendOutAnim(battler, FALSE);
StartSendOutAnim(battler, FALSE, ShouldDoSlideInAnim());
battlerPartner = BATTLE_PARTNER(battler);
gBattleResources->bufferA[battlerPartner][1] = gBattlerPartyIndexes[battlerPartner];
BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battlerPartner]], battlerPartner);
StartSendOutAnim(battlerPartner, FALSE);
StartSendOutAnim(battlerPartner, FALSE, ShouldDoSlideInAnim());
}
else
{
gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler];
StartSendOutAnim(battler, FALSE);
StartSendOutAnim(battler, FALSE, ShouldDoSlideInAnim());
}
gBattlerControllerFuncs[battler] = (void*)(GetWordTaskArg(taskId, tControllerFunc_1));
DestroyTask(taskId);

View File

@@ -697,8 +697,7 @@ void CB2_BattleDebugMenu(void)
break;
case 3:
LoadPalette(sBgColor, 0, 2);
// LoadPalette(GetOverworldTextboxPalettePtr(), 0xf0, 16); // TODO: debug
LoadPalette(GetTextWindowPalette(2), 0xC0, 0x20);
LoadPalette(GetTextWindowPalette(2), 0xf0, 16);
gMain.state++;
break;
case 4:
@@ -1213,6 +1212,7 @@ static void Task_DebugMenuProcessInput(u8 taskId)
{
data->currentSecondaryListItemId = listItemId;
data->modifyWindowId = AddWindow(&sModifyWindowTemplate);
ClearStdWindowAndFrameToTransparent(data->modifyWindowId, TRUE); // FRLG change: fixes number background
PutWindowTilemap(data->modifyWindowId);
CopyWindowToVram(data->modifyWindowId, COPYWIN_FULL);
SetUpModifyArrows(data);

View File

@@ -367,24 +367,30 @@ static const struct SubspriteTable sStatusSummaryBar_SubspriteTable_Exit[] = {
static const u16 sBattleInterface_Unused[] = INCBIN_U16("graphics/battle_interface/unused.4bpp");
static const struct CompressedSpriteSheet sPartySummaryBarSpriteSheets[] = {
{gBattleInterface_PartySummaryBar_Gfx, 16 * TILE_SIZE_4BPP, TAG_PARTY_SUMMARY_BAR_PLAYER_TILE},
{gBattleInterface_PartySummaryBar_Gfx, 16 * TILE_SIZE_4BPP, TAG_PARTY_SUMMARY_BAR_OPPONENT_TILE}
static const struct CompressedSpriteSheet sStatusSummaryBarSpriteSheet =
{
.data = gBattleInterface_PartySummaryBar_Gfx,
.size = 16 * TILE_SIZE_4BPP,
.tag = TAG_PARTY_SUMMARY_BAR_TILE,
};
static const struct SpritePalette sPartySummaryBarSpritePals[] = {
{gBattleInterface_Healthbox_Pal, TAG_PARTY_SUMMARY_BAR_PLAYER_PAL},
{gBattleInterface_Healthbox_Pal, TAG_PARTY_SUMMARY_BAR_OPPONENT_PAL}
static const struct SpritePalette sPartySummaryBarSpritePals =
{
.data = gBattleInterface_Healthbox_Pal,
.tag = TAG_PARTY_SUMMARY_BAR_PAL,
};
static const struct SpritePalette sPartySummaryBallSpritePals[] = {
{gBattleInterface_Healthbar_Pal, TAG_PARTY_SUMMARY_BALL_PLAYER_PAL},
{gBattleInterface_Healthbar_Pal, TAG_PARTY_SUMMARY_BALL_OPPONENT_PAL}
static const struct SpritePalette sPartySummaryBallSpritePals =
{
.data = gBattleInterface_Healthbar_Pal,
.tag = TAG_PARTY_SUMMARY_BALL_PAL,
};
static const struct SpriteSheet sPartySummaryBallSpriteSheets[] = {
{gBattleInterface_Gfx + B_INTERFACE_GFX_BALL_PARTY_SUMMARY, 4 * TILE_SIZE_4BPP, TAG_PARTY_SUMMARY_BALL_PLAYER_TILE},
{gBattleInterface_Gfx + B_INTERFACE_GFX_BALL_PARTY_SUMMARY, 4 * TILE_SIZE_4BPP, TAG_PARTY_SUMMARY_BALL_OPPONENT_TILE}
static const struct SpriteSheet sPartySummaryBallSpriteSheets =
{
.data = gBattleInterface_Gfx + B_INTERFACE_GFX_BALL_PARTY_SUMMARY,
.size = 4 * TILE_SIZE_4BPP,
.tag = TAG_PARTY_SUMMARY_BALL_TILE,
};
// Unused
@@ -402,15 +408,15 @@ static const struct OamData sOamData_PartySummaryBall = {
static const struct SpriteTemplate sPartySummaryBarSpriteTemplates[] = {
{
.tileTag = TAG_PARTY_SUMMARY_BAR_PLAYER_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BAR_PLAYER_PAL,
.tileTag = TAG_PARTY_SUMMARY_BAR_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BAR_PAL,
.oam = &sOamData_Healthbox,
.anims = gDummySpriteAnimTable,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_PartySummaryBar
}, {
.tileTag = TAG_PARTY_SUMMARY_BAR_OPPONENT_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BAR_OPPONENT_PAL,
.tileTag = TAG_PARTY_SUMMARY_BAR_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BAR_PAL,
.oam = &sOamData_Healthbox,
.anims = gDummySpriteAnimTable,
.affineAnims = gDummySpriteAffineAnimTable,
@@ -420,15 +426,15 @@ static const struct SpriteTemplate sPartySummaryBarSpriteTemplates[] = {
static const struct SpriteTemplate sPartySummaryBallSpriteTemplates[] = {
{
.tileTag = TAG_PARTY_SUMMARY_BALL_PLAYER_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BALL_PLAYER_PAL,
.tileTag = TAG_PARTY_SUMMARY_BALL_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BALL_PAL,
.oam = &sOamData_PartySummaryBall,
.anims = gDummySpriteAnimTable,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCB_PartySummaryBall_OnBattleStart
}, {
.tileTag = TAG_PARTY_SUMMARY_BALL_OPPONENT_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BALL_OPPONENT_PAL,
.tileTag = TAG_PARTY_SUMMARY_BALL_TILE,
.paletteTag = TAG_PARTY_SUMMARY_BALL_PAL,
.oam = &sOamData_PartySummaryBall,
.anims = gDummySpriteAnimTable,
.affineAnims = gDummySpriteAffineAnimTable,
@@ -1125,10 +1131,10 @@ u8 CreatePartyStatusSummarySprites(u8 battlerId, struct HpAndStatus *partyInfo,
nValidMons++;
}
LoadCompressedSpriteSheetUsingHeap(&sPartySummaryBarSpriteSheets[isOpponent]);
LoadSpriteSheet(&sPartySummaryBallSpriteSheets[isOpponent]);
LoadSpritePalette(&sPartySummaryBarSpritePals[isOpponent]);
LoadSpritePalette(&sPartySummaryBallSpritePals[isOpponent]);
LoadCompressedSpriteSheetUsingHeap(&sStatusSummaryBarSpriteSheet);
LoadSpriteSheet(&sPartySummaryBallSpriteSheets);
LoadSpritePalette(&sPartySummaryBarSpritePals);
LoadSpritePalette(&sPartySummaryBallSpritePals);
summaryBarSpriteId = CreateSprite(&sPartySummaryBarSpriteTemplates[isOpponent], x, y, 10);
SetSubspriteTables(&gSprites[summaryBarSpriteId], sStatusSummaryBar_SubspriteTable_Enter);

View File

@@ -90,6 +90,9 @@ s32 GetAnimBgAttribute(u8 bgId, u8 attributeId)
return 0;
}
#define tState data[0]
#define tTerrain data[1]
void HandleIntroSlide(u8 terrain)
{
u8 taskId;
@@ -107,8 +110,9 @@ void HandleIntroSlide(u8 terrain)
{
taskId = CreateTask(sBattleIntroSlideFuncs[terrain], 0);
}
gTasks[taskId].data[0] = 0;
gTasks[taskId].data[1] = terrain;
gTasks[taskId].tState = 0;
gTasks[taskId].tTerrain = terrain;
gTasks[taskId].data[2] = 0;
gTasks[taskId].data[3] = 0;
gTasks[taskId].data[4] = 0;

View File

@@ -50,6 +50,7 @@
#include "constants/moves.h"
#include "constants/pokemon.h"
#include "constants/songs.h"
#include "constants/sound.h"
#include "constants/trainers.h"
static void HandleEndTurn_ContinueBattle(void);
@@ -2145,6 +2146,37 @@ void SpriteCB_PlayerMonFromBall(struct Sprite *sprite)
BattleAnimateBackSprite(sprite, sprite->sSpeciesId);
}
void SpriteCB_PlayerMonSlideIn(struct Sprite *sprite)
{
if (sprite->data[3] == 0)
{
PlaySE(SE_BALL_TRAY_ENTER);
sprite->data[3]++;
}
else if (sprite->data[3] == 1)
{
if (sprite->animEnded)
return;
sprite->data[4] = sprite->x;
sprite->x = -33;
sprite->invisible = FALSE;
sprite->data[3]++;
}
else if (sprite->data[3] < 27)
{
sprite->x += 4;
sprite->data[3]++;
}
else
{
sprite->data[3] = 0;
sprite->x = sprite->data[4];
sprite->data[4] = 0;
sprite->callback = SpriteCB_PlayerMonFromBall;
PlayCry_ByMode(sprite->sSpeciesId, -25, CRY_MODE_NORMAL);
}
}
void SpriteCB_PlayerThrowInit(struct Sprite *sprite)
{
StartSpriteAnim(sprite, 1);

View File

@@ -3178,12 +3178,22 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
}
break;
case B_TXT_TRAINER2_LOSE_TEXT:
GetTrainerTowerOpponentLoseText(gStringVar4, 1);
toCpy = gStringVar4;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER)
{
GetTrainerTowerOpponentLoseText(gStringVar4, 1);
toCpy = gStringVar4;
}
else
{
toCpy = GetTrainerBLoseText();
}
break;
case B_TXT_TRAINER2_WIN_TEXT:
GetTrainerTowerOpponentWinText(gStringVar4, 1);
toCpy = gStringVar4;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER)
{
GetTrainerTowerOpponentWinText(gStringVar4, 1);
toCpy = gStringVar4;
}
break;
case B_TXT_26: // ?
HANDLE_NICKNAME_STRING_CASE(gBattleScripting.battler)
@@ -3240,7 +3250,8 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
// TODO: implement partner trainers?
// if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
// toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name;
toCpy = gTrainerClasses[TRAINER_CLASS_NONE].name;
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
toCpy = gTrainerClasses[gPartnerTrainerId].name;
break;
case B_POSITION_OPPONENT_LEFT:
toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A);
@@ -3267,7 +3278,6 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
break;
case B_TXT_DEF_NAME: // target name
HANDLE_NICKNAME_STRING_CASE(gBattlerTarget)
// GetBattlerNick(gBattlerTarget, text);
toCpy = text;
break;
case B_TXT_DEF_TEAM1:
@@ -3284,12 +3294,15 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
break;
}
// missing if (toCpy != NULL) check
while (*toCpy != EOS)
if (toCpy != NULL)
{
dst[dstId++] = *toCpy;
toCpy++;
while (*toCpy != EOS)
{
dst[dstId++] = *toCpy;
toCpy++;
}
}
if (*src == B_TXT_TRAINER1_LOSE_TEXT || *src == B_TXT_TRAINER1_WIN_TEXT
|| *src == B_TXT_TRAINER2_LOSE_TEXT || *src == B_TXT_TRAINER2_WIN_TEXT)
{

View File

@@ -77,11 +77,14 @@ EWRAM_DATA u16 gTrainerBattleOpponent_B = 0;
EWRAM_DATA u16 gPartnerTrainerId = 0;
static EWRAM_DATA u16 sTrainerObjectEventLocalId = 0;
static EWRAM_DATA u8 *sTrainerAIntroSpeech = NULL;
EWRAM_DATA static u8 *sTrainerBIntroSpeech = NULL;
static EWRAM_DATA u8 *sTrainerADefeatSpeech = NULL;
EWRAM_DATA static u8 *sTrainerBDefeatSpeech = NULL;
static EWRAM_DATA u8 *sTrainerVictorySpeech = NULL;
static EWRAM_DATA u8 *sTrainerCannotBattleSpeech = NULL;
static EWRAM_DATA u8 *sTrainerBattleEndScript = NULL;
static EWRAM_DATA u8 *sTrainerABattleScriptRetAddr = NULL;
EWRAM_DATA static u8 *sTrainerBBattleScriptRetAddr = NULL;
static EWRAM_DATA u16 sRivalBattleFlags = 0;
EWRAM_DATA static bool8 sShouldCheckTrainerBScript = FALSE;
EWRAM_DATA static u8 sNoOfPossibleTrainerRetScripts = 0;
@@ -182,6 +185,49 @@ static const struct TrainerBattleParameter sContinueScriptDoubleBattleParams[] =
{&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR},
};
static const struct TrainerBattleParameter sTrainerBOrdinaryBattleParams[] =
{
{&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT},
{&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT},
{&sTrainerObjectEventLocalId, TRAINER_PARAM_LOAD_VAL_16BIT},
{&sTrainerBIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
{&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
{&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR},
};
static const struct TrainerBattleParameter sTrainerBContinueScriptBattleParams[] =
{
{&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT},
{&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT},
{&sTrainerObjectEventLocalId, TRAINER_PARAM_LOAD_VAL_16BIT},
{&sTrainerBIntroSpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
{&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
{&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_LOAD_VAL_32BIT},
{&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR},
};
// two trainers, each with a defeat speech
static const struct TrainerBattleParameter sTrainerTwoTrainerBattleParams[] =
{
{&sTrainerBattleMode, TRAINER_PARAM_LOAD_VAL_8BIT},
{&sTrainerObjectEventLocalId, TRAINER_PARAM_CLEAR_VAL_16BIT},
{&gTrainerBattleOpponent_A, TRAINER_PARAM_LOAD_VAL_16BIT},
{&sTrainerAIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerADefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
{&gTrainerBattleOpponent_B, TRAINER_PARAM_LOAD_VAL_16BIT},
{&sTrainerBIntroSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerBDefeatSpeech, TRAINER_PARAM_LOAD_VAL_32BIT},
{&sTrainerVictorySpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerCannotBattleSpeech, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerBBattleScriptRetAddr, TRAINER_PARAM_CLEAR_VAL_32BIT},
{&sTrainerBattleEndScript, TRAINER_PARAM_LOAD_SCRIPT_RET_ADDR},
};
#define tState data[0]
#define tTransition data[1]
@@ -705,6 +751,11 @@ static u16 GetTrainerAFlag(void)
return TRAINER_FLAGS_START + gTrainerBattleOpponent_A;
}
static u16 GetTrainerBFlag(void)
{
return TRAINER_FLAGS_START + gTrainerBattleOpponent_B;
}
static bool32 IsPlayerDefeated(u32 battleOutcome)
{
switch (battleOutcome)
@@ -723,17 +774,33 @@ static bool32 IsPlayerDefeated(u32 battleOutcome)
}
}
void ResetTrainerOpponentIds(void)
{
gTrainerBattleOpponent_A = 0;
gTrainerBattleOpponent_B = 0;
}
static void InitTrainerBattleVariables(void)
{
sTrainerBattleMode = 0;
gTrainerBattleOpponent_A = 0;
if (gApproachingTrainerId == 0)
{
sTrainerAIntroSpeech = NULL;
sTrainerADefeatSpeech = NULL;
sTrainerABattleScriptRetAddr = NULL;
}
else
{
sTrainerBIntroSpeech = NULL;
sTrainerBDefeatSpeech = NULL;
sTrainerBBattleScriptRetAddr = NULL;
}
sTrainerObjectEventLocalId = 0;
sTrainerAIntroSpeech = NULL;
sTrainerADefeatSpeech = NULL;
sTrainerVictorySpeech = NULL;
sTrainerCannotBattleSpeech = NULL;
sTrainerBattleEndScript = NULL;
sTrainerABattleScriptRetAddr = NULL;
sRivalBattleFlags = 0;
}
@@ -840,8 +907,15 @@ const u8 *BattleSetup_ConfigureTrainerBattle(const u8 *data)
TrainerBattleLoadArgs(sEarlyRivalBattleParams, data);
return EventScript_DoNoIntroTrainerBattle;
default:
TrainerBattleLoadArgs(sOrdinaryBattleParams, data);
SetMapVarsToTrainer();
if (gApproachingTrainerId == 0)
{
TrainerBattleLoadArgs(sOrdinaryBattleParams, data);
SetMapVarsToTrainer();
}
else
{
TrainerBattleLoadArgs(sTrainerBOrdinaryBattleParams, data);
}
return EventScript_TryDoNormalTrainerBattle;
}
}
@@ -855,6 +929,19 @@ void ConfigureAndSetUpOneTrainerBattle(u8 trainerEventObjId, const u8 *trainerSc
LockPlayerFieldControls();
}
void ConfigureTwoTrainersBattle(u8 trainerObjEventId, const u8 *trainerScript)
{
gSelectedObjectEvent = trainerObjEventId;
gSpecialVar_LastTalked = gObjectEvents[trainerObjEventId].localId;
BattleSetup_ConfigureTrainerBattle(trainerScript + 1);
}
void SetUpTwoTrainersBattle(void)
{
ScriptContext_SetupScript(EventScript_DoTrainerBattleFromApproach);
LockPlayerFieldControls();
}
bool32 GetTrainerFlagFromScriptPointer(const u8 *data)
{
u32 flag = TrainerBattleLoadArg16(data + 2);
@@ -886,6 +973,8 @@ u16 Script_HasTrainerBeenFought(void)
void SetBattledTrainerFlag(void)
{
if (gTrainerBattleOpponent_B != 0)
FlagSet(GetTrainerBFlag());
FlagSet(GetTrainerAFlag());
}
@@ -910,6 +999,9 @@ void BattleSetup_StartTrainerBattle(void)
gBattleTypeFlags = (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_TRAINER);
else
gBattleTypeFlags = (BATTLE_TYPE_TRAINER);
if (GetTrainerBattleMode() == TRAINER_BATTLE_EARLY_RIVAL && GetRivalBattleFlags() & RIVAL_BATTLE_TUTORIAL)
gBattleTypeFlags |= BATTLE_TYPE_FIRST_BATTLE;
sNoOfPossibleTrainerRetScripts = gNoOfApproachingTrainers;
gNoOfApproachingTrainers = 0;
@@ -935,16 +1027,6 @@ void BattleSetup_StartTrainerBattle_Debug(void)
ScriptContext_Stop();
}
void StartTrainerBattle(void)
{
gBattleTypeFlags = BATTLE_TYPE_TRAINER;
if (GetTrainerBattleMode() == TRAINER_BATTLE_EARLY_RIVAL && GetRivalBattleFlags() & RIVAL_BATTLE_TUTORIAL)
gBattleTypeFlags |= BATTLE_TYPE_FIRST_BATTLE;
gMain.savedCallback = CB2_EndTrainerBattle;
DoTrainerBattle();
ScriptContext_Stop();
}
static void SaveChangesToPlayerParty(void)
{
u8 i = 0, j = 0;
@@ -1078,13 +1160,19 @@ void ShowTrainerCantBattleSpeech(void)
void PlayTrainerEncounterMusic(void)
{
u16 trainerId;
u16 music;
if (gApproachingTrainerId == 0)
trainerId = gTrainerBattleOpponent_A;
else
trainerId = gTrainerBattleOpponent_B;
if (!QL_IS_PLAYBACK_STATE
&& sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_NO_MUSIC
&& sTrainerBattleMode != TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE_NO_MUSIC)
{
switch (GetTrainerEncounterMusicId(gTrainerBattleOpponent_A))
switch (GetTrainerEncounterMusicId(trainerId))
{
case TRAINER_ENCOUNTER_MUSIC_FEMALE:
case TRAINER_ENCOUNTER_MUSIC_GIRL:
@@ -1119,7 +1207,10 @@ static const u8 *ReturnEmptyStringIfNull(const u8 *string)
static const u8 *GetIntroSpeechOfApproachingTrainer(void)
{
return ReturnEmptyStringIfNull(sTrainerAIntroSpeech);
if (gApproachingTrainerId == 0)
return ReturnEmptyStringIfNull(sTrainerAIntroSpeech);
else
return ReturnEmptyStringIfNull(sTrainerBIntroSpeech);
}
const u8 *GetTrainerALoseText(void)
@@ -1130,6 +1221,12 @@ const u8 *GetTrainerALoseText(void)
return gStringVar4;
}
const u8 *GetTrainerBLoseText(void)
{
StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(sTrainerBDefeatSpeech));
return gStringVar4;
}
const u8 *GetTrainerWonSpeech(void)
{
StringExpandPlaceholders(gStringVar4, ReturnEmptyStringIfNull(sTrainerVictorySpeech));

View File

@@ -404,20 +404,19 @@ void SetEReaderTrainerGfxId(void)
SetBattleTowerTrainerGfxId(BATTLE_TOWER_EREADER_TRAINER_ID);
}
u8 GetBattleTowerTrainerFrontSpriteId(void)
u8 GetBattleTowerTrainerFrontSpriteId(u16 trainerId)
{
if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
if (trainerId == BATTLE_TOWER_EREADER_TRAINER_ID)
{
return gFacilityClassToPicIndex[gSaveBlock2Ptr->battleTower.ereaderTrainer.trainerClass];
}
else if (gSaveBlock2Ptr->battleTower.battleTowerTrainerId < BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID)
else if (trainerId < BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID)
{
// TODO: fix?
return gFacilityClassToPicIndex[sBattleTowerTrainers[gSaveBlock2Ptr->battleTower.battleTowerTrainerId].trainerClass];
return gFacilityClassToPicIndex[sBattleTowerTrainers[trainerId].trainerClass];
}
else
{
return gFacilityClassToPicIndex[gSaveBlock2Ptr->battleTower.records[gSaveBlock2Ptr->battleTower.battleTowerTrainerId - BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID].trainerClass];
return gFacilityClassToPicIndex[gSaveBlock2Ptr->battleTower.records[trainerId - BATTLE_TOWER_RECORD_MIXING_TRAINER_BASE_ID].trainerClass];
}
}

View File

@@ -252,12 +252,10 @@ bool8 RS_IsRunningDisallowed(u8 r0)
bool32 IsRunningDisallowed(u8 metatileBehavior)
{
if (!gMapHeader.allowRunning)
return TRUE;
if (MetatileBehaviorForbidsBiking(metatileBehavior) != TRUE)
return FALSE;
else
if ((OW_RUNNING_INDOORS == GEN_3 && !gMapHeader.allowRunning) || MetatileBehaviorForbidsBiking(metatileBehavior) == TRUE)
return TRUE;
return FALSE;
}
static bool8 MetatileBehaviorForbidsBiking(u8 metatileBehavior)

View File

@@ -2,6 +2,7 @@
#include "gflib.h"
#include "battle.h"
#include "battle_records.h"
#include "battle_setup.h"
#include "cable_club.h"
#include "event_data.h"
#include "event_scripts.h"

View File

@@ -1,14 +1,15 @@
#include "global.h"
#include "task.h"
#include "field_player_avatar.h"
#include "event_object_movement.h"
#include "script_movement.h"
#include "event_data.h"
#include "event_object_movement.h"
#include "field_player_avatar.h"
#include "script_movement.h"
#include "task.h"
#include "trainer_see.h"
#include "constants/event_objects.h"
bool8 walkrun_is_standing_still(void)
bool8 IsPlayerStandingStill(void)
{
if (gPlayerAvatar.tileTransitionState == 1)
if (gPlayerAvatar.tileTransitionState == T_TILE_TRANSITION)
return FALSE;
else
return TRUE;
@@ -16,7 +17,7 @@ bool8 walkrun_is_standing_still(void)
void Task_WaitPlayerStopMoving(u8 taskId)
{
if (walkrun_is_standing_still())
if (IsPlayerStandingStill())
{
HandleEnforcedLookDirectionOnPlayerStopMoving();
DestroyTask(taskId);
@@ -44,7 +45,7 @@ void Task_WaitPlayerAndTargetNPCStopMoving(u8 taskId)
{
struct Task *task = &gTasks[taskId];
if (task->data[0] == 0 && walkrun_is_standing_still() == TRUE)
if (task->data[0] == 0 && IsPlayerStandingStill() == TRUE)
{
HandleEnforcedLookDirectionOnPlayerStopMoving();
task->data[0] = 1;
@@ -112,3 +113,78 @@ void Script_ClearHeldMovement(void)
{
ObjectEventClearHeldMovementIfActive(&gObjectEvents[gSelectedObjectEvent]);
}
#define tPlayerFrozen data[0]
#define tObjectFrozen data[1]
#define tObjectId data[2]
// Freeze designated object and player once their movement is finished
static void Task_FreezeObjectAndPlayer(u8 taskId)
{
struct Task *task = &gTasks[taskId];
u8 objectEventId = task->tObjectId;
if (!task->tPlayerFrozen && IsPlayerStandingStill() == TRUE)
{
HandleEnforcedLookDirectionOnPlayerStopMoving();
task->tPlayerFrozen = TRUE;
}
if (!task->tObjectFrozen && !gObjectEvents[objectEventId].singleMovementActive)
{
FreezeObjectEvent(&gObjectEvents[objectEventId]);
task->tObjectFrozen = TRUE;
}
if (task->tPlayerFrozen && task->tObjectFrozen)
DestroyTask(taskId);
}
// Freeze all objects immediately except the player and the approaching trainers.
// The approaching trainers and player are frozen once their movement is finished
void FreezeForApproachingTrainers(void)
{
u8 trainerObjectId1, trainerObjectId2, taskId;
struct ObjectEvent *followerObj = GetFollowerObject();
trainerObjectId1 = GetChosenApproachingTrainerObjectEventId(0);
if (gNoOfApproachingTrainers == 2)
{
// Get second trainer, freeze all other objects
trainerObjectId2 = GetChosenApproachingTrainerObjectEventId(1);
FreezeObjectEventsExceptTwo(trainerObjectId1, trainerObjectId2);
// Start task to freeze trainer 1 (and player) after movement
taskId = CreateTask(Task_FreezeObjectAndPlayer, 80);
gTasks[taskId].tObjectId = trainerObjectId1;
if (!gObjectEvents[trainerObjectId1].singleMovementActive)
{
FreezeObjectEvent(&gObjectEvents[trainerObjectId1]);
gTasks[taskId].tObjectFrozen = TRUE;
}
// Start task to freeze trainer 2 after movement
taskId = CreateTask(Task_FreezeObjectAndPlayer, 81);
gTasks[taskId].tObjectId = trainerObjectId2;
if (!gObjectEvents[trainerObjectId2].singleMovementActive)
{
FreezeObjectEvent(&gObjectEvents[trainerObjectId2]);
gTasks[taskId].tObjectFrozen = TRUE;
}
}
else
{
FreezeObjectEventsExceptOne(trainerObjectId1);
taskId = CreateTask(Task_FreezeObjectAndPlayer, 80);
gTasks[taskId].tObjectId = trainerObjectId1;
if (!gObjectEvents[trainerObjectId1].singleMovementActive)
{
FreezeObjectEvent(&gObjectEvents[trainerObjectId1]);
gTasks[taskId].tObjectFrozen = TRUE;
}
}
if (followerObj) // Unfreeze follower so it can move behind player
UnfreezeObjectEvent(followerObj);
}
#undef tPlayerFrozen
#undef tObjectFrozen
#undef tObjectId

View File

@@ -1828,7 +1828,7 @@ u8 SpawnSpecialObjectEvent(struct ObjectEventTemplate *objectEventTemplate)
return TrySpawnObjectEventTemplate(objectEventTemplate, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, cameraX, cameraY);
}
int SpawnSpecialObjectEventParameterized(u16 graphicsId, u8 movementBehavior, u8 localId, s16 x, s16 y, u8 elevation)
u32 SpawnSpecialObjectEventParameterized(u16 graphicsId, u8 movementBehavior, u8 localId, s16 x, s16 y, u8 elevation)
{
struct ObjectEventTemplate objectEventTemplate;
@@ -10281,6 +10281,19 @@ void FreezeObjectEventsExceptOne(u8 noFreeze)
}
}
// Used to freeze other objects except two trainers approaching for battle
void FreezeObjectEventsExceptTwo(u8 objectEventId1, u8 objectEventId2)
{
u8 i;
for(i = 0; i < OBJECT_EVENTS_COUNT; i++)
{
if(i != objectEventId1 && i != objectEventId2 &&
gObjectEvents[i].active && i != gPlayerAvatar.objectEventId)
FreezeObjectEvent(&gObjectEvents[i]);
}
}
void UnfreezeObjectEvent(struct ObjectEvent *objectEvent)
{
if (objectEvent->active && objectEvent->frozen)

View File

@@ -351,7 +351,7 @@ static void Task_ExitDoor(u8 taskId)
}
break;
case 9:
if (FieldFadeTransitionBackgroundEffectIsFinished() && walkrun_is_standing_still() && !FieldIsDoorAnimationRunning() && !FuncIsActiveTask(Task_BarnDoorWipe))
if (FieldFadeTransitionBackgroundEffectIsFinished() && IsPlayerStandingStill() && !FieldIsDoorAnimationRunning() && !FuncIsActiveTask(Task_BarnDoorWipe))
{
ObjectEventClearHeldMovementIfFinished(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]);
task->data[0] = 4;
@@ -367,7 +367,7 @@ static void Task_ExitDoor(u8 taskId)
}
break;
case 2:
if (walkrun_is_standing_still())
if (IsPlayerStandingStill())
{
task->data[1] = FieldAnimateDoorClose(*x, *y);
ObjectEventClearHeldMovementIfFinished(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]);
@@ -409,7 +409,7 @@ static void Task_ExitNonAnimDoor(u8 taskId)
}
break;
case 2:
if (walkrun_is_standing_still())
if (IsPlayerStandingStill())
{
task->data[0] = 3;
}
@@ -747,7 +747,7 @@ static void Task_DoorWarp(u8 taskId)
}
break;
case 2:
if (walkrun_is_standing_still())
if (IsPlayerStandingStill())
{
task->data[1] = FieldAnimateDoorClose(*xp, *yp - 1);
ObjectEventClearHeldMovementIfFinished(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]);

View File

@@ -7,8 +7,10 @@
#include "event_data.h"
#include "fldeff.h"
#include "party_menu.h"
#include "pokemon.h"
#include "field_poison.h"
#include "constants/battle.h"
#include "constants/form_change_types.h"
static bool32 IsMonValidSpecies(struct Pokemon *pokemon)
{
@@ -33,7 +35,8 @@ static void FaintFromFieldPoison(u8 partyIdx)
{
struct Pokemon *pokemon = gPlayerParty + partyIdx;
u32 status = STATUS1_NONE;
AdjustFriendship(pokemon, FRIENDSHIP_EVENT_FAINT_OUTSIDE_BATTLE);
if (OW_POISON_DAMAGE < GEN_4)
AdjustFriendship(pokemon, FRIENDSHIP_EVENT_FAINT_OUTSIDE_BATTLE);
SetMonData(pokemon, MON_DATA_STATUS, &status);
GetMonData(pokemon, MON_DATA_NICKNAME, gStringVar1);
StringGet_Nickname(gStringVar1);
@@ -42,7 +45,7 @@ static void FaintFromFieldPoison(u8 partyIdx)
static bool32 MonFaintedFromPoison(u8 partyIdx)
{
struct Pokemon *pokemon = gPlayerParty + partyIdx;
if (IsMonValidSpecies(pokemon) && !GetMonData(pokemon, MON_DATA_HP) && GetAilmentFromStatus(GetMonData(pokemon, MON_DATA_STATUS)) == AILMENT_PSN)
if (IsMonValidSpecies(pokemon) && GetMonData(pokemon, MON_DATA_HP) == ((OW_POISON_DAMAGE < GEN_4) ? 0 : 1) && GetAilmentFromStatus(GetMonData(pokemon, MON_DATA_STATUS)) == AILMENT_PSN)
return TRUE;
return FALSE;
}
@@ -61,7 +64,7 @@ static void Task_TryFieldPoisonWhiteOut(u8 taskId)
if (MonFaintedFromPoison(tPartyId))
{
FaintFromFieldPoison(tPartyId);
ShowFieldMessage(gText_PkmnFainted3);
ShowFieldMessage(gText_PkmnFainted_FldPsn);
tState++;
return;
}
@@ -101,9 +104,16 @@ s32 DoPoisonFieldEffect(void)
{
if (GetMonData(pokemon, MON_DATA_SANITY_HAS_SPECIES) && GetAilmentFromStatus(GetMonData(pokemon, MON_DATA_STATUS)) == AILMENT_PSN)
{
// Apply poison damage
hp = GetMonData(pokemon, MON_DATA_HP);
if (hp == 0 || --hp == 0)
if (OW_POISON_DAMAGE < GEN_4 && (hp == 0 || --hp == 0))
{
TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_FAINT);
numFainted++;
}
else if (OW_POISON_DAMAGE >= GEN_4 && (hp == 1 || --hp == 1))
numFainted++;
SetMonData(pokemon, MON_DATA_HP, &hp);
numPoisoned++;
}

View File

@@ -355,7 +355,7 @@ void AnimatePcTurnOff()
void SpawnCameraObject(void)
{
u8 objectEventId = SpawnSpecialObjectEventParameterized(OBJ_EVENT_GFX_YOUNGSTER, 8, OBJ_EVENT_ID_CAMERA, gSaveBlock1Ptr->pos.x + MAP_OFFSET, gSaveBlock1Ptr->pos.y + MAP_OFFSET, 3);
u32 objectEventId = SpawnSpecialObjectEventParameterized(OBJ_EVENT_GFX_YOUNGSTER, 8, OBJ_EVENT_ID_CAMERA, gSaveBlock1Ptr->pos.x + MAP_OFFSET, gSaveBlock1Ptr->pos.y + MAP_OFFSET, 3);
gObjectEvents[objectEventId].invisible = TRUE;
CameraObjectSetFollowedObjectId(gObjectEvents[objectEventId].spriteId);
}

View File

@@ -546,13 +546,8 @@ u8 DoPokeballSendOutAnimation(u32 battler, s16 pan, u8 kindOfThrow)
static void Task_DoPokeballSendOutAnim(u8 taskId)
{
u16 throwCaseId;
u8 battlerId;
u16 itemId, ballId;
u8 ballSpriteId;
bool8 notSendOut = FALSE;
s16 x, y;
u32 gender;
u32 throwCaseId, battlerId, ballId, ballSpriteId;
bool32 notSendOut = FALSE;
u32 throwXoffset = (B_ENEMY_THROW_BALLS >= GEN_6) ? 24 : 0;
s32 throwYoffset = (B_ENEMY_THROW_BALLS >= GEN_6) ? -16 : 24;
@@ -564,20 +559,8 @@ static void Task_DoPokeballSendOutAnim(u8 taskId)
throwCaseId = gTasks[taskId].tThrowId;
battlerId = gTasks[taskId].tBattler;
if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
itemId = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_POKEBALL);
else
itemId = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_POKEBALL);
ballId = ItemIdToBallId(itemId);
ballId = ItemIdToBallId(GetBattlerPokeballItemId(battlerId));
LoadBallGfx(ballId);
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
gender = gLinkPlayers[GetBattlerMultiplayerId(battlerId)].gender;
else
gender = gSaveBlock2Ptr->playerGender;
ballSpriteId = CreateSprite(&gBallSpriteTemplates[ballId], 32, 80, 29);
gSprites[ballSpriteId].data[0] = 0x80;
gSprites[ballSpriteId].data[1] = 0;
@@ -585,22 +568,15 @@ static void Task_DoPokeballSendOutAnim(u8 taskId)
switch (throwCaseId)
{
case POKEBALL_PLAYER_SENDOUT:
if (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE)
{
x = 32;
y = 64;
}
else
{
gender = !!gender; // something unknown got optimized out
x = 48;
y = 70;
}
case POKEBALL_PLAYER_SLIDEIN: // don't actually send out, trigger the slide-in animation
gBattlerTarget = battlerId;
gSprites[ballSpriteId].x = x;
gSprites[ballSpriteId].y = y;
gSprites[ballSpriteId].callback = HandleBallAnimEnd;
gSprites[ballSpriteId].invisible = TRUE;
break;
case POKEBALL_PLAYER_SENDOUT:
gBattlerTarget = battlerId;
gSprites[ballSpriteId].x = (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE) ? 32 : 48;
gSprites[ballSpriteId].y = (gBattleTypeFlags & BATTLE_TYPE_POKEDUDE) ? 64 : 70;
gSprites[ballSpriteId].callback = SpriteCB_MonSendOut_1;
DoPokeballSendOutSoundEffect(battlerId);
break;
@@ -1085,6 +1061,13 @@ static void HandleBallAnimEnd(struct Sprite *sprite)
bool8 affineAnimEnded = FALSE;
u8 battlerId = sprite->sBattler;
if (sprite->data[7] == POKEBALL_PLAYER_SLIDEIN)
{
gSprites[gBattlerSpriteIds[sprite->sBattler]].callback = SpriteCB_PlayerMonSlideIn;
AnimateSprite(&gSprites[gBattlerSpriteIds[sprite->sBattler]]);
gSprites[gBattlerSpriteIds[sprite->sBattler]].data[1] = 0x1000;
}
gSprites[gBattlerSpriteIds[battlerId]].invisible = FALSE;
if (sprite->animEnded)
sprite->invisible = TRUE;

View File

@@ -8,6 +8,7 @@
#include "data.h"
#include "battle.h"
#include "battle_anim.h"
#include "battle_setup.h"
#include "item.h"
#include "event_data.h"
#include "util.h"
@@ -3255,22 +3256,45 @@ u8 GetMonsStateToDoubles(void)
s32 i;
CalculatePlayerPartyCount();
if (OW_DOUBLE_APPROACH_WITH_ONE_MON)
return PLAYER_HAS_TWO_USABLE_MONS;
if (gPlayerPartyCount == 1)
return gPlayerPartyCount; // PLAYER_HAS_ONE_MON
for (i = 0; i < gPlayerPartyCount; i++)
{
// FRLG changed the order of these checks, but there's no point to doing that
// because of the requirement of all 3 of these checks.
if (GetMonData(&gPlayerParty[i], MON_DATA_HP, NULL) != 0
&& GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) != SPECIES_NONE
&& GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) != SPECIES_EGG)
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) != SPECIES_EGG
&& GetMonData(&gPlayerParty[i], MON_DATA_HP, NULL) != 0
&& GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL) != SPECIES_NONE)
aliveCount++;
}
return (aliveCount > 1) ? PLAYER_HAS_TWO_USABLE_MONS : PLAYER_HAS_ONE_USABLE_MON;
}
u8 GetMonsStateToDoubles_2(void)
{
s32 aliveCount = 0;
s32 i;
if (OW_DOUBLE_APPROACH_WITH_ONE_MON)
return PLAYER_HAS_TWO_USABLE_MONS;
for (i = 0; i < PARTY_SIZE; i++)
{
u32 species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG, NULL);
if (species != SPECIES_EGG && species != SPECIES_NONE
&& GetMonData(&gPlayerParty[i], MON_DATA_HP, NULL) != 0)
aliveCount++;
}
if (aliveCount == 1)
return PLAYER_HAS_ONE_MON; // may have more than one, but only one is alive
return (aliveCount > 1) ? PLAYER_HAS_TWO_USABLE_MONS : PLAYER_HAS_ONE_USABLE_MON;
}
u16 GetAbilityBySpecies(u16 species, u8 abilityNum)
{
int i;

View File

@@ -2,6 +2,7 @@
#include "gflib.h"
#include "battle.h"
#include "battle_anim.h"
#include "battle_setup.h"
#include "link.h"
#include "overworld.h"
#include "quest_log.h"

View File

@@ -23,6 +23,7 @@
#include "field_message_box.h"
#include "new_menu_helpers.h"
#include "script_menu.h"
#include "trainer_see.h"
#include "data.h"
#include "field_specials.h"
#include "constants/items.h"
@@ -1887,7 +1888,7 @@ bool8 ScrCmd_trainerbattle(struct ScriptContext * ctx)
bool8 ScrCmd_dotrainerbattle(struct ScriptContext * ctx)
{
StartTrainerBattle();
BattleSetup_StartTrainerBattle();
return TRUE;
}
@@ -2235,6 +2236,29 @@ bool8 ScrCmd_normalmsg(struct ScriptContext * ctx)
return FALSE;
}
bool8 ScrCmd_selectapproachingtrainer(struct ScriptContext *ctx)
{
gSelectedObjectEvent = GetCurrentApproachingTrainerObjectEventId();
return FALSE;
}
bool8 ScrCmd_lockfortrainer(struct ScriptContext *ctx)
{
if (IsUpdateLinkStateCBActive())
{
return FALSE;
}
else
{
if (gObjectEvents[gSelectedObjectEvent].active)
{
FreezeForApproachingTrainers();
SetupNativeScript(ctx, IsFreezePlayerFinished);
}
return TRUE;
}
}
// This command will set a Pokémon's modernFatefulEncounter bit; there is no similar command to clear it.
bool8 ScrCmd_setmonmodernfatefulencounter(struct ScriptContext * ctx)
{
@@ -2262,3 +2286,8 @@ bool8 ScrCmd_setmonmetlocation(struct ScriptContext * ctx)
SetMonData(&gPlayerParty[partyIndex], MON_DATA_MET_LOCATION, &location);
return FALSE;
}
void SetMovingNpcId(u16 npcId)
{
sMovingNpcId = npcId;
}

View File

@@ -318,6 +318,11 @@ const u8 gText_PkmnGainedExp[] = _("{STR_VAR_1} gained {STR_VAR_2} Exp. Points!{
const u8 gText_PkmnGainedExpAndElevatedToLvVar3[] = _("{STR_VAR_1} gained {STR_VAR_2} Exp. Points\nand was elevated to Lv. {STR_VAR_3}!");
const u8 gText_PkmnSnappedOutOfConfusion[] = _("{STR_VAR_1} snapped out of its\nconfusion.{PAUSE_UNTIL_PRESS}");
const u8 gText_PkmnGotOverInfatuation[] = _("{STR_VAR_1} got over its\ninfatuation.{PAUSE_UNTIL_PRESS}");
#if OW_POISON_DAMAGE < GEN_4
const u8 gText_PkmnFainted_FldPsn[] = _("{STR_VAR_1} fainted…\p\n");
#else
const u8 gText_PkmnFainted_FldPsn[] = _("{STR_VAR_1} survived the poisoning.\nThe poison faded away!\p");
#endif
const u8 gText_OnlyPkmnForBattle[] = _("That's your only\nPOKéMON for battle.");
ALIGNED(4) const u8 gText_PkmnCantBeTradedNow[] = _("That POKéMON can't be traded\nnow.");
ALIGNED(4) const u8 gText_EggCantBeTradedNow[] = _("An EGG can't be traded now.");

View File

@@ -1,11 +1,14 @@
#include "global.h"
#include "battle_setup.h"
#include "event_data.h"
#include "event_object_movement.h"
#include "field_effect.h"
#include "field_player_avatar.h"
#include "quest_log.h"
#include "script.h"
#include "script_movement.h"
#include "task.h"
#include "trainer_see.h"
#include "util.h"
#include "constants/battle_setup.h"
#include "constants/event_object_movement.h"
@@ -13,9 +16,9 @@
#include "constants/trainer_types.h"
typedef u8 (*TrainerApproachFunc)(struct ObjectEvent *, s16, s16, s16);
typedef bool8 (*TrainerSeeFunc)(u8, struct Task *, struct ObjectEvent *);
typedef bool32 (*TrainerSeeFunc)(u8, struct Task *, struct ObjectEvent *);
static bool8 CheckTrainer(u8 trainerObjId);
static u32 CheckTrainer(u8 trainerObjId);
static u8 GetTrainerApproachDistance(struct ObjectEvent * trainerObj);
static u8 GetTrainerApproachDistanceSouth(struct ObjectEvent * trainerObj, s16 range, s16 x, s16 y);
static u8 GetTrainerApproachDistanceNorth(struct ObjectEvent * trainerObj, s16 range, s16 x, s16 y);
@@ -24,21 +27,21 @@ static u8 GetTrainerApproachDistanceEast(struct ObjectEvent * trainerObj, s16 ra
static u8 CheckPathBetweenTrainerAndPlayer(struct ObjectEvent * trainerObj, u8 approachDistance, u8 facingDirection);
static void TrainerApproachPlayer(struct ObjectEvent * trainerObj, u8 approachDistance);
static void Task_RunTrainerSeeFuncList(u8 taskId);
static bool8 TrainerSeeFunc_Dummy(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_StartExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_WaitExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_TrainerApproach(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_PrepareToEngage(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_End(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_BeginRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_WaitRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_TrainerInAshFacesPlayer(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_BeginJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_WaitJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_EndJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_OffscreenAboveTrainerCreateCameraObj(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveUp(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool8 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveDown(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_Dummy(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_StartExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_WaitExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_TrainerApproach(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_PrepareToEngage(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_End(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_BeginRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_WaitRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_TrainerInAshFacesPlayer(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_BeginJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_WaitJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_EndJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_OffscreenAboveTrainerCreateCameraObj(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveUp(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static bool32 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveDown(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj);
static void Task_DestroyTrainerApproachTask(u8 taskId);
static void SpriteCB_TrainerIcons(struct Sprite *sprite);
static void SetIconSpriteData(struct Sprite *sprite, u16 fldEffId, u8 spriteAnimNum);
@@ -46,6 +49,11 @@ static void SetIconSpriteData(struct Sprite *sprite, u16 fldEffId, u8 spriteAnim
// IWRAM common
u16 gWhichTrainerToFaceAfterBattle;
u8 gNoOfApproachingTrainers;
struct ApproachingTrainer gApproachingTrainers[2];
bool8 gTrainerApproachedPlayer;
// EWRAM
EWRAM_DATA u8 gApproachingTrainerId = 0;
static const u16 sGfx_Emoticons[] = INCBIN_U16("graphics/misc/emoticons.4bpp");
static const u8 sEmotion_Gfx[] = INCBIN_U8("graphics/misc/emotes.4bpp");
@@ -62,25 +70,43 @@ static const TrainerApproachFunc sDirectionalApproachDistanceFuncs[] = {
GetTrainerApproachDistanceEast
};
enum {
TRSEE_NONE,
TRSEE_EXCLAMATION,
TRSEE_EXCLAMATION_WAIT,
TRSEE_MOVE_TO_PLAYER,
TRSEE_PLAYER_FACE,
TRSEE_PLAYER_FACE_WAIT,
TRSEE_REVEAL_DISGUISE,
TRSEE_REVEAL_DISGUISE_WAIT,
TRSEE_REVEAL_BURIED,
TRSEE_BURIED_POP_OUT,
TRSEE_BURIED_JUMP,
TRSEE_REVEAL_BURIED_WAIT,
TRSEE_OFFSCREEN_CREATE_CAMERA,
TRSEE_OFFSCREEN_MOVE_CAMERA_UP,
TRSEE_OFFSCREEN_MOVE_CAMERA_DOWN,
};
// bool8 func(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
// Returns TRUE to run the next func immediately
// Returns FALSE to delay the next func to the next frame
static const TrainerSeeFunc sTrainerSeeFuncList[] = {
TrainerSeeFunc_Dummy,
TrainerSeeFunc_StartExclMark,
TrainerSeeFunc_WaitExclMark,
TrainerSeeFunc_TrainerApproach,
TrainerSeeFunc_PrepareToEngage,
TrainerSeeFunc_End,
TrainerSeeFunc_BeginRemoveDisguise,
TrainerSeeFunc_WaitRemoveDisguise,
TrainerSeeFunc_TrainerInAshFacesPlayer,
TrainerSeeFunc_BeginJumpOutOfAsh,
TrainerSeeFunc_WaitJumpOutOfAsh,
TrainerSeeFunc_EndJumpOutOfAsh,
TrainerSeeFunc_OffscreenAboveTrainerCreateCameraObj,
TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveUp,
TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveDown
[TRSEE_NONE] = TrainerSeeFunc_Dummy,
[TRSEE_EXCLAMATION] = TrainerSeeFunc_StartExclMark,
[TRSEE_EXCLAMATION_WAIT] = TrainerSeeFunc_WaitExclMark,
[TRSEE_MOVE_TO_PLAYER] = TrainerSeeFunc_TrainerApproach,
[TRSEE_PLAYER_FACE] = TrainerSeeFunc_PrepareToEngage,
[TRSEE_PLAYER_FACE_WAIT] = TrainerSeeFunc_End,
[TRSEE_REVEAL_DISGUISE] = TrainerSeeFunc_BeginRemoveDisguise,
[TRSEE_REVEAL_DISGUISE_WAIT] = TrainerSeeFunc_WaitRemoveDisguise,
[TRSEE_REVEAL_BURIED] = TrainerSeeFunc_TrainerInAshFacesPlayer,
[TRSEE_BURIED_POP_OUT] = TrainerSeeFunc_BeginJumpOutOfAsh,
[TRSEE_BURIED_JUMP] = TrainerSeeFunc_WaitJumpOutOfAsh,
[TRSEE_REVEAL_BURIED_WAIT] = TrainerSeeFunc_EndJumpOutOfAsh,
[TRSEE_OFFSCREEN_CREATE_CAMERA] = TrainerSeeFunc_OffscreenAboveTrainerCreateCameraObj,
[TRSEE_OFFSCREEN_MOVE_CAMERA_UP] = TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveUp,
[TRSEE_OFFSCREEN_MOVE_CAMERA_DOWN] = TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveDown,
};
static const TrainerSeeFunc sTrainerSeeFuncList2[] = {
@@ -96,33 +122,87 @@ bool8 CheckForTrainersWantingBattle(void)
if (QL_IsTrainerSightDisabled() == TRUE)
return FALSE;
if (FlagGet(OW_FLAG_NO_TRAINER_SEE))
return FALSE;
gNoOfApproachingTrainers = 0;
gApproachingTrainerId = 0;
for (i = 0; i < OBJECT_EVENTS_COUNT; i++)
{
if (gObjectEvents[i].active
&& (gObjectEvents[i].trainerType == TRAINER_TYPE_NORMAL
|| gObjectEvents[i].trainerType == TRAINER_TYPE_BURIED)
&& CheckTrainer(i))
return TRUE;
u8 numTrainers;
if (!gObjectEvents[i].active)
continue;
if (gObjectEvents[i].trainerType != TRAINER_TYPE_NORMAL && gObjectEvents[i].trainerType != TRAINER_TYPE_BURIED)
continue;
numTrainers = CheckTrainer(i);
if (numTrainers == 2)
break;
if (numTrainers == 0)
continue;
if (gNoOfApproachingTrainers > 1)
break;
if (GetMonsStateToDoubles_2() != PLAYER_HAS_TWO_USABLE_MONS) // one trainer found and cant have a double battle
break;
}
if (gNoOfApproachingTrainers == 1)
{
ResetTrainerOpponentIds();
ConfigureAndSetUpOneTrainerBattle(gApproachingTrainers[gNoOfApproachingTrainers - 1].objectEventId,
gApproachingTrainers[gNoOfApproachingTrainers - 1].trainerScriptPtr);
gTrainerApproachedPlayer = TRUE;
return TRUE;
}
else if (gNoOfApproachingTrainers == 2)
{
ResetTrainerOpponentIds();
for (i = 0; i < gNoOfApproachingTrainers; i++, gApproachingTrainerId++)
{
ConfigureTwoTrainersBattle(gApproachingTrainers[i].objectEventId,
gApproachingTrainers[i].trainerScriptPtr);
}
SetUpTwoTrainersBattle();
gApproachingTrainerId = 0;
gTrainerApproachedPlayer = TRUE;
return TRUE;
}
else
{
gTrainerApproachedPlayer = FALSE;
return FALSE;
}
return FALSE;
}
static bool8 CheckTrainer(u8 trainerObjId)
static u32 CheckTrainer(u8 trainerObjId)
{
const u8 *script = GetObjectEventScriptPointerByObjectEventId(trainerObjId);
u8 approachDistance;
u32 numTrainers = 1;
u32 approachDistance;
if (GetTrainerFlagFromScriptPointer(script))
return FALSE;
approachDistance = GetTrainerApproachDistance(&gObjectEvents[trainerObjId]);
if (approachDistance != 0)
{
if (script[1] == TRAINER_BATTLE_DOUBLE && GetMonsStateToDoubles())
return FALSE;
ConfigureAndSetUpOneTrainerBattle(trainerObjId, script);
{
if (GetMonsStateToDoubles_2() != PLAYER_HAS_TWO_USABLE_MONS)
return 0;
numTrainers = 2;
}
gApproachingTrainers[gNoOfApproachingTrainers].objectEventId = trainerObjId;
gApproachingTrainers[gNoOfApproachingTrainers].trainerScriptPtr = script;
gApproachingTrainers[gNoOfApproachingTrainers].radius = approachDistance;
TrainerApproachPlayer(&gObjectEvents[trainerObjId], approachDistance - 1);
return TRUE;
gNoOfApproachingTrainers++;
return numTrainers;
}
return FALSE;
return 0;
}
static u8 GetTrainerApproachDistance(struct ObjectEvent *trainerObj)
@@ -238,38 +318,41 @@ static u8 CheckPathBetweenTrainerAndPlayer(struct ObjectEvent *trainerObj, u8 ap
}
#define tFuncId data[0]
#define tTrainerObjHi data[1]
#define tTrainerObjLo data[2]
#define tTrainerRange data[3]
#define tOutOfAshSpriteId data[4]
#define tData5 data[5]
#define TaskGetTrainerObj(dest, task) do { \
(dest) = (struct ObjectEvent *)(((task)->tTrainerObjHi << 16) | ((u16)(task)->tTrainerObjLo)); \
} while (0)
#define tTrainerObjectEventId data[7]
static void TrainerApproachPlayer(struct ObjectEvent * trainerObj, u8 approachDistance)
{
u8 taskId = CreateTask(Task_RunTrainerSeeFuncList, 80);
struct Task *task = &gTasks[taskId];
task->tTrainerObjHi = ((uintptr_t)trainerObj) >> 16;
task->tTrainerObjLo = (uintptr_t)trainerObj;
struct Task *task;
gApproachingTrainers[gNoOfApproachingTrainers].taskId = CreateTask(Task_RunTrainerSeeFuncList, 80);
task = &gTasks[gApproachingTrainers[gNoOfApproachingTrainers].taskId];
task->tTrainerRange = approachDistance;
task->tTrainerObjectEventId = gApproachingTrainers[gNoOfApproachingTrainers].objectEventId;
}
static void StartTrainerApproachWithFollowupTask(TaskFunc taskFunc)
static void StartTrainerApproachWithFollowupTask(TaskFunc followupFunc)
{
u8 taskId = FindTaskIdByFunc(Task_RunTrainerSeeFuncList);
SetTaskFuncWithFollowupFunc(taskId, Task_RunTrainerSeeFuncList, taskFunc);
u8 taskId;
TaskFunc taskFunc;
if (gApproachingTrainerId == 0)
taskId = gApproachingTrainers[0].taskId;
else
taskId = gApproachingTrainers[1].taskId;
taskFunc = Task_RunTrainerSeeFuncList;
SetTaskFuncWithFollowupFunc(taskId, taskFunc, followupFunc);
gTasks[taskId].tFuncId = 1;
Task_RunTrainerSeeFuncList(taskId);
taskFunc(taskId);
}
static void Task_RunTrainerSeeFuncList(u8 taskId)
{
struct Task *task = &gTasks[taskId];
struct ObjectEvent * trainerObj;
TaskGetTrainerObj(trainerObj, task);
struct ObjectEvent *trainerObj = &gObjectEvents[task->tTrainerObjectEventId];
if (!trainerObj->active)
{
@@ -277,19 +360,18 @@ static void Task_RunTrainerSeeFuncList(u8 taskId)
}
else
{
while (sTrainerSeeFuncList[task->tFuncId](taskId, task, trainerObj))
;
while (sTrainerSeeFuncList[task->tFuncId](taskId, task, trainerObj));
}
}
// TrainerSeeFuncs
static bool8 TrainerSeeFunc_Dummy(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_Dummy(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
return FALSE;
}
static bool8 TrainerSeeFunc_StartExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_StartExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
u8 action;
// FRLG introduces trainers who can see the player from offscreen above.
@@ -309,7 +391,7 @@ static bool8 TrainerSeeFunc_StartExclMark(u8 taskId, struct Task *task, struct O
return TRUE;
}
static bool8 TrainerSeeFunc_WaitExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_WaitExclMark(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
if (FieldEffectActiveListContains(FLDEFF_EXCLAMATION_MARK_ICON))
{
@@ -326,7 +408,7 @@ static bool8 TrainerSeeFunc_WaitExclMark(u8 taskId, struct Task *task, struct Ob
}
}
static bool8 TrainerSeeFunc_TrainerApproach(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_TrainerApproach(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
if (!ObjectEventIsMovementOverridden(trainerObj) || ObjectEventClearHeldMovementIfFinished(trainerObj))
{
@@ -344,7 +426,7 @@ static bool8 TrainerSeeFunc_TrainerApproach(u8 taskId, struct Task *task, struct
return FALSE;
}
static bool8 TrainerSeeFunc_PrepareToEngage(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_PrepareToEngage(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
struct ObjectEvent *playerObj;
@@ -360,13 +442,12 @@ static bool8 TrainerSeeFunc_PrepareToEngage(u8 taskId, struct Task *task, struct
return FALSE;
CancelPlayerForcedMovement();
// Uncomment to have player turn to face their opponent
// ObjectEventSetHeldMovement(&gObjectEvents[gPlayerAvatar.objectEventId], GetFaceDirectionMovementAction(GetOppositeDirection(trainerObj->facingDirection)));
ObjectEventSetHeldMovement(&gObjectEvents[gPlayerAvatar.objectEventId], GetFaceDirectionMovementAction(GetOppositeDirection(trainerObj->facingDirection)));
task->tFuncId++;
return FALSE;
}
static bool8 TrainerSeeFunc_End(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_End(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId];
@@ -377,7 +458,7 @@ static bool8 TrainerSeeFunc_End(u8 taskId, struct Task *task, struct ObjectEvent
}
// Jumps here if disguised. Not used in FRLG.
static bool8 TrainerSeeFunc_BeginRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_BeginRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
if (!ObjectEventIsMovementOverridden(trainerObj)
|| ObjectEventClearHeldMovementIfFinished(trainerObj))
@@ -388,7 +469,7 @@ static bool8 TrainerSeeFunc_BeginRemoveDisguise(u8 taskId, struct Task *task, st
return FALSE;
}
static bool8 TrainerSeeFunc_WaitRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_WaitRemoveDisguise(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
if (ObjectEventClearHeldMovementIfFinished(trainerObj))
task->tFuncId = 3;
@@ -397,7 +478,7 @@ static bool8 TrainerSeeFunc_WaitRemoveDisguise(u8 taskId, struct Task *task, str
}
// Jump here if buried in ash. Not used in FRLG.
static bool8 TrainerSeeFunc_TrainerInAshFacesPlayer(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_TrainerInAshFacesPlayer(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
if (!ObjectEventIsMovementOverridden(trainerObj)
|| ObjectEventClearHeldMovementIfFinished(trainerObj))
@@ -408,7 +489,7 @@ static bool8 TrainerSeeFunc_TrainerInAshFacesPlayer(u8 taskId, struct Task *task
return FALSE;
}
static bool8 TrainerSeeFunc_BeginJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_BeginJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
if (ObjectEventCheckHeldMovementStatus(trainerObj))
{
@@ -422,7 +503,7 @@ static bool8 TrainerSeeFunc_BeginJumpOutOfAsh(u8 taskId, struct Task *task, stru
return FALSE;
}
static bool8 TrainerSeeFunc_WaitJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_WaitJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
struct Sprite *sprite;
@@ -441,7 +522,7 @@ static bool8 TrainerSeeFunc_WaitJumpOutOfAsh(u8 taskId, struct Task *task, struc
return FALSE;
}
static bool8 TrainerSeeFunc_EndJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent *trainerObj)
static bool32 TrainerSeeFunc_EndJumpOutOfAsh(u8 taskId, struct Task *task, struct ObjectEvent *trainerObj)
{
if (!FieldEffectActiveListContains(FLDEFF_POP_OUT_OF_ASH))
task->tFuncId = 3;
@@ -450,9 +531,9 @@ static bool8 TrainerSeeFunc_EndJumpOutOfAsh(u8 taskId, struct Task *task, struct
}
// FRLG exclusive: Scroll the camera up to reveal an offscreen above trainer
static bool8 TrainerSeeFunc_OffscreenAboveTrainerCreateCameraObj(u8 taskId, struct Task *task, struct ObjectEvent *trainerObj)
static bool32 TrainerSeeFunc_OffscreenAboveTrainerCreateCameraObj(u8 taskId, struct Task *task, struct ObjectEvent *trainerObj)
{
int specialObjectId;
u32 specialObjectId;
task->tData5 = 0;
specialObjectId = SpawnSpecialObjectEventParameterized(OBJ_EVENT_GFX_YOUNGSTER, 7, OBJ_EVENT_ID_CAMERA, gSaveBlock1Ptr->pos.x + 7, gSaveBlock1Ptr->pos.y + 7, 3);
gObjectEvents[specialObjectId].invisible = TRUE;
@@ -461,7 +542,7 @@ static bool8 TrainerSeeFunc_OffscreenAboveTrainerCreateCameraObj(u8 taskId, stru
return FALSE;
}
static bool8 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveUp(u8 taskId, struct Task *task, struct ObjectEvent *trainerObj)
static bool32 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveUp(u8 taskId, struct Task *task, struct ObjectEvent *trainerObj)
{
u8 specialObjectId;
TryGetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_CAMERA, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &specialObjectId);
@@ -484,7 +565,7 @@ static bool8 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveUp(u8 taskId, stru
return FALSE;
}
static bool8 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveDown(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
static bool32 TrainerSeeFunc_OffscreenAboveTrainerCameraObjMoveDown(u8 taskId, struct Task *task, struct ObjectEvent * trainerObj)
{
u8 specialObjectId;
TryGetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_CAMERA, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, &specialObjectId);
@@ -921,3 +1002,44 @@ static void SpriteCB_TrainerIcons(struct Sprite *sprite)
#undef sData3
#undef sData4
#undef sFldEffId
u8 GetCurrentApproachingTrainerObjectEventId(void)
{
if (gApproachingTrainerId == 0)
return gApproachingTrainers[0].objectEventId;
else
return gApproachingTrainers[1].objectEventId;
}
u8 GetChosenApproachingTrainerObjectEventId(u8 arrayId)
{
if (arrayId >= ARRAY_COUNT(gApproachingTrainers))
return 0;
else if (arrayId == 0)
return gApproachingTrainers[0].objectEventId;
else
return gApproachingTrainers[1].objectEventId;
}
void TryPrepareSecondApproachingTrainer(void)
{
if (gNoOfApproachingTrainers == 2)
{
if (gApproachingTrainerId == 0)
{
gApproachingTrainerId++;
gSpecialVar_Result = TRUE;
UnfreezeObjectEvents();
FreezeObjectEventsExceptOne(gApproachingTrainers[1].objectEventId);
}
else
{
gApproachingTrainerId = 0;
gSpecialVar_Result = FALSE;
}
}
else
{
gSpecialVar_Result = FALSE;
}
}

View File

@@ -1,6 +1,7 @@
#include "global.h"
#include "gflib.h"
#include "battle.h"
#include "battle_setup.h"
#include "link.h"
#include "menu.h"
#include "new_menu_helpers.h"

View File

@@ -603,7 +603,7 @@ static void Task_ResetObjectsRematchWantedState(u8 taskId)
struct Task *task = &gTasks[taskId];
u8 i;
if (task->data[0] == 0 && walkrun_is_standing_still() == TRUE)
if (task->data[0] == 0 && IsPlayerStandingStill() == TRUE)
{
HandleEnforcedLookDirectionOnPlayerStopMoving();
task->data[0] = 1;