Merge branch 'master' into field_map_obj

This commit is contained in:
PikalaxALT
2017-09-13 19:29:19 -04:00
221 changed files with 152332 additions and 152431 deletions

601
src/battle_4.c Normal file
View File

@@ -0,0 +1,601 @@
#include "global.h"
#include "battle.h"
#include "battle_move_effects.h"
#include "moves.h"
#include "abilities.h"
#include "item.h"
#include "items.h"
#include "hold_effects.h"
void atk00_attackcanceler(void);
void atk01_accuracycheck(void);
void atk02_attackstring(void);
void atk03_ppreduce(void);
void atk04_critcalc(void);
void atk05_damagecalc1(void);
void atk06_typecalc(void);
void atk07_dmg_adjustment(void);
void atk08_dmg_adjustment2(void);
void atk09_attackanimation(void);
void atk0A_waitanimation(void);
void atk0B_healthbarupdate(void);
void atk0C_datahpupdate(void);
void atk0D_critmessage(void);
void atk0E_effectiveness_sound(void);
void atk0F_resultmessage(void);
void atk10_printstring(void);
void atk11_printstring_playeronly(void);
void atk12_waitmessage(void);
void atk13_printfromtable(void);
void atk14_printfromtable_playeronly(void);
void atk15_seteffectwithchancetarget(void);
void atk16_seteffectprimary(void);
void atk17_seteffectsecondary(void);
void atk18_status_effect_clear(void);
void atk19_faint_pokemon(void);
void atk1A_faint_animation(void);
void atk1B_faint_effects_clear(void);
void atk1C_jumpifstatus(void);
void atk1D_jumpifstatus2(void);
void atk1E_jumpifability(void);
void atk1F_jumpifsideaffecting(void);
void atk20_jumpifstat(void);
void atk21_jumpifstatus3(void);
void atk22_jumpiftype(void);
void atk23_getexp(void);
void atk24(void);
void atk25_move_values_cleanup(void);
void atk26_set_multihit(void);
void atk27_decrement_multihit(void);
void atk28_goto(void);
void atk29_jumpifbyte(void);
void atk2A_jumpifhalfword(void);
void atk2B_jumpifword(void);
void atk2C_jumpifarrayequal(void);
void atk2D_jumpifarraynotequal(void);
void atk2E_setbyte(void);
void atk2F_addbyte(void);
void atk30_subbyte(void);
void atk31_copyarray(void);
void atk32_copyarray_withindex(void);
void atk33_orbyte(void);
void atk34_orhalfword(void);
void atk35_orword(void);
void atk36_bicbyte(void);
void atk37_bichalfword(void);
void atk38_bicword(void);
void atk39_pause(void);
void atk3A_waitstate(void);
void atk3B_healthbar_update(void);
void atk3C_return(void);
void atk3D_end(void);
void atk3E_end2(void);
void atk3F_end3(void);
void atk40_jump_if_move_affected_by_protect(void);
void atk41_call(void);
void atk42_jumpiftype2(void);
void atk43_jumpifabilitypresent(void);
void atk44(void);
void atk45_playanimation(void);
void atk46_playanimation2(void);
void atk47_setgraphicalstatchangevalues(void);
void atk48_playstatchangeanimation(void);
void atk49_moveendturn(void);
void atk4A_typecalc2(void);
void atk4B_return_atk_to_ball(void);
void atk4C_copy_poke_data(void);
void atk4D_switch_data_update(void);
void atk4E_switchin_anim(void);
void atk4F_jump_if_cannot_switch(void);
void atk50_openpartyscreen(void);
void atk51_switch_handle_order(void);
void atk52_switch_in_effects(void);
void atk53_trainer_slide(void);
void atk54_effectiveness_sound(void);
void atk55_play_sound(void);
void atk56_fainting_cry(void);
void atk57(void);
void atk58_return_to_ball(void);
void atk59_learnmove_inbattle(void);
void atk5A(void);
void atk5B_80256E0(void);
void atk5C_hitanimation(void);
void atk5D_getmoneyreward(void);
void atk5E_8025A70(void);
void atk5F_8025B24(void);
void atk60_increment_gamestat(void);
void atk61_8025BA4(void);
void atk62_08025C6C(void);
void atk63_jumptorandomattack(void);
void atk64_statusanimation(void);
void atk65_status2animation(void);
void atk66_chosenstatusanimation(void);
void atk67_8025ECC(void);
void atk68_80246A0(void);
void atk69_dmg_adjustment2(void);
void atk6A_removeitem(void);
void atk6B_atknameinbuff1(void);
void atk6C_lvlbox_display(void);
void atk6D_set_sentpokes_values(void);
void atk6E_set_atk_to_player0(void);
void atk6F_set_visible(void);
void atk70_record_ability(void);
void atk71_buffer_move_to_learn(void);
void atk72_jump_if_can_run_frombattle(void);
void atk73_hp_thresholds(void);
void atk74_hp_thresholds2(void);
void atk75_8026A58(void);
void atk76_various(void);
void atk77_setprotect(void);
void atk78_faintifabilitynotdamp(void);
void atk79_setatkhptozero(void);
void atk7A_jumpwhiletargetvalid(void);
void atk7B_healhalfHP_if_possible(void);
void atk7C_8025508(void);
void atk7D_set_rain(void);
void atk7E_setreflect(void);
void atk7F_setseeded(void);
void atk80_manipulatedamage(void);
void atk81_setrest(void);
void atk82_jumpifnotfirstturn(void);
void atk83_nop(void);
void atk84_jump_if_cant_sleep(void);
void atk85_stockpile(void);
void atk86_stockpiletobasedamage(void);
void atk87_stockpiletohpheal(void);
void atk88_negativedamage(void);
void atk89_statbuffchange(void);
void atk8A_normalisebuffs(void);
void atk8B_setbide(void);
void atk8C_confuseifrepeatingattackends(void);
void atk8D_setmultihit_counter(void);
void atk8E_prepare_multihit(void);
void atk8F_forcerandomswitch(void);
void atk90_conversion_type_change(void);
void atk91_givepaydaymoney(void);
void atk92_setlightscreen(void);
void atk93_ko_move(void);
void atk94_gethalfcurrentenemyhp(void);
void atk95_setsandstorm(void);
void atk96_weatherdamage(void);
void atk97_try_infatuation(void);
void atk98_status_icon_update(void);
void atk99_setmist(void);
void atk9A_set_focusenergy(void);
void atk9B_transformdataexecution(void);
void atk9C_set_substitute(void);
void atk9D_copyattack(void);
void atk9E_metronome(void);
void atk9F_dmgtolevel(void);
void atkA0_psywavedamageeffect(void);
void atkA1_counterdamagecalculator(void);
void atkA2_mirrorcoatdamagecalculator(void);
void atkA3_disablelastusedattack(void);
void atkA4_setencore(void);
void atkA5_painsplitdmgcalc(void);
void atkA6_settypetorandomresistance(void);
void atkA7_setalwayshitflag(void);
void atkA8_copymovepermanently(void);
void atkA9_sleeptalk_choose_move(void);
void atkAA_set_destinybond(void);
void atkAB_DestinyBondFlagUpdate(void);
void atkAC_remaininghptopower(void);
void atkAD_spite_ppreduce(void);
void atkAE_heal_party_status(void);
void atkAF_cursetarget(void);
void atkB0_set_spikes(void);
void atkB1_set_foresight(void);
void atkB2_setperishsong(void);
void atkB3_rolloutdamagecalculation(void);
void atkB4_jumpifconfusedandstatmaxed(void);
void atkB5_furycuttercalc(void);
void atkB6_happinesstodamagecalculation(void);
void atkB7_presentdamagecalculation(void);
void atkB8_set_safeguard(void);
void atkB9_magnitudedamagecalculation(void);
void atkBA_jumpifnopursuitswitchdmg(void);
void atkBB_setsunny(void);
void atkBC_maxattackhalvehp(void);
void atkBD_copyfoestats(void);
void atkBE_breakfree(void);
void atkBF_set_defense_curl(void);
void atkC0_recoverbasedonsunlight(void);
void atkC1_hidden_power(void);
void atkC2_selectnexttarget(void);
void atkC3_setfutureattack(void);
void atkC4_beat_up(void);
void atkC5_hidepreattack(void);
void atkC6_unhidepostattack(void);
void atkC7_setminimize(void);
void atkC8_sethail(void);
void atkC9_jumpifattackandspecialattackcannotfall(void);
void atkCA_setforcedtarget(void);
void atkCB_setcharge(void);
void atkCC_callterrainattack(void);
void atkCD_cureifburnedparalysedorpoisoned(void);
void atkCE_settorment(void);
void atkCF_jumpifnodamage(void);
void atkD0_settaunt(void);
void atkD1_set_helpinghand(void);
void atkD2_swap_items(void);
void atkD3_copy_ability(void);
void atkD4_wish_effect(void);
void atkD5_setroots(void);
void atkD6_doubledamagedealtifdamaged(void);
void atkD7_setyawn(void);
void atkD8_setdamagetohealthdifference(void);
void atkD9_scaledamagebyhealthratio(void);
void atkDA_abilityswap(void);
void atkDB_imprisoneffect(void);
void atkDC_setgrudge(void);
void atkDD_weightdamagecalculation(void);
void atkDE_asistattackselect(void);
void atkDF_setmagiccoat(void);
void atkE0_setstealstatchange(void);
void atkE1_intimidate_string_loader(void);
void atkE2_switchout_abilities(void);
void atkE3_jumpiffainted(void);
void atkE4_getsecretpowereffect(void);
void atkE5_pickup(void);
void atkE6_castform_change_animation(void);
void atkE7_castform_data_change(void);
void atkE8_settypebasedhalvers(void);
void atkE9_setweatherballtype(void);
void atkEA_recycleitem(void);
void atkEB_settypetoterrain(void);
void atkEC_pursuit_sth(void);
void atkED_802B4B4(void);
void atkEE_removelightscreenreflect(void);
void atkEF_pokeball_catch_calculation(void);
void atkF0_copy_caught_poke(void);
void atkF1_setpoke_as_caught(void);
void atkF2_display_dex_info(void);
void atkF3_nickname_caught_poke(void);
void atkF4_802BEF0(void);
void atkF5_removeattackerstatus1(void);
void atkF6_802BF48(void);
void atkF7_802BF54(void);
void sub_8056EF8(void);
void (* const gBattleScriptingCommandsTable[])(void) =
{
atk00_attackcanceler,
atk01_accuracycheck,
atk02_attackstring,
atk03_ppreduce,
atk04_critcalc,
atk05_damagecalc1,
atk06_typecalc,
atk07_dmg_adjustment,
atk08_dmg_adjustment2,
atk09_attackanimation,
atk0A_waitanimation,
atk0B_healthbarupdate,
atk0C_datahpupdate,
atk0D_critmessage,
atk0E_effectiveness_sound,
atk0F_resultmessage,
atk10_printstring,
atk11_printstring_playeronly,
atk12_waitmessage,
atk13_printfromtable,
atk14_printfromtable_playeronly,
atk15_seteffectwithchancetarget,
atk16_seteffectprimary,
atk17_seteffectsecondary,
atk18_status_effect_clear,
atk19_faint_pokemon,
atk1A_faint_animation,
atk1B_faint_effects_clear,
atk1C_jumpifstatus,
atk1D_jumpifstatus2,
atk1E_jumpifability,
atk1F_jumpifsideaffecting,
atk20_jumpifstat,
atk21_jumpifstatus3,
atk22_jumpiftype,
atk23_getexp,
atk24,
atk25_move_values_cleanup,
atk26_set_multihit,
atk27_decrement_multihit,
atk28_goto,
atk29_jumpifbyte,
atk2A_jumpifhalfword,
atk2B_jumpifword,
atk2C_jumpifarrayequal,
atk2D_jumpifarraynotequal,
atk2E_setbyte,
atk2F_addbyte,
atk30_subbyte,
atk31_copyarray,
atk32_copyarray_withindex,
atk33_orbyte,
atk34_orhalfword,
atk35_orword,
atk36_bicbyte,
atk37_bichalfword,
atk38_bicword,
atk39_pause,
atk3A_waitstate,
atk3B_healthbar_update,
atk3C_return,
atk3D_end,
atk3E_end2,
atk3F_end3,
atk40_jump_if_move_affected_by_protect,
atk41_call,
atk42_jumpiftype2,
atk43_jumpifabilitypresent,
atk44,
atk45_playanimation,
atk46_playanimation2,
atk47_setgraphicalstatchangevalues,
atk48_playstatchangeanimation,
atk49_moveendturn,
atk4A_typecalc2,
atk4B_return_atk_to_ball,
atk4C_copy_poke_data,
atk4D_switch_data_update,
atk4E_switchin_anim,
atk4F_jump_if_cannot_switch,
atk50_openpartyscreen,
atk51_switch_handle_order,
atk52_switch_in_effects,
atk53_trainer_slide,
atk54_effectiveness_sound,
atk55_play_sound,
atk56_fainting_cry,
atk57,
atk58_return_to_ball,
atk59_learnmove_inbattle,
atk5A,
atk5B_80256E0,
atk5C_hitanimation,
atk5D_getmoneyreward,
atk5E_8025A70,
atk5F_8025B24,
atk60_increment_gamestat,
atk61_8025BA4,
atk62_08025C6C,
atk63_jumptorandomattack,
atk64_statusanimation,
atk65_status2animation,
atk66_chosenstatusanimation,
atk67_8025ECC,
atk68_80246A0,
atk69_dmg_adjustment2,
atk6A_removeitem,
atk6B_atknameinbuff1,
atk6C_lvlbox_display,
atk6D_set_sentpokes_values,
atk6E_set_atk_to_player0,
atk6F_set_visible,
atk70_record_ability,
atk71_buffer_move_to_learn,
atk72_jump_if_can_run_frombattle,
atk73_hp_thresholds,
atk74_hp_thresholds2,
atk75_8026A58,
atk76_various,
atk77_setprotect,
atk78_faintifabilitynotdamp,
atk79_setatkhptozero,
atk7A_jumpwhiletargetvalid,
atk7B_healhalfHP_if_possible,
atk7C_8025508,
atk7D_set_rain,
atk7E_setreflect,
atk7F_setseeded,
atk80_manipulatedamage,
atk81_setrest,
atk82_jumpifnotfirstturn,
atk83_nop,
atk84_jump_if_cant_sleep,
atk85_stockpile,
atk86_stockpiletobasedamage,
atk87_stockpiletohpheal,
atk88_negativedamage,
atk89_statbuffchange,
atk8A_normalisebuffs,
atk8B_setbide,
atk8C_confuseifrepeatingattackends,
atk8D_setmultihit_counter,
atk8E_prepare_multihit,
atk8F_forcerandomswitch,
atk90_conversion_type_change,
atk91_givepaydaymoney,
atk92_setlightscreen,
atk93_ko_move,
atk94_gethalfcurrentenemyhp,
atk95_setsandstorm,
atk96_weatherdamage,
atk97_try_infatuation,
atk98_status_icon_update,
atk99_setmist,
atk9A_set_focusenergy,
atk9B_transformdataexecution,
atk9C_set_substitute,
atk9D_copyattack,
atk9E_metronome,
atk9F_dmgtolevel,
atkA0_psywavedamageeffect,
atkA1_counterdamagecalculator,
atkA2_mirrorcoatdamagecalculator,
atkA3_disablelastusedattack,
atkA4_setencore,
atkA5_painsplitdmgcalc,
atkA6_settypetorandomresistance,
atkA7_setalwayshitflag,
atkA8_copymovepermanently,
atkA9_sleeptalk_choose_move,
atkAA_set_destinybond,
atkAB_DestinyBondFlagUpdate,
atkAC_remaininghptopower,
atkAD_spite_ppreduce,
atkAE_heal_party_status,
atkAF_cursetarget,
atkB0_set_spikes,
atkB1_set_foresight,
atkB2_setperishsong,
atkB3_rolloutdamagecalculation,
atkB4_jumpifconfusedandstatmaxed,
atkB5_furycuttercalc,
atkB6_happinesstodamagecalculation,
atkB7_presentdamagecalculation,
atkB8_set_safeguard,
atkB9_magnitudedamagecalculation,
atkBA_jumpifnopursuitswitchdmg,
atkBB_setsunny,
atkBC_maxattackhalvehp,
atkBD_copyfoestats,
atkBE_breakfree,
atkBF_set_defense_curl,
atkC0_recoverbasedonsunlight,
atkC1_hidden_power,
atkC2_selectnexttarget,
atkC3_setfutureattack,
atkC4_beat_up,
atkC5_hidepreattack,
atkC6_unhidepostattack,
atkC7_setminimize,
atkC8_sethail,
atkC9_jumpifattackandspecialattackcannotfall,
atkCA_setforcedtarget,
atkCB_setcharge,
atkCC_callterrainattack,
atkCD_cureifburnedparalysedorpoisoned,
atkCE_settorment,
atkCF_jumpifnodamage,
atkD0_settaunt,
atkD1_set_helpinghand,
atkD2_swap_items,
atkD3_copy_ability,
atkD4_wish_effect,
atkD5_setroots,
atkD6_doubledamagedealtifdamaged,
atkD7_setyawn,
atkD8_setdamagetohealthdifference,
atkD9_scaledamagebyhealthratio,
atkDA_abilityswap,
atkDB_imprisoneffect,
atkDC_setgrudge,
atkDD_weightdamagecalculation,
atkDE_asistattackselect,
atkDF_setmagiccoat,
atkE0_setstealstatchange,
atkE1_intimidate_string_loader,
atkE2_switchout_abilities,
atkE3_jumpiffainted,
atkE4_getsecretpowereffect,
atkE5_pickup,
atkE6_castform_change_animation,
atkE7_castform_data_change,
atkE8_settypebasedhalvers,
atkE9_setweatherballtype,
atkEA_recycleitem,
atkEB_settypetoterrain,
atkEC_pursuit_sth,
atkED_802B4B4,
atkEE_removelightscreenreflect,
atkEF_pokeball_catch_calculation,
atkF0_copy_caught_poke,
atkF1_setpoke_as_caught,
atkF2_display_dex_info,
atkF3_nickname_caught_poke,
atkF4_802BEF0,
atkF5_removeattackerstatus1,
atkF6_802BF48,
atkF7_802BF54,
sub_8056EF8
};
struct statFractions
{
u8 dividend;
u8 divisor;
};
const struct statFractions gAccuracyStageRatios[] =
{
{ 33, 100}, // -6
{ 36, 100}, // -5
{ 43, 100}, // -4
{ 50, 100}, // -3
{ 60, 100}, // -2
{ 75, 100}, // -1
{ 1, 1}, // 0
{133, 100}, // +1
{166, 100}, // +2
{ 2, 1}, // +3
{233, 100}, // +4
{133, 50}, // +5
{ 3, 1}, // +6
};
// The chance is 1/N for each stage.
const u16 gCriticalHitChance[] = {16, 8, 4, 3, 2};
const u32 gStatusFlagsForMoveEffects[] =
{
0x00000000,
0x00000007,
0x00000008,
0x00000010,
0x00000020,
0x00000040,
0x00000080,
0x00000007,
0x00000008,
0x00000000,
0x00000070,
0x00000000,
0x00001000,
0x0000E000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00400000,
0x00000000,
0x00000000,
0x04000000,
0x08000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000C00,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000
};

File diff suppressed because it is too large Load Diff

1642
src/bg.c Normal file

File diff suppressed because it is too large Load Diff

284
src/calculate_base_damage.c Normal file
View File

@@ -0,0 +1,284 @@
#include "global.h"
#include "abilities.h"
#include "battle.h"
#include "hold_effects.h"
#include "event_data.h"
#include "item.h"
#include "items.h"
#include "pokemon.h"
#include "species.h"
#include "moves.h"
#include "battle_move_effects.h"
extern u32 gBattleTypeFlags;
extern struct BattlePokemon gBattleMons[4];
extern u16 gCurrentMove;
extern u8 gCritMultiplier;
extern u16 gBattleWeather;
extern struct BattleEnigmaBerry gEnigmaBerries[];
extern u16 gBattleMovePower;
extern u16 gTrainerBattleOpponent_A;
u8 CountAliveMonsInBattle(u8);
bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 bank);
extern const struct BattleMove gBattleMoves[];
extern const u8 gHoldEffectToType[][2];
extern const u8 gStatStageRatios[][2];
#define APPLY_STAT_MOD(var, mon, stat, statIndex) \
{ \
(var) = (stat) * (gStatStageRatios)[(mon)->statStages[(statIndex)]][0]; \
(var) /= (gStatStageRatios)[(mon)->statStages[(statIndex)]][1]; \
}
s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u16 sideStatus, u16 powerOverride, u8 typeOverride, u8 bankAtk, u8 bankDef)
{
u32 i;
s32 damage = 0;
s32 damageHelper;
u8 type;
u16 attack, defense;
u16 spAttack, spDefense;
u8 defenderHoldEffect;
u8 defenderHoldEffectParam;
u8 attackerHoldEffect;
u8 attackerHoldEffectParam;
if (!powerOverride)
gBattleMovePower = gBattleMoves[move].power;
else
gBattleMovePower = powerOverride;
if (!typeOverride)
type = gBattleMoves[move].type;
else
type = typeOverride & 0x3F;
attack = attacker->attack;
defense = defender->defense;
spAttack = attacker->spAttack;
spDefense = defender->spDefense;
if (attacker->item == ITEM_ENIGMA_BERRY)
{
attackerHoldEffect = gEnigmaBerries[bankAtk].holdEffect;
attackerHoldEffectParam = gEnigmaBerries[bankAtk].holdEffectParam;
}
else
{
attackerHoldEffect = ItemId_GetHoldEffect(attacker->item);
attackerHoldEffectParam = ItemId_GetHoldEffectParam(attacker->item);
}
if (defender->item == ITEM_ENIGMA_BERRY)
{
defenderHoldEffect = gEnigmaBerries[bankDef].holdEffect;
defenderHoldEffectParam = gEnigmaBerries[bankDef].holdEffectParam;
}
else
{
defenderHoldEffect = ItemId_GetHoldEffect(defender->item);
defenderHoldEffectParam = ItemId_GetHoldEffectParam(defender->item);
}
if (attacker->ability == ABILITY_HUGE_POWER || attacker->ability == ABILITY_PURE_POWER)
attack *= 2;
if (ShouldGetStatBadgeBoost(BADGE01_GET, bankAtk))
attack = (110 * attack) / 100;
if (ShouldGetStatBadgeBoost(BADGE05_GET, bankDef))
defense = (110 * defense) / 100;
if (ShouldGetStatBadgeBoost(BADGE07_GET, bankAtk))
spAttack = (110 * spAttack) / 100;
if (ShouldGetStatBadgeBoost(BADGE07_GET, bankDef))
spDefense = (110 * spDefense) / 100;
for (i = 0; i < 17; i++)
{
if (attackerHoldEffect == gHoldEffectToType[i][0]
&& type == gHoldEffectToType[i][1])
{
if (type <= 8)
attack = (attack * (attackerHoldEffectParam + 100)) / 100;
else
spAttack = (spAttack * (attackerHoldEffectParam + 100)) / 100;
break;
}
}
if (attackerHoldEffect == HOLD_EFFECT_CHOICE_BAND)
attack = (150 * attack) / 100;
if (attackerHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) && (attacker->species == SPECIES_LATIAS || attacker->species == SPECIES_LATIOS))
spAttack = (150 * spAttack) / 100;
if (defenderHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) && (defender->species == SPECIES_LATIAS || defender->species == SPECIES_LATIOS))
spDefense = (150 * spDefense) / 100;
if (attackerHoldEffect == HOLD_EFFECT_DEEP_SEA_TOOTH && attacker->species == SPECIES_CLAMPERL)
spAttack *= 2;
if (defenderHoldEffect == HOLD_EFFECT_DEEP_SEA_SCALE && defender->species == SPECIES_CLAMPERL)
spDefense *= 2;
if (attackerHoldEffect == HOLD_EFFECT_LIGHT_BALL && attacker->species == SPECIES_PIKACHU)
spAttack *= 2;
if (defenderHoldEffect == HOLD_EFFECT_METAL_POWDER && defender->species == SPECIES_DITTO)
defense *= 2;
if (attackerHoldEffect == HOLD_EFFECT_THICK_CLUB && (attacker->species == SPECIES_CUBONE || attacker->species == SPECIES_MAROWAK))
attack *= 2;
if (defender->ability == ABILITY_THICK_FAT && (type == TYPE_FIRE || type == TYPE_ICE))
spAttack /= 2;
if (attacker->ability == ABILITY_HUSTLE)
attack = (150 * attack) / 100;
if (attacker->ability == ABILITY_PLUS && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_MINUS, 0, 0))
spAttack = (150 * spAttack) / 100;
if (attacker->ability == ABILITY_MINUS && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_PLUS, 0, 0))
spAttack = (150 * spAttack) / 100;
if (attacker->ability == ABILITY_GUTS && attacker->status1)
attack = (150 * attack) / 100;
if (defender->ability == ABILITY_MARVEL_SCALE && defender->status1)
defense = (150 * defense) / 100;
if (type == TYPE_ELECTRIC && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, 0xFD, 0))
gBattleMovePower /= 2;
if (type == TYPE_FIRE && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, 0xFE, 0))
gBattleMovePower /= 2;
if (type == TYPE_GRASS && attacker->ability == ABILITY_OVERGROW && attacker->hp <= (attacker->maxHP / 3))
gBattleMovePower = (150 * gBattleMovePower) / 100;
if (type == TYPE_FIRE && attacker->ability == ABILITY_BLAZE && attacker->hp <= (attacker->maxHP / 3))
gBattleMovePower = (150 * gBattleMovePower) / 100;
if (type == TYPE_WATER && attacker->ability == ABILITY_TORRENT && attacker->hp <= (attacker->maxHP / 3))
gBattleMovePower = (150 * gBattleMovePower) / 100;
if (type == TYPE_BUG && attacker->ability == ABILITY_SWARM && attacker->hp <= (attacker->maxHP / 3))
gBattleMovePower = (150 * gBattleMovePower) / 100;
if (gBattleMoves[gCurrentMove].effect == EFFECT_EXPLOSION)
defense /= 2;
if (type < TYPE_MYSTERY) // is physical
{
if (gCritMultiplier == 2)
{
if (attacker->statStages[STAT_STAGE_ATK] > 6)
APPLY_STAT_MOD(damage, attacker, attack, STAT_STAGE_ATK)
else
damage = attack;
}
else
APPLY_STAT_MOD(damage, attacker, attack, STAT_STAGE_ATK)
damage = damage * gBattleMovePower;
damage *= (2 * attacker->level / 5 + 2);
if (gCritMultiplier == 2)
{
if (defender->statStages[STAT_STAGE_DEF] < 6)
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_STAGE_DEF)
else
damageHelper = defense;
}
else
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_STAGE_DEF)
damage = damage / damageHelper;
damage /= 50;
if ((attacker->status1 & STATUS_BURN) && attacker->ability != ABILITY_GUTS)
damage /= 2;
if ((sideStatus & SIDE_STATUS_REFLECT) && gCritMultiplier == 1)
{
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(2) == 2)
damage = 2 * (damage / 3);
else
damage /= 2;
}
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gBattleMoves[move].target == 8 && CountAliveMonsInBattle(2) == 2)
damage /= 2;
// moves always do at least 1 damage.
if (damage == 0)
damage = 1;
}
if (type == TYPE_MYSTERY)
damage = 0; // is ??? type. does 0 damage.
if (type > TYPE_MYSTERY) // is special?
{
if (gCritMultiplier == 2)
{
if (attacker->statStages[STAT_STAGE_SPATK] > 6)
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_STAGE_SPATK)
else
damage = spAttack;
}
else
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_STAGE_SPATK)
damage = damage * gBattleMovePower;
damage *= (2 * attacker->level / 5 + 2);
if (gCritMultiplier == 2)
{
if (defender->statStages[STAT_STAGE_SPDEF] < 6)
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_STAGE_SPDEF)
else
damageHelper = spDefense;
}
else
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_STAGE_SPDEF)
damage = (damage / damageHelper);
damage /= 50;
if ((sideStatus & SIDE_STATUS_LIGHTSCREEN) && gCritMultiplier == 1)
{
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(2) == 2)
damage = 2 * (damage / 3);
else
damage /= 2;
}
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gBattleMoves[move].target == 8 && CountAliveMonsInBattle(2) == 2)
damage /= 2;
// are effects of weather negated with cloud nine or air lock
if (!AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_CLOUD_NINE, 0, 0)
&& !AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_AIR_LOCK, 0, 0))
{
if (gBattleWeather & WEATHER_RAIN_TEMPORARY)
{
switch (type)
{
case TYPE_FIRE:
damage /= 2;
break;
case TYPE_WATER:
damage = (15 * damage) / 10;
break;
}
}
// any weather except sun weakens solar beam
if ((gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SANDSTORM_ANY | WEATHER_HAIL)) && gCurrentMove == MOVE_SOLAR_BEAM)
damage /= 2;
// sunny
if (gBattleWeather & WEATHER_SUN_ANY)
{
switch (type)
{
case TYPE_FIRE:
damage = (15 * damage) / 10;
break;
case TYPE_WATER:
damage /= 2;
break;
}
}
}
// flash fire triggered
if ((gBattleResources->flags->flags[bankAtk] & UNKNOWN_FLAG_FLASH_FIRE) && type == TYPE_FIRE)
damage = (15 * damage) / 10;
}
return damage + 2;
}

77
src/coins.c Normal file
View File

@@ -0,0 +1,77 @@
#include "global.h"
#include "coins.h"
#include "text.h"
#include "window.h"
#include "text_window.h"
#include "string_util.h"
#define MAX_COINS 9999
EWRAM_DATA u8 sCoinsWindowId = 0;
extern s32 GetStringRightAlignXOffset(u8 fontId, u8 *str, s32 totalWidth);
extern void SetWindowTemplateFields(struct WindowTemplate* template, u8 priority, u8 tilemapLeft, u8 tilemapTop, u8 width, u8 height, u8 palNum, u16 baseBlock);
extern void SetWindowBorderStyle(u8 windowId, bool8 copyToVram, s16 tileStart, s8 palette);
extern void sub_819746C(u8 windowId, bool8 copyToVram);
extern const u8 gOtherText_Coins2[];
void PrintCoinsString(u32 coinAmount)
{
u32 xAlign;
ConvertIntToDecimalStringN(gStringVar1, coinAmount, STR_CONV_MODE_RIGHT_ALIGN, 4);
StringExpandPlaceholders(gStringVar4, gOtherText_Coins2);
xAlign = GetStringRightAlignXOffset(1, gStringVar4, 0x40);
PrintTextOnWindow(sCoinsWindowId, 1, gStringVar4, xAlign, 1, 0, NULL);
}
void ShowCoinsWindow(u32 coinAmount, u8 x, u8 y)
{
struct WindowTemplate template;
SetWindowTemplateFields(&template, 0, x, y, 8, 2, 0xF, 0x141);
sCoinsWindowId = AddWindow(&template);
FillWindowPixelBuffer(sCoinsWindowId, 0);
PutWindowTilemap(sCoinsWindowId);
SetWindowBorderStyle(sCoinsWindowId, FALSE, 0x214, 0xE);
PrintCoinsString(coinAmount);
}
void HideCoinsWindow(void)
{
sub_819746C(sCoinsWindowId, TRUE);
RemoveWindow(sCoinsWindowId);
}
u16 GetCoins(void)
{
return gSaveBlock1Ptr->coins ^ gSaveBlock2Ptr->encryptionKey;
}
void SetCoins(u16 coinAmount)
{
gSaveBlock1Ptr->coins = coinAmount ^ gSaveBlock2Ptr->encryptionKey;
}
/* Can't match it lol
bool8 AddCoins(u16 toAdd)
{
u16 newAmount;
u16 ownedCoins = GetCoins();
if (ownedCoins >= MAX_COINS)
return FALSE;
// check overflow, can't have less coins than previously
if (ownedCoins > ownedCoins + toAdd)
{
newAmount = MAX_COINS;
}
else
{
newAmount = ownedCoins + toAdd;
if (newAmount > MAX_COINS)
newAmount = MAX_COINS;
}
SetCoins(newAmount);
return TRUE;
}*/

114
src/load_save.c Normal file
View File

@@ -0,0 +1,114 @@
#include "global.h"
#include "gba/flash_internal.h"
#include "load_save.h"
#include "main.h"
#include "pokemon.h"
#include "rng.h"
#include "malloc.h"
extern u8 gPlayerPartyCount;
extern struct PokemonStorage* gPokemonStoragePtr;
extern void* gUnknown_0203CF5C;
extern u8 gHeap[0x1C000];
extern bool16 IdentifyFlash(void);
extern void SetBagItemsPointers(void);
extern void SetDecorationInventoriesPointers(void);
extern void InitHeap(void *heapStart, u32 heapSize);
void ApplyNewEncyprtionKeyToAllEncryptedData(u32 encryptionKey);
#define SAVEBLOCK_MOVE_RANGE 128
EWRAM_DATA struct SaveBlock2 gSaveblock2 = {0};
EWRAM_DATA u8 gSaveblock2_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
EWRAM_DATA struct SaveBlock1 gSaveblock1 = {0};
EWRAM_DATA u8 gSaveblock1_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
EWRAM_DATA struct PokemonStorage gPokemonStorage = {0};
EWRAM_DATA u8 gSaveblock3_DMA[SAVEBLOCK_MOVE_RANGE] = {0};
void CheckForFlashMemory(void)
{
if (!IdentifyFlash())
{
gFlashMemoryPresent = TRUE;
InitFlashTimer();
}
else
gFlashMemoryPresent = FALSE;
}
void ClearSav2(void)
{
CpuFill16(0, &gSaveblock2, sizeof(struct SaveBlock2) + sizeof(gSaveblock2_DMA));
}
void ClearSav1(void)
{
CpuFill16(0, &gSaveblock1, sizeof(struct SaveBlock1) + sizeof(gSaveblock1_DMA));
}
void SetSaveBlocksPointers(u16 offset)
{
struct SaveBlock1** sav1_LocalVar = &gSaveBlock1Ptr;
offset = (offset + Random()) & (SAVEBLOCK_MOVE_RANGE - 4);
gSaveBlock2Ptr = (void*)(&gSaveblock2) + offset;
*sav1_LocalVar = (void*)(&gSaveblock1) + offset;
gPokemonStoragePtr = (void*)(&gPokemonStorage) + offset;
SetBagItemsPointers();
SetDecorationInventoriesPointers();
}
struct SaveBlocksInOne
{
struct SaveBlock2 sav2;
struct SaveBlock1 sav1;
struct PokemonStorage sav3;
};
/*
void MoveSaveBlocks_ResetHeap(void)
{
void *vblankCB, *hblankCB;
u32 encryptionKey;
struct SaveBlocksInOne* copiedSavs;
// save interrupt functions and turn them off
vblankCB = gMain.vblankCallback;
hblankCB = gMain.hblankCallback;
gMain.vblankCallback = NULL;
gMain.hblankCallback = NULL;
gUnknown_0203CF5C = NULL;
copiedSavs = (void*)(gHeap);
// copy saveblocks' content
copiedSavs->sav2 = *gSaveBlock2Ptr;
copiedSavs->sav1 = *gSaveBlock1Ptr;
copiedSavs->sav3 = *gPokemonStoragePtr;
// change saveblocks' pointers
// argument is a sum of the individual trainerId bytes
SetSaveBlocksPointers(copiedSavs->sav2.playerTrainerId[0] + copiedSavs->sav2.playerTrainerId[1] + copiedSavs->sav2.playerTrainerId[2] + copiedSavs->sav2.playerTrainerId[3]);
// restore saveblock data since the pointers changed
*gSaveBlock2Ptr = copiedSavs->sav2;
*gSaveBlock1Ptr = copiedSavs->sav1;
*gPokemonStoragePtr = copiedSavs->sav3;
// heap was destroyed in the copying process, so reset it
InitHeap(gHeap, sizeof(gHeap));
// restore interrupt functions
gMain.hblankCallback = hblankCB;
gMain.vblankCallback = vblankCB;
// create a new encryption key
encryptionKey = (Random() << 0x10) + (Random());
ApplyNewEncyprtionKeyToAllEncryptedData(encryptionKey);
gSaveBlock2Ptr->encryptionKey = encryptionKey;
}*/

167
src/lottery_corner.c Normal file
View File

@@ -0,0 +1,167 @@
#include "global.h"
#include "lottery_corner.h"
#include "event_data.h"
#include "pokemon.h"
#include "items.h"
#include "rng.h"
#include "species.h"
#include "string_util.h"
#include "text.h"
static EWRAM_DATA u16 sWinNumberDigit = 0;
static EWRAM_DATA u16 sOtIdDigit = 0;
static const u16 sLotteryPrizes[] =
{
ITEM_PP_UP,
ITEM_EXP_SHARE,
ITEM_MAX_REVIVE,
ITEM_MASTER_BALL,
};
static u8 GetMatchingDigits(u16, u16);
void ResetLotteryCorner(void)
{
u16 rand = Random();
SetLotteryNumber((Random() << 16) | rand);
VarSet(VAR_POKELOT_PRIZE, 0);
}
void SetRandomLotteryNumber(u16 i)
{
u32 var = Random();
while (--i != 0xFFFF)
var = var * 1103515245 + 12345;
SetLotteryNumber(var);
}
void RetrieveLotteryNumber(void)
{
u16 lottoNumber = GetLotteryNumber();
gScriptResult = lottoNumber;
}
void PickLotteryCornerTicket(void)
{
u16 i;
u16 j;
u32 box;
u32 slot;
gSpecialVar_0x8004 = 0;
slot = 0;
box = 0;
for (i = 0; i < 6; i++)
{
struct Pokemon *pkmn = &gPlayerParty[i];
// UB: Too few arguments for function GetMonData
if (GetMonData(pkmn, MON_DATA_SPECIES) != SPECIES_NONE)
{
// do not calculate ticket values for eggs.
if (!GetMonData(pkmn, MON_DATA_IS_EGG))
{
u32 otId = GetMonData(pkmn, MON_DATA_OT_ID);
u8 numMatchingDigits = GetMatchingDigits(gScriptResult, otId);
if (numMatchingDigits > gSpecialVar_0x8004 && numMatchingDigits > 1)
{
gSpecialVar_0x8004 = numMatchingDigits - 1;
box = 14;
slot = i;
}
}
}
else // pokemon are always arranged from populated spots first to unpopulated, so the moment a NONE species is found, that's the end of the list.
break;
}
// player has 14 boxes.
for (i = 0; i < 14; i++)
{
// player has 30 slots per box.
for (j = 0; j < 30; j++)
{
if (GetBoxMonData(&gPokemonStoragePtr->boxes[i][j], MON_DATA_SPECIES) != SPECIES_NONE &&
!GetBoxMonData(&gPokemonStoragePtr->boxes[i][j], MON_DATA_IS_EGG))
{
u32 otId = GetBoxMonData(&gPokemonStoragePtr->boxes[i][j], MON_DATA_OT_ID);
u8 numMatchingDigits = GetMatchingDigits(gScriptResult, otId);
if (numMatchingDigits > gSpecialVar_0x8004 && numMatchingDigits > 1)
{
gSpecialVar_0x8004 = numMatchingDigits - 1;
box = i;
slot = j;
}
}
}
}
if (gSpecialVar_0x8004 != 0)
{
gSpecialVar_0x8005 = sLotteryPrizes[gSpecialVar_0x8004 - 1];
if (box == 14)
{
gSpecialVar_0x8006 = 0;
GetMonData(&gPlayerParty[slot], MON_DATA_NICKNAME, gStringVar1);
}
else
{
gSpecialVar_0x8006 = 1;
GetBoxMonData(&gPokemonStoragePtr->boxes[box][slot], MON_DATA_NICKNAME, gStringVar1);
}
StringGetEnd10(gStringVar1);
}
}
static u8 GetMatchingDigits(u16 winNumber, u16 otId)
{
u8 i;
u8 matchingDigits = 0;
for (i = 0; i < 5; i++)
{
sWinNumberDigit = winNumber % 10;
sOtIdDigit = otId % 10;
if (sWinNumberDigit == sOtIdDigit)
{
winNumber = winNumber / 10;
otId = otId / 10;
matchingDigits++;
}
else
break;
}
return matchingDigits;
}
// lottery numbers go from 0 to 99999, not 65535 (0xFFFF). interestingly enough, the function that calls GetLotteryNumber shifts to u16, so it cant be anything above 65535 anyway.
void SetLotteryNumber(u32 lotteryNum)
{
u16 lowNum = lotteryNum >> 16;
u16 highNum = lotteryNum;
VarSet(VAR_POKELOT_RND1, highNum);
VarSet(VAR_POKELOT_RND2, lowNum);
}
u32 GetLotteryNumber(void)
{
u16 highNum = VarGet(VAR_POKELOT_RND1);
u16 lowNum = VarGet(VAR_POKELOT_RND2);
return (lowNum << 16) | highNum;
}
// interestingly, this may have been the original lottery number set function, but GF tried to change it to 32-bit later but didnt finish changing all calls as one GetLotteryNumber still shifts to u16.
void SetLotteryNumber16_Unused(u16 lotteryNum)
{
SetLotteryNumber(lotteryNum);
}

View File

@@ -5,6 +5,7 @@
#include "rng.h"
#include "dma3.h"
#include "gba/flash_internal.h"
#include "battle.h"
extern u16 GetGpuReg(u8);
extern void SetGpuReg(u8, u16);
@@ -34,9 +35,8 @@ extern struct SoundInfo gSoundInfo;
extern u32 gFlashMemoryPresent;
extern u32 IntrMain[];
extern u8 gHeap[];
extern struct SaveBlock2 gUnknown_02024A54;
extern char *gUnknown_03005D94;
extern char gUnknown_02029808[];
extern struct SaveBlock2 gSaveblock2;
extern struct PokemonStorage gPokemonStorage;
extern u32 gBattleTypeFlags;
extern u8 gUnknown_03002748;
extern u32 *gUnknown_0203CF5C;
@@ -185,8 +185,8 @@ static void InitMainCallbacks(void)
gMain.vblankCounter2 = 0;
gMain.callback1 = NULL;
SetMainCallback2(c2_copyright_1);
gSaveBlock2Ptr = &gUnknown_02024A54;
gUnknown_03005D94 = gUnknown_02029808;
gSaveBlock2Ptr = &gSaveblock2;
gPokemonStoragePtr = &gPokemonStorage;
}
static void CallCallbacks(void)
@@ -359,7 +359,7 @@ static void VBlankIntr(void)
m4aSoundMain();
sub_8033648();
if (!gMain.inBattle || (gBattleTypeFlags & 0x013F0102) == 0)
if (!gMain.inBattle || !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_RECORDED)))
Random();
sub_800E174();
@@ -368,7 +368,7 @@ static void VBlankIntr(void)
gMain.intrCheck |= INTR_FLAG_VBLANK;
}
void StartFlashMemoryTimer(void)
void InitFlashTimer(void)
{
SetFlashTimerIntr(2, gIntrTable + 0x7);
}

View File

@@ -1,7 +1,5 @@
#include "global.h"
EWRAM_DATA u8 gHeap[0x1C000] = {0};
static void *sHeapStart;
static u32 sHeapSize;

55
src/money.c Normal file
View File

@@ -0,0 +1,55 @@
#include "global.h"
#include "money.h"
#define MAX_MONEY 999999
u32 GetMoney(u32* moneyPtr)
{
return *moneyPtr ^ gSaveBlock2Ptr->encryptionKey;
}
void SetMoney(u32* moneyPtr, u32 newValue)
{
*moneyPtr = gSaveBlock2Ptr->encryptionKey ^ newValue;
}
bool8 IsEnoughMoney(u32* moneyPtr, u32 cost)
{
if (GetMoney(moneyPtr) >= cost)
return TRUE;
else
return FALSE;
}
void AddMoney(u32* moneyPtr, u32 toAdd)
{
u32 toSet = GetMoney(moneyPtr);
// can't have more money than MAX
if (toSet + toAdd > MAX_MONEY)
{
toSet = MAX_MONEY;
}
else
{
toSet += toAdd;
// check overflow, can't have less money after you receive more
if (toSet < GetMoney(moneyPtr))
toSet = MAX_MONEY;
}
SetMoney(moneyPtr, toSet);
}
void SubtractMoney(u32* moneyPtr, u32 toSub)
{
u32 toSet = GetMoney(moneyPtr);
// can't subtract more than you already have
if (toSet < toSub)
toSet = 0;
else
toSet -= toSub;
SetMoney(moneyPtr, toSet);
}

View File

@@ -1,22 +1,64 @@
#include "global.h"
#include "new_game.h"
#include "rng.h"
#include "pokemon.h"
#include "roamer.h"
#include "pokemon_size_record.h"
#include "script.h"
#include "lottery_corner.h"
#include "play_time.h"
#include "mauville_old_man.h"
#include "lilycove_lady.h"
#include "load_save.h"
#include "pokeblock.h"
#include "dewford_trend.h"
#include "berry.h"
#include "rtc.h"
#include "easy_chat.h"
#include "event_data.h"
#include "money.h"
#include "coins.h"
extern u8 gPlayerPartyCount;
extern u8 gDifferentSaveFile;
extern u16 gSaveFileStatus;
extern u8 gUnknown_030060B0;
// TODO: replace those declarations with file headers
extern u16 GetGeneratedTrainerIdLower(void);
extern void ClearContestWinnerPicsInContestHall(void);
extern void warp1_set(s8 mapBank, s8 mapNo, s8 warpNo, s8 xPos, s8 yPos);
extern void warp_in(void);
extern void sub_80BB358(void);
extern void ZeroPlayerPartyMons(void);
extern void ZeroEnemyPartyMons(void);
extern void ResetBagScrollPositions(void);
extern void sub_813624C(void); // clears something pokeblock related
extern void ClearSav2(void); // clears something pokeblock related
extern void ResetPokedex(void);
extern void sub_8084400(void);
extern void ClearMailData(void);
extern void ClearTVShowData(void);
extern void ResetGabbyAndTy(void);
extern void ResetSecretBases(void);
extern void ResetLinkContestBoolean(void);
extern void ResetGameStats(void);
extern void sub_8052DA8(void);
extern void InitLinkBattleRecords(void);
extern void ResetPokemonStorageSystem(void);
extern void ClearBag(void);
extern void NewGameInitPCItems(void);
extern void ClearDecorationInventories(void);
extern void ResetFanClub(void);
extern void copy_strings_to_sav1(void);
extern void sub_819FAA0(void);
extern void sub_81A4B14(void);
extern void sub_8195E10(void);
extern void sub_801AFD8(void);
extern void sub_800E5AC(void);
extern void sub_81D54BC(void);
extern void ResetContestLinkResults(void);
extern void ResetPokeJumpResults(void);
extern void SetBerryPowder(u32* powder, u32 newValue);
extern u8 gUnknown_082715DE[];
void WriteUnalignedWord(u32 var, u8 *dataPtr)
{
@@ -104,8 +146,71 @@ void sub_808447C(void)
ResetBagScrollPositions();
sub_813624C();
}
/*
void NewGameInitData(void)
{
Finish when more header files are available
}*/
if (gSaveFileStatus == 0 || gSaveFileStatus == 2)
RtcReset();
gDifferentSaveFile = 1;
gSaveBlock2Ptr->encryptionKey = 0;
ZeroPlayerPartyMons();
ZeroEnemyPartyMons();
ResetPokedex();
sub_8084400();
ClearSav1();
ClearMailData();
gSaveBlock2Ptr->specialSaveWarp = 0;
gSaveBlock2Ptr->field_A8 = 0;
InitPlayerTrainerId();
PlayTimeCounter_Reset();
ClearPokedexFlags();
InitEventData();
ClearTVShowData();
ResetGabbyAndTy();
ResetSecretBases();
ClearBerryTrees();
SetMoney(&gSaveBlock1Ptr->money, 3000);
SetCoins(0);
ResetLinkContestBoolean();
ResetGameStats();
ClearAllContestWinnerPics();
InitLinkBattleRecords();
InitSeedotSizeRecord();
InitLotadSizeRecord();
gPlayerPartyCount = 0;
ZeroPlayerPartyMons();
ResetPokemonStorageSystem();
ClearRoamerData();
ClearRoamerLocationData();
gSaveBlock1Ptr->registeredItem = 0;
ClearBag();
NewGameInitPCItems();
ClearPokeblocks();
ClearDecorationInventories();
InitEasyChatPhrases();
SetMauvilleOldMan();
InitDewfordTrend();
ResetFanClub();
ResetLotteryCorner();
WarpToTruck();
ScriptContext2_RunNewScript(gUnknown_082715DE);
ResetMiniGamesResults();
copy_strings_to_sav1();
SetLilycoveLady();
sub_819FAA0();
sub_81A4B14();
sub_8195E10();
sub_801AFD8();
sub_800E5AC();
sub_81D54BC();
ResetContestLinkResults();
}
void ResetMiniGamesResults(void)
{
CpuFill16(0, &gSaveBlock2Ptr->berryCrush, sizeof(struct BerryCrush));
SetBerryPowder(&gSaveBlock2Ptr->berryCrush.berryPowderAmount, 0);
ResetPokeJumpResults();
CpuFill16(0, &gSaveBlock2Ptr->berryPick, sizeof(struct BerryPickingResults));
}

View File

@@ -54,7 +54,7 @@ EWRAM_DATA struct PaletteStruct sPaletteStructs[0x10] = {0};
EWRAM_DATA struct PaletteFadeControl gPaletteFade = {0};
EWRAM_DATA u32 gFiller_2037FE0 = 0;
EWRAM_DATA u32 sPlttBufferTransferPending = 0;
EWRAM_DATA u8 sPaletteDecompressionBuffer[0x400] = {0};
EWRAM_DATA u8 gPaletteDecompressionBuffer[0x400] = {0};
extern struct PaletteStructTemplate gDummyPaletteStructTemplate;
extern void *gUnknown_0852487C;
@@ -102,9 +102,9 @@ void sub_80A1884(u16 a1)
void LoadCompressedPalette(const void *src, u16 offset, u16 size)
{
LZDecompressWram(src, sPaletteDecompressionBuffer);
CpuCopy16(sPaletteDecompressionBuffer, gPlttBufferUnfaded + offset, size);
CpuCopy16(sPaletteDecompressionBuffer, gPlttBufferFaded + offset, size);
LZDecompressWram(src, gPaletteDecompressionBuffer);
CpuCopy16(gPaletteDecompressionBuffer, gPlttBufferUnfaded + offset, size);
CpuCopy16(gPaletteDecompressionBuffer, gPlttBufferFaded + offset, size);
}
void LoadPalette(const void *src, u16 offset, u16 size)

View File

@@ -10,7 +10,7 @@ enum
static u8 sPlayTimeCounterState;
void PlayTimeCounter_Reset()
void PlayTimeCounter_Reset(void)
{
sPlayTimeCounterState = STOPPED;
@@ -20,7 +20,7 @@ void PlayTimeCounter_Reset()
gSaveBlock2Ptr->playTimeVBlanks = 0;
}
void PlayTimeCounter_Start()
void PlayTimeCounter_Start(void)
{
sPlayTimeCounterState = RUNNING;
@@ -28,12 +28,12 @@ void PlayTimeCounter_Start()
PlayTimeCounter_SetToMax();
}
void PlayTimeCounter_Stop()
void PlayTimeCounter_Stop(void)
{
sPlayTimeCounterState = STOPPED;
}
void PlayTimeCounter_Update()
void PlayTimeCounter_Update(void)
{
if (sPlayTimeCounterState == RUNNING)
{
@@ -62,7 +62,7 @@ void PlayTimeCounter_Update()
}
}
void PlayTimeCounter_SetToMax()
void PlayTimeCounter_SetToMax(void)
{
sPlayTimeCounterState = MAXED_OUT;

325
src/pokemon_1.c Normal file
View File

@@ -0,0 +1,325 @@
#include "global.h"
#include "pokemon.h"
#include "rng.h"
#include "main.h"
#include "items.h"
#include "string_util.h"
#include "text.h"
//Extracts the upper 16 bits of a 32-bit number
#define HIHALF(n) (((n) & 0xFFFF0000) >> 16)
//Extracts the lower 16 bits of a 32-bit number
#define LOHALF(n) ((n) & 0xFFFF)
extern u8 sav1_map_get_name(void);
void ZeroBoxMonData(struct BoxPokemon *boxMon)
{
u8 *raw = (u8 *)boxMon;
u32 i;
for (i = 0; i < sizeof(struct BoxPokemon); i++)
raw[i] = 0;
}
void ZeroMonData(struct Pokemon *mon)
{
u32 arg;
ZeroBoxMonData(&mon->box);
arg = 0;
SetMonData(mon, MON_DATA_STATUS, &arg);
SetMonData(mon, MON_DATA_LEVEL, &arg);
SetMonData(mon, MON_DATA_HP, &arg);
SetMonData(mon, MON_DATA_MAX_HP, &arg);
SetMonData(mon, MON_DATA_ATK, &arg);
SetMonData(mon, MON_DATA_DEF, &arg);
SetMonData(mon, MON_DATA_SPD, &arg);
SetMonData(mon, MON_DATA_SPATK, &arg);
SetMonData(mon, MON_DATA_SPDEF, &arg);
arg = 255;
SetMonData(mon, MON_DATA_MAIL, &arg);
}
void ZeroPlayerPartyMons(void)
{
s32 i;
for (i = 0; i < 6; i++)
ZeroMonData(&gPlayerParty[i]);
}
void ZeroEnemyPartyMons(void)
{
s32 i;
for (i = 0; i < 6; i++)
ZeroMonData(&gEnemyParty[i]);
}
void CreateMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId)
{
u32 arg;
ZeroMonData(mon);
CreateBoxMon(&mon->box, species, level, fixedIV, hasFixedPersonality, fixedPersonality, otIdType, fixedOtId);
SetMonData(mon, MON_DATA_LEVEL, &level);
arg = 255;
SetMonData(mon, MON_DATA_MAIL, &arg);
CalculateMonStats(mon);
}
void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId)
{
u8 speciesName[POKEMON_NAME_LENGTH + 1];
u32 personality;
u32 value;
u16 checksum;
ZeroBoxMonData(boxMon);
if (hasFixedPersonality)
personality = fixedPersonality;
else
personality = Random32();
SetBoxMonData(boxMon, MON_DATA_PERSONALITY, &personality);
//Determine original trainer ID
if (otIdType == OT_ID_RANDOM_NO_SHINY) //Pokemon cannot be shiny
{
u32 shinyValue;
do
{
value = Random32();
shinyValue = HIHALF(value) ^ LOHALF(value) ^ HIHALF(personality) ^ LOHALF(personality);
} while (shinyValue < 8);
}
else if (otIdType == OT_ID_PRESET) //Pokemon has a preset OT ID
{
value = fixedOtId;
}
else //Player is the OT
{
value = gSaveBlock2Ptr->playerTrainerId[0]
| (gSaveBlock2Ptr->playerTrainerId[1] << 8)
| (gSaveBlock2Ptr->playerTrainerId[2] << 16)
| (gSaveBlock2Ptr->playerTrainerId[3] << 24);
}
SetBoxMonData(boxMon, MON_DATA_OT_ID, &value);
checksum = CalculateBoxMonChecksum(boxMon);
SetBoxMonData(boxMon, MON_DATA_CHECKSUM, &checksum);
EncryptBoxMon(boxMon);
GetSpeciesName(speciesName, species);
SetBoxMonData(boxMon, MON_DATA_NICKNAME, speciesName);
SetBoxMonData(boxMon, MON_DATA_LANGUAGE, &gGameLanguage);
SetBoxMonData(boxMon, MON_DATA_OT_NAME, gSaveBlock2Ptr->playerName);
SetBoxMonData(boxMon, MON_DATA_SPECIES, &species);
SetBoxMonData(boxMon, MON_DATA_EXP, &gExperienceTables[gBaseStats[species].growthRate][level]);
SetBoxMonData(boxMon, MON_DATA_FRIENDSHIP, &gBaseStats[species].friendship);
value = sav1_map_get_name();
SetBoxMonData(boxMon, MON_DATA_MET_LOCATION, &value);
SetBoxMonData(boxMon, MON_DATA_MET_LEVEL, &level);
SetBoxMonData(boxMon, MON_DATA_MET_GAME, &gGameVersion);
value = ITEM_POKE_BALL;
SetBoxMonData(boxMon, MON_DATA_POKEBALL, &value);
SetBoxMonData(boxMon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender);
if (fixedIV < 32)
{
SetBoxMonData(boxMon, MON_DATA_HP_IV, &fixedIV);
SetBoxMonData(boxMon, MON_DATA_ATK_IV, &fixedIV);
SetBoxMonData(boxMon, MON_DATA_DEF_IV, &fixedIV);
SetBoxMonData(boxMon, MON_DATA_SPD_IV, &fixedIV);
SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &fixedIV);
SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &fixedIV);
}
else
{
u32 iv;
value = Random();
iv = value & 0x1F;
SetBoxMonData(boxMon, MON_DATA_HP_IV, &iv);
iv = (value & 0x3E0) >> 5;
SetBoxMonData(boxMon, MON_DATA_ATK_IV, &iv);
iv = (value & 0x7C00) >> 10;
SetBoxMonData(boxMon, MON_DATA_DEF_IV, &iv);
value = Random();
iv = value & 0x1F;
SetBoxMonData(boxMon, MON_DATA_SPD_IV, &iv);
iv = (value & 0x3E0) >> 5;
SetBoxMonData(boxMon, MON_DATA_SPATK_IV, &iv);
iv = (value & 0x7C00) >> 10;
SetBoxMonData(boxMon, MON_DATA_SPDEF_IV, &iv);
}
if (gBaseStats[species].ability2)
{
value = personality & 1;
SetBoxMonData(boxMon, MON_DATA_ALT_ABILITY, &value);
}
GiveBoxMonInitialMoveset(boxMon);
}
void CreateMonWithNature(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 nature)
{
u32 personality;
do
{
personality = Random32();
}
while (nature != GetNatureFromPersonality(personality));
CreateMon(mon, species, level, fixedIV, 1, personality, OT_ID_PLAYER_ID, 0);
}
void CreateMonWithGenderNatureLetter(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 gender, u8 nature, u8 unownLetter)
{
u32 personality;
if ((u8)(unownLetter - 1) < 28)
{
u16 actualLetter;
do
{
personality = Random32();
actualLetter = ((((personality & 0x3000000) >> 18) | ((personality & 0x30000) >> 12) | ((personality & 0x300) >> 6) | (personality & 0x3)) % 28);
}
while (nature != GetNatureFromPersonality(personality)
|| gender != GetGenderFromSpeciesAndPersonality(species, personality)
|| actualLetter != unownLetter - 1);
}
else
{
do
{
personality = Random32();
}
while (nature != GetNatureFromPersonality(personality)
|| gender != GetGenderFromSpeciesAndPersonality(species, personality));
}
CreateMon(mon, species, level, fixedIV, 1, personality, OT_ID_PLAYER_ID, 0);
}
// This is only used to create Wally's Ralts.
void CreateMaleMon(struct Pokemon *mon, u16 species, u8 level)
{
u32 personality;
u32 otId;
do
{
otId = Random32();
personality = Random32();
}
while (GetGenderFromSpeciesAndPersonality(species, personality) != MON_MALE);
CreateMon(mon, species, level, 32, 1, personality, OT_ID_PRESET, otId);
}
void CreateMonWithIVsPersonality(struct Pokemon *mon, u16 species, u8 level, u32 ivs, u32 personality)
{
CreateMon(mon, species, level, 0, 1, personality, OT_ID_PLAYER_ID, 0);
SetMonData(mon, MON_DATA_IVS, &ivs);
CalculateMonStats(mon);
}
void CreateMonWithIVsOTID(struct Pokemon *mon, u16 species, u8 level, u8 *ivs, u32 otId)
{
CreateMon(mon, species, level, 0, 0, 0, OT_ID_PRESET, otId);
SetMonData(mon, MON_DATA_HP_IV, &ivs[0]);
SetMonData(mon, MON_DATA_ATK_IV, &ivs[1]);
SetMonData(mon, MON_DATA_DEF_IV, &ivs[2]);
SetMonData(mon, MON_DATA_SPD_IV, &ivs[3]);
SetMonData(mon, MON_DATA_SPATK_IV, &ivs[4]);
SetMonData(mon, MON_DATA_SPDEF_IV, &ivs[5]);
CalculateMonStats(mon);
}
void CreateMonWithEVSpread(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 evSpread)
{
s32 i;
s32 statCount = 0;
u16 evAmount;
u8 temp;
CreateMon(mon, species, level, fixedIV, 0, 0, 0, 0);
temp = evSpread;
for (i = 0; i < 6; i++)
{
if (temp & 1)
statCount++;
temp >>= 1;
}
evAmount = 510 / statCount;
temp = 1;
for (i = 0; i < 6; i++)
{
if (evSpread & temp)
SetMonData(mon, MON_DATA_HP_EV + i, &evAmount);
temp <<= 1;
}
CalculateMonStats(mon);
}
void sub_806819C(struct Pokemon *mon, struct UnknownPokemonStruct *src)
{
s32 i;
u8 nickname[30];
u8 language;
u8 value;
CreateMon(mon, src->species, src->level, 0, 1, src->personality, 1, src->otId);
for (i = 0; i < 4; i++)
SetMonMoveSlot(mon, src->moves[i], i);
SetMonData(mon, MON_DATA_PP_BONUSES, &src->ppBonuses);
SetMonData(mon, MON_DATA_HELD_ITEM, &src->heldItem);
SetMonData(mon, MON_DATA_FRIENDSHIP, &src->friendship);
StringCopy(nickname, src->nickname);
if (nickname[0] == EXT_CTRL_CODE_BEGIN && nickname[1] == EXT_CTRL_CODE_JPN)
{
language = LANGUAGE_JAPANESE;
StripExtCtrlCodes(nickname);
}
else
language = GAME_LANGUAGE;
SetMonData(mon, MON_DATA_LANGUAGE, &language);
SetMonData(mon, MON_DATA_NICKNAME, nickname);
SetMonData(mon, MON_DATA_HP_EV, &src->hpEV);
SetMonData(mon, MON_DATA_ATK_EV, &src->attackEV);
SetMonData(mon, MON_DATA_DEF_EV, &src->defenseEV);
SetMonData(mon, MON_DATA_SPD_EV, &src->speedEV);
SetMonData(mon, MON_DATA_SPATK_EV, &src->spAttackEV);
SetMonData(mon, MON_DATA_SPDEF_EV, &src->spDefenseEV);
value = src->altAbility;
SetMonData(mon, MON_DATA_ALT_ABILITY, &value);
value = src->hpIV;
SetMonData(mon, MON_DATA_HP_IV, &value);
value = src->attackIV;
SetMonData(mon, MON_DATA_ATK_IV, &value);
value = src->defenseIV;
SetMonData(mon, MON_DATA_DEF_IV, &value);
value = src->speedIV;
SetMonData(mon, MON_DATA_SPD_IV, &value);
value = src->spAttackIV;
SetMonData(mon, MON_DATA_SPATK_IV, &value);
value = src->spDefenseIV;
SetMonData(mon, MON_DATA_SPDEF_IV, &value);
MonRestorePP(mon);
CalculateMonStats(mon);
}

4
src/pokemon_2.c Normal file
View File

@@ -0,0 +1,4 @@
#include "global.h"
#include "pokemon.h"

222
src/pokemon_size_record.c Normal file
View File

@@ -0,0 +1,222 @@
#include "global.h"
#include "pokemon_size_record.h"
#include "event_data.h"
#include "species.h"
#include "string_util.h"
#include "text.h"
#include "pokemon.h"
#define DEFAULT_MAX_SIZE 0x8000 // was 0x8100 in Ruby/Sapphire
struct UnknownStruct
{
u16 unk0;
u8 unk2;
u16 unk4;
};
extern u16 GetPokedexHeightWeight(u16 dexNo, bool8 height);
extern u16 SpeciesToNationalPokedexNum(u16 species);
static const struct UnknownStruct sBigMonSizeTable[] =
{
{ 290, 1, 0 },
{ 300, 1, 10 },
{ 400, 2, 110 },
{ 500, 4, 310 },
{ 600, 20, 710 },
{ 700, 50, 2710 },
{ 800, 100, 7710 },
{ 900, 150, 17710 },
{ 1000, 150, 32710 },
{ 1100, 100, -17826 },
{ 1200, 50, -7826 },
{ 1300, 20, -2826 },
{ 1400, 5, -826 },
{ 1500, 2, -326 },
{ 1600, 1, -126 },
{ 1700, 1, -26 },
};
static const u8 sGiftRibbonsMonDataIds[] =
{
MON_DATA_GIFT_RIBBON_1, MON_DATA_GIFT_RIBBON_2, MON_DATA_GIFT_RIBBON_3,
MON_DATA_GIFT_RIBBON_4, MON_DATA_GIFT_RIBBON_5, MON_DATA_GIFT_RIBBON_6,
MON_DATA_GIFT_RIBBON_7
};
extern const u8 gOtherText_DecimalPoint[];
extern const u8 gOtherText_Marco[];
extern const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1];
#define CM_PER_INCH 2.54
static u32 GetMonSizeHash(struct Pokemon *pkmn)
{
u16 personality = GetMonData(pkmn, MON_DATA_PERSONALITY);
u16 hpIV = GetMonData(pkmn, MON_DATA_HP_IV) & 0xF;
u16 attackIV = GetMonData(pkmn, MON_DATA_ATK_IV) & 0xF;
u16 defenseIV = GetMonData(pkmn, MON_DATA_DEF_IV) & 0xF;
u16 speedIV = GetMonData(pkmn, MON_DATA_SPD_IV) & 0xF;
u16 spAtkIV = GetMonData(pkmn, MON_DATA_SPATK_IV) & 0xF;
u16 spDefIV = GetMonData(pkmn, MON_DATA_SPDEF_IV) & 0xF;
u32 hibyte = ((attackIV ^ defenseIV) * hpIV) ^ (personality & 0xFF);
u32 lobyte = ((spAtkIV ^ spDefIV) * speedIV) ^ (personality >> 8);
return (hibyte << 8) + lobyte;
}
static u8 TranslateBigMonSizeTableIndex(u16 a)
{
u8 i;
for (i = 1; i < 15; i++)
{
if (a < sBigMonSizeTable[i].unk4)
return i - 1;
}
return i;
}
static u32 GetMonSize(u16 species, u16 b)
{
u64 unk2;
u64 unk4;
u64 unk0;
u32 height;
u32 var;
height = GetPokedexHeightWeight(SpeciesToNationalPokedexNum(species), 0);
var = TranslateBigMonSizeTableIndex(b);
unk0 = sBigMonSizeTable[var].unk0;
unk2 = sBigMonSizeTable[var].unk2;
unk4 = sBigMonSizeTable[var].unk4;
unk0 += (b - unk4) / unk2;
return height * unk0 / 10;
}
static void FormatMonSizeRecord(u8 *string, u32 size)
{
#ifdef UNITS_IMPERIAL
//Convert size from centimeters to inches
size = (double)(size * 10) / (CM_PER_INCH * 10);
#endif
string = ConvertIntToDecimalStringN(string, size / 10, 0, 8);
string = StringAppend(string, gOtherText_DecimalPoint);
ConvertIntToDecimalStringN(string, size % 10, 0, 1);
}
static u8 CompareMonSize(u16 species, u16 *sizeRecord)
{
if (gScriptResult == 0xFF)
{
return 0;
}
else
{
struct Pokemon *pkmn = &gPlayerParty[gScriptResult];
if (GetMonData(pkmn, MON_DATA_IS_EGG) == TRUE || GetMonData(pkmn, MON_DATA_SPECIES) != species)
{
return 1;
}
else
{
u32 oldSize;
u32 newSize;
u16 sizeParams;
*(&sizeParams) = GetMonSizeHash(pkmn);
newSize = GetMonSize(species, sizeParams);
oldSize = GetMonSize(species, *sizeRecord);
FormatMonSizeRecord(gStringVar2, newSize);
if (newSize <= oldSize)
{
return 2;
}
else
{
*sizeRecord = sizeParams;
return 3;
}
}
}
}
// Stores species name in gStringVar1, trainer's name in gStringVar2, and size in gStringVar3
static void GetMonSizeRecordInfo(u16 species, u16 *sizeRecord)
{
u32 size = GetMonSize(species, *sizeRecord);
FormatMonSizeRecord(gStringVar3, size);
StringCopy(gStringVar1, gSpeciesNames[species]);
if (*sizeRecord == DEFAULT_MAX_SIZE)
StringCopy(gStringVar2, gOtherText_Marco);
else
StringCopy(gStringVar2, gSaveBlock2Ptr->playerName);
}
void InitSeedotSizeRecord(void)
{
VarSet(VAR_SEEDOT_SIZE_RECORD, DEFAULT_MAX_SIZE);
}
void GetSeedotSizeRecordInfo(void)
{
u16 *sizeRecord = GetVarPointer(VAR_SEEDOT_SIZE_RECORD);
GetMonSizeRecordInfo(SPECIES_SEEDOT, sizeRecord);
}
void CompareSeedotSize(void)
{
u16 *sizeRecord = GetVarPointer(VAR_SEEDOT_SIZE_RECORD);
gScriptResult = CompareMonSize(SPECIES_SEEDOT, sizeRecord);
}
void InitLotadSizeRecord(void)
{
VarSet(VAR_LOTAD_SIZE_RECORD, DEFAULT_MAX_SIZE);
}
void GetLotadSizeRecordInfo(void)
{
u16 *sizeRecord = GetVarPointer(VAR_LOTAD_SIZE_RECORD);
GetMonSizeRecordInfo(SPECIES_LOTAD, sizeRecord);
}
void CompareLotadSize(void)
{
u16 *sizeRecord = GetVarPointer(VAR_LOTAD_SIZE_RECORD);
gScriptResult = CompareMonSize(SPECIES_LOTAD, sizeRecord);
}
void GiveGiftRibbonToParty(u8 index, u8 ribbonId)
{
s32 i;
bool32 gotRibbon = FALSE;
u8 data = 1;
u8 array[8];
memcpy(array, sGiftRibbonsMonDataIds, sizeof(sGiftRibbonsMonDataIds));
if (index < 11 && ribbonId < 65)
{
gSaveBlock1Ptr->giftRibbons[index] = ribbonId;
for (i = 0; i < 6; i++)
{
struct Pokemon *pkmn = &gPlayerParty[i];
if (GetMonData(pkmn, MON_DATA_SPECIES) != 0 && GetMonData(pkmn, MON_DATA_SANITY_BIT3) == 0)
{
SetMonData(pkmn, array[index], &data);
gotRibbon = TRUE;
}
}
if (gotRibbon)
FlagSet(SYS_RIBBON_GET);
}
}

View File

@@ -4,13 +4,10 @@
// The number 1103515245 comes from the example implementation of rand and srand
// in the ISO C standard.
extern u32 gRngValue;
extern u32 gRng2Value;
EWRAM_DATA static u8 sUnknown = 0;
EWRAM_DATA static u32 sRandCount = 0;
u16 Random()
u16 Random(void)
{
gRngValue = 1103515245 * gRngValue + 24691;
sRandCount++;

268
src/safari_zone.c Normal file
View File

@@ -0,0 +1,268 @@
#include "global.h"
#include "safari_zone.h"
#include "event_data.h"
#include "game_stat.h"
#include "main.h"
#include "battle.h"
#include "string_util.h"
struct PokeblockFeeder
{
/*0x00*/ s16 x;
/*0x02*/ s16 y;
/*0x04*/ s8 mapNum;
/*0x05*/ u8 stepCounter;
/*0x08*/ struct Pokeblock pokeblock;
};
#define NUM_POKEBLOCK_FEEDERS 10
extern u8 gBattleOutcome;
extern void* gUnknown_03005DAC;
extern u8 gUnknown_082A4B8A[];
extern u8 gUnknown_082A4B6F[];
extern u8 gUnknown_082A4B4C[];
extern u8 gUnknown_082A4B9B[];
extern const u8* const gPokeblockNames[];
extern void sub_80EE44C(u8, u8);
extern void IncrementGameStat(u8 index);
extern void ScriptContext1_SetupScript(u8*);
extern void ScriptContext2_RunNewScript(u8*);
extern void c2_exit_to_overworld_2_switch(void);
extern void c2_exit_to_overworld_1_continue_scripts_restart_music(void);
extern void c2_load_new_map(void);
extern void sub_80AF6F0(void);
extern void ScriptContext1_Stop(void);
extern void warp_in(void);
extern void GetXYCoordsOneStepInFrontOfPlayer(s16* x, s16* y);
extern void PlayerGetDestCoords(s16* x, s16* y);
EWRAM_DATA u8 gNumSafariBalls = 0;
EWRAM_DATA static u16 sSafariZoneStepCounter = 0;
EWRAM_DATA static u8 sSafariZoneCaughtMons = 0;
EWRAM_DATA static u8 sSafariZoneFleedMons = 0;
EWRAM_DATA static struct PokeblockFeeder sPokeblockFeeders[NUM_POKEBLOCK_FEEDERS] = {0};
static void ClearAllPokeblockFeeders(void);
static void DecrementFeederStepCounters(void);
bool32 GetSafariZoneFlag(void)
{
return FlagGet(SYS_SAFARI_MODE);
}
void SetSafariZoneFlag(void)
{
FlagSet(SYS_SAFARI_MODE);
}
void ResetSafariZoneFlag(void)
{
FlagReset(SYS_SAFARI_MODE);
}
void EnterSafariMode(void)
{
IncrementGameStat(GAME_STAT_ENTERED_SAFARI_ZONE);
SetSafariZoneFlag();
ClearAllPokeblockFeeders();
gNumSafariBalls = 30;
sSafariZoneStepCounter = 500;
sSafariZoneCaughtMons = 0;
sSafariZoneFleedMons = 0;
}
void ExitSafariMode(void)
{
sub_80EE44C(sSafariZoneCaughtMons, sSafariZoneFleedMons);
ResetSafariZoneFlag();
ClearAllPokeblockFeeders();
gNumSafariBalls = 0;
sSafariZoneStepCounter = 0;
}
bool8 SafariZoneTakeStep(void)
{
if (GetSafariZoneFlag() == FALSE)
{
return FALSE;
}
DecrementFeederStepCounters();
sSafariZoneStepCounter--;
if (sSafariZoneStepCounter == 0)
{
ScriptContext1_SetupScript(gUnknown_082A4B8A);
return TRUE;
}
return FALSE;
}
void SafariZoneRetirePrompt(void)
{
ScriptContext1_SetupScript(gUnknown_082A4B6F);
}
void sub_80FC190(void)
{
sSafariZoneFleedMons += gBattleResults.field_1F;
if (gBattleOutcome == BATTLE_CAUGHT)
sSafariZoneCaughtMons++;
if (gNumSafariBalls != 0)
{
SetMainCallback2(c2_exit_to_overworld_2_switch);
}
else if (gBattleOutcome == 8)
{
ScriptContext2_RunNewScript(gUnknown_082A4B4C);
warp_in();
gUnknown_03005DAC = sub_80AF6F0;
SetMainCallback2(c2_load_new_map);
}
else if (gBattleOutcome == BATTLE_CAUGHT)
{
ScriptContext1_SetupScript(gUnknown_082A4B9B);
ScriptContext1_Stop();
SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music);
}
}
static void ClearPokeblockFeeder(u8 index)
{
memset(&sPokeblockFeeders[index], 0, sizeof(struct PokeblockFeeder));
}
static void ClearAllPokeblockFeeders(void)
{
memset(sPokeblockFeeders, 0, sizeof(sPokeblockFeeders));
}
static void GetPokeblockFeederInFront(void)
{
s16 x, y;
u16 i;
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
{
if (gSaveBlock1Ptr->location.mapNum == sPokeblockFeeders[i].mapNum
&& sPokeblockFeeders[i].x == x
&& sPokeblockFeeders[i].y == y)
{
gScriptResult = i;
StringCopy(gStringVar1, gPokeblockNames[sPokeblockFeeders[i].pokeblock.color]);
return;
}
}
gScriptResult = -1;
}
void GetPokeblockFeederWithinRange(void)
{
s16 x, y;
u16 i;
PlayerGetDestCoords(&x, &y);
for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
{
if (gSaveBlock1Ptr->location.mapNum == sPokeblockFeeders[i].mapNum)
{
//Get absolute value of x and y distance from Pokeblock feeder on current map
x -= sPokeblockFeeders[i].x;
y -= sPokeblockFeeders[i].y;
if (x < 0)
x *= -1;
if (y < 0)
y *= -1;
if ((x + y) <= 5)
{
gScriptResult = i;
return;
}
}
}
gScriptResult = -1;
}
// unused
struct Pokeblock *SafariZoneGetPokeblockInFront(void)
{
GetPokeblockFeederInFront();
if (gScriptResult == 0xFFFF)
return NULL;
else
return &sPokeblockFeeders[gScriptResult].pokeblock;
}
struct Pokeblock *SafariZoneGetActivePokeblock(void)
{
GetPokeblockFeederWithinRange();
if (gScriptResult == 0xFFFF)
return NULL;
else
return &sPokeblockFeeders[gScriptResult].pokeblock;
}
void SafariZoneActivatePokeblockFeeder(u8 pkblId)
{
s16 x, y;
u8 i;
for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
{
// Find free entry in sPokeblockFeeders
if (sPokeblockFeeders[i].mapNum == 0
&& sPokeblockFeeders[i].x == 0
&& sPokeblockFeeders[i].y == 0)
{
// Initialize Pokeblock feeder
GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
sPokeblockFeeders[i].mapNum = gSaveBlock1Ptr->location.mapNum;
sPokeblockFeeders[i].pokeblock = gSaveBlock1Ptr->pokeblocks[pkblId];
sPokeblockFeeders[i].stepCounter = 100;
sPokeblockFeeders[i].x = x;
sPokeblockFeeders[i].y = y;
break;
}
}
}
static void DecrementFeederStepCounters(void)
{
u8 i;
for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
{
if (sPokeblockFeeders[i].stepCounter != 0)
{
sPokeblockFeeders[i].stepCounter--;
if (sPokeblockFeeders[i].stepCounter == 0)
ClearPokeblockFeeder(i);
}
}
}
// unused
bool8 GetInFrontFeederPokeblockAndSteps(void)
{
GetPokeblockFeederInFront();
if (gScriptResult == 0xFFFF)
{
return FALSE;
}
ConvertIntToDecimalStringN(gStringVar2,
sPokeblockFeeders[gScriptResult].stepCounter,
STR_CONV_MODE_LEADING_ZEROS, 3);
return TRUE;
}

View File

@@ -5,7 +5,6 @@
extern struct SaveSectionOffsets gSaveSectionOffsets[0xE];
extern struct SaveSectionLocation gRamSaveSectionLocations[0xE];
extern void *gUnknown_03005D94;
extern u8 gDecompressionBuffer[];
extern u32 gFlashMemoryPresent;
extern u16 gUnknown_03006294;
@@ -593,7 +592,7 @@ void UpdateSaveAddresses(void)
for(i = 5; i < 14; i++)
{
gRamSaveSectionLocations[i].data = gUnknown_03005D94 + gSaveSectionOffsets[i].toAdd;
gRamSaveSectionLocations[i].data = gPokemonStoragePtr + gSaveSectionOffsets[i].toAdd;
gRamSaveSectionLocations[i].size = gSaveSectionOffsets[i].size;
}
}
@@ -630,7 +629,7 @@ _081531AC:\n\
bge _081531AC\n\
movs r4, 0x5\n\
ldr r1, =gRamSaveSectionLocations\n\
ldr r5, =gUnknown_03005D94\n\
ldr r5, =gPokemonStoragePtr\n\
ldr r0, =gSaveSectionOffsets\n\
adds r3, r1, 0\n\
adds r3, 0x28\n\

434
src/script.c Normal file
View File

@@ -0,0 +1,434 @@
#include "global.h"
#include "script.h"
#include "event_data.h"
#include "util.h"
#define RAM_SCRIPT_MAGIC 51
extern u8* gUnknown_020375C0;
extern bool32 sub_801B27C(void);
// ewram bss
IWRAM_DATA static u8 sScriptContext1Status;
IWRAM_DATA static u32 sUnusedVariable1;
IWRAM_DATA static struct ScriptContext sScriptContext1;
IWRAM_DATA static u32 sUnusedVariable2;
IWRAM_DATA static struct ScriptContext sScriptContext2;
IWRAM_DATA static bool8 sScriptContext2Enabled;
extern ScrCmdFunc gScriptCmdTable[];
extern ScrCmdFunc gScriptCmdTableEnd[];
extern void *gNullScriptPtr;
void InitScriptContext(struct ScriptContext *ctx, void *cmdTable, void *cmdTableEnd)
{
s32 i;
ctx->mode = 0;
ctx->scriptPtr = 0;
ctx->stackDepth = 0;
ctx->nativePtr = 0;
ctx->cmdTable = cmdTable;
ctx->cmdTableEnd = cmdTableEnd;
for (i = 0; i < 4; i++)
ctx->data[i] = 0;
for (i = 0; i < 20; i++)
ctx->stack[i] = 0;
}
u8 SetupBytecodeScript(struct ScriptContext *ctx, const u8 *ptr)
{
ctx->scriptPtr = ptr;
ctx->mode = 1;
return 1;
}
void SetupNativeScript(struct ScriptContext *ctx, bool8 (*ptr)(void))
{
ctx->mode = 2;
ctx->nativePtr = ptr;
}
void StopScript(struct ScriptContext *ctx)
{
ctx->mode = 0;
ctx->scriptPtr = 0;
}
bool8 RunScriptCommand(struct ScriptContext *ctx)
{
if (ctx->mode == 0)
return FALSE;
switch (ctx->mode)
{
case 0:
return FALSE;
case 2:
if (ctx->nativePtr)
{
if (ctx->nativePtr() == TRUE)
ctx->mode = 1;
return TRUE;
}
ctx->mode = 1;
case 1:
while (1)
{
u8 cmdCode;
ScrCmdFunc *func;
if (!ctx->scriptPtr)
{
ctx->mode = 0;
return FALSE;
}
if (ctx->scriptPtr == gNullScriptPtr)
{
while (1)
asm("svc 2"); // HALT
}
cmdCode = *(ctx->scriptPtr);
ctx->scriptPtr++;
func = &ctx->cmdTable[cmdCode];
if (func >= ctx->cmdTableEnd)
{
ctx->mode = 0;
return FALSE;
}
if ((*func)(ctx) == 1)
return TRUE;
}
}
return TRUE;
}
u8 ScriptPush(struct ScriptContext *ctx, const u8 *ptr)
{
if (ctx->stackDepth + 1 >= 20)
{
return 1;
}
else
{
ctx->stack[ctx->stackDepth] = ptr;
ctx->stackDepth++;
return 0;
}
}
const u8 *ScriptPop(struct ScriptContext *ctx)
{
if (ctx->stackDepth == 0)
return NULL;
ctx->stackDepth--;
return ctx->stack[ctx->stackDepth];
}
void ScriptJump(struct ScriptContext *ctx, u8 *ptr)
{
ctx->scriptPtr = ptr;
}
void ScriptCall(struct ScriptContext *ctx, u8 *ptr)
{
ScriptPush(ctx, ctx->scriptPtr);
ctx->scriptPtr = ptr;
}
void ScriptReturn(struct ScriptContext *ctx)
{
ctx->scriptPtr = ScriptPop(ctx);
}
u16 ScriptReadHalfword(struct ScriptContext *ctx)
{
u16 value = *(ctx->scriptPtr++);
value |= *(ctx->scriptPtr++) << 8;
return value;
}
u32 ScriptReadWord(struct ScriptContext *ctx)
{
u32 value0 = *(ctx->scriptPtr++);
u32 value1 = *(ctx->scriptPtr++);
u32 value2 = *(ctx->scriptPtr++);
u32 value3 = *(ctx->scriptPtr++);
return (((((value3 << 8) + value2) << 8) + value1) << 8) + value0;
}
void ScriptContext2_Enable(void)
{
sScriptContext2Enabled = TRUE;
}
void ScriptContext2_Disable(void)
{
sScriptContext2Enabled = FALSE;
}
bool8 ScriptContext2_IsEnabled(void)
{
return sScriptContext2Enabled;
}
bool8 ScriptContext1_IsScriptSetUp(void)
{
if (sScriptContext1Status == 0)
return TRUE;
else
return FALSE;
}
void ScriptContext1_Init(void)
{
InitScriptContext(&sScriptContext1, gScriptCmdTable, gScriptCmdTableEnd);
sScriptContext1Status = 2;
}
bool8 ScriptContext2_RunScript(void)
{
if (sScriptContext1Status == 2)
return 0;
if (sScriptContext1Status == 1)
return 0;
ScriptContext2_Enable();
if (!RunScriptCommand(&sScriptContext1))
{
sScriptContext1Status = 2;
ScriptContext2_Disable();
return 0;
}
return 1;
}
void ScriptContext1_SetupScript(const u8 *ptr)
{
InitScriptContext(&sScriptContext1, gScriptCmdTable, gScriptCmdTableEnd);
SetupBytecodeScript(&sScriptContext1, ptr);
ScriptContext2_Enable();
sScriptContext1Status = 0;
}
void ScriptContext1_Stop(void)
{
sScriptContext1Status = 1;
}
void EnableBothScriptContexts(void)
{
sScriptContext1Status = 0;
ScriptContext2_Enable();
}
void ScriptContext2_RunNewScript(const u8 *ptr)
{
InitScriptContext(&sScriptContext2, &gScriptCmdTable, &gScriptCmdTableEnd);
SetupBytecodeScript(&sScriptContext2, ptr);
while (RunScriptCommand(&sScriptContext2) == TRUE);
}
u8 *mapheader_get_tagged_pointer(u8 tag)
{
u8 *mapScripts = gMapHeader.mapScripts;
if (!mapScripts)
return NULL;
while (1)
{
if (!*mapScripts)
return NULL;
if (*mapScripts == tag)
{
mapScripts++;
return (u8 *)(mapScripts[0] + (mapScripts[1] << 8) + (mapScripts[2] << 16) + (mapScripts[3] << 24));
}
mapScripts += 5;
}
}
void mapheader_run_script_by_tag(u8 tag)
{
u8 *ptr = mapheader_get_tagged_pointer(tag);
if (ptr)
ScriptContext2_RunNewScript(ptr);
}
u8 *mapheader_get_first_match_from_tagged_ptr_list(u8 tag)
{
u8 *ptr = mapheader_get_tagged_pointer(tag);
if (!ptr)
return NULL;
while (1)
{
u16 varIndex1;
u16 varIndex2;
varIndex1 = ptr[0] | (ptr[1] << 8);
if (!varIndex1)
return NULL;
ptr += 2;
varIndex2 = ptr[0] | (ptr[1] << 8);
ptr += 2;
if (VarGet(varIndex1) == VarGet(varIndex2))
return (u8 *)(ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24));
ptr += 4;
}
}
void mapheader_run_script_with_tag_x1(void)
{
mapheader_run_script_by_tag(1);
}
void mapheader_run_script_with_tag_x3(void)
{
mapheader_run_script_by_tag(3);
}
void mapheader_run_script_with_tag_x5(void)
{
mapheader_run_script_by_tag(5);
}
void mapheader_run_script_with_tag_x7(void)
{
mapheader_run_script_by_tag(7);
}
void mapheader_run_script_with_tag_x6(void)
{
mapheader_run_script_by_tag(6);
}
bool8 mapheader_run_first_tag2_script_list_match(void)
{
u8 *ptr = mapheader_get_first_match_from_tagged_ptr_list(2);
if (!ptr)
return 0;
ScriptContext1_SetupScript(ptr);
return 1;
}
void mapheader_run_first_tag4_script_list_match(void)
{
u8 *ptr = mapheader_get_first_match_from_tagged_ptr_list(4);
if (ptr)
ScriptContext2_RunNewScript(ptr);
}
u32 CalculateRamScriptChecksum(void)
{
return CalcCRC16WithTable((u8*)(&gSaveBlock1Ptr->ramScript.data), sizeof(gSaveBlock1Ptr->ramScript.data));
}
void ClearRamScript(void)
{
CpuFill32(0, &gSaveBlock1Ptr->ramScript, sizeof(struct RamScript));
}
bool8 InitRamScript(u8 *script, u16 scriptSize, u8 mapGroup, u8 mapNum, u8 objectId)
{
struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
ClearRamScript();
if (scriptSize > sizeof(scriptData->script))
return FALSE;
scriptData->magic = RAM_SCRIPT_MAGIC;
scriptData->mapGroup = mapGroup;
scriptData->mapNum = mapNum;
scriptData->objectId = objectId;
memcpy(scriptData->script, script, scriptSize);
gSaveBlock1Ptr->ramScript.checksum = CalculateRamScriptChecksum();
return TRUE;
}
u8 *GetRamScript(u8 objectId, u8 *script)
{
struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
gUnknown_020375C0 = NULL;
if (scriptData->magic != RAM_SCRIPT_MAGIC)
return script;
if (scriptData->mapGroup != gSaveBlock1Ptr->location.mapGroup)
return script;
if (scriptData->mapNum != gSaveBlock1Ptr->location.mapNum)
return script;
if (scriptData->objectId != objectId)
return script;
if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum)
{
ClearRamScript();
return script;
}
else
{
gUnknown_020375C0 = script;
return scriptData->script;
}
}
bool32 sub_80991F8(void)
{
struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
if (scriptData->magic != RAM_SCRIPT_MAGIC)
return FALSE;
if (scriptData->mapGroup != 0xFF)
return FALSE;
if (scriptData->mapNum != 0xFF)
return FALSE;
if (scriptData->objectId != 0xFF)
return FALSE;
if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum)
return FALSE;
return TRUE;
}
u8 *sub_8099244(void)
{
struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
if (!sub_801B27C())
return NULL;
if (scriptData->magic != RAM_SCRIPT_MAGIC)
return NULL;
if (scriptData->mapGroup != 0xFF)
return NULL;
if (scriptData->mapNum != 0xFF)
return NULL;
if (scriptData->objectId != 0xFF)
return NULL;
if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum)
{
ClearRamScript();
return NULL;
}
else
{
return scriptData->script;
}
}
void sub_80992A0(u8 *script, u16 scriptSize)
{
if (scriptSize > sizeof(gSaveBlock1Ptr->ramScript.data.script))
scriptSize = sizeof(gSaveBlock1Ptr->ramScript.data.script);
InitRamScript(script, scriptSize, 0xFF, 0xFF, 0xFF);
}

231
src/start_menu.c Normal file
View File

@@ -0,0 +1,231 @@
#include "global.h"
#include "start_menu.h"
#include "menu.h"
#include "safari_zone.h"
#include "event_data.h"
#include "window.h"
#include "string_util.h"
#include "text.h"
// Menu actions
enum
{
MENU_ACTION_POKEDEX,
MENU_ACTION_POKEMON,
MENU_ACTION_BAG,
MENU_ACTION_POKENAV,
MENU_ACTION_PLAYER,
MENU_ACTION_SAVE,
MENU_ACTION_OPTION,
MENU_ACTION_EXIT,
MENU_ACTION_RETIRE_SAFARI,
MENU_ACTION_PLAYER_LINK,
MENU_ACTION_REST_FRONTIER,
MENU_ACTION_RETIRE_FRONTIER,
MENU_ACTION_PYRAMID_BAG
};
static void BuildStartMenuActions_LinkMode(void);
static void BuildStartMenuActions_UnionRoom(void);
static void BuildStartMenuActions_SafariZone(void);
static void BuildStartMenuActions_BattlePike(void);
static void BuildStartMenuActions_BattlePyramid(void);
static void BuildStartMenuActions_MultiBattleRoom(void);
static void BuildStartMenuActions_Normal(void);
u8 StartMenu_PlayerName(void);
extern bool32 is_c1_link_related_active(void);
extern bool32 InUnionRoom(void);
extern bool8 InBattlePike(void);
extern bool8 InBattlePyramid(void);
extern bool8 InMultiBattleRoom(void);
extern void sub_81973FC(u8 windowId, u8 a1);
extern void sub_8198070(u8 windowId, u8 a1);
EWRAM_DATA u8 sSafariBallsWindowId = 0;
EWRAM_DATA u8 sBattlePyramidFloorWindowId = 0;
EWRAM_DATA u8 sStartMenuCursorPos = 0;
EWRAM_DATA u8 sNumStartMenuActions = 0;
EWRAM_DATA u8 sCurrentStartMenuActions[9] = {0};
void BuildStartMenuActions(void)
{
sNumStartMenuActions = 0;
if (is_c1_link_related_active() == TRUE)
BuildStartMenuActions_LinkMode();
else if (InUnionRoom() == TRUE)
BuildStartMenuActions_UnionRoom();
else if (GetSafariZoneFlag() == TRUE)
BuildStartMenuActions_SafariZone();
else if (InBattlePike())
BuildStartMenuActions_BattlePike();
else if (InBattlePyramid())
BuildStartMenuActions_BattlePyramid();
else if (InMultiBattleRoom())
BuildStartMenuActions_MultiBattleRoom();
else
BuildStartMenuActions_Normal();
}
void AddStartMenuAction(u8 action)
{
AppendToList(sCurrentStartMenuActions, &sNumStartMenuActions, action);
}
static void BuildStartMenuActions_Normal(void)
{
if (FlagGet(SYS_POKEDEX_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKEDEX);
if (FlagGet(SYS_POKEMON_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
if (FlagGet(SYS_POKENAV_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKENAV);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_SAVE);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildStartMenuActions_SafariZone(void)
{
AddStartMenuAction(MENU_ACTION_RETIRE_SAFARI);
AddStartMenuAction(MENU_ACTION_POKEDEX);
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildStartMenuActions_LinkMode(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
if (FlagGet(SYS_POKENAV_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKENAV);
AddStartMenuAction(MENU_ACTION_PLAYER_LINK);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildStartMenuActions_UnionRoom(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_BAG);
if (FlagGet(SYS_POKENAV_GET) == TRUE)
AddStartMenuAction(MENU_ACTION_POKENAV);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildStartMenuActions_BattlePike(void)
{
AddStartMenuAction(MENU_ACTION_POKEDEX);
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildStartMenuActions_BattlePyramid(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_PYRAMID_BAG);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_REST_FRONTIER);
AddStartMenuAction(MENU_ACTION_RETIRE_FRONTIER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
static void BuildStartMenuActions_MultiBattleRoom(void)
{
AddStartMenuAction(MENU_ACTION_POKEMON);
AddStartMenuAction(MENU_ACTION_PLAYER);
AddStartMenuAction(MENU_ACTION_OPTION);
AddStartMenuAction(MENU_ACTION_EXIT);
}
extern const struct WindowTemplate gSafariBallsWindowTemplate;
extern const struct WindowTemplate gPyramidFloorWindowTemplate_1;
extern const struct WindowTemplate gPyramidFloorWindowTemplate_2;
extern const u8 gOtherText_SafariStock[];
void DisplaySafariBallsWindow(void)
{
sSafariBallsWindowId = AddWindow(&gSafariBallsWindowTemplate);
PutWindowTilemap(sSafariBallsWindowId);
sub_81973FC(sSafariBallsWindowId, 0);
ConvertIntToDecimalStringN(gStringVar1, gNumSafariBalls, STR_CONV_MODE_RIGHT_ALIGN, 2);
StringExpandPlaceholders(gStringVar4, gOtherText_SafariStock);
PrintTextOnWindow(sSafariBallsWindowId, 1, gStringVar4, 0, 1, 0xFF, NULL);
CopyWindowToVram(sSafariBallsWindowId, 2);
}
extern const u8* const gUnknown_08510510[];
extern const u8 gOtherText_BattlePyramid_X[];
void DisplayPyramidFloorWindow(void)
{
// TODO: fix location
if (*(u16*)(&gSaveBlock2Ptr->field_CAA[8]) == 7)
sBattlePyramidFloorWindowId = AddWindow(&gPyramidFloorWindowTemplate_1);
else
sBattlePyramidFloorWindowId = AddWindow(&gPyramidFloorWindowTemplate_2);
PutWindowTilemap(sBattlePyramidFloorWindowId);
sub_81973FC(sBattlePyramidFloorWindowId, 0);
StringCopy(gStringVar1, gUnknown_08510510[*(u16*)(&gSaveBlock2Ptr->field_CAA[8])]);
StringExpandPlaceholders(gStringVar4, gOtherText_BattlePyramid_X);
PrintTextOnWindow(sBattlePyramidFloorWindowId, 1, gStringVar4, 0, 1, 0xFF, NULL);
CopyWindowToVram(sBattlePyramidFloorWindowId, 2);
}
void RemoveExtraStartMenuWindows(void)
{
if (GetSafariZoneFlag())
{
sub_8198070(sSafariBallsWindowId, 0);
CopyWindowToVram(sSafariBallsWindowId, 2);
RemoveWindow(sSafariBallsWindowId);
}
if (InBattlePyramid())
{
sub_8198070(sBattlePyramidFloorWindowId, 0);
RemoveWindow(sBattlePyramidFloorWindowId);
}
}
extern const struct MenuAction sStartMenuItems[];
/*
// Prints n menu items starting at *index
static bool32 PrintStartMenuItemsMultistep(s16 *index, u32 n)
{
s8 _index = *index;
do
{
if (sStartMenuItems[sCurrentStartMenuActions[_index]].func == StartMenu_PlayerName)
{
}
else
{
}
} while (++_index > sNumStartMenuActions);
if (--n == 0)
{
*index = _index;
return FALSE;
}
else
{
*index = _index;
return TRUE;
}
}*/

View File

@@ -9,7 +9,7 @@ struct Task gTasks[NUM_TASKS];
static void InsertTask(u8 newTaskId);
static u8 FindFirstActiveTask();
void ResetTasks()
void ResetTasks(void)
{
u8 i;
@@ -110,7 +110,7 @@ void DestroyTask(u8 taskId)
}
}
void RunTasks()
void RunTasks(void)
{
u8 taskId = FindFirstActiveTask();
@@ -189,7 +189,7 @@ u8 FindTaskIdByFunc(TaskFunc func)
return -1;
}
u8 GetTaskCount()
u8 GetTaskCount(void)
{
u8 i;
u8 count = 0;

View File

@@ -149,7 +149,7 @@ void DeactivateAllTextPrinters (void)
gTextPrinters[printer].sub_union.sub.active = 0;
}
u16 Print(u8 windowId, u8 fontId, u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextSubPrinter *, u16))
u16 PrintTextOnWindow(u8 windowId, u8 fontId, u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextSubPrinter *, u16))
{
struct TextSubPrinter subPrinter;

503
src/util.c Normal file
View File

@@ -0,0 +1,503 @@
#include "global.h"
#include "util.h"
#include "sprite.h"
const u32 gBitTable[] =
{
1 << 0,
1 << 1,
1 << 2,
1 << 3,
1 << 4,
1 << 5,
1 << 6,
1 << 7,
1 << 8,
1 << 9,
1 << 10,
1 << 11,
1 << 12,
1 << 13,
1 << 14,
1 << 15,
1 << 16,
1 << 17,
1 << 18,
1 << 19,
1 << 20,
1 << 21,
1 << 22,
1 << 23,
1 << 24,
1 << 25,
1 << 26,
1 << 27,
1 << 28,
1 << 29,
1 << 30,
1 << 31,
};
static const struct SpriteTemplate sInvisibleSpriteTemplate =
{
.tileTag = 0,
.paletteTag = 0,
.oam = &gDummyOamData,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = SpriteCallbackDummy,
};
static const u8 sSpriteDimensions[3][4][2] =
{
// square
{
{1, 1},
{2, 2},
{4, 4},
{8, 8},
},
// horizontal rectangle
{
{2, 1},
{4, 1},
{4, 2},
{8, 4},
},
// vertical rectangle
{
{1, 2},
{1, 4},
{2, 4},
{4, 8},
},
};
static const u16 sCrc16Table[] =
{
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78,
};
const u8 gMiscBlank_Gfx[] = INCBIN_U8("graphics/interface/blank.4bpp"); // unused in Emerald
u8 CreateInvisibleSpriteWithCallback(void (*callback)(struct Sprite *))
{
u8 sprite = CreateSprite(&sInvisibleSpriteTemplate, 248, 168, 14);
gSprites[sprite].invisible = TRUE;
gSprites[sprite].callback = callback;
return sprite;
}
void StoreWordInTwoHalfwords(u16 *h, u32 w)
{
h[0] = (u16)(w);
h[1] = (u16)(w >> 16);
}
void LoadWordFromTwoHalfwords(u16 *h, u32 *w)
{
*w = h[0] | (s16)h[1] << 16;
}
void SetBgAffineStruct(struct BgAffineSrcData *src, u32 texX, u32 texY, s16 scrX, s16 scrY, s16 sx, s16 sy, u16 alpha)
{
src->texX = texX;
src->texY = texY;
src->scrX = scrX;
src->scrY = scrY;
src->sx = sx;
src->sy = sy;
src->alpha = alpha;
}
void DoBgAffineSet(struct BgAffineDstData *dest, u32 texX, u32 texY, s16 scrX, s16 scrY, s16 sx, s16 sy, u16 alpha)
{
struct BgAffineSrcData src;
SetBgAffineStruct(&src, texX, texY, scrX, scrY, sx, sy, alpha);
BgAffineSet(&src, dest, 1);
}
#ifdef NONMATCHING
// Functionally equivalent.
// Only the two yflip loops don't match.
void CopySpriteTiles(u8 shape, u8 size, u8 *tiles, u16 *tilemap, u8 *output)
{
u8 x, y;
s8 i, j;
u8 xflip[32];
u8 h = sSpriteDimensions[shape][size][1];
u8 w = sSpriteDimensions[shape][size][0];
for (y = 0; y < h; y++)
{
int filler = 32 - w;
for (x = 0; x < w; x++)
{
int tile = (*tilemap & 0x3ff) * 32;
int attr = *tilemap & 0xc00;
if (attr == 0)
{
void *src = tiles + tile;
void *dest = output;
int length = 32;
DmaCopy32(3, src, dest, length);
}
else if (attr == 0x800) // yflip
{
for (i = 0; i < 8; i++)
{
void *src = tiles;
void *dest = output;
int length = 4;
// this is likely wrong, but makes it closer to matching
src += tile + (7 - i) * 4;
dest += i * 4;
DmaCopy32(3, src, dest, length);
}
}
else // xflip
{
for (i = 0; i < 8; i++)
{
for (j = 0; j < 4; j++)
{
u8 i2 = i * 4;
xflip[i2 + (3-j)] = (tiles[tile + i2 + j] & 0xf) << 4;
xflip[i2 + (3-j)] |= tiles[tile + i2 + j] >> 4;
}
}
if (*tilemap & 0x800) // yflip
{
for (i = 0; i < 8; i++)
{
void *src = xflip + (7-i) * 4;
void *dest = output + i*4;
int length = 4;
DmaCopy32(3, src, dest, length);
}
}
else
{
void *src = xflip;
void *dest = output;
int length = 32;
DmaCopy32(3, src, dest, length);
}
}
tilemap++;
output += 32;
}
tilemap += filler;
}
}
#else
__attribute__((naked)) void CopySpriteTiles(u8 shape, u8 size, u8 *tiles, u16 *tilemap, u8 *output)
{
asm("\n\
.syntax unified\n\
push {r4-r7,lr}\n\
mov r7, r10\n\
mov r6, r9\n\
mov r5, r8\n\
push {r5-r7}\n\
sub sp, 0x38\n\
str r2, [sp, 0x20]\n\
adds r4, r3, 0\n\
ldr r7, [sp, 0x58]\n\
lsls r0, 24\n\
lsls r1, 24\n\
ldr r2, =sSpriteDimensions\n\
lsrs r1, 23\n\
lsrs r0, 21\n\
adds r1, r0\n\
adds r0, r2, 0x1\n\
adds r0, r1, r0\n\
ldrb r0, [r0]\n\
str r0, [sp, 0x24]\n\
adds r1, r2\n\
ldrb r1, [r1]\n\
str r1, [sp, 0x28]\n\
movs r0, 0\n\
b _0806F88C\n\
.pool\n\
_0806F740:\n\
movs r5, 0\n\
adds r0, 0x1\n\
str r0, [sp, 0x30]\n\
b _0806F874\n\
_0806F748:\n\
ldrh r0, [r4]\n\
ldr r2, =0x000003ff\n\
adds r1, r2, 0\n\
ands r1, r0\n\
lsls r1, 5\n\
mov r8, r1\n\
movs r2, 0xC0\n\
lsls r2, 4\n\
adds r1, r2, 0\n\
ands r1, r0\n\
mov r2, sp\n\
strh r0, [r2, 0x34]\n\
cmp r1, 0\n\
bne _0806F788\n\
ldr r0, [sp, 0x20]\n\
add r0, r8\n\
adds r1, r7, 0\n\
ldr r2, =0x04000008\n\
bl CpuSet\n\
adds r4, 0x2\n\
str r4, [sp, 0x2C]\n\
adds r7, 0x20\n\
mov r10, r7\n\
adds r5, 0x1\n\
mov r9, r5\n\
b _0806F86A\n\
.pool\n\
_0806F788:\n\
movs r0, 0x80\n\
lsls r0, 4\n\
cmp r1, r0\n\
bne _0806F7CC\n\
movs r1, 0\n\
adds r4, 0x2\n\
str r4, [sp, 0x2C]\n\
movs r2, 0x20\n\
adds r2, r7\n\
mov r10, r2\n\
adds r5, 0x1\n\
mov r9, r5\n\
_0806F7A0:\n\
lsls r4, r1, 24\n\
asrs r4, 24\n\
movs r0, 0x7\n\
subs r0, r4\n\
lsls r0, 2\n\
add r0, r8\n\
ldr r1, [sp, 0x20]\n\
adds r0, r1, r0\n\
lsls r1, r4, 2\n\
adds r1, r7, r1\n\
ldr r2, =0x04000001\n\
bl CpuSet\n\
adds r4, 0x1\n\
lsls r4, 24\n\
lsrs r1, r4, 24\n\
asrs r4, 24\n\
cmp r4, 0x7\n\
ble _0806F7A0\n\
b _0806F86A\n\
.pool\n\
_0806F7CC:\n\
movs r1, 0\n\
adds r4, 0x2\n\
str r4, [sp, 0x2C]\n\
movs r2, 0x20\n\
adds r2, r7\n\
mov r10, r2\n\
adds r5, 0x1\n\
mov r9, r5\n\
movs r0, 0xF\n\
mov r12, r0\n\
_0806F7E0:\n\
movs r2, 0\n\
lsls r4, r1, 24\n\
lsls r0, r4, 2\n\
lsrs r0, 24\n\
adds r6, r0, 0x3\n\
mov r1, r8\n\
adds r5, r1, r0\n\
_0806F7EE:\n\
lsls r1, r2, 24\n\
asrs r1, 24\n\
subs r0, r6, r1\n\
mov r2, sp\n\
adds r3, r2, r0\n\
adds r0, r5, r1\n\
ldr r2, [sp, 0x20]\n\
adds r0, r2, r0\n\
ldrb r2, [r0]\n\
mov r0, r12\n\
ands r0, r2\n\
lsls r0, 4\n\
lsrs r2, 4\n\
orrs r0, r2\n\
strb r0, [r3]\n\
adds r1, 0x1\n\
lsls r1, 24\n\
lsrs r2, r1, 24\n\
asrs r1, 24\n\
cmp r1, 0x3\n\
ble _0806F7EE\n\
movs r1, 0x80\n\
lsls r1, 17\n\
adds r0, r4, r1\n\
lsrs r1, r0, 24\n\
asrs r0, 24\n\
cmp r0, 0x7\n\
ble _0806F7E0\n\
mov r2, sp\n\
ldrh r0, [r2, 0x34]\n\
movs r2, 0x80\n\
lsls r2, 4\n\
ands r0, r2\n\
cmp r0, 0\n\
beq _0806F860\n\
movs r1, 0\n\
_0806F836:\n\
lsls r4, r1, 24\n\
asrs r4, 24\n\
movs r0, 0x7\n\
subs r0, r4\n\
lsls r0, 2\n\
add r0, sp\n\
lsls r1, r4, 2\n\
adds r1, r7, r1\n\
ldr r2, =0x04000001\n\
bl CpuSet\n\
adds r4, 0x1\n\
lsls r4, 24\n\
lsrs r1, r4, 24\n\
asrs r4, 24\n\
cmp r4, 0x7\n\
ble _0806F836\n\
b _0806F86A\n\
.pool\n\
_0806F860:\n\
mov r0, sp\n\
adds r1, r7, 0\n\
ldr r2, =0x04000008\n\
bl CpuSet\n\
_0806F86A:\n\
ldr r4, [sp, 0x2C]\n\
mov r7, r10\n\
mov r1, r9\n\
lsls r0, r1, 24\n\
lsrs r5, r0, 24\n\
_0806F874:\n\
ldr r2, [sp, 0x28]\n\
cmp r5, r2\n\
bcs _0806F87C\n\
b _0806F748\n\
_0806F87C:\n\
movs r0, 0x20\n\
ldr r1, [sp, 0x28]\n\
subs r0, r1\n\
lsls r0, 1\n\
adds r4, r0\n\
ldr r2, [sp, 0x30]\n\
lsls r0, r2, 24\n\
lsrs r0, 24\n\
_0806F88C:\n\
ldr r1, [sp, 0x24]\n\
cmp r0, r1\n\
bcs _0806F894\n\
b _0806F740\n\
_0806F894:\n\
add sp, 0x38\n\
pop {r3-r5}\n\
mov r8, r3\n\
mov r9, r4\n\
mov r10, r5\n\
pop {r4-r7}\n\
pop {r0}\n\
bx r0\n\
.pool\n\
.syntax divided");
}
#endif // NONMATCHING
int CountTrailingZeroBits(u32 value)
{
u8 i;
for (i = 0; i < 32; i++)
{
if ((value & 1) == 0)
value >>= 1;
else
return i;
}
return 0;
}
u16 CalcCRC16(u8 *data, s32 length)
{
u16 i, j;
u16 crc = 0x1121;
for (i = 0; i < length; i++)
{
crc ^= data[i];
for (j = 0; j < 8; j++)
{
if (crc & 1)
crc = (crc >> 1) ^ 0x8408;
else
crc >>= 1;
}
}
return ~crc;
}
u16 CalcCRC16WithTable(u8 *data, u32 length)
{
u16 i;
u16 crc = 0x1121;
u8 byte;
for (i = 0; i < length; i++)
{
byte = crc >> 8;
crc ^= data[i];
crc = byte ^ sCrc16Table[(u8)crc];
}
return ~crc;
}
u32 CalcByteArraySum(const u8* data, u32 length)
{
u32 sum, i;
for (sum = 0, i = 0; i < length; i++)
sum += data[i];
return sum;
}

View File

@@ -118,7 +118,7 @@ bool16 InitWindows(struct WindowTemplate *templates)
return TRUE;
}
u16 AddWindow(struct WindowTemplate *template)
u16 AddWindow(const struct WindowTemplate *template)
{
u16 win;
u8 bgLayer;