summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/battle_4.c601
-rw-r--r--src/battle_ai.c1505
-rw-r--r--src/calculate_base_damage.c284
-rw-r--r--src/coins.c77
-rw-r--r--src/load_save.c114
-rw-r--r--src/lottery_corner.c167
-rw-r--r--src/main.c14
-rw-r--r--src/malloc.c2
-rw-r--r--src/money.c55
-rw-r--r--src/new_game.c117
-rw-r--r--src/palette.c8
-rw-r--r--src/play_time.c10
-rw-r--r--src/pokemon_1.c325
-rw-r--r--src/pokemon_2.c4
-rw-r--r--src/pokemon_size_record.c222
-rw-r--r--src/rng.c5
-rw-r--r--src/safari_zone.c268
-rw-r--r--src/save.c5
-rw-r--r--src/start_menu.c231
-rw-r--r--src/task.c6
-rw-r--r--src/text.c2
-rw-r--r--src/window.c2
22 files changed, 3279 insertions, 745 deletions
diff --git a/src/battle_4.c b/src/battle_4.c
new file mode 100644
index 000000000..92561251f
--- /dev/null
+++ b/src/battle_4.c
@@ -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
+};
diff --git a/src/battle_ai.c b/src/battle_ai.c
index 7c4b7604d..76bf4156d 100644
--- a/src/battle_ai.c
+++ b/src/battle_ai.c
@@ -1,32 +1,36 @@
#include "global.h"
+#include "battle_ai.h"
#include "pokemon.h"
#include "battle.h"
#include "species.h"
#include "abilities.h"
+#include "rng.h"
+#include "item.h"
+#include "battle_move_effects.h"
#define AIScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24)
#define AIScriptRead16(ptr) ((ptr)[0] | (ptr)[1] << 8)
#define AIScriptRead8(ptr) ((ptr)[0])
#define AIScriptReadPtr(ptr) (u8*) AIScriptRead32(ptr)
-#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai))
-#define UNK_2016A00_STRUCT ((struct UnknownStruct2 *)(gBattleResources->unk18))
-#define UNK_2016C00_STRUCT ((struct UnknownStruct4 *)(gBattleResources->unk1C))
-#define UNK_BATTLE_STRUCT ((struct UnknownStruct1 *)(gBattleResources))
-
-#define AI_ACTION_UNK1 0x0001
-#define AI_ACTION_UNK2 0x0002
-#define AI_ACTION_UNK3 0x0004
-#define AI_ACTION_UNK4 0x0008
+#define AI_ACTION_DONE 0x0001
+#define AI_ACTION_FLEE 0x0002
+#define AI_ACTION_WATCH 0x0004
+#define AI_ACTION_DO_NOT_ATTACK 0x0008
#define AI_ACTION_UNK5 0x0010
#define AI_ACTION_UNK6 0x0020
#define AI_ACTION_UNK7 0x0040
#define AI_ACTION_UNK8 0x0080
+#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai))
+#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory))
+
enum
{
- TARGET,
- USER
+ AI_TARGET,
+ AI_USER,
+ AI_TARGET_PARTNER,
+ AI_USER_PARTNER
};
// AI states
@@ -38,128 +42,6 @@ enum
AIState_DoNotProcess
};
-//Copied from pokeruby -- hopefully the same
-struct Trainer
-{
- /*0x00*/ u8 partyFlags;
- /*0x01*/ u8 trainerClass;
- /*0x02*/ u8 encounterMusic:7;
- /*0x02*/ u8 gender:1;
- /*0x03*/ u8 trainerPic;
- /*0x04*/ u8 trainerName[12];
- /*0x10*/ u16 items[4];
- /*0x18*/ bool8 doubleBattle;
- /*0x1C*/ u32 aiFlags;
- /*0x20*/ u8 partySize;
- /*0x24*/ void *party;
-};
-
-#define POKEMON_NAME_LENGTH 10
-
-struct BattlePokemon
-{
- /* 0x00 */ u16 species;
- /* 0x02 */ u16 attack;
- /* 0x04 */ u16 defense;
- /* 0x06 */ u16 speed;
- /* 0x08 */ u16 spAttack;
- /* 0x0A */ u16 spDefense;
- /* 0x0C */ u16 moves[4];
- /* 0x14 */ u32 hpIV:5;
- /* 0x14 */ u32 attackIV:5;
- /* 0x15 */ u32 defenseIV:5;
- /* 0x15 */ u32 speedIV:5;
- /* 0x16 */ u32 spAttackIV:5;
- /* 0x17 */ u32 spDefenseIV:5;
- /* 0x17 */ u32 isEgg:1;
- /* 0x17 */ u32 altAbility:1;
- /* 0x18 */ s8 statStages[8];
- /* 0x20 */ u8 ability;
- /* 0x21 */ u8 type1;
- /* 0x22 */ u8 type2;
- /* 0x23 */ u8 unknown;
- /* 0x24 */ u8 pp[4];
- /* 0x28 */ u16 hp;
- /* 0x2A */ u8 level;
- /* 0x2B */ u8 friendship;
- /* 0x2C */ u16 maxHP;
- /* 0x2E */ u16 item;
- /* 0x30 */ u8 nickname[POKEMON_NAME_LENGTH + 1];
- /* 0x3B */ u8 ppBonuses;
- /* 0x3C */ u8 otName[8];
- /* 0x44 */ u32 experience;
- /* 0x48 */ u32 personality;
- /* 0x4C */ u32 status1;
- /* 0x50 */ u32 status2;
- /* 0x54 */ u32 otId;
-};
-
-//size should be 0x1C
-struct AI_ThinkingStruct
-{
- u8 aiState;
- u8 movesetIndex;
- u16 moveConsidered;
- s8 score[4];
- u32 funcResult;
- u32 aiFlags;
- u8 aiAction;
- u8 aiLogicId;
- u8 filler12[6];
- u8 unk18[4];
-};
-
-//size should be 0x54
-struct UnknownStruct2
-{
- u16 unk0[2][8];
- u8 unk20[2];
- u8 filler20[0x1E];
- u8 unk40[4];
- u8 unk44[4];
- u16 unk48[4];
- u8 unk50;
-};
-
-struct UnknownStruct4
-{
- u8 *ptr[8];
- u8 unk20;
-};
-
-struct SimpleUnknownStruct
-{
- u32 unkArray[4]; // unknown size
-};
-
-struct UnknownStruct1
-{
- u8 unk0;
- u8 filler1[0x3];
- struct SimpleUnknownStruct *unk4;
- u8 filler8[0xC];
- struct AI_ThinkingStruct *ai;
- struct UnknownStruct2 *unk18;
- struct UnknownStruct4 *unk1C;
-};
-
-struct UnknownStruct5
-{
- u8 filler0[0x3];
- u16 unk4;
- u16 unk6;
- u8 unk8;
- u8 unk9;
- u8 fillerA[0x9];
- u8 taunt:4;
- u8 unkC:4;
- u8 fillerD[0x2];
- u8 unk16;
- u8 filler17[0x4];
-};
-
-extern struct UnknownStruct5 gDisableStructs[];
-
/*
gAIScriptPtr is a pointer to the next battle AI cmd command to read.
when a command finishes processing, gAIScriptPtr is incremented by
@@ -167,168 +49,388 @@ the number of bytes that the current command had reserved for arguments
in order to read the next command correctly. refer to battle_ai_scripts.s for the
AI scripts.
*/
-extern u8 *gAIScriptPtr;
extern u32 gBattleTypeFlags;
extern u8 gActiveBank;
-extern struct BattlePokemon gBattleMons[];
+extern struct BattlePokemon gBattleMons[4];
extern u16 gCurrentMove;
extern u8 gBankTarget;
extern u8 gAbsentBankFlags;
-extern u16 gUnknown_02024248[];
-extern u8 *gBattleStruct;
-extern struct UnknownStruct1 *gBattleResources;
-extern u16 gUnknown_02038BCA;
-extern u16 gUnknown_02038BCC;
-extern u8 gPlayerMonIndex;
-extern struct Trainer gTrainers[];
-extern const u32 gBitTable[];
-extern u8 *gUnknown_082DBEF8[];
-extern u32 gStatuses3[];
-extern u16 gUnknown_0202428E[];
-extern struct BattleMove gBattleMoves[];
-extern u8 gUnknown_03005D10[];
-extern u8 gBattlePartyID[][2];
-extern struct BaseStats gBaseStats[];
-extern u16 gUnknown_02024400;
-extern u8 gBattleScripting[];
+extern u16 gLastUsedMovesByBanks[4];
+extern u16 gTrainerBattleOpponent_A;
+extern u16 gTrainerBattleOpponent_B;
+extern u32 gStatuses3[4];
+extern u16 gSideAffecting[2];
+extern u16 gBattlePartyID[4];
+extern u16 gDynamicBasePower;
extern u8 gBattleMoveFlags;
-extern int gBattleMoveDamage;
+extern s32 gBattleMoveDamage;
extern u8 gCritMultiplier;
extern u16 gBattleWeather;
+extern const struct BattleMove gBattleMoves[];
+extern const struct BaseStats gBaseStats[];
+extern const u32 gBitTable[];
+extern u8 * const gBattleAI_ScriptsTable[];
+
extern u8 GetBankIdentity(u8);
extern u8 b_first_side(u8, u8, u8);
extern u8 GetBankByPlayerAI(u8);
-extern void move_effectiveness_something(u16, u8, u8);
-extern u8 ItemId_GetHoldEffect();
-extern void b_mc_stack_push(u8 *);
-extern bool8 b_mc_stack_pop_cursor(void);
-extern void sub_8046E7C(u8, u8);
+extern void TypeCalc(u16 move, u8 bankAtk, u8 bankDef);
+extern void AI_CalcDmg(u8, u8);
+
+extern u8 CheckMoveLimitations();
+extern u32 GetAiScriptsInRecordedBattle();
+extern u32 GetAiScriptsInBattleFactory();
+
+static u8 BattleAI_ChooseMoveOrAction_Singles(void);
+static u8 BattleAI_ChooseMoveOrAction_Doubles(void);
+static void RecordLastUsedMoveByTarget(void);
+static void BattleAI_DoAIProcessing(void);
+static void AIStackPushVar(u8 *);
+static bool8 AIStackPop(void);
+
+static void BattleAICmd_if_random_less_than(void);
+static void BattleAICmd_if_random_greater_than(void);
+static void BattleAICmd_if_random_equal(void);
+static void BattleAICmd_if_random_not_equal(void);
+static void BattleAICmd_score(void);
+static void BattleAICmd_if_hp_less_than(void);
+static void BattleAICmd_if_hp_more_than(void);
+static void BattleAICmd_if_hp_equal(void);
+static void BattleAICmd_if_hp_not_equal(void);
+static void BattleAICmd_if_status(void);
+static void BattleAICmd_if_not_status(void);
+static void BattleAICmd_if_status2(void);
+static void BattleAICmd_if_not_status2(void);
+static void BattleAICmd_if_status3(void);
+static void BattleAICmd_if_not_status3(void);
+static void BattleAICmd_if_side_affecting(void);
+static void BattleAICmd_if_not_side_affecting(void);
+static void BattleAICmd_if_less_than(void);
+static void BattleAICmd_if_more_than(void);
+static void BattleAICmd_if_equal(void);
+static void BattleAICmd_if_not_equal(void);
+static void BattleAICmd_if_less_than_32(void);
+static void BattleAICmd_if_more_than_32(void);
+static void BattleAICmd_if_equal_32(void);
+static void BattleAICmd_if_not_equal_32(void);
+static void BattleAICmd_if_move(void);
+static void BattleAICmd_if_not_move(void);
+static void BattleAICmd_if_in_bytes(void);
+static void BattleAICmd_if_not_in_bytes(void);
+static void BattleAICmd_if_in_words(void);
+static void BattleAICmd_if_not_in_words(void);
+static void BattleAICmd_if_user_can_damage(void);
+static void BattleAICmd_if_user_cant_damage(void);
+static void BattleAICmd_get_turn_count(void);
+static void BattleAICmd_get_type(void);
+static void BattleAICmd_get_last_used_bank_move_power(void);
+static void BattleAICmd_is_most_powerful_move(void);
+static void BattleAICmd_get_last_used_bank_move(void);
+static void BattleAICmd_if_arg_equal(void);
+static void BattleAICmd_if_arg_not_equal(void);
+static void BattleAICmd_if_would_go_first(void);
+static void BattleAICmd_if_would_not_go_first(void);
+static void BattleAICmd_nullsub_2A(void);
+static void BattleAICmd_nullsub_2B(void);
+static void BattleAICmd_count_alive_pokemon(void);
+static void BattleAICmd_get_considered_move(void);
+static void BattleAICmd_get_considered_move_effect(void);
+static void BattleAICmd_get_ability(void);
+static void BattleAICmd_get_highest_type_effectiveness(void);
+static void BattleAICmd_if_type_effectiveness(void);
+static void BattleAICmd_nullsub_32(void);
+static void BattleAICmd_nullsub_33(void);
+static void BattleAICmd_if_status_in_party(void);
+static void BattleAICmd_if_status_not_in_party(void);
+static void BattleAICmd_get_weather(void);
+static void BattleAICmd_if_effect(void);
+static void BattleAICmd_if_not_effect(void);
+static void BattleAICmd_if_stat_level_less_than(void);
+static void BattleAICmd_if_stat_level_more_than(void);
+static void BattleAICmd_if_stat_level_equal(void);
+static void BattleAICmd_if_stat_level_not_equal(void);
+static void BattleAICmd_if_can_faint(void);
+static void BattleAICmd_if_cant_faint(void);
+static void BattleAICmd_if_has_move(void);
+static void BattleAICmd_if_dont_have_move(void);
+static void BattleAICmd_if_move_effect(void);
+static void BattleAICmd_if_not_move_effect(void);
+static void BattleAICmd_if_any_move_disabled_or_encored(void);
+static void BattleAICmd_if_curr_move_disabled_or_encored(void);
+static void BattleAICmd_flee(void);
+static void BattleAICmd_if_random_100(void);
+static void BattleAICmd_watch(void);
+static void BattleAICmd_get_hold_effect(void);
+static void BattleAICmd_get_gender(void);
+static void BattleAICmd_is_first_turn(void);
+static void BattleAICmd_get_stockpile_count(void);
+static void BattleAICmd_is_double_battle(void);
+static void BattleAICmd_get_used_held_item(void);
+static void BattleAICmd_get_move_type_from_result(void);
+static void BattleAICmd_get_move_power_from_result(void);
+static void BattleAICmd_get_move_effect_from_result(void);
+static void BattleAICmd_get_protect_count(void);
+static void BattleAICmd_nullsub_52(void);
+static void BattleAICmd_nullsub_53(void);
+static void BattleAICmd_nullsub_54(void);
+static void BattleAICmd_nullsub_55(void);
+static void BattleAICmd_nullsub_56(void);
+static void BattleAICmd_nullsub_57(void);
+static void BattleAICmd_call(void);
+static void BattleAICmd_jump(void);
+static void BattleAICmd_end(void);
+static void BattleAICmd_if_level_cond(void);
+static void BattleAICmd_if_target_taunted(void);
+static void BattleAICmd_if_target_not_taunted(void);
+static void BattleAICmd_check_ability(void);
+static void BattleAICmd_is_of_type(void);
+static void BattleAICmd_if_target_is_ally(void);
+static void BattleAICmd_if_flash_fired(void);
+static void BattleAICmd_if_holds_item(void);
+
+// ewram
+
+EWRAM_DATA u8 *gAIScriptPtr = NULL;
+EWRAM_DATA static u8 sBank_AI = 0;
+
+// const rom data
typedef void (*BattleAICmdFunc)(void);
-extern const BattleAICmdFunc sBattleAICmdTable[];
-
-extern u8 sub_803FECC();
-extern u16 Random();
-extern u8 GetBankSide();
-extern u32 sub_8186438();
-extern u32 sub_81A6FB4();
+static const BattleAICmdFunc sBattleAICmdTable[] =
+{
+ BattleAICmd_if_random_less_than, // 0x0
+ BattleAICmd_if_random_greater_than, // 0x1
+ BattleAICmd_if_random_equal, // 0x2
+ BattleAICmd_if_random_not_equal, // 0x3
+ BattleAICmd_score, // 0x4
+ BattleAICmd_if_hp_less_than, // 0x5
+ BattleAICmd_if_hp_more_than, // 0x6
+ BattleAICmd_if_hp_equal, // 0x7
+ BattleAICmd_if_hp_not_equal, // 0x8
+ BattleAICmd_if_status, // 0x9
+ BattleAICmd_if_not_status, // 0xA
+ BattleAICmd_if_status2, // 0xB
+ BattleAICmd_if_not_status2, // 0xC
+ BattleAICmd_if_status3, // 0xD
+ BattleAICmd_if_not_status3, // 0xE
+ BattleAICmd_if_side_affecting, // 0xF
+ BattleAICmd_if_not_side_affecting, // 0x10
+ BattleAICmd_if_less_than, // 0x11
+ BattleAICmd_if_more_than, // 0x12
+ BattleAICmd_if_equal, // 0x13
+ BattleAICmd_if_not_equal, // 0x14
+ BattleAICmd_if_less_than_32, // 0x15
+ BattleAICmd_if_more_than_32, // 0x16
+ BattleAICmd_if_equal_32, // 0x17
+ BattleAICmd_if_not_equal_32, // 0x18
+ BattleAICmd_if_move, // 0x19
+ BattleAICmd_if_not_move, // 0x1A
+ BattleAICmd_if_in_bytes, // 0x1B
+ BattleAICmd_if_not_in_bytes, // 0x1C
+ BattleAICmd_if_in_words, // 0x1D
+ BattleAICmd_if_not_in_words, // 0x1E
+ BattleAICmd_if_user_can_damage, // 0x1F
+ BattleAICmd_if_user_cant_damage, // 0x20
+ BattleAICmd_get_turn_count, // 0x21
+ BattleAICmd_get_type, // 0x22
+ BattleAICmd_get_last_used_bank_move_power, // 0x23
+ BattleAICmd_is_most_powerful_move, // 0x24
+ BattleAICmd_get_last_used_bank_move, // 0x25
+ BattleAICmd_if_arg_equal, // 0x26
+ BattleAICmd_if_arg_not_equal, // 0x27
+ BattleAICmd_if_would_go_first, // 0x28
+ BattleAICmd_if_would_not_go_first, // 0x29
+ BattleAICmd_nullsub_2A, // 0x2A
+ BattleAICmd_nullsub_2B, // 0x2B
+ BattleAICmd_count_alive_pokemon, // 0x2C
+ BattleAICmd_get_considered_move, // 0x2D
+ BattleAICmd_get_considered_move_effect, // 0x2E
+ BattleAICmd_get_ability, // 0x2F
+ BattleAICmd_get_highest_type_effectiveness, // 0x30
+ BattleAICmd_if_type_effectiveness, // 0x31
+ BattleAICmd_nullsub_32, // 0x32
+ BattleAICmd_nullsub_33, // 0x33
+ BattleAICmd_if_status_in_party, // 0x34
+ BattleAICmd_if_status_not_in_party, // 0x35
+ BattleAICmd_get_weather, // 0x36
+ BattleAICmd_if_effect, // 0x37
+ BattleAICmd_if_not_effect, // 0x38
+ BattleAICmd_if_stat_level_less_than, // 0x39
+ BattleAICmd_if_stat_level_more_than, // 0x3A
+ BattleAICmd_if_stat_level_equal, // 0x3B
+ BattleAICmd_if_stat_level_not_equal, // 0x3C
+ BattleAICmd_if_can_faint, // 0x3D
+ BattleAICmd_if_cant_faint, // 0x3E
+ BattleAICmd_if_has_move, // 0x3F
+ BattleAICmd_if_dont_have_move, // 0x40
+ BattleAICmd_if_move_effect, // 0x41
+ BattleAICmd_if_not_move_effect, // 0x42
+ BattleAICmd_if_any_move_disabled_or_encored, // 0x43
+ BattleAICmd_if_curr_move_disabled_or_encored, // 0x44
+ BattleAICmd_flee, // 0x45
+ BattleAICmd_if_random_100, // 0x46
+ BattleAICmd_watch, // 0x47
+ BattleAICmd_get_hold_effect, // 0x48
+ BattleAICmd_get_gender, // 0x49
+ BattleAICmd_is_first_turn, // 0x4A
+ BattleAICmd_get_stockpile_count, // 0x4B
+ BattleAICmd_is_double_battle, // 0x4C
+ BattleAICmd_get_used_held_item, // 0x4D
+ BattleAICmd_get_move_type_from_result, // 0x4E
+ BattleAICmd_get_move_power_from_result, // 0x4F
+ BattleAICmd_get_move_effect_from_result, // 0x50
+ BattleAICmd_get_protect_count, // 0x51
+ BattleAICmd_nullsub_52, // 0x52
+ BattleAICmd_nullsub_53, // 0x53
+ BattleAICmd_nullsub_54, // 0x54
+ BattleAICmd_nullsub_55, // 0x55
+ BattleAICmd_nullsub_56, // 0x56
+ BattleAICmd_nullsub_57, // 0x57
+ BattleAICmd_call, // 0x58
+ BattleAICmd_jump, // 0x59
+ BattleAICmd_end, // 0x5A
+ BattleAICmd_if_level_cond, // 0x5B
+ BattleAICmd_if_target_taunted, // 0x5C
+ BattleAICmd_if_target_not_taunted, // 0x5D
+ BattleAICmd_if_target_is_ally, // 0x5E
+ BattleAICmd_is_of_type, // 0x5F
+ BattleAICmd_check_ability, // 0x60
+ BattleAICmd_if_flash_fired, // 0x61
+ BattleAICmd_if_holds_item, // 0x62
+};
-void BattleAI_SetupAIData(u8 a);
-u8 BattleAI_GetAIActionToUse(void);
-u8 sub_8130CF4(void);
-void sub_8131074(void);
-void BattleAI_DoAIProcessing(void);
+static const u16 sDiscouragedPowerfulMoveEffects[] =
+{
+ EFFECT_EXPLOSION,
+ EFFECT_DREAM_EATER,
+ EFFECT_RAZOR_WIND,
+ EFFECT_SKY_ATTACK,
+ EFFECT_RECHARGE,
+ EFFECT_SKULL_BASH,
+ EFFECT_SOLARBEAM,
+ EFFECT_SPIT_UP,
+ EFFECT_FOCUS_PUNCH,
+ EFFECT_SUPERPOWER,
+ EFFECT_ERUPTION,
+ EFFECT_OVERHEAT,
+ 0xFFFF
+};
-void BattleAI_HandleItemUseBeforeAISetup(u8 a)
+void BattleAI_HandleItemUseBeforeAISetup(u8 defaultScoreMoves)
{
s32 i;
- u8 *data = (u8 *)gBattleResources->unk18;
-
- for (i = 0; (u32)i < 0x54; i++)
+ u8 *data = (u8 *)gBattleResources->battleHistory;
+
+ for (i = 0; i < sizeof(struct BattleHistory); i++)
data[i] = 0;
- if ((gBattleTypeFlags & 0x0A7F098A) == 8)
+ // items are allowed to use in ONLY trainer battles
+ if ((gBattleTypeFlags &
+ (BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_BATTLE_TOWER |
+ BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER
+ | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_x2000000 | BATTLE_TYPE_SECRET_BASE))
+ == BATTLE_TYPE_TRAINER)
{
for (i = 0; i < 4; i++)
{
- if (gTrainers[gUnknown_02038BCA].items[i] != 0)
+ if (gTrainers[gTrainerBattleOpponent_A].items[i] != 0)
{
- gBattleResources->unk18->unk48[gBattleResources->unk18->unk50] = gTrainers[gUnknown_02038BCA].items[i];
- gBattleResources->unk18->unk50++;
+ gBattleResources->battleHistory->TrainerItems[gBattleResources->battleHistory->itemsNo] = gTrainers[gTrainerBattleOpponent_A].items[i];
+ gBattleResources->battleHistory->itemsNo++;
}
}
}
-
- BattleAI_SetupAIData(a);
+
+ BattleAI_SetupAIData(defaultScoreMoves);
}
-void BattleAI_SetupAIData(u8 a)
+void BattleAI_SetupAIData(u8 defaultScoreMoves)
{
s32 i;
u8 *data = (u8 *)AI_THINKING_STRUCT;
- u8 r6;
+ u8 moveLimitations;
// clear AI data.
- for (i = 0; (u32)i < sizeof(struct AI_ThinkingStruct); i++)
+ for (i = 0; i < sizeof(struct AI_ThinkingStruct); i++)
data[i] = 0;
// conditional score reset, unlike Ruby.
for (i = 0; i < 4; i++)
{
- if (a & 1)
+ if (defaultScoreMoves & 1)
AI_THINKING_STRUCT->score[i] = 100;
else
AI_THINKING_STRUCT->score[i] = 0;
- a >>= 1;
+ defaultScoreMoves >>= 1;
}
- r6 = sub_803FECC(gActiveBank, 0, 0xFF);
+ moveLimitations = CheckMoveLimitations(gActiveBank, 0, 0xFF);
+ // ignore moves that aren't possible to use
for (i = 0; i < 4; i++)
{
- if (gBitTable[i] & r6)
+ if (gBitTable[i] & moveLimitations)
AI_THINKING_STRUCT->score[i] = 0;
- AI_THINKING_STRUCT->unk18[i] = 100 - (Random() % 16);
+ AI_THINKING_STRUCT->simulatedRNG[i] = 100 - (Random() % 16);
}
- gBattleResources->unk1C->unk20 = 0;
- gPlayerMonIndex = gActiveBank;
- if (gBattleTypeFlags & 1)
+ gBattleResources->AI_ScriptsStack->size = 0;
+ sBank_AI = gActiveBank;
+ // decide a random target bank in doubles
+ if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
- gBankTarget = (Random() & 2) + ((u32)GetBankSide(gActiveBank) ^ 1);
+ gBankTarget = (Random() & 2) + (GetBankSide(gActiveBank) ^ 1);
if (gAbsentBankFlags & gBitTable[gBankTarget])
gBankTarget ^= 2;
}
+ // in singles there's only one choice
else
- {
- //_08130A60
- gBankTarget = gPlayerMonIndex ^ 1;
- }
- //_08130A68
- if (gBattleTypeFlags & 0x1000000)
- AI_THINKING_STRUCT->aiFlags = sub_8186438();
- else if (gBattleTypeFlags & 0x80)
+ gBankTarget = sBank_AI ^ 1;
+
+ if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
+ AI_THINKING_STRUCT->aiFlags = GetAiScriptsInRecordedBattle();
+ else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
AI_THINKING_STRUCT->aiFlags = 0x40000000;
- else if (gBattleTypeFlags & 0x400)
+ else if (gBattleTypeFlags & BATTLE_TYPE_ROAMER)
AI_THINKING_STRUCT->aiFlags = 0x20000000;
- else if (gBattleTypeFlags & 0x10)
+ else if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
AI_THINKING_STRUCT->aiFlags = 0x80000000;
- else if (gBattleTypeFlags & 0x80000)
- AI_THINKING_STRUCT->aiFlags = sub_81A6FB4();
- else if (gBattleTypeFlags & 0x0C3F0900)
- AI_THINKING_STRUCT->aiFlags = 7;
- else if (gBattleTypeFlags & 0x8000)
- AI_THINKING_STRUCT->aiFlags = gTrainers[gUnknown_02038BCA].aiFlags | gTrainers[gUnknown_02038BCC].aiFlags;
- else
- AI_THINKING_STRUCT->aiFlags = gTrainers[gUnknown_02038BCA].aiFlags;
- if (gBattleTypeFlags & 1)
- AI_THINKING_STRUCT->aiFlags |= 0x80;
+ else if (gBattleTypeFlags & BATTLE_TYPE_FACTORY)
+ AI_THINKING_STRUCT->aiFlags = GetAiScriptsInBattleFactory();
+ else if (gBattleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_x4000000 | BATTLE_TYPE_SECRET_BASE))
+ AI_THINKING_STRUCT->aiFlags = 7; // the smartest possible set
+ else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
+ AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags | gTrainers[gTrainerBattleOpponent_B].aiFlags;
+ else
+ AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags;
+ if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
+ AI_THINKING_STRUCT->aiFlags |= 0x80; // act smart in doubles and don't attack your partner
}
-u8 sub_8130BA4(void)
+u8 BattleAI_ChooseMoveOrAction(void)
{
- u16 r4 = gCurrentMove;
+ u16 savedCurrentMove = gCurrentMove;
u8 ret;
-
- if (!(gBattleTypeFlags & 1))
- ret = BattleAI_GetAIActionToUse();
+
+ if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
+ ret = BattleAI_ChooseMoveOrAction_Singles();
else
- ret = sub_8130CF4();
+ ret = BattleAI_ChooseMoveOrAction_Doubles();
- gCurrentMove = r4;
+ gCurrentMove = savedCurrentMove;
return ret;
}
-u8 BattleAI_GetAIActionToUse(void)
+static u8 BattleAI_ChooseMoveOrAction_Singles(void)
{
u8 currentMoveArray[4];
u8 consideredMoveArray[4];
u8 numOfBestMoves;
s32 i;
-
- sub_8131074();
+
+ RecordLastUsedMoveByTarget();
while (AI_THINKING_STRUCT->aiFlags != 0)
{
@@ -342,10 +444,10 @@ u8 BattleAI_GetAIActionToUse(void)
AI_THINKING_STRUCT->movesetIndex = 0;
}
- // special flags for safari watch/flee.
- if (AI_THINKING_STRUCT->aiAction & 2)
+ // special flags for safari
+ if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE)
return 4;
- if (AI_THINKING_STRUCT->aiAction & 4)
+ if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH)
return 5;
numOfBestMoves = 1;
@@ -354,7 +456,7 @@ u8 BattleAI_GetAIActionToUse(void)
for (i = 1; i < 4; i++)
{
- if (gBattleMons[gPlayerMonIndex].moves[i] != 0) // emerald adds an extra move ID check for some reason.
+ if (gBattleMons[sBank_AI].moves[i] != 0) // emerald adds an extra move ID check for some reason.
{
// in ruby, the order of these if statements are reversed.
if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i])
@@ -374,126 +476,121 @@ u8 BattleAI_GetAIActionToUse(void)
}
#ifdef NONMATCHING
-u8 sub_8130CF4(void)
+static u8 BattleAI_ChooseMoveOrAction_Doubles(void)
{
s32 i;
s32 j;
- //s32 r4_2;
- #define r4_2 r4
- s32 r5;
- s16 r5_2;
- s32 r4;
- s16 sp0[4];
- s8 sp8[4];
- s8 spC[4];
- u8 sp10[4]; // definitely unsigned
- u8 sp14[4];
- //u8 *sp1C = spC;
- //u8 *sp18 = sp8;
- //u8 *sp20 = spC;
-
- for (i = 0; i < 4; i++) //_08130D14
+ s32 scriptsToRun;
+ s16 mostMovePoints;
+ s16 bestMovePointsForTarget[4];
+ s8 mostViableTargetsArray[4];
+ u8 actionOrMoveIndex[4];
+ u8 mostViableMovesScores[4];
+ u8 mostViableMovesIndices[4];
+ s32 mostViableTargetsNo;
+ s32 mostViableMovesNo;
+
+ for (i = 0; i < 4; i++) //08130D14
{
- if (i == gPlayerMonIndex || gBattleMons[i].hp == 0)
+ if (i == sBank_AI || gBattleMons[i].hp == 0)
{
//_08130D2E
- spC[i] = -1;
- sp0[i] = -1;
+ actionOrMoveIndex[i] = -1;
+ bestMovePointsForTarget[i] = -1;
}
//_08130D48
else
{
- if (gBattleTypeFlags & 0x20000)
- BattleAI_SetupAIData(gBattleStruct[0x92] >> 4);
+ if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
+ BattleAI_SetupAIData(gBattleStruct->field_92 >> 4);
else
BattleAI_SetupAIData(0xF);
//_08130D76
gBankTarget = i;
- if ((i & 1) != (gPlayerMonIndex & 1))
- sub_8131074();
+ if ((i & 1) != (sBank_AI & 1))
+ RecordLastUsedMoveByTarget();
//_08130D90
- AI_THINKING_STRUCT->unk11 = 0;
- AI_THINKING_STRUCT->unk1 = 0;
- r4 = AI_THINKING_STRUCT->aiFlags;
- while (r4 != 0)
+ AI_THINKING_STRUCT->aiLogicId = 0;
+ AI_THINKING_STRUCT->movesetIndex = 0;
+ scriptsToRun = AI_THINKING_STRUCT->aiFlags;
+ while (scriptsToRun != 0)
{
- if (r4 & 1)
+ if (scriptsToRun & 1)
{
AI_THINKING_STRUCT->aiState = AIState_SettingUp;
BattleAI_DoAIProcessing();
}
- r4 >>= 1;
- AI_THINKING_STRUCT->unk11++;
- AI_THINKING_STRUCT->unk1 = 0;
+ scriptsToRun >>= 1;
+ AI_THINKING_STRUCT->aiLogicId++;
+ AI_THINKING_STRUCT->movesetIndex = 0;
}
//_08130DD8
- if (AI_THINKING_STRUCT->unk10 & 2)
- spC[i] = 4;
- else if (AI_THINKING_STRUCT->unk10 & 4)
- spC[i] = 5;
+ if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE)
+ actionOrMoveIndex[i] = 4;
+ else if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH)
+ actionOrMoveIndex[i] = 5;
else
{
//_08130E10
- sp10[0] = AI_THINKING_STRUCT->score[0];
- sp14[0] = 0;
- r5 = 1;
+ mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0];
+ mostViableMovesIndices[0] = 0;
+ mostViableMovesNo = 1;
for (j = 1; j < 4; j++)
{
- if (gBattleMons[gPlayerMonIndex].moves[j] != 0)
+ if (gBattleMons[sBank_AI].moves[j] != 0)
{
- if (sp10[0] == AI_THINKING_STRUCT->score[j])
+ if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j])
{
- sp10[r5] = AI_THINKING_STRUCT->score[j];
- sp14[r5] = j;
- r5++;
+ mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j];
+ mostViableMovesIndices[mostViableMovesNo] = j;
+ mostViableMovesNo++;
}
- if (sp10[0] < AI_THINKING_STRUCT->score[j])
+ if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j])
{
- sp10[0] = AI_THINKING_STRUCT->score[j];
- sp14[0] = j;
- r5 = 1;
+ mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j];
+ mostViableMovesIndices[0] = j;
+ mostViableMovesNo = 1;
}
}
//_08130E72
}
- spC[i] = sp14[Random() % r5];
- //asm("":::"r3");
- sp0[i] = sp10[0];
- if (i == (gPlayerMonIndex ^ 2) && sp0[i] < 100)
- sp0[i] = -1;
+ actionOrMoveIndex[i] = mostViableMovesIndices[Random() % mostViableMovesNo];
+ bestMovePointsForTarget[i] = mostViableMovesScores[0];
+
+ // don't use a move against ally if it has less than 100 pts
+ if (i == (sBank_AI ^ 2) && bestMovePointsForTarget[i] < 100)
+ bestMovePointsForTarget[i] = -1;
}
}
//_08130EAE
}
-
- //#define i r5
-
- //_08130EC4
- r5_2 = sp0[0];
- sp8[0] = 0;
- r4_2 = 1;
+
+ //08130EC4
+ mostMovePoints = bestMovePointsForTarget[0];
+ mostViableTargetsArray[0] = 0;
+ mostViableTargetsNo = 1;
for (i = 1; i < 4; i++)
{
//_08130EDA
- if (r5_2 == sp0[i])
+ if (mostMovePoints == bestMovePointsForTarget[i])
{
- sp8[r4_2] = i;
- r4_2++;
+ mostViableTargetsArray[mostViableTargetsNo] = i;
+ mostViableTargetsNo++;
}
//_08130EEE
- if (r5_2 < sp0[i])
+ if (mostMovePoints < bestMovePointsForTarget[i])
{
- r5_2 = sp0[i];
- sp8[0] = i;
- r4_2 = 1;
+ mostMovePoints = bestMovePointsForTarget[i];
+ mostViableTargetsArray[0] = i;
+ mostViableTargetsNo = 1;
}
}
- gBankTarget = sp8[Random() % r4_2];
- return spC[gBankTarget];
+ gBankTarget = mostViableTargetsArray[Random() % mostViableTargetsNo];
+ return actionOrMoveIndex[gBankTarget];
}
#else
__attribute__((naked))
-u8 sub_8130CF4(void)
+static u8 BattleAI_ChooseMoveOrAction_Doubles(void)
{
asm(".syntax unified\n\
push {r4-r7,lr}\n\
@@ -513,7 +610,7 @@ u8 sub_8130CF4(void)
str r1, [sp, 0x20]\n\
mov r10, sp\n\
_08130D14:\n\
- ldr r0, =gPlayerMonIndex\n\
+ ldr r0, =sBank_AI\n\
ldrb r0, [r0]\n\
cmp r8, r0\n\
beq _08130D2E\n\
@@ -561,12 +658,12 @@ _08130D76:\n\
movs r1, 0x1\n\
mov r2, r8\n\
ands r2, r1\n\
- ldr r0, =gPlayerMonIndex\n\
+ ldr r0, =sBank_AI\n\
ldrb r0, [r0]\n\
ands r1, r0\n\
cmp r2, r1\n\
beq _08130D90\n\
- bl sub_8131074\n\
+ bl RecordLastUsedMoveByTarget\n\
_08130D90:\n\
ldr r2, =gBattleResources\n\
ldr r0, [r2]\n\
@@ -639,11 +736,11 @@ _08130E10:\n\
movs r5, 0x1\n\
movs r3, 0x1\n\
adds r6, r1, 0\n\
- ldr r0, =gPlayerMonIndex\n\
+ ldr r0, =sBank_AI\n\
ldrb r1, [r0]\n\
movs r0, 0x58\n\
muls r0, r1\n\
- ldr r2, =gUnknown_02024090\n\
+ ldr r2, =gBattleMons + 0xC\n\
adds r0, r2\n\
adds r4, r0, 0x2\n\
add r7, sp, 0x14\n\
@@ -700,7 +797,7 @@ _08130E72:\n\
ldrb r2, [r6]\n\
mov r0, r10\n\
strh r2, [r0]\n\
- ldr r0, =gPlayerMonIndex\n\
+ ldr r0, =sBank_AI\n\
ldrb r1, [r0]\n\
movs r0, 0x2\n\
eors r0, r1\n\
@@ -788,7 +885,7 @@ _08130EFE:\n\
}
#endif
-void BattleAI_DoAIProcessing(void)
+static void BattleAI_DoAIProcessing(void)
{
while (AI_THINKING_STRUCT->aiState != AIState_FinishedProcessing)
{
@@ -797,14 +894,14 @@ void BattleAI_DoAIProcessing(void)
case AIState_DoNotProcess: //Needed to match.
break;
case AIState_SettingUp:
- gAIScriptPtr = gUnknown_082DBEF8[AI_THINKING_STRUCT->aiLogicId]; // set AI ptr to logic ID.
- if (gBattleMons[gPlayerMonIndex].pp[AI_THINKING_STRUCT->movesetIndex] == 0)
+ gAIScriptPtr = gBattleAI_ScriptsTable[AI_THINKING_STRUCT->aiLogicId]; // set AI ptr to logic ID.
+ if (gBattleMons[sBank_AI].pp[AI_THINKING_STRUCT->movesetIndex] == 0)
{
AI_THINKING_STRUCT->moveConsidered = 0;
}
else
{
- AI_THINKING_STRUCT->moveConsidered = gBattleMons[gPlayerMonIndex].moves[AI_THINKING_STRUCT->movesetIndex];
+ AI_THINKING_STRUCT->moveConsidered = gBattleMons[sBank_AI].moves[AI_THINKING_STRUCT->movesetIndex];
}
AI_THINKING_STRUCT->aiState++;
break;
@@ -814,70 +911,70 @@ void BattleAI_DoAIProcessing(void)
else
{
AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0;
- AI_THINKING_STRUCT->aiAction |= 1;
+ AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE;
}
- if (AI_THINKING_STRUCT->aiAction & 1)
+ if (AI_THINKING_STRUCT->aiAction & AI_ACTION_DONE)
{
AI_THINKING_STRUCT->movesetIndex++;
- if (AI_THINKING_STRUCT->movesetIndex < 4 && !(AI_THINKING_STRUCT->aiAction & 8))
+ if (AI_THINKING_STRUCT->movesetIndex < 4 && !(AI_THINKING_STRUCT->aiAction & AI_ACTION_DO_NOT_ATTACK))
AI_THINKING_STRUCT->aiState = AIState_SettingUp;
else
AI_THINKING_STRUCT->aiState++;
- AI_THINKING_STRUCT->aiAction &= 0xFE;
+ AI_THINKING_STRUCT->aiAction &= ~(AI_ACTION_DONE);
}
break;
}
}
}
-void sub_8131074(void)
+static void RecordLastUsedMoveByTarget(void)
{
s32 i;
-
+
for (i = 0; i < 4; i++)
{
- if (gBattleResources->unk18->unk0[gBankTarget][i] == gUnknown_02024248[gBankTarget])
+ if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == gLastUsedMovesByBanks[gBankTarget])
break;
- if (gBattleResources->unk18->unk0[gBankTarget][i] != gUnknown_02024248[gBankTarget] //HACK: This redundant condition is a hack to make the asm match.
- && gBattleResources->unk18->unk0[gBankTarget][i] == 0)
+ if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] != gLastUsedMovesByBanks[gBankTarget] //HACK: This redundant condition is a hack to make the asm match.
+ && gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == 0)
{
- gBattleResources->unk18->unk0[gBankTarget][i] = gUnknown_02024248[gBankTarget];
+ gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] = gLastUsedMovesByBanks[gBankTarget];
break;
}
}
}
-void sub_81310F0(u8 a)
+void ClearBankMoveHistory(u8 bank)
{
s32 i;
-
+
for (i = 0; i < 4; i++)
- gBattleResources->unk18->unk0[a][i] = 0;
+ gBattleResources->battleHistory->usedMoves[bank].moves[i] = 0;
}
-void RecordAbilityBattle(u8 a, u8 b)
+void RecordAbilityBattle(u8 bank, u8 abilityId)
{
- gBattleResources->unk18->unk40[a] = b;
+ gBattleResources->battleHistory->abilities[bank] = abilityId;
}
-void sub_8131130(u8 a)
+void ClearBankAbilityHistory(u8 bank)
{
- gBattleResources->unk18->unk40[a] = 0;
+ gBattleResources->battleHistory->abilities[bank] = 0;
}
-void b_history__record_item_x12_of_player(u8 a, u8 b)
+void RecordItemEffectBattle(u8 bank, u8 itemEffect)
{
- gBattleResources->unk18->unk44[a] = b;
+ gBattleResources->battleHistory->itemEffects[bank] = itemEffect;
}
-void sub_8131160(u8 a)
+void ClearBankItemEffectHistory(u8 bank)
{
- gBattleResources->unk18->unk44[a] = 0;
+ gBattleResources->battleHistory->itemEffects[bank] = 0;
}
-void BattleAICmd_if_random_less_than(void)
+static void BattleAICmd_if_random_less_than(void)
{
u16 random = Random();
@@ -887,7 +984,7 @@ void BattleAICmd_if_random_less_than(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_random_greater_than(void)
+static void BattleAICmd_if_random_greater_than(void)
{
u16 random = Random();
@@ -897,7 +994,7 @@ void BattleAICmd_if_random_greater_than(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_random_equal(void)
+static void BattleAICmd_if_random_equal(void)
{
u16 random = Random();
@@ -907,7 +1004,7 @@ void BattleAICmd_if_random_equal(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_random_not_equal(void)
+static void BattleAICmd_if_random_not_equal(void)
{
u16 random = Random();
@@ -917,7 +1014,7 @@ void BattleAICmd_if_random_not_equal(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_score(void)
+static void BattleAICmd_score(void)
{
AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += gAIScriptPtr[1]; // add the result to the array of the move consider's score.
@@ -927,12 +1024,12 @@ void BattleAICmd_score(void)
gAIScriptPtr += 2; // AI return.
}
-void BattleAICmd_if_hp_less_than(void)
+static void BattleAICmd_if_hp_less_than(void)
{
u16 index;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -942,12 +1039,12 @@ void BattleAICmd_if_hp_less_than(void)
gAIScriptPtr += 7;
}
-void BattleAICmd_if_hp_more_than(void)
+static void BattleAICmd_if_hp_more_than(void)
{
u16 index;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -957,12 +1054,12 @@ void BattleAICmd_if_hp_more_than(void)
gAIScriptPtr += 7;
}
-void BattleAICmd_if_hp_equal(void)
+static void BattleAICmd_if_hp_equal(void)
{
u16 index;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -972,12 +1069,12 @@ void BattleAICmd_if_hp_equal(void)
gAIScriptPtr += 7;
}
-void BattleAICmd_if_hp_not_equal(void)
+static void BattleAICmd_if_hp_not_equal(void)
{
u16 index;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -987,13 +1084,13 @@ void BattleAICmd_if_hp_not_equal(void)
gAIScriptPtr += 7;
}
-void BattleAICmd_if_status(void)
+static void BattleAICmd_if_status(void)
{
u16 index;
u32 arg;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -1005,13 +1102,13 @@ void BattleAICmd_if_status(void)
gAIScriptPtr += 10;
}
-void BattleAICmd_if_not_status(void)
+static void BattleAICmd_if_not_status(void)
{
u16 index;
u32 arg;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -1023,13 +1120,13 @@ void BattleAICmd_if_not_status(void)
gAIScriptPtr += 10;
}
-void BattleAICmd_if_status2(void)
+static void BattleAICmd_if_status2(void)
{
u16 index;
u32 arg;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -1041,13 +1138,13 @@ void BattleAICmd_if_status2(void)
gAIScriptPtr += 10;
}
-void BattleAICmd_if_not_status2(void)
+static void BattleAICmd_if_not_status2(void)
{
u16 index;
u32 arg;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -1059,13 +1156,13 @@ void BattleAICmd_if_not_status2(void)
gAIScriptPtr += 10;
}
-void BattleAICmd_if_status3(void)
+static void BattleAICmd_if_status3(void)
{
u16 index;
u32 arg;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -1077,13 +1174,13 @@ void BattleAICmd_if_status3(void)
gAIScriptPtr += 10;
}
-void BattleAICmd_if_not_status3(void)
+static void BattleAICmd_if_not_status3(void)
{
u16 index;
u32 arg;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -1095,45 +1192,45 @@ void BattleAICmd_if_not_status3(void)
gAIScriptPtr += 10;
}
-void BattleAICmd_if_status4(void)
+static void BattleAICmd_if_side_affecting(void)
{
u16 index;
u32 arg1, arg2;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
arg1 = GetBankIdentity(index) & 1;
arg2 = AIScriptRead32(gAIScriptPtr + 2);
- if ((gUnknown_0202428E[arg1] & arg2) != 0)
+ if ((gSideAffecting[arg1] & arg2) != 0)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6);
else
gAIScriptPtr += 10;
}
-void BattleAICmd_if_not_status4(void)
+static void BattleAICmd_if_not_side_affecting(void)
{
u16 index;
u32 arg1, arg2;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
arg1 = GetBankIdentity(index) & 1;
arg2 = AIScriptRead32(gAIScriptPtr + 2);
- if ((gUnknown_0202428E[arg1] & arg2) == 0)
+ if ((gSideAffecting[arg1] & arg2) == 0)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6);
else
gAIScriptPtr += 10;
}
-void BattleAICmd_if_less_than(void)
+static void BattleAICmd_if_less_than(void)
{
if (AI_THINKING_STRUCT->funcResult < gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -1141,7 +1238,7 @@ void BattleAICmd_if_less_than(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_more_than(void)
+static void BattleAICmd_if_more_than(void)
{
if (AI_THINKING_STRUCT->funcResult > gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -1149,7 +1246,7 @@ void BattleAICmd_if_more_than(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_equal(void)
+static void BattleAICmd_if_equal(void)
{
if (AI_THINKING_STRUCT->funcResult == gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -1157,7 +1254,7 @@ void BattleAICmd_if_equal(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_not_equal(void)
+static void BattleAICmd_if_not_equal(void)
{
if (AI_THINKING_STRUCT->funcResult != gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -1165,7 +1262,7 @@ void BattleAICmd_if_not_equal(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_less_than_32(void)
+static void BattleAICmd_if_less_than_32(void)
{
u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1175,7 +1272,7 @@ void BattleAICmd_if_less_than_32(void)
gAIScriptPtr += 9;
}
-void BattleAICmd_if_more_than_32(void)
+static void BattleAICmd_if_more_than_32(void)
{
u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1185,7 +1282,7 @@ void BattleAICmd_if_more_than_32(void)
gAIScriptPtr += 9;
}
-void BattleAICmd_if_equal_32(void)
+static void BattleAICmd_if_equal_32(void)
{
u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1195,7 +1292,7 @@ void BattleAICmd_if_equal_32(void)
gAIScriptPtr += 9;
}
-void BattleAICmd_if_not_equal_32(void)
+static void BattleAICmd_if_not_equal_32(void)
{
u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1205,7 +1302,7 @@ void BattleAICmd_if_not_equal_32(void)
gAIScriptPtr += 9;
}
-void BattleAICmd_if_move(void)
+static void BattleAICmd_if_move(void)
{
u16 move = AIScriptRead16(gAIScriptPtr + 1);
@@ -1215,7 +1312,7 @@ void BattleAICmd_if_move(void)
gAIScriptPtr += 7;
}
-void BattleAICmd_if_not_move(void)
+static void BattleAICmd_if_not_move(void)
{
u16 move = AIScriptRead16(gAIScriptPtr + 1);
@@ -1225,7 +1322,7 @@ void BattleAICmd_if_not_move(void)
gAIScriptPtr += 7;
}
-void BattleAICmd_if_in_bytes(void)
+static void BattleAICmd_if_in_bytes(void)
{
u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1241,7 +1338,7 @@ void BattleAICmd_if_in_bytes(void)
gAIScriptPtr += 9;
}
-void BattleAICmd_if_not_in_bytes(void)
+static void BattleAICmd_if_not_in_bytes(void)
{
u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1257,7 +1354,7 @@ void BattleAICmd_if_not_in_bytes(void)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5);
}
-void BattleAICmd_if_in_words(void)
+static void BattleAICmd_if_in_words(void)
{
u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1273,7 +1370,7 @@ void BattleAICmd_if_in_words(void)
gAIScriptPtr += 9;
}
-void BattleAICmd_if_not_in_words(void)
+static void BattleAICmd_if_not_in_words(void)
{
u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1);
@@ -1289,14 +1386,14 @@ void BattleAICmd_if_not_in_words(void)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5);
}
-void BattleAICmd_if_user_can_damage(void)
+static void BattleAICmd_if_user_can_damage(void)
{
s32 i;
for (i = 0; i < 4; i++)
{
- if (gBattleMons[gPlayerMonIndex].moves[i] != 0
- && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].power != 0)
+ if (gBattleMons[sBank_AI].moves[i] != 0
+ && gBattleMoves[gBattleMons[sBank_AI].moves[i]].power != 0)
break;
}
if (i == 4)
@@ -1305,14 +1402,14 @@ void BattleAICmd_if_user_can_damage(void)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
}
-void BattleAICmd_if_user_cant_damage(void)
+static void BattleAICmd_if_user_cant_damage(void)
{
s32 i;
for (i = 0; i < 4; i++)
{
- if (gBattleMons[gPlayerMonIndex].moves[i] != 0
- && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].power != 0)
+ if (gBattleMons[sBank_AI].moves[i] != 0
+ && gBattleMoves[gBattleMons[sBank_AI].moves[i]].power != 0)
break;
}
if (i != 4)
@@ -1321,26 +1418,26 @@ void BattleAICmd_if_user_cant_damage(void)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
}
-void BattleAICmd_get_turn_count(void)
+static void BattleAICmd_get_turn_count(void)
{
- AI_THINKING_STRUCT->funcResult = gUnknown_03005D10[19];
+ AI_THINKING_STRUCT->funcResult = gBattleResults.battleTurnCounter;
gAIScriptPtr += 1;
}
-void BattleAICmd_get_type(void)
+static void BattleAICmd_get_type(void)
{
u8 typeVar = gAIScriptPtr[1];
switch (typeVar)
{
case 1: // player primary type
- AI_THINKING_STRUCT->funcResult = gBattleMons[gPlayerMonIndex].type1;
+ AI_THINKING_STRUCT->funcResult = gBattleMons[sBank_AI].type1;
break;
case 0: // enemy primary type
AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type1;
break;
case 3: // player secondary type
- AI_THINKING_STRUCT->funcResult = gBattleMons[gPlayerMonIndex].type2;
+ AI_THINKING_STRUCT->funcResult = gBattleMons[sBank_AI].type2;
break;
case 2: // enemy secondary type
AI_THINKING_STRUCT->funcResult = gBattleMons[gBankTarget].type2;
@@ -1352,28 +1449,27 @@ void BattleAICmd_get_type(void)
gAIScriptPtr += 2;
}
-// util for double battles? whats this doing in the middle of the battle AI macros?
-u8 sub_8131E70(u8 index)
+static u8 BattleAI_GetWantedBank(u8 index)
{
switch (index)
{
- case 1:
- return gPlayerMonIndex;
- case 0:
+ case AI_USER:
+ return sBank_AI;
+ case AI_TARGET:
default:
return gBankTarget;
- case 3:
- return gPlayerMonIndex ^ 2;
- case 2:
+ case AI_USER_PARTNER:
+ return sBank_AI ^ 2;
+ case AI_TARGET_PARTNER:
return gBankTarget ^ 2;
}
}
-void BattleAICmd_unk_5F(void)
+static void BattleAICmd_is_of_type(void)
{
- u8 index = sub_8131E70(gAIScriptPtr[1]);
-
- if(gBattleMons[index].type1 == gAIScriptPtr[2] || gBattleMons[index].type2 == gAIScriptPtr[2])
+ u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]);
+
+ if(gBattleMons[bank].type1 == gAIScriptPtr[2] || gBattleMons[bank].type2 == gAIScriptPtr[2])
{
AI_THINKING_STRUCT->funcResult = 1;
}
@@ -1385,14 +1481,14 @@ void BattleAICmd_unk_5F(void)
gAIScriptPtr += 3;
}
-void BattleAICmd_get_move_power(void)
+static void BattleAICmd_get_last_used_bank_move_power(void)
{
AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power;
gAIScriptPtr += 1;
}
__attribute__((naked)) // not even going to try. if it doesnt match in ruby, it wont match in emerald (yet).
-void BattleAICmd_is_most_powerful_move(void)
+static void BattleAICmd_is_most_powerful_move(void)
{
asm(".syntax unified\n\
push {r4-r7,lr}\n\
@@ -1402,7 +1498,7 @@ void BattleAICmd_is_most_powerful_move(void)
push {r5-r7}\n\
sub sp, 0x14\n\
movs r3, 0\n\
- ldr r0, =gUnknown_085B09C8\n\
+ ldr r0, =sDiscouragedPowerfulMoveEffects\n\
ldrh r1, [r0]\n\
ldr r5, =0x0000ffff\n\
ldr r6, =gBattleMoves\n\
@@ -1417,7 +1513,7 @@ void BattleAICmd_is_most_powerful_move(void)
lsls r0, 2\n\
adds r0, r6\n\
ldrb r4, [r0]\n\
- ldr r1, =gUnknown_085B09C8\n\
+ ldr r1, =sDiscouragedPowerfulMoveEffects\n\
_08131F76:\n\
ldrh r0, [r1]\n\
cmp r4, r0\n\
@@ -1441,7 +1537,7 @@ _08131F86:\n\
b _08132126\n\
_08131F9C:\n\
lsls r0, r3, 1\n\
- ldr r1, =gUnknown_085B09C8\n\
+ ldr r1, =sDiscouragedPowerfulMoveEffects\n\
adds r0, r1\n\
ldrh r3, [r0]\n\
ldr r0, =0x0000ffff\n\
@@ -1449,7 +1545,7 @@ _08131F9C:\n\
beq _08131FAC\n\
b _08132126\n\
_08131FAC:\n\
- ldr r0, =gUnknown_02024400\n\
+ ldr r0, =gDynamicBasePower\n\
movs r1, 0\n\
strh r1, [r0]\n\
ldr r0, =gBattleStruct\n\
@@ -1464,14 +1560,14 @@ _08131FAC:\n\
strb r2, [r0]\n\
movs r6, 0\n\
mov r9, r3\n\
- ldr r2, =gUnknown_085B09C8\n\
+ ldr r2, =sDiscouragedPowerfulMoveEffects\n\
ldrh r2, [r2]\n\
str r2, [sp, 0x10]\n\
_08131FD0:\n\
movs r3, 0\n\
ldr r5, =gBattleMons\n\
lsls r4, r6, 1\n\
- ldr r7, =gPlayerMonIndex\n\
+ ldr r7, =sBank_AI\n\
lsls r0, r6, 2\n\
mov r8, r0\n\
adds r1, r6, 0x1\n\
@@ -1493,7 +1589,7 @@ _08131FD0:\n\
lsls r0, 2\n\
adds r0, r2\n\
ldrb r2, [r0]\n\
- ldr r1, =gUnknown_085B09C8\n\
+ ldr r1, =sDiscouragedPowerfulMoveEffects\n\
_08132004:\n\
ldrh r0, [r1]\n\
cmp r2, r0\n\
@@ -1515,7 +1611,7 @@ _08132014:\n\
cmp r0, 0\n\
beq _081320C0\n\
lsls r0, r3, 1\n\
- ldr r2, =gUnknown_085B09C8\n\
+ ldr r2, =sDiscouragedPowerfulMoveEffects\n\
adds r0, r2\n\
ldrh r0, [r0]\n\
cmp r0, r9\n\
@@ -1534,11 +1630,11 @@ _08132014:\n\
ldrb r0, [r7]\n\
ldr r4, =gBankTarget\n\
ldrb r1, [r4]\n\
- bl sub_8046E7C\n\
+ bl AI_CalcDmg\n\
ldrh r0, [r5]\n\
ldrb r1, [r7]\n\
ldrb r2, [r4]\n\
- bl move_effectiveness_something\n\
+ bl TypeCalc\n\
mov r4, sp\n\
add r4, r8\n\
ldr r2, =gBattleMoveDamage\n\
@@ -1635,17 +1731,17 @@ _08132130:\n\
.syntax divided");
}
-void BattleAICmd_get_move(void)
+static void BattleAICmd_get_last_used_bank_move(void)
{
- if (gAIScriptPtr[1] == USER)
- AI_THINKING_STRUCT->funcResult = gUnknown_02024248[gPlayerMonIndex];
+ if (gAIScriptPtr[1] == AI_USER)
+ AI_THINKING_STRUCT->funcResult = gLastUsedMovesByBanks[sBank_AI];
else
- AI_THINKING_STRUCT->funcResult = gUnknown_02024248[gBankTarget];
+ AI_THINKING_STRUCT->funcResult = gLastUsedMovesByBanks[gBankTarget];
gAIScriptPtr += 2;
}
-void BattleAICmd_if_arg_equal(void)
+static void BattleAICmd_if_arg_equal(void)
{
if (gAIScriptPtr[1] == AI_THINKING_STRUCT->funcResult)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -1653,7 +1749,7 @@ void BattleAICmd_if_arg_equal(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_arg_not_equal(void)
+static void BattleAICmd_if_arg_not_equal(void)
{
if (gAIScriptPtr[1] != AI_THINKING_STRUCT->funcResult)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -1661,41 +1757,41 @@ void BattleAICmd_if_arg_not_equal(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_would_go_first(void)
+static void BattleAICmd_if_would_go_first(void)
{
- if (b_first_side(gPlayerMonIndex, gBankTarget, 1) == gAIScriptPtr[1])
+ if (b_first_side(sBank_AI, gBankTarget, 1) == gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
else
gAIScriptPtr += 6;
}
-void BattleAICmd_if_would_not_go_first(void)
+static void BattleAICmd_if_would_not_go_first(void)
{
- if (b_first_side(gPlayerMonIndex, gBankTarget, 1) != gAIScriptPtr[1])
+ if (b_first_side(sBank_AI, gBankTarget, 1) != gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
else
gAIScriptPtr += 6;
}
-void BattleAICmd_nullsub_2A(void)
+static void BattleAICmd_nullsub_2A(void)
{
}
-void BattleAICmd_nullsub_2B(void)
+static void BattleAICmd_nullsub_2B(void)
{
}
-void BattleAICmd_count_alive_pokemon(void)
+static void BattleAICmd_count_alive_pokemon(void)
{
u8 index;
- u8 var, var2;
+ u8 bankOnField1, bankOnField2;
struct Pokemon *party;
int i;
AI_THINKING_STRUCT->funcResult = 0;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
@@ -1707,19 +1803,19 @@ void BattleAICmd_count_alive_pokemon(void)
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
u32 status;
- var = gBattlePartyID[index][0];
+ bankOnField1 = gBattlePartyID[index];
status = GetBankIdentity(index) ^ 2;
- var2 = gBattlePartyID[GetBankByPlayerAI(status)][0];
+ bankOnField2 = gBattlePartyID[GetBankByPlayerAI(status)];
}
- else
+ else // in singles there's only one bank by side
{
- var = gBattlePartyID[index][0];
- var2 = gBattlePartyID[index][0];
+ bankOnField1 = gBattlePartyID[index];
+ bankOnField2 = gBattlePartyID[index];
}
for (i = 0; i < 6; i++)
{
- if (i != var && i != var2
+ if (i != bankOnField1 && i != bankOnField2
&& GetMonData(&party[i], MON_DATA_HP) != 0
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
@@ -1731,39 +1827,39 @@ void BattleAICmd_count_alive_pokemon(void)
gAIScriptPtr += 2;
}
-void BattleAICmd_get_considered_move(void)
+static void BattleAICmd_get_considered_move(void)
{
AI_THINKING_STRUCT->funcResult = AI_THINKING_STRUCT->moveConsidered;
gAIScriptPtr += 1;
}
-void BattleAICmd_get_considered_move_effect(void)
+static void BattleAICmd_get_considered_move_effect(void)
{
AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect;
gAIScriptPtr += 1;
}
-void BattleAICmd_get_ability(void)
+static void BattleAICmd_get_ability(void)
{
u8 index;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ index = sBank_AI;
else
index = gBankTarget;
if(gActiveBank != index)
{
- if(UNK_2016A00_STRUCT->unk40[index] != 0)
+ if(BATTLE_HISTORY->abilities[index] != 0)
{
- AI_THINKING_STRUCT->funcResult = UNK_2016A00_STRUCT->unk40[index];
+ AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->abilities[index];
gAIScriptPtr += 2;
return;
}
-
+
// abilities that prevent fleeing.
- if (gBattleMons[index].ability == ABILITY_SHADOW_TAG
- || gBattleMons[index].ability == ABILITY_MAGNET_PULL
+ if (gBattleMons[index].ability == ABILITY_SHADOW_TAG
+ || gBattleMons[index].ability == ABILITY_MAGNET_PULL
|| gBattleMons[index].ability == ABILITY_ARENA_TRAP)
{
AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability;
@@ -1776,7 +1872,7 @@ void BattleAICmd_get_ability(void)
if (gBaseStats[gBattleMons[index].species].ability2 != ABILITY_NONE)
{
// AI has no knowledge of opponent, so it guesses which ability.
- if(Random() & 1)
+ if (Random() & 1)
{
AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1;
}
@@ -1784,7 +1880,7 @@ void BattleAICmd_get_ability(void)
{
AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2;
}
- }
+ }
else
{
AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; // it's definitely ability 1.
@@ -1804,90 +1900,76 @@ void BattleAICmd_get_ability(void)
}
#ifdef NONMATCHING
-void tai60_unk(void)
+static void BattleAICmd_check_ability(void)
{
- u8 index = sub_8131E70(gAIScriptPtr[1]);
- u8 arg2 = gAIScriptPtr[2];
- u8 var;
-
- if(gAIScriptPtr[1] == 0 || gAIScriptPtr[1] == 2)
+ u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]);
+ u8 ability = gAIScriptPtr[2];
+
+ if (gAIScriptPtr[1] == AI_TARGET || gAIScriptPtr[1] == AI_TARGET_PARTNER)
{
- // _0813253A
- if(UNK_2016A00_STRUCT->unk40[index] != 0)
+ if (BATTLE_HISTORY->abilities[bank] != 0)
{
- var = UNK_2016A00_STRUCT->unk40[index];
- AI_THINKING_STRUCT->funcResult = var;
+ ability = BATTLE_HISTORY->abilities[bank];
+ AI_THINKING_STRUCT->funcResult = ability;
}
- else
+ // abilities that prevent fleeing.
+ else if (gBattleMons[bank].ability == ABILITY_SHADOW_TAG
+ || gBattleMons[bank].ability == ABILITY_MAGNET_PULL
+ || gBattleMons[bank].ability == ABILITY_ARENA_TRAP)
{
- // _0813255C
- if (gBattleMons[index].ability == ABILITY_SHADOW_TAG
- || gBattleMons[index].ability == ABILITY_MAGNET_PULL
- || gBattleMons[index].ability == ABILITY_ARENA_TRAP)
- {
- var = gBattleMons[index].ability;
- }
- else
+ ability = gBattleMons[bank].ability;
+ }
+ else if (gBaseStats[gBattleMons[bank].species].ability1 != ABILITY_NONE)
+ {
+ if (gBaseStats[gBattleMons[bank].species].ability2 != ABILITY_NONE)
{
- // _08132588
- if (gBaseStats[gBattleMons[index].species].ability1 != ABILITY_NONE)
+ if (gBaseStats[gBattleMons[bank].species].ability1 != ability
+ && gBaseStats[gBattleMons[bank].species].ability2 != ability)
{
- if (gBaseStats[gBattleMons[index].species].ability2 != ABILITY_NONE)
- {
- if(gBaseStats[gBattleMons[index].species].ability1 != arg2 && gBaseStats[gBattleMons[index].species].ability2 != arg2)
- {
- var = 2;
- }
- else
- {
- var = gBaseStats[gBattleMons[index].species].ability1;
- }
- }
- else
- {
- // _081325B4
- var = gBaseStats[gBattleMons[index].species].ability1;
- }
+ ability = gBaseStats[gBattleMons[bank].species].ability1;
}
else
- {
- // _081325B8
- var = gBaseStats[gBattleMons[index].species].ability2;
- }
+ ability = 0;
+ }
+ else
+ {
+ ability = gBaseStats[gBattleMons[bank].species].ability1;
}
}
+ else
+ {
+ ability = gBaseStats[gBattleMons[bank].species].ability2; // AI cant actually reach this part since every mon has at least 1 ability.
+ }
}
else
{
- // _081325BC
- var = gBattleMons[index].ability;
+ // The AI knows its own or partner's ability.
+ ability = gBattleMons[bank].ability;
}
-
- // _081325CA
- if(var == ABILITY_NONE)
+ if (ability == 0)
{
- AI_THINKING_STRUCT->funcResult = 2;
+ AI_THINKING_STRUCT->funcResult = 2; // unable to answer
}
- else if(var == arg2)
+ else if (ability == gAIScriptPtr[2])
{
- AI_THINKING_STRUCT->funcResult = 1;
+ AI_THINKING_STRUCT->funcResult = 1; // pokemon has the ability we wanted to check
}
else
{
- AI_THINKING_STRUCT->funcResult = 0;
+ AI_THINKING_STRUCT->funcResult = 0; // pokemon doesn't have the ability we wanted to check
}
gAIScriptPtr += 3;
}
#else
__attribute__((naked))
-void tai60_unk(void)
+static void BattleAICmd_check_ability(void)
{
asm(".syntax unified\n\
push {r4-r6,lr}\n\
ldr r4, =gAIScriptPtr\n\
ldr r0, [r4]\n\
ldrb r0, [r0, 0x1]\n\
- bl sub_8131E70\n\
+ bl BattleAI_GetWantedBank\n\
lsls r0, 24\n\
lsrs r5, r0, 24\n\
ldr r0, [r4]\n\
@@ -2010,13 +2092,15 @@ _08132608:\n\
}
#endif
-void BattleAICmd_get_highest_possible_damage(void)
+static void BattleAICmd_get_highest_type_effectiveness(void)
{
s32 i;
+ u8* dynamicMoveType;
- gUnknown_02024400 = 0;
- gBattleStruct[0x13] = 0;
- gBattleScripting[0xE] = 1;
+ gDynamicBasePower = 0;
+ dynamicMoveType = &gBattleStruct->dynamicMoveType;
+ *dynamicMoveType = 0;
+ gBattleScripting.dmgMultiplier = 1;
gBattleMoveFlags = 0;
gCritMultiplier = 1;
AI_THINKING_STRUCT->funcResult = 0;
@@ -2024,11 +2108,11 @@ void BattleAICmd_get_highest_possible_damage(void)
for (i = 0; i < 4; i++)
{
gBattleMoveDamage = 40;
- gCurrentMove = gBattleMons[gPlayerMonIndex].moves[i];
+ gCurrentMove = gBattleMons[sBank_AI].moves[i];
if (gCurrentMove)
{
- move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget);
+ TypeCalc(gCurrentMove, sBank_AI, gBankTarget);
// reduce by 1/3.
if (gBattleMoveDamage == 120)
@@ -2040,7 +2124,7 @@ void BattleAICmd_get_highest_possible_damage(void)
if (gBattleMoveDamage == 15)
gBattleMoveDamage = 10;
- if (gBattleMoveFlags & 8) // if it's a status move, it wont do anything.
+ if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED)
gBattleMoveDamage = 0;
if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage)
@@ -2050,20 +2134,20 @@ void BattleAICmd_get_highest_possible_damage(void)
gAIScriptPtr += 1;
}
-void BattleAICmd_if_damage_bonus(void)
+static void BattleAICmd_if_type_effectiveness(void)
{
u8 damageVar;
- gUnknown_02024400 = 0;
- gBattleStruct[0x13] = 0;
- gBattleScripting[0xE] = 1;
+ gDynamicBasePower = 0;
+ gBattleStruct->dynamicMoveType = 0;
+ gBattleScripting.dmgMultiplier = 1;
gBattleMoveFlags = 0;
gCritMultiplier = 1;
gBattleMoveDamage = 40;
gCurrentMove = AI_THINKING_STRUCT->moveConsidered;
- move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget);
+ TypeCalc(gCurrentMove, sBank_AI, gBankTarget);
if (gBattleMoveDamage == 120)
gBattleMoveDamage = 80;
@@ -2074,7 +2158,7 @@ void BattleAICmd_if_damage_bonus(void)
if (gBattleMoveDamage == 15)
gBattleMoveDamage = 10;
- if (gBattleMoveFlags & 8)
+ if (gBattleMoveFlags & MOVESTATUS_NOTAFFECTED)
gBattleMoveDamage = 0;
// store gBattleMoveDamage in a u8 variable because gAIScriptPtr[1] is a u8.
@@ -2086,15 +2170,15 @@ void BattleAICmd_if_damage_bonus(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_nullsub_32(void)
+static void BattleAICmd_nullsub_32(void)
{
}
-void BattleAICmd_nullsub_33(void)
+static void BattleAICmd_nullsub_33(void)
{
}
-void BattleAICmd_if_status_in_party(void)
+static void BattleAICmd_if_status_in_party(void)
{
struct Pokemon *party;
int i;
@@ -2104,7 +2188,7 @@ void BattleAICmd_if_status_in_party(void)
switch(gAIScriptPtr[1])
{
case 1:
- index = gPlayerMonIndex;
+ index = sBank_AI;
break;
default:
index = gBankTarget;
@@ -2131,7 +2215,7 @@ void BattleAICmd_if_status_in_party(void)
gAIScriptPtr += 10;
}
-void BattleAICmd_if_status_not_in_party(void)
+static void BattleAICmd_if_status_not_in_party(void)
{
struct Pokemon *party;
int i;
@@ -2141,7 +2225,7 @@ void BattleAICmd_if_status_not_in_party(void)
switch(gAIScriptPtr[1])
{
case 1:
- index = gPlayerMonIndex;
+ index = sBank_AI;
break;
default:
index = gBankTarget;
@@ -2167,21 +2251,21 @@ void BattleAICmd_if_status_not_in_party(void)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6);
}
-void BattleAICmd_get_weather(void)
+static void BattleAICmd_get_weather(void)
{
- if (gBattleWeather & 7)
+ if (gBattleWeather & WEATHER_RAIN_ANY)
AI_THINKING_STRUCT->funcResult = 1;
- if (gBattleWeather & 0x18)
+ if (gBattleWeather & WEATHER_SANDSTORM_ANY)
AI_THINKING_STRUCT->funcResult = 2;
- if (gBattleWeather & 0x60)
+ if (gBattleWeather & WEATHER_SUN_ANY)
AI_THINKING_STRUCT->funcResult = 0;
- if (gBattleWeather & 0x80)
+ if (gBattleWeather & WEATHER_HAIL_ANY)
AI_THINKING_STRUCT->funcResult = 3;
gAIScriptPtr += 1;
}
-void BattleAICmd_if_effect(void)
+static void BattleAICmd_if_effect(void)
{
if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -2189,7 +2273,7 @@ void BattleAICmd_if_effect(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_not_effect(void)
+static void BattleAICmd_if_not_effect(void)
{
if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect != gAIScriptPtr[1])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
@@ -2197,67 +2281,67 @@ void BattleAICmd_if_not_effect(void)
gAIScriptPtr += 6;
}
-void BattleAICmd_if_stat_level_less_than(void)
+static void BattleAICmd_if_stat_level_less_than(void)
{
- u32 party;
+ u32 bank;
- if (gAIScriptPtr[1] == USER)
- party = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- party = gBankTarget;
+ bank = gBankTarget;
- if (gBattleMons[party].statStages[gAIScriptPtr[2]] < gAIScriptPtr[3])
+ if (gBattleMons[bank].statStages[gAIScriptPtr[2]] < gAIScriptPtr[3])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
else
gAIScriptPtr += 8;
}
-void BattleAICmd_if_stat_level_more_than(void)
+static void BattleAICmd_if_stat_level_more_than(void)
{
- u32 party;
+ u32 bank;
- if (gAIScriptPtr[1] == USER)
- party = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- party = gBankTarget;
+ bank = gBankTarget;
- if (gBattleMons[party].statStages[gAIScriptPtr[2]] > gAIScriptPtr[3])
+ if (gBattleMons[bank].statStages[gAIScriptPtr[2]] > gAIScriptPtr[3])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
else
gAIScriptPtr += 8;
}
-void BattleAICmd_if_stat_level_equal(void)
+static void BattleAICmd_if_stat_level_equal(void)
{
- u32 party;
+ u32 bank;
- if (gAIScriptPtr[1] == USER)
- party = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- party = gBankTarget;
+ bank = gBankTarget;
- if (gBattleMons[party].statStages[gAIScriptPtr[2]] == gAIScriptPtr[3])
+ if (gBattleMons[bank].statStages[gAIScriptPtr[2]] == gAIScriptPtr[3])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
else
gAIScriptPtr += 8;
}
-void BattleAICmd_if_stat_level_not_equal(void)
+static void BattleAICmd_if_stat_level_not_equal(void)
{
- u32 party;
+ u32 bank;
- if (gAIScriptPtr[1] == USER)
- party = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- party = gBankTarget;
+ bank = gBankTarget;
- if (gBattleMons[party].statStages[gAIScriptPtr[2]] != gAIScriptPtr[3])
+ if (gBattleMons[bank].statStages[gAIScriptPtr[2]] != gAIScriptPtr[3])
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
else
gAIScriptPtr += 8;
}
-void BattleAICmd_if_can_faint(void)
+static void BattleAICmd_if_can_faint(void)
{
if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2)
{
@@ -2265,16 +2349,16 @@ void BattleAICmd_if_can_faint(void)
return;
}
- gUnknown_02024400 = 0;
- gBattleStruct[0x13] = 0;
- gBattleScripting[0xE] = 1;
+ gDynamicBasePower = 0;
+ gBattleStruct->dynamicMoveType = 0;
+ gBattleScripting.dmgMultiplier = 1;
gBattleMoveFlags = 0;
gCritMultiplier = 1;
gCurrentMove = AI_THINKING_STRUCT->moveConsidered;
- sub_8046E7C(gPlayerMonIndex, gBankTarget);
- move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget);
+ AI_CalcDmg(sBank_AI, gBankTarget);
+ TypeCalc(gCurrentMove, sBank_AI, gBankTarget);
- gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->unk18[AI_THINKING_STRUCT->movesetIndex] / 100;
+ gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100;
// moves always do at least 1 damage.
if (gBattleMoveDamage == 0)
@@ -2286,7 +2370,7 @@ void BattleAICmd_if_can_faint(void)
gAIScriptPtr += 5;
}
-void BattleAICmd_if_cant_faint(void)
+static void BattleAICmd_if_cant_faint(void)
{
if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2)
{
@@ -2294,16 +2378,16 @@ void BattleAICmd_if_cant_faint(void)
return;
}
- gUnknown_02024400 = 0;
- gBattleStruct[0x13] = 0;
- gBattleScripting[0xE] = 1;
+ gDynamicBasePower = 0;
+ gBattleStruct->dynamicMoveType = 0;
+ gBattleScripting.dmgMultiplier = 1;
gBattleMoveFlags = 0;
gCritMultiplier = 1;
gCurrentMove = AI_THINKING_STRUCT->moveConsidered;
- sub_8046E7C(gPlayerMonIndex, gBankTarget);
- move_effectiveness_something(gCurrentMove, gPlayerMonIndex, gBankTarget);
+ AI_CalcDmg(sBank_AI, gBankTarget);
+ TypeCalc(gCurrentMove, sBank_AI, gBankTarget);
- gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->unk18[AI_THINKING_STRUCT->movesetIndex] / 100;
+ gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->simulatedRNG[AI_THINKING_STRUCT->movesetIndex] / 100;
// this macro is missing the damage 0 = 1 assumption.
@@ -2313,18 +2397,17 @@ void BattleAICmd_if_cant_faint(void)
gAIScriptPtr += 5;
}
-void BattleAICmd_if_has_move(void)
+static void BattleAICmd_if_has_move(void)
{
int i;
u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2);
-
+
switch(gAIScriptPtr[1])
{
- case 1:
- // _08132E42
+ case AI_USER:
for (i = 0; i < 4; i++)
{
- if (gBattleMons[gPlayerMonIndex].moves[i] == *temp_ptr)
+ if (gBattleMons[sBank_AI].moves[i] == *temp_ptr)
break;
}
if (i == 4)
@@ -2336,9 +2419,9 @@ void BattleAICmd_if_has_move(void)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
return;
- }
- case 3: // new to Emerald
- if(gBattleMons[gPlayerMonIndex ^ 2].hp == 0)
+ }
+ case AI_USER_PARTNER:
+ if (gBattleMons[sBank_AI ^ 2].hp == 0)
{
gAIScriptPtr += 8;
return;
@@ -2347,7 +2430,7 @@ void BattleAICmd_if_has_move(void)
{
for (i = 0; i < 4; i++)
{
- if (gBattleMons[gPlayerMonIndex ^ 2].moves[i] == *temp_ptr)
+ if (gBattleMons[sBank_AI ^ 2].moves[i] == *temp_ptr)
break;
}
}
@@ -2360,12 +2443,12 @@ void BattleAICmd_if_has_move(void)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
return;
- }
- case 0:
- case 2:
+ }
+ case AI_TARGET:
+ case AI_TARGET_PARTNER:
for (i = 0; i < 4; i++)
{
- if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] == *temp_ptr)
+ if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr)
break;
}
if (i == 4)
@@ -2381,18 +2464,18 @@ void BattleAICmd_if_has_move(void)
}
}
-void BattleAICmd_if_dont_have_move(void)
+static void BattleAICmd_if_dont_have_move(void)
{
int i;
u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2);
-
+
switch(gAIScriptPtr[1])
{
- case 1:
- case 3: // if_dont_have_move does not have the seperate 3 case check in Emerald unlike if_has_move.
+ case AI_USER:
+ case AI_USER_PARTNER: // UB: no separate check for user partner
for (i = 0; i < 4; i++)
{
- if (gBattleMons[gPlayerMonIndex].moves[i] == *temp_ptr)
+ if (gBattleMons[sBank_AI].moves[i] == *temp_ptr)
break;
}
if (i != 4)
@@ -2405,11 +2488,11 @@ void BattleAICmd_if_dont_have_move(void)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
return;
}
- case 0:
- case 2:
+ case AI_TARGET:
+ case AI_TARGET_PARTNER:
for (i = 0; i < 4; i++)
{
- if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] == *temp_ptr)
+ if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr)
break;
}
if (i != 4)
@@ -2425,17 +2508,17 @@ void BattleAICmd_if_dont_have_move(void)
}
}
-void BattleAICmd_if_move_effect(void)
+static void BattleAICmd_if_move_effect(void)
{
int i;
switch (gAIScriptPtr[1])
{
- case 1:
- case 3: // _08133044
- for(i = 0; i < 4; i++)
+ case AI_USER:
+ case AI_USER_PARTNER:
+ for (i = 0; i < 4; i++)
{
- if(gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].effect == gAIScriptPtr[2])
+ if(gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBank_AI].moves[i]].effect == gAIScriptPtr[2])
break;
}
if (i == 4)
@@ -2443,11 +2526,11 @@ void BattleAICmd_if_move_effect(void)
else
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3);
break;
- case 0:
- case 2: // _08133090
+ case AI_TARGET:
+ case AI_TARGET_PARTNER:
for (i = 0; i < 4; i++)
{
- if (gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[UNK_2016A00_STRUCT->unk0[gBankTarget][i]].effect == gAIScriptPtr[2])
+ if (gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2])
break;
}
if (i == 4)
@@ -2458,17 +2541,17 @@ void BattleAICmd_if_move_effect(void)
}
}
-void BattleAICmd_if_not_move_effect(void)
+static void BattleAICmd_if_not_move_effect(void)
{
int i;
switch (gAIScriptPtr[1])
{
- case 1:
- case 3: // _0813313C
- for(i = 0; i < 4; i++)
+ case AI_USER:
+ case AI_USER_PARTNER:
+ for (i = 0; i < 4; i++)
{
- if(gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].effect == gAIScriptPtr[2])
+ if(gBattleMons[sBank_AI].moves[i] != 0 && gBattleMoves[gBattleMons[sBank_AI].moves[i]].effect == gAIScriptPtr[2])
break;
}
if (i != 4)
@@ -2476,11 +2559,11 @@ void BattleAICmd_if_not_move_effect(void)
else
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3);
break;
- case 0:
- case 2: // _08133188
+ case AI_TARGET:
+ case AI_TARGET_PARTNER:
for (i = 0; i < 4; i++)
{
- if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] && gBattleMoves[UNK_2016A00_STRUCT->unk0[gBankTarget][i]].effect == gAIScriptPtr[2])
+ if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2])
break;
}
if (i != 4)
@@ -2491,18 +2574,18 @@ void BattleAICmd_if_not_move_effect(void)
}
}
-void BattleAICmd_if_last_move_did_damage(void)
+static void BattleAICmd_if_any_move_disabled_or_encored(void)
{
- u8 index;
+ u8 bank;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- index = gBankTarget;
+ bank = gBankTarget;
if (gAIScriptPtr[2] == 0)
{
- if (gDisableStructs[index].unk4 == 0)
+ if (gDisableStructs[bank].disabledMove == 0)
{
gAIScriptPtr += 7;
return;
@@ -2515,7 +2598,7 @@ void BattleAICmd_if_last_move_did_damage(void)
gAIScriptPtr += 7;
return;
}
- else if (gDisableStructs[index].unk6 != 0)
+ else if (gDisableStructs[bank].encoredMove != 0)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3);
return;
@@ -2523,20 +2606,20 @@ void BattleAICmd_if_last_move_did_damage(void)
gAIScriptPtr += 7;
}
-void BattleAICmd_if_encored(void)
+static void BattleAICmd_if_curr_move_disabled_or_encored(void)
{
switch (gAIScriptPtr[1])
{
- case 0: // _08109348
- if (gDisableStructs[gActiveBank].unk4 == AI_THINKING_STRUCT->moveConsidered)
+ case 0:
+ if (gDisableStructs[gActiveBank].disabledMove == AI_THINKING_STRUCT->moveConsidered)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
return;
}
gAIScriptPtr += 6;
return;
- case 1: // _08109370
- if (gDisableStructs[gActiveBank].unk6 == AI_THINKING_STRUCT->moveConsidered)
+ case 1:
+ if (gDisableStructs[gActiveBank].encoredMove == AI_THINKING_STRUCT->moveConsidered)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
return;
@@ -2549,14 +2632,14 @@ void BattleAICmd_if_encored(void)
}
}
-void BattleAICmd_flee(void)
+static void BattleAICmd_flee(void)
{
- AI_THINKING_STRUCT->aiAction |= (AI_ACTION_UNK1 | AI_ACTION_UNK2 | AI_ACTION_UNK4); // what matters is UNK2 being enabled.
+ AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK2 being enabled.
}
-void BattleAICmd_if_random_100(void)
+static void BattleAICmd_if_random_100(void)
{
- u8 safariFleeRate = gBattleStruct[0x7B] * 5; // safari flee rate, from 0-20
+ u8 safariFleeRate = gBattleStruct->field_7B * 5; // safari flee rate, from 0-20
if ((u8)(Random() % 100) < safariFleeRate)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
@@ -2564,198 +2647,202 @@ void BattleAICmd_if_random_100(void)
gAIScriptPtr += 5;
}
-void BattleAICmd_watch(void)
+static void BattleAICmd_watch(void)
{
- AI_THINKING_STRUCT->aiAction |= (AI_ACTION_UNK1 | AI_ACTION_UNK3 | AI_ACTION_UNK4); // what matters is UNK3 being enabled.
+ AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); // what matters is UNK3 being enabled.
}
-void BattleAICmd_get_hold_effect(void)
+static void BattleAICmd_get_hold_effect(void)
{
- u8 index;
+ u8 bank;
u16 status;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- index = gBankTarget;
+ bank = gBankTarget;
- if (gActiveBank != index)
+ if (gActiveBank != bank)
{
- AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(UNK_2016A00_STRUCT->unk44[index]);
+ AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(BATTLE_HISTORY->itemEffects[bank]);
}
else
- AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(gBattleMons[index].item);
+ AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(gBattleMons[bank].item);
gAIScriptPtr += 2;
}
-void tai62_unk(void)
+static void BattleAICmd_if_holds_item(void)
{
- u8 index = sub_8131E70(gAIScriptPtr[1]);
+ u8 bank = BattleAI_GetWantedBank(gAIScriptPtr[1]);
u16 item;
u8 var1, var2;
-
- if((index & 1) == (gPlayerMonIndex & 1))
- item = gBattleMons[index].item;
+
+ if ((bank & 1) == (sBank_AI & 1))
+ item = gBattleMons[bank].item;
else
- item = UNK_2016A00_STRUCT->unk44[index];
+ item = BATTLE_HISTORY->itemEffects[bank];
- // strange way of loading a 16-bit argument from the AI command.
+ // UB: doesn't properly read an unaligned u16
var2 = gAIScriptPtr[2];
var1 = gAIScriptPtr[3];
-
- if((var1 | var2) == item)
+
+ if ((var1 | var2) == item)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4);
else
gAIScriptPtr += 8;
}
-void BattleAICmd_get_gender(void)
+static void BattleAICmd_get_gender(void)
{
- u8 index;
+ u8 bank;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- index = gBankTarget;
+ bank = gBankTarget;
- AI_THINKING_STRUCT->funcResult = pokemon_species_get_gender_info(gBattleMons[index].species, gBattleMons[index].personality);
+ AI_THINKING_STRUCT->funcResult = GetGenderFromSpeciesAndPersonality(gBattleMons[bank].species, gBattleMons[bank].personality);
gAIScriptPtr += 2;
}
-void BattleAICmd_is_first_turn(void)
+static void BattleAICmd_is_first_turn(void)
{
- u8 index;
+ u8 bank;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- index = gBankTarget;
+ bank = gBankTarget;
- AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk16;
+ AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].isFirstTurn;
gAIScriptPtr += 2;
}
-void BattleAICmd_get_stockpile_count(void)
+static void BattleAICmd_get_stockpile_count(void)
{
- u8 index;
+ u8 bank;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- index = gBankTarget;
+ bank = gBankTarget;
- AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk9;
+ AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].stockpileCounter;
gAIScriptPtr += 2;
}
-void BattleAICmd_is_double_battle(void)
+static void BattleAICmd_is_double_battle(void)
{
AI_THINKING_STRUCT->funcResult = gBattleTypeFlags & BATTLE_TYPE_DOUBLE;
gAIScriptPtr += 1;
}
-void BattleAICmd_get_item(void)
+static void BattleAICmd_get_used_held_item(void)
{
- u8 index;
+ u8 bank;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- index = gBankTarget;
+ bank = gBankTarget;
- // this hack and a half matches. whatever. i dont care. someone else fix this mess later. PS: still cant fix this.
- AI_THINKING_STRUCT->funcResult = gBattleStruct[0xB8 + (index * 2)];
+ // This is likely a leftover from Ruby's code and its ugly ewram access
+ #ifdef NONMATCHING
+ AI_THINKING_STRUCT->funcResult = gBattleStruct->usedHeldItems[bank];
+ #else
+ AI_THINKING_STRUCT->funcResult = *(u8*)((u8*)(gBattleStruct) + 0xB8 + (bank * 2));
+ #endif // NONMATCHING
gAIScriptPtr += 2;
}
-void BattleAICmd_get_move_type_from_result(void)
+static void BattleAICmd_get_move_type_from_result(void)
{
AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].type;
gAIScriptPtr += 1;
}
-void BattleAICmd_get_move_power_from_result(void)
+static void BattleAICmd_get_move_power_from_result(void)
{
AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].power;
gAIScriptPtr += 1;
}
-void BattleAICmd_get_move_effect_from_result(void)
+static void BattleAICmd_get_move_effect_from_result(void)
{
AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].effect;
gAIScriptPtr += 1;
}
-void BattleAICmd_get_protect_count(void)
+static void BattleAICmd_get_protect_count(void)
{
- u8 index;
+ u8 bank;
- if (gAIScriptPtr[1] == USER)
- index = gPlayerMonIndex;
+ if (gAIScriptPtr[1] == AI_USER)
+ bank = sBank_AI;
else
- index = gBankTarget;
+ bank = gBankTarget;
- AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk8;
+ AI_THINKING_STRUCT->funcResult = gDisableStructs[bank].protectUses;
gAIScriptPtr += 2;
}
-void BattleAICmd_nullsub_52(void)
+static void BattleAICmd_nullsub_52(void)
{
}
-void BattleAICmd_nullsub_53(void)
+static void BattleAICmd_nullsub_53(void)
{
}
-void BattleAICmd_nullsub_54(void)
+static void BattleAICmd_nullsub_54(void)
{
}
-void BattleAICmd_nullsub_55(void)
+static void BattleAICmd_nullsub_55(void)
{
}
-void BattleAICmd_nullsub_56(void)
+static void BattleAICmd_nullsub_56(void)
{
}
-void BattleAICmd_nullsub_57(void)
+static void BattleAICmd_nullsub_57(void)
{
}
-void BattleAICmd_call(void)
+static void BattleAICmd_call(void)
{
- b_mc_stack_push(gAIScriptPtr + 5);
+ AIStackPushVar(gAIScriptPtr + 5);
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
}
-void BattleAICmd_jump(void)
+static void BattleAICmd_jump(void)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
}
-void BattleAICmd_end(void)
+static void BattleAICmd_end(void)
{
- if (b_mc_stack_pop_cursor() == 0)
- AI_THINKING_STRUCT->aiAction |= AI_ACTION_UNK1;
+ if (AIStackPop() == 0)
+ AI_THINKING_STRUCT->aiAction |= AI_ACTION_DONE;
}
-void BattleAICmd_if_level_cond(void)
+static void BattleAICmd_if_level_cond(void)
{
switch (gAIScriptPtr[1])
{
case 0: // greater than
- if (gBattleMons[gPlayerMonIndex].level > gBattleMons[gBankTarget].level)
+ if (gBattleMons[sBank_AI].level > gBattleMons[gBankTarget].level)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
return;
@@ -2763,7 +2850,7 @@ void BattleAICmd_if_level_cond(void)
gAIScriptPtr += 6;
return;
case 1: // less than
- if (gBattleMons[gPlayerMonIndex].level < gBattleMons[gBankTarget].level)
+ if (gBattleMons[sBank_AI].level < gBattleMons[gBankTarget].level)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
return;
@@ -2771,7 +2858,7 @@ void BattleAICmd_if_level_cond(void)
gAIScriptPtr += 6;
return;
case 2: // equal
- if (gBattleMons[gPlayerMonIndex].level == gBattleMons[gBankTarget].level)
+ if (gBattleMons[sBank_AI].level == gBattleMons[gBankTarget].level)
{
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
return;
@@ -2781,56 +2868,56 @@ void BattleAICmd_if_level_cond(void)
}
}
-void BattleAICmd_if_taunted(void)
+static void BattleAICmd_if_target_taunted(void)
{
- if (gDisableStructs[gBankTarget].taunt != 0)
+ if (gDisableStructs[gBankTarget].tauntTimer1 != 0)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
else
gAIScriptPtr += 5;
}
-void BattleAICmd_if_not_taunted(void)
+static void BattleAICmd_if_target_not_taunted(void)
{
- if (gDisableStructs[gBankTarget].taunt == 0)
+ if (gDisableStructs[gBankTarget].tauntTimer1 == 0)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
else
gAIScriptPtr += 5;
}
-void tai5E_unk(void)
+static void BattleAICmd_if_target_is_ally(void)
{
- if((gPlayerMonIndex & 1) == (gBankTarget & 1))
+ if((sBank_AI & 1) == (gBankTarget & 1))
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1);
else
gAIScriptPtr += 5;
}
-void tai61_unk(void)
+static void BattleAICmd_if_flash_fired(void)
{
- u8 index = sub_8131E70(gAIScriptPtr[1]);
-
- if(UNK_BATTLE_STRUCT->unk4->unkArray[index] & 1)
+ u8 index = BattleAI_GetWantedBank(gAIScriptPtr[1]);
+
+ if(gBattleResources->flags->flags[index] & UNKNOWN_FLAG_FLASH_FIRE)
gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2);
else
gAIScriptPtr += 6;
}
-void b_mc_stack_push(u8 *var)
+static void AIStackPushVar(u8 *var)
{
- UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20++] = var;
+ gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = var;
}
-void b_mc_stack_push_cursor(void)
+static void AIStackPushVar_cursor(void)
{
- UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20++] = gAIScriptPtr;
+ gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = gAIScriptPtr;
}
-bool8 b_mc_stack_pop_cursor(void)
+static bool8 AIStackPop(void)
{
- if (UNK_2016C00_STRUCT->unk20 != 0)
+ if (gBattleResources->AI_ScriptsStack->size != 0)
{
- --UNK_2016C00_STRUCT->unk20;
- gAIScriptPtr = UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20];
+ --gBattleResources->AI_ScriptsStack->size;
+ gAIScriptPtr = gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size];
return TRUE;
}
else
diff --git a/src/calculate_base_damage.c b/src/calculate_base_damage.c
new file mode 100644
index 000000000..105b334f2
--- /dev/null
+++ b/src/calculate_base_damage.c
@@ -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;
+}
diff --git a/src/coins.c b/src/coins.c
new file mode 100644
index 000000000..f43b5b336
--- /dev/null
+++ b/src/coins.c
@@ -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;
+}*/
diff --git a/src/load_save.c b/src/load_save.c
new file mode 100644
index 000000000..588387186
--- /dev/null
+++ b/src/load_save.c
@@ -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;
+}*/
diff --git a/src/lottery_corner.c b/src/lottery_corner.c
new file mode 100644
index 000000000..3939f7d7f
--- /dev/null
+++ b/src/lottery_corner.c
@@ -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);
+}
diff --git a/src/main.c b/src/main.c
index 7c8075a6f..5707e18af 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);
}
diff --git a/src/malloc.c b/src/malloc.c
index 948303c6f..3901c5a35 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -1,7 +1,5 @@
#include "global.h"
-EWRAM_DATA u8 gHeap[0x1C000] = {0};
-
static void *sHeapStart;
static u32 sHeapSize;
diff --git a/src/money.c b/src/money.c
new file mode 100644
index 000000000..be64d9633
--- /dev/null
+++ b/src/money.c
@@ -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);
+}
diff --git a/src/new_game.c b/src/new_game.c
index 649cf4e6d..2bf774c69 100644
--- a/src/new_game.c
+++ b/src/new_game.c
@@ -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));
+}
diff --git a/src/palette.c b/src/palette.c
index eb055a294..aa9a84e4c 100644
--- a/src/palette.c
+++ b/src/palette.c
@@ -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)
diff --git a/src/play_time.c b/src/play_time.c
index 444c2c86c..27a57f28b 100644
--- a/src/play_time.c
+++ b/src/play_time.c
@@ -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;
diff --git a/src/pokemon_1.c b/src/pokemon_1.c
new file mode 100644
index 000000000..e28c56252
--- /dev/null
+++ b/src/pokemon_1.c
@@ -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);
+}
diff --git a/src/pokemon_2.c b/src/pokemon_2.c
new file mode 100644
index 000000000..d50853383
--- /dev/null
+++ b/src/pokemon_2.c
@@ -0,0 +1,4 @@
+#include "global.h"
+#include "pokemon.h"
+
+
diff --git a/src/pokemon_size_record.c b/src/pokemon_size_record.c
new file mode 100644
index 000000000..804dbda74
--- /dev/null
+++ b/src/pokemon_size_record.c
@@ -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);
+ }
+}
diff --git a/src/rng.c b/src/rng.c
index 6f4f2ce55..ddd149018 100644
--- a/src/rng.c
+++ b/src/rng.c
@@ -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++;
diff --git a/src/safari_zone.c b/src/safari_zone.c
new file mode 100644
index 000000000..37ee664cd
--- /dev/null
+++ b/src/safari_zone.c
@@ -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 script_env_2_set_ctx_paused(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);
+ script_env_2_set_ctx_paused();
+ 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;
+}
diff --git a/src/save.c b/src/save.c
index ccb653f66..5ca855247 100644
--- a/src/save.c
+++ b/src/save.c
@@ -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\
diff --git a/src/start_menu.c b/src/start_menu.c
new file mode 100644
index 000000000..ffcab5220
--- /dev/null
+++ b/src/start_menu.c
@@ -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;
+ }
+}*/
diff --git a/src/task.c b/src/task.c
index 70dd6b292..fafa7c70d 100644
--- a/src/task.c
+++ b/src/task.c
@@ -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;
diff --git a/src/text.c b/src/text.c
index 6754e1a42..cad8326e3 100644
--- a/src/text.c
+++ b/src/text.c
@@ -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;
diff --git a/src/window.c b/src/window.c
index f3d2e833e..574b13aa0 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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;