summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPikalaxALT <pikalaxalt@gmail.com>2017-09-13 19:29:19 -0400
committerPikalaxALT <pikalaxalt@gmail.com>2017-09-13 19:29:19 -0400
commit64ffa8f9639c0dae2075d722fb12610e42b2129f (patch)
treeabb297307bf48a399052aa0c6f7d1db7498b9cc3 /src
parentc2e31f0618e19a1edad6bfface74901c8cd405f7 (diff)
parent78009a835f840864b3d30af00c65a745f75b80fa (diff)
Merge branch 'master' into field_map_obj
Diffstat (limited to 'src')
-rw-r--r--src/battle_4.c601
-rw-r--r--src/battle_ai.c1505
-rw-r--r--src/bg.c1642
-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/script.c434
-rw-r--r--src/start_menu.c231
-rw-r--r--src/task.c6
-rw-r--r--src/text.c2
-rw-r--r--src/util.c503
-rw-r--r--src/window.c2
25 files changed, 5858 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/bg.c b/src/bg.c
new file mode 100644
index 000000000..8979eaecd
--- /dev/null
+++ b/src/bg.c
@@ -0,0 +1,1642 @@
+#include "global.h"
+#include "dma3.h"
+
+#define DISPCNT_ALL_BG_AND_MODE_BITS 0x0F07
+
+enum {
+ BG_CTRL_ATTR_VISIBLE = 1,
+ BG_CTRL_ATTR_CHARBASEINDEX = 2,
+ BG_CTRL_ATTR_MAPBASEINDEX = 3,
+ BG_CTRL_ATTR_SCREENSIZE = 4,
+ BG_CTRL_ATTR_PALETTEMODE = 5,
+ BG_CTRL_ATTR_PRIORITY = 6,
+ BG_CTRL_ATTR_MOSAIC = 7,
+ BG_CTRL_ATTR_WRAPAROUND = 8,
+};
+
+struct BgControl {
+ struct BgConfig {
+ u16 visible:1;
+ u16 unknown_1:1;
+ u16 screenSize:2;
+ u16 priority:2;
+ u16 mosaic:1;
+ u16 wraparound:1;
+
+ u16 charBaseIndex:2;
+ u16 mapBaseIndex:5;
+ u16 paletteMode:1;
+
+ u8 unknown_2;
+ u8 unknown_3;
+ } configs[4];
+
+ u16 bgVisibilityAndMode;
+};
+
+struct BgTemplate {
+ u32 bg:2;
+ u32 charBaseIndex:2;
+ u32 mapBaseIndex:5;
+ u32 screenSize:2;
+ u32 paletteMode:1;
+ u32 priority:2;
+ u32 baseTile:10;
+};
+
+struct BgConfig2 {
+ u32 baseTile:10;
+ u32 basePalette:4;
+ u32 unk_3:18;
+
+ void* tilemap;
+ u32 bg_x;
+ u32 bg_y;
+};
+
+static struct BgControl gGpuBgConfigs;
+static struct BgConfig2 gGpuBgConfigs2[4];
+static u32 gDmaBusyBitfield[4];
+
+u32 gUnneededFireRedVariable;
+
+static const struct BgConfig gZeroedBgControlStruct = { 0 };
+
+extern void SetGpuReg(u8 regOffset, u16 value);
+extern void SetGpuReg_ForcedBlank(u8 regOffset, u16 value);
+extern u16 GetGpuReg(u8 regOffset);
+extern int CheckForSpaceForDma3Request(s16 index);
+
+bool32 IsInvalidBg32(u8);
+void ResetBgControlStructs();
+u16 GetBgMetricTextMode(u8, u8);
+u32 GetBgMetricAffineMode(u8, u8);
+u32 GetBgType(u8);
+void SetTextModeAndHideBgs();
+bool8 IsInvalidBg(u8);
+bool32 IsTileMapOutsideWram(u8);
+void CopyRectToBgTilemapBufferRect(u8, void*, u8, u8, u8, u8, u8, u8, u8, u8, u8, u16, u16);
+void CopyTileMapEntry(u16*, u16*, s32, u32, u32);
+u32 GetTileMapIndexFromCoords(s32, s32, s32, u32, u32);
+void WriteSequenceToBgTilemapBuffer(u8, u16, u8, u8, u8, u8, u8, s16);
+
+void ResetBgs(void)
+{
+ ResetBgControlStructs();
+ gGpuBgConfigs.bgVisibilityAndMode = 0;
+ SetTextModeAndHideBgs();
+}
+
+void SetBgModeInternal(u8 bgMode)
+{
+ gGpuBgConfigs.bgVisibilityAndMode &= 0xFFF8;
+ gGpuBgConfigs.bgVisibilityAndMode |= bgMode;
+}
+
+u8 GetBgMode(void)
+{
+ return gGpuBgConfigs.bgVisibilityAndMode & 0x7;
+}
+
+void ResetBgControlStructs(void)
+{
+ struct BgConfig* bgConfigs = &gGpuBgConfigs.configs[0];
+ struct BgConfig zeroedConfig = gZeroedBgControlStruct;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ bgConfigs[i] = zeroedConfig;
+ }
+}
+
+void Unused_ResetBgControlStruct(u8 bg)
+{
+ if (IsInvalidBg(bg) == FALSE)
+ {
+ gGpuBgConfigs.configs[bg] = gZeroedBgControlStruct;
+ }
+}
+
+void SetBgControlAttributes(u8 bg, u8 charBaseIndex, u8 mapBaseIndex, u8 screenSize, u8 paletteMode, u8 priority, u8 mosaic, u8 wraparound)
+{
+ if (IsInvalidBg(bg) == FALSE)
+ {
+ if (charBaseIndex != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].charBaseIndex = charBaseIndex & 0x3;
+ }
+
+ if (mapBaseIndex != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].mapBaseIndex = mapBaseIndex & 0x1F;
+ }
+
+ if (screenSize != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].screenSize = screenSize & 0x3;
+ }
+
+ if (paletteMode != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].paletteMode = paletteMode;
+ }
+
+ if (priority != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].priority = priority & 0x3;
+ }
+
+ if (mosaic != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].mosaic = mosaic & 0x1;
+ }
+
+ if (wraparound != 0xFF)
+ {
+ gGpuBgConfigs.configs[bg].wraparound = wraparound;
+ }
+
+ gGpuBgConfigs.configs[bg].unknown_2 = 0;
+ gGpuBgConfigs.configs[bg].unknown_3 = 0;
+
+ gGpuBgConfigs.configs[bg].visible = 1;
+ }
+}
+
+u16 GetBgControlAttribute(u8 bg, u8 attributeId)
+{
+ if (IsInvalidBg(bg) == FALSE && gGpuBgConfigs.configs[bg].visible != FALSE)
+ {
+ switch (attributeId)
+ {
+ case BG_CTRL_ATTR_VISIBLE:
+ return gGpuBgConfigs.configs[bg].visible;
+ case BG_CTRL_ATTR_CHARBASEINDEX:
+ return gGpuBgConfigs.configs[bg].charBaseIndex;
+ case BG_CTRL_ATTR_MAPBASEINDEX:
+ return gGpuBgConfigs.configs[bg].mapBaseIndex;
+ case BG_CTRL_ATTR_SCREENSIZE:
+ return gGpuBgConfigs.configs[bg].screenSize;
+ case BG_CTRL_ATTR_PALETTEMODE:
+ return gGpuBgConfigs.configs[bg].paletteMode;
+ case BG_CTRL_ATTR_PRIORITY:
+ return gGpuBgConfigs.configs[bg].priority;
+ case BG_CTRL_ATTR_MOSAIC:
+ return gGpuBgConfigs.configs[bg].mosaic;
+ case BG_CTRL_ATTR_WRAPAROUND:
+ return gGpuBgConfigs.configs[bg].wraparound;
+ }
+ }
+
+ return 0xFF;
+}
+
+u8 LoadBgVram(u8 bg, void *src, u16 size, u16 destOffset, u8 mode)
+{
+ u16 offset;
+ s8 cursor;
+
+ if (IsInvalidBg(bg) == FALSE && gGpuBgConfigs.configs[bg].visible != FALSE)
+ {
+ switch (mode)
+ {
+ case 0x1:
+ offset = gGpuBgConfigs.configs[bg].charBaseIndex * BG_CHAR_SIZE;
+ break;
+ case 0x2:
+ offset = gGpuBgConfigs.configs[bg].mapBaseIndex * BG_SCREEN_SIZE;
+ break;
+ default:
+ cursor = -1;
+ goto end;
+ }
+
+ offset = destOffset + offset;
+
+ cursor = RequestDma3Copy(src, (void*)(offset + BG_VRAM), size, 0);
+
+ if (cursor == -1)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+
+end:
+ return cursor;
+}
+
+void ShowBgInternal(u8 bg)
+{
+ u16 value;
+ if (IsInvalidBg(bg) == FALSE && gGpuBgConfigs.configs[bg].visible != FALSE)
+ {
+ value = gGpuBgConfigs.configs[bg].priority |
+ (gGpuBgConfigs.configs[bg].charBaseIndex << 2) |
+ (gGpuBgConfigs.configs[bg].mosaic << 6) |
+ (gGpuBgConfigs.configs[bg].paletteMode << 7) |
+ (gGpuBgConfigs.configs[bg].mapBaseIndex << 8) |
+ (gGpuBgConfigs.configs[bg].wraparound << 13) |
+ (gGpuBgConfigs.configs[bg].screenSize << 14);
+
+ SetGpuReg((bg << 1) + 0x8, value);
+
+ gGpuBgConfigs.bgVisibilityAndMode |= 1 << (bg + 8);
+ gGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS;
+ }
+}
+
+void HideBgInternal(u8 bg)
+{
+ if (IsInvalidBg(bg) == FALSE)
+ {
+ gGpuBgConfigs.bgVisibilityAndMode &= ~(1 << (bg + 8));
+ gGpuBgConfigs.bgVisibilityAndMode &= DISPCNT_ALL_BG_AND_MODE_BITS;
+ }
+}
+
+void SyncBgVisibilityAndMode()
+{
+ SetGpuReg(0, (GetGpuReg(0) & ~DISPCNT_ALL_BG_AND_MODE_BITS) | gGpuBgConfigs.bgVisibilityAndMode);
+}
+
+void SetTextModeAndHideBgs()
+{
+ SetGpuReg(0, GetGpuReg(0) & ~DISPCNT_ALL_BG_AND_MODE_BITS);
+}
+
+void SetBgAffineInternal(u8 bg, u32 srcCenterX, u32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle)
+{
+ struct BgAffineSrcData src;
+ struct BgAffineDstData dest;
+
+ switch (gGpuBgConfigs.bgVisibilityAndMode & 0x7)
+ {
+ case 1:
+ if (bg != 2)
+ return;
+ break;
+ case 2:
+ if (bg < 2 || bg > 3)
+ return;
+ break;
+ case 0:
+ default:
+ return;
+ }
+
+ src.texX = srcCenterX;
+ src.texY = srcCenterY;
+ src.scrX = dispCenterX;
+ src.scrY = dispCenterY;
+ src.sx = scaleX;
+ src.sy = scaleY;
+ src.alpha = rotationAngle;
+
+ BgAffineSet(&src, &dest, 1);
+
+ SetGpuReg(REG_OFFSET_BG2PA, dest.pa);
+ SetGpuReg(REG_OFFSET_BG2PB, dest.pb);
+ SetGpuReg(REG_OFFSET_BG2PC, dest.pc);
+ SetGpuReg(REG_OFFSET_BG2PD, dest.pd);
+ SetGpuReg(REG_OFFSET_BG2PA, dest.pa);
+ SetGpuReg(REG_OFFSET_BG2X_L, (s16)(dest.dx));
+ SetGpuReg(REG_OFFSET_BG2X_H, (s16)(dest.dx >> 16));
+ SetGpuReg(REG_OFFSET_BG2Y_L, (s16)(dest.dy));
+ SetGpuReg(REG_OFFSET_BG2Y_H, (s16)(dest.dy >> 16));
+}
+
+bool8 IsInvalidBg(u8 bg)
+{
+ if (bg > 3)
+ return TRUE;
+ return FALSE;
+}
+
+int DummiedOutFireRedLeafGreenTileAllocFunc(int a1, int a2, int a3, int a4)
+{
+ return 0;
+}
+
+void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable)
+{
+ int i;
+ ResetBgs();
+
+ for (i = 0; i < 4; i++)
+ {
+ gDmaBusyBitfield[i] = 0;
+ }
+
+ gUnneededFireRedVariable = leftoverFireRedLeafGreenVariable;
+}
+
+void InitBgsFromTemplates(u8 bgMode, struct BgTemplate *templates, u8 numTemplates)
+{
+ int i;
+ u8 bg;
+
+ SetBgModeInternal(bgMode);
+ ResetBgControlStructs();
+
+ for (i = 0; i < numTemplates; i++)
+ {
+ bg = templates[i].bg;
+ if (bg < 4) {
+ SetBgControlAttributes(bg,
+ templates[i].charBaseIndex,
+ templates[i].mapBaseIndex,
+ templates[i].screenSize,
+ templates[i].paletteMode,
+ templates[i].priority,
+ 0,
+ 0);
+
+ gGpuBgConfigs2[bg].baseTile = templates[i].baseTile;
+ gGpuBgConfigs2[bg].basePalette = 0;
+ gGpuBgConfigs2[bg].unk_3 = 0;
+
+ gGpuBgConfigs2[bg].tilemap = NULL;
+ gGpuBgConfigs2[bg].bg_x = 0;
+ gGpuBgConfigs2[bg].bg_y = 0;
+ }
+ }
+}
+
+void InitBgFromTemplate(struct BgTemplate *template)
+{
+ u8 bg = template->bg;
+
+ if (bg < 4)
+ {
+ SetBgControlAttributes(bg,
+ template->charBaseIndex,
+ template->mapBaseIndex,
+ template->screenSize,
+ template->paletteMode,
+ template->priority,
+ 0,
+ 0);
+
+ gGpuBgConfigs2[bg].baseTile = template->baseTile;
+ gGpuBgConfigs2[bg].basePalette = 0;
+ gGpuBgConfigs2[bg].unk_3 = 0;
+
+ gGpuBgConfigs2[bg].tilemap = NULL;
+ gGpuBgConfigs2[bg].bg_x = 0;
+ gGpuBgConfigs2[bg].bg_y = 0;
+ }
+}
+
+void SetBgMode(u8 bgMode)
+{
+ SetBgModeInternal(bgMode);
+}
+
+u16 LoadBgTiles(u8 bg, void* src, u16 size, u16 destOffset)
+{
+ u16 tileOffset;
+ u8 cursor;
+
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE) == 0)
+ {
+ tileOffset = (gGpuBgConfigs2[bg].baseTile + destOffset) * 0x20;
+ }
+ else
+ {
+ tileOffset = (gGpuBgConfigs2[bg].baseTile + destOffset) * 0x40;
+ }
+
+ cursor = LoadBgVram(bg, src, size, tileOffset, DISPCNT_MODE_1);
+
+ if (cursor == 0xFF)
+ {
+ return -1;
+ }
+
+ gDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
+
+ if (gUnneededFireRedVariable == 1)
+ {
+ DummiedOutFireRedLeafGreenTileAllocFunc(bg, tileOffset / 0x20, size / 0x20, 1);
+ }
+
+ return cursor;
+}
+
+u16 LoadBgTilemap(u8 bg, void *src, u16 size, u16 destOffset)
+{
+ u8 cursor;
+
+ cursor = LoadBgVram(bg, src, size, destOffset * 2, DISPCNT_MODE_2);
+
+ if (cursor == 0xFF)
+ {
+ return -1;
+ }
+
+ gDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
+
+ return cursor;
+}
+
+u16 Unused_LoadBgPalette(u8 bg, void *src, u16 size, u16 destOffset)
+{
+ u16 paletteOffset;
+ s8 cursor;
+
+ if (IsInvalidBg32(bg) == FALSE)
+ {
+ paletteOffset = (gGpuBgConfigs2[bg].basePalette * 0x20) + (destOffset * 2);
+ cursor = RequestDma3Copy(src, (void*)(paletteOffset + BG_PLTT), size, 0);
+
+ if (cursor == -1)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+
+ gDmaBusyBitfield[cursor / 0x20] |= (1 << (cursor % 0x20));
+
+ return (u8)cursor;
+}
+
+#ifdef NONMATCHING // Matches everything but r5 and r6 are flipped, rrr
+bool8 IsDma3ManagerBusyWithBgCopy(void)
+{
+ u8 mod;
+ u8 div;
+ s8 reqSpace;
+
+ int i;
+
+ for (i = 0; i < 0x80; i++)
+ {
+ div = i / 0x20;
+ mod = i % 0x20;
+
+ if ((gDmaBusyBitfield[div] & (1 << mod)) != FALSE)
+ {
+ reqSpace = CheckForSpaceForDma3Request(i);
+ if (reqSpace == -1)
+ {
+ return TRUE;
+ }
+
+ gDmaBusyBitfield[div] &= ~(1 << mod);
+ }
+ }
+
+ return FALSE;
+}
+#else
+__attribute__((naked))
+bool8 IsDma3ManagerBusyWithBgCopy(void)
+{
+ asm("push {r4-r7,lr}\n\
+ mov r5, #0\n\
+ mov r7, #0x1\n\
+ neg r7, r7\n\
+_08001ADC:\n\
+ add r0, r5, #0\n\
+ cmp r5, #0\n\
+ bge _08001AE4\n\
+ add r0, #0x1F\n\
+_08001AE4:\n\
+ asr r0, #5\n\
+ lsl r2, r0, #24\n\
+ lsl r0, #5\n\
+ sub r0, r5, r0\n\
+ lsl r0, #24\n\
+ lsr r0, #24\n\
+ ldr r1, =gDmaBusyBitfield\n\
+ lsr r2, #22\n\
+ add r4, r2, r1\n\
+ mov r6, #0x1\n\
+ lsl r6, r0\n\
+ ldr r0, [r4]\n\
+ and r0, r6\n\
+ cmp r0, #0\n\
+ beq _08001B22\n\
+ lsl r0, r5, #16\n\
+ asr r0, #16\n\
+ bl CheckForSpaceForDma3Request\n\
+ lsl r0, #24\n\
+ asr r0, #24\n\
+ cmp r0, r7\n\
+ bne _08001B1C\n\
+ mov r0, #0x1\n\
+ b _08001B2A\n\
+ .pool\n\
+_08001B1C:\n\
+ ldr r0, [r4]\n\
+ bic r0, r6\n\
+ str r0, [r4]\n\
+_08001B22:\n\
+ add r5, #0x1\n\
+ cmp r5, #0x7F\n\
+ ble _08001ADC\n\
+ mov r0, #0\n\
+_08001B2A:\n\
+ pop {r4-r7}\n\
+ pop {r1}\n\
+ bx r1\n");
+}
+#endif // NONMATCHING
+
+void ShowBg(u8 bg)
+{
+ ShowBgInternal(bg);
+ SyncBgVisibilityAndMode();
+}
+
+void HideBg(u8 bg)
+{
+ HideBgInternal(bg);
+ SyncBgVisibilityAndMode();
+}
+
+void SetBgAttribute(u8 bg, u8 attributeId, u8 value)
+{
+ switch (attributeId)
+ {
+ case 1:
+ SetBgControlAttributes(bg, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
+ break;
+ case 2:
+ SetBgControlAttributes(bg, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
+ break;
+ case 3:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF, 0xFF);
+ break;
+ case 4:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF, 0xFF);
+ break;
+ case 7:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF, 0xFF);
+ break;
+ case 5:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value, 0xFF);
+ break;
+ case 6:
+ SetBgControlAttributes(bg, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, value);
+ break;
+ }
+}
+
+u16 GetBgAttribute(u8 bg, u8 attributeId)
+{
+ switch (attributeId)
+ {
+ case 1:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_CHARBASEINDEX);
+ case 2:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_MAPBASEINDEX);
+ case 3:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+ case 4:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_PALETTEMODE);
+ case 7:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_PRIORITY);
+ case 5:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_MOSAIC);
+ case 6:
+ return GetBgControlAttribute(bg, BG_CTRL_ATTR_WRAPAROUND);
+ case 8:
+ switch (GetBgType(bg))
+ {
+ case 0:
+ return GetBgMetricTextMode(bg, 0) * 0x800;
+ case 1:
+ return GetBgMetricAffineMode(bg, 0) * 0x100;
+ default:
+ return 0;
+ }
+ case 9:
+ return GetBgType(bg);
+ case 10:
+ return gGpuBgConfigs2[bg].baseTile;
+ default:
+ return -1;
+ }
+}
+
+u32 ChangeBgX(u8 bg, u32 value, u8 op)
+{
+ u8 mode;
+ u16 temp1;
+ u16 temp2;
+
+ if (IsInvalidBg32(bg) != FALSE || GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ {
+ return -1;
+ }
+
+ switch (op)
+ {
+ case 0:
+ default:
+ gGpuBgConfigs2[bg].bg_x = value;
+ break;
+ case 1:
+ gGpuBgConfigs2[bg].bg_x += value;
+ break;
+ case 2:
+ gGpuBgConfigs2[bg].bg_x -= value;
+ break;
+ }
+
+ mode = GetBgMode();
+
+ switch (bg)
+ {
+ case 0:
+ temp1 = gGpuBgConfigs2[0].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG0HOFS, temp1);
+ break;
+ case 1:
+ temp1 = gGpuBgConfigs2[1].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG1HOFS, temp1);
+ break;
+ case 2:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[2].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG2HOFS, temp1);
+ }
+ else
+ {
+ temp1 = gGpuBgConfigs2[2].bg_x >> 0x10;
+ temp2 = gGpuBgConfigs2[2].bg_x & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG2X_H, temp1);
+ SetGpuReg(REG_OFFSET_BG2X_L, temp2);
+ }
+ break;
+ case 3:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_x >> 0x8;
+ SetGpuReg(REG_OFFSET_BG3HOFS, temp1);
+ }
+ else if (mode == 2)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_x >> 0x10;
+ temp2 = gGpuBgConfigs2[3].bg_x & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG3X_H, temp1);
+ SetGpuReg(REG_OFFSET_BG3X_L, temp2);
+ }
+ break;
+ }
+
+ return gGpuBgConfigs2[bg].bg_x;
+}
+
+u32 GetBgX(u8 bg)
+{
+ if (IsInvalidBg32(bg) != FALSE)
+ return -1;
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ return -1;
+ return gGpuBgConfigs2[bg].bg_x;
+}
+
+u32 ChangeBgY(u8 bg, u32 value, u8 op)
+{
+ u8 mode;
+ u16 temp1;
+ u16 temp2;
+
+ if (IsInvalidBg32(bg) != FALSE || GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ {
+ return -1;
+ }
+
+ switch (op)
+ {
+ case 0:
+ default:
+ gGpuBgConfigs2[bg].bg_y = value;
+ break;
+ case 1:
+ gGpuBgConfigs2[bg].bg_y += value;
+ break;
+ case 2:
+ gGpuBgConfigs2[bg].bg_y -= value;
+ break;
+ }
+
+ mode = GetBgMode();
+
+ switch (bg)
+ {
+ case 0:
+ temp1 = gGpuBgConfigs2[0].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG0VOFS, temp1);
+ break;
+ case 1:
+ temp1 = gGpuBgConfigs2[1].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG1VOFS, temp1);
+ break;
+ case 2:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG2VOFS, temp1);
+ }
+ else
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[2].bg_y & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG2Y_H, temp1);
+ SetGpuReg(REG_OFFSET_BG2Y_L, temp2);
+ }
+ break;
+ case 3:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_y >> 0x8;
+ SetGpuReg(REG_OFFSET_BG3VOFS, temp1);
+ }
+ else if (mode == 2)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[3].bg_y & 0xFFFF;
+ SetGpuReg(REG_OFFSET_BG3Y_H, temp1);
+ SetGpuReg(REG_OFFSET_BG3Y_L, temp2);
+ }
+ break;
+ }
+
+ return gGpuBgConfigs2[bg].bg_y;
+}
+
+u32 ChangeBgY_ScreenOff(u8 bg, u32 value, u8 op)
+{
+ u8 mode;
+ u16 temp1;
+ u16 temp2;
+
+ if (IsInvalidBg32(bg) != FALSE || GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ {
+ return -1;
+ }
+
+ switch (op)
+ {
+ case 0:
+ default:
+ gGpuBgConfigs2[bg].bg_y = value;
+ break;
+ case 1:
+ gGpuBgConfigs2[bg].bg_y += value;
+ break;
+ case 2:
+ gGpuBgConfigs2[bg].bg_y -= value;
+ break;
+ }
+
+ mode = GetBgMode();
+
+ switch (bg)
+ {
+ case 0:
+ temp1 = gGpuBgConfigs2[0].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG0VOFS, temp1);
+ break;
+ case 1:
+ temp1 = gGpuBgConfigs2[1].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG1VOFS, temp1);
+ break;
+ case 2:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG2VOFS, temp1);
+
+ }
+ else
+ {
+ temp1 = gGpuBgConfigs2[2].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[2].bg_y & 0xFFFF;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_H, temp1);
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG2Y_L, temp2);
+ }
+ break;
+ case 3:
+ if (mode == 0)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_y >> 0x8;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG3VOFS, temp1);
+ }
+ else if (mode == 2)
+ {
+ temp1 = gGpuBgConfigs2[3].bg_y >> 0x10;
+ temp2 = gGpuBgConfigs2[3].bg_y & 0xFFFF;
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_H, temp1);
+ SetGpuReg_ForcedBlank(REG_OFFSET_BG3Y_L, temp2);
+ }
+ break;
+ }
+
+ return gGpuBgConfigs2[bg].bg_y;
+}
+
+u32 GetBgY(u8 bg)
+{
+ if (IsInvalidBg32(bg) != FALSE)
+ return -1;
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ return -1;
+ return gGpuBgConfigs2[bg].bg_y;
+}
+
+void SetBgAffine(u8 bg, u32 srcCenterX, u32 srcCenterY, s16 dispCenterX, s16 dispCenterY, s16 scaleX, s16 scaleY, u16 rotationAngle)
+{
+ SetBgAffineInternal(bg, srcCenterX, srcCenterY, dispCenterX, dispCenterY, scaleX, scaleY, rotationAngle);
+}
+
+u8 Unused_AdjustBgMosaic(u8 a1, u8 a2)
+{
+ u16 result;
+ s16 test1;
+ s16 test2;
+
+ result = GetGpuReg(REG_OFFSET_MOSAIC);
+
+ test1 = result & 0xF;
+ test2 = (result >> 4) & 0xF;
+ result &= 0xFF00;
+
+ switch (a2)
+ {
+ case 0:
+ default:
+ test1 = a1 & 0xF;
+ test2 = a1 >> 0x4;
+ break;
+ case 1:
+ test1 = a1 & 0xF;
+ break;
+ case 2:
+ if ((test1 + a1) > 0xF)
+ {
+ test1 = 0xF;
+ }
+ else
+ {
+ test1 += a1;
+ }
+ break;
+ case 3:
+ if ((test1 - a1) < 0)
+ {
+ test1 = 0x0;
+ }
+ else
+ {
+ test1 -= a1;
+ }
+ break;
+ case 4:
+ test2 = a1 & 0xF;
+ break;
+ case 5:
+ if ((test2 + a1) > 0xF)
+ {
+ test2 = 0xF;
+ }
+ else
+ {
+ test2 += a1;
+ }
+ break;
+ case 6:
+ if ((test2 - a1) < 0)
+ {
+ test2 = 0x0;
+ }
+ else
+ {
+ test2 -= a1;
+ }
+ break;
+ }
+
+ result |= ((test2 << 0x4) & 0xF0);
+ result |= (test1 & 0xF);
+
+ SetGpuReg(REG_OFFSET_MOSAIC, result);
+
+ return result;
+}
+
+void SetBgTilemapBuffer(u8 bg, void *tilemap)
+{
+ if (IsInvalidBg32(bg) == FALSE && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) != 0x0)
+ {
+ gGpuBgConfigs2[bg].tilemap = tilemap;
+ }
+}
+
+void UnsetBgTilemapBuffer(u8 bg)
+{
+ if (IsInvalidBg32(bg) == FALSE && GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) != 0x0)
+ {
+ gGpuBgConfigs2[bg].tilemap = NULL;
+ }
+}
+
+void* GetBgTilemapBuffer(u8 bg)
+{
+ if (IsInvalidBg32(bg) != FALSE)
+ return NULL;
+ if (GetBgControlAttribute(bg, BG_CTRL_ATTR_VISIBLE) == 0)
+ return NULL;
+ return gGpuBgConfigs2[bg].tilemap;
+}
+
+void CopyToBgTilemapBuffer(u8 bg, void *src, u16 mode, u16 destOffset)
+{
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ if (mode != 0)
+ {
+ CpuCopy16(src, (void *)(gGpuBgConfigs2[bg].tilemap + (destOffset * 2)), mode);
+ }
+ else
+ {
+ LZ77UnCompWram(src, (void *)(gGpuBgConfigs2[bg].tilemap + (destOffset * 2)));
+ }
+ }
+}
+
+void CopyBgTilemapBufferToVram(u8 bg)
+{
+ u16 sizeToLoad;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ switch (GetBgType(bg))
+ {
+ case 0:
+ sizeToLoad = GetBgMetricTextMode(bg, 0) * 0x800;
+ break;
+ case 1:
+ sizeToLoad = GetBgMetricAffineMode(bg, 0) * 0x100;
+ break;
+ default:
+ sizeToLoad = 0;
+ break;
+ }
+ LoadBgVram(bg, gGpuBgConfigs2[bg].tilemap, sizeToLoad, 0, 2);
+ }
+}
+
+void CopyToBgTilemapBufferRect(u8 bg, void* src, u8 destX, u8 destY, u8 width, u8 height)
+{
+ void* srcCopy;
+ u16 destX16;
+ u16 destY16;
+ u16 mode;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ switch (GetBgType(bg))
+ {
+ case 0:
+ srcCopy = src;
+ for (destY16 = destY; destY16 < (destY + height); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + width); destX16++)
+ {
+ ((u16*)gGpuBgConfigs2[bg].tilemap)[((destY16 * 0x20) + destX16)] = *((u16*)srcCopy)++;
+ }
+ }
+ break;
+ case 1:
+ srcCopy = src;
+ mode = GetBgMetricAffineMode(bg, 0x1);
+ for (destY16 = destY; destY16 < (destY + height); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + width); destX16++)
+ {
+ ((u8*)gGpuBgConfigs2[bg].tilemap)[((destY16 * mode) + destX16)] = *((u8*)srcCopy)++;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void CopyToBgTilemapBufferRect_ChangePalette(u8 bg, void *src, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette)
+{
+ CopyRectToBgTilemapBufferRect(bg, src, 0, 0, rectWidth, rectHeight, destX, destY, rectWidth, rectHeight, palette, 0, 0);
+}
+// Skipping for now, it probably uses structs passed by value
+/*
+void CopyRectToBgTilemapBufferRect(u8 bg, void* src, u8 srcX, u8 srcY, u8 srcWidth, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette1, u16 tileOffset, u16 palette2)
+{
+ u16 attribute;
+ u16 mode;
+ u16 mode2;
+
+ void* srcCopy;
+ u16 destX16;
+ u16 destY16;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+ mode = GetBgMetricTextMode(bg, 0x1) * 0x20;
+ mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20;
+ switch (GetBgType(bg))
+ {
+ case 0:
+ srcCopy = src;
+ for (destY16 = destY; destY16 < (destY + rectHeight); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + rectWidth); destX16++)
+ {
+ CopyTileMapEntry(&((u16*)srcCopy)[(srcY * rectWidth) + srcX], &((u16*)gGpuBgConfigs2[bg].tilemap)[GetTileMapIndexFromCoords(destX16, destY16, attribute, mode, mode2)], palette1, tileOffset, palette2);
+ }
+ }
+ break;
+ case 1:
+ srcCopy = src;
+ mode = GetBgMetricAffineMode(bg, 0x1);
+ for (destY16 = destY; destY16 < (destY + rectHeight); destY16++)
+ {
+ for (destX16 = destX; destX16 < (destX + rectWidth); destX16++)
+ {
+ CopyTileMapEntry(&((u16*)srcCopy)[(srcY * rectWidth) + srcX], &((u16*)gGpuBgConfigs2[bg].tilemap)[GetTileMapIndexFromCoords(destX16, destY16, attribute, mode, mode2)], palette1, tileOffset, palette2);
+ }
+ }
+ break;
+ }
+ }
+}*/
+__attribute__((naked))
+void CopyRectToBgTilemapBufferRect(u8 bg, void* src, u8 srcX, u8 srcY, u8 srcWidth, u8 srcHeight, u8 destX, u8 destY, u8 rectWidth, u8 rectHeight, u8 palette1, u16 tileOffset, u16 palette2)
+{
+ asm("push {r4-r7,lr}\n\
+ mov r7, r10\n\
+ mov r6, r9\n\
+ mov r5, r8\n\
+ push {r5-r7}\n\
+ sub sp, #0x40\n\
+ str r1, [sp, #0x8]\n\
+ ldr r1, [sp, #0x60]\n\
+ ldr r4, [sp, #0x68]\n\
+ ldr r5, [sp, #0x6C]\n\
+ ldr r6, [sp, #0x70]\n\
+ ldr r7, [sp, #0x74]\n\
+ mov r8, r7\n\
+ ldr r7, [sp, #0x78]\n\
+ mov r9, r7\n\
+ ldr r7, [sp, #0x7C]\n\
+ mov r10, r7\n\
+ ldr r7, [sp, #0x80]\n\
+ mov r12, r7\n\
+ lsl r0, #24\n\
+ lsr r0, #24\n\
+ str r0, [sp, #0x4]\n\
+ lsl r2, #24\n\
+ lsr r2, #24\n\
+ str r2, [sp, #0xC]\n\
+ lsl r3, #24\n\
+ lsr r3, #24\n\
+ str r3, [sp, #0x10]\n\
+ lsl r1, #24\n\
+ lsr r7, r1, #24\n\
+ lsl r4, #24\n\
+ lsr r4, #24\n\
+ str r4, [sp, #0x14]\n\
+ lsl r5, #24\n\
+ lsr r5, #24\n\
+ lsl r6, #24\n\
+ lsr r6, #24\n\
+ str r6, [sp, #0x18]\n\
+ mov r0, r8\n\
+ lsl r0, #24\n\
+ lsr r4, r0, #24\n\
+ mov r1, r9\n\
+ lsl r1, #24\n\
+ lsr r1, #24\n\
+ str r1, [sp, #0x1C]\n\
+ mov r2, r10\n\
+ lsl r2, #16\n\
+ lsr r2, #16\n\
+ str r2, [sp, #0x20]\n\
+ mov r0, r12\n\
+ lsl r0, #16\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x24]\n\
+ ldr r0, [sp, #0x4]\n\
+ bl IsInvalidBg32\n\
+ cmp r0, #0\n\
+ beq _08002592\n\
+ b _080026EE\n\
+_08002592:\n\
+ ldr r0, [sp, #0x4]\n\
+ bl IsTileMapOutsideWram\n\
+ cmp r0, #0\n\
+ beq _0800259E\n\
+ b _080026EE\n\
+_0800259E:\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x4\n\
+ bl GetBgControlAttribute\n\
+ lsl r0, #16\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x30]\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x1\n\
+ bl GetBgMetricTextMode\n\
+ lsl r0, #21\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x28]\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x2\n\
+ bl GetBgMetricTextMode\n\
+ lsl r0, #21\n\
+ lsr r0, #16\n\
+ str r0, [sp, #0x2C]\n\
+ ldr r0, [sp, #0x4]\n\
+ bl GetBgType\n\
+ cmp r0, #0\n\
+ beq _080025D8\n\
+ cmp r0, #0x1\n\
+ beq _08002674\n\
+ b _080026EE\n\
+_080025D8:\n\
+ ldr r1, [sp, #0x10]\n\
+ add r0, r1, #0\n\
+ mul r0, r7\n\
+ ldr r2, [sp, #0xC]\n\
+ add r0, r2\n\
+ lsl r0, #1\n\
+ ldr r1, [sp, #0x8]\n\
+ add r6, r1, r0\n\
+ add r0, r5, r4\n\
+ cmp r5, r0\n\
+ blt _080025F0\n\
+ b _080026EE\n\
+_080025F0:\n\
+ ldr r2, [sp, #0x18]\n\
+ sub r2, r7, r2\n\
+ str r2, [sp, #0x34]\n\
+ str r0, [sp, #0x38]\n\
+_080025F8:\n\
+ ldr r4, [sp, #0x14]\n\
+ ldr r7, [sp, #0x18]\n\
+ add r0, r4, r7\n\
+ add r1, r5, #0x1\n\
+ str r1, [sp, #0x3C]\n\
+ cmp r4, r0\n\
+ bge _0800265A\n\
+ ldr r2, [sp, #0x4]\n\
+ lsl r0, r2, #4\n\
+ ldr r1, =gGpuBgConfigs2+4\n\
+ add r0, r1\n\
+ mov r10, r0\n\
+ ldr r7, [sp, #0x20]\n\
+ lsl r7, #16\n\
+ mov r9, r7\n\
+ ldr r1, [sp, #0x24]\n\
+ lsl r0, r1, #16\n\
+ asr r0, #16\n\
+ mov r8, r0\n\
+_0800261E:\n\
+ ldr r2, [sp, #0x2C]\n\
+ str r2, [sp]\n\
+ add r0, r4, #0\n\
+ add r1, r5, #0\n\
+ ldr r2, [sp, #0x30]\n\
+ ldr r3, [sp, #0x28]\n\
+ bl GetTileMapIndexFromCoords\n\
+ lsl r0, #16\n\
+ lsr r0, #15\n\
+ mov r7, r10\n\
+ ldr r1, [r7]\n\
+ add r1, r0\n\
+ mov r0, r8\n\
+ str r0, [sp]\n\
+ add r0, r6, #0\n\
+ ldr r2, [sp, #0x1C]\n\
+ mov r7, r9\n\
+ asr r3, r7, #16\n\
+ bl CopyTileMapEntry\n\
+ add r6, #0x2\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #16\n\
+ lsr r4, r0, #16\n\
+ ldr r1, [sp, #0x14]\n\
+ ldr r2, [sp, #0x18]\n\
+ add r0, r1, r2\n\
+ cmp r4, r0\n\
+ blt _0800261E\n\
+_0800265A:\n\
+ ldr r5, [sp, #0x34]\n\
+ lsl r0, r5, #1\n\
+ add r6, r0\n\
+ ldr r7, [sp, #0x3C]\n\
+ lsl r0, r7, #16\n\
+ lsr r5, r0, #16\n\
+ ldr r0, [sp, #0x38]\n\
+ cmp r5, r0\n\
+ blt _080025F8\n\
+ b _080026EE\n\
+ .pool\n\
+_08002674:\n\
+ ldr r1, [sp, #0x10]\n\
+ add r0, r1, #0\n\
+ mul r0, r7\n\
+ ldr r2, [sp, #0xC]\n\
+ add r0, r2\n\
+ ldr r1, [sp, #0x8]\n\
+ add r6, r1, r0\n\
+ ldr r0, [sp, #0x4]\n\
+ mov r1, #0x1\n\
+ bl GetBgMetricAffineMode\n\
+ lsl r0, #16\n\
+ lsr r0, #16\n\
+ mov r9, r0\n\
+ add r0, r5, r4\n\
+ cmp r5, r0\n\
+ bge _080026EE\n\
+ ldr r2, [sp, #0x18]\n\
+ sub r2, r7, r2\n\
+ str r2, [sp, #0x34]\n\
+ str r0, [sp, #0x38]\n\
+ ldr r7, =gGpuBgConfigs2+4\n\
+ mov r10, r7\n\
+ ldr r0, [sp, #0x4]\n\
+ lsl r0, #4\n\
+ mov r8, r0\n\
+_080026A8:\n\
+ ldr r4, [sp, #0x14]\n\
+ ldr r1, [sp, #0x18]\n\
+ add r0, r4, r1\n\
+ add r2, r5, #0x1\n\
+ str r2, [sp, #0x3C]\n\
+ cmp r4, r0\n\
+ bge _080026DE\n\
+ mov r3, r8\n\
+ add r3, r10\n\
+ mov r7, r9\n\
+ mul r7, r5\n\
+ mov r12, r7\n\
+ add r2, r0, #0\n\
+_080026C2:\n\
+ ldr r1, [r3]\n\
+ mov r5, r12\n\
+ add r0, r5, r4\n\
+ add r1, r0\n\
+ ldrb r0, [r6]\n\
+ ldr r7, [sp, #0x20]\n\
+ add r0, r7\n\
+ strb r0, [r1]\n\
+ add r6, #0x1\n\
+ add r0, r4, #0x1\n\
+ lsl r0, #16\n\
+ lsr r4, r0, #16\n\
+ cmp r4, r2\n\
+ blt _080026C2\n\
+_080026DE:\n\
+ ldr r0, [sp, #0x34]\n\
+ add r6, r0\n\
+ ldr r1, [sp, #0x3C]\n\
+ lsl r0, r1, #16\n\
+ lsr r5, r0, #16\n\
+ ldr r2, [sp, #0x38]\n\
+ cmp r5, r2\n\
+ blt _080026A8\n\
+_080026EE:\n\
+ add sp, #0x40\n\
+ pop {r3-r5}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ mov r10, r5\n\
+ pop {r4-r7}\n\
+ pop {r0}\n\
+ bx r0\n\
+ .pool\n");
+}
+
+void FillBgTilemapBufferRect_Palette0(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height)
+{
+ u16 x16;
+ u16 y16;
+ u16 mode;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ switch (GetBgType(bg))
+ {
+ case 0:
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ ((u16*)gGpuBgConfigs2[bg].tilemap)[((y16 * 0x20) + x16)] = tileNum;
+ }
+ }
+ break;
+ case 1:
+ mode = GetBgMetricAffineMode(bg, 0x1);
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ ((u8*)gGpuBgConfigs2[bg].tilemap)[((y16 * mode) + x16)] = tileNum;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void FillBgTilemapBufferRect(u8 bg, u16 tileNum, u8 x, u8 y, u8 width, u8 height, u8 palette)
+{
+ WriteSequenceToBgTilemapBuffer(bg, tileNum, x, y, width, height, palette, 0);
+}
+
+void WriteSequenceToBgTilemapBuffer(u8 bg, u16 firstTileNum, u8 x, u8 y, u8 width, u8 height, u8 paletteSlot, s16 tileNumDelta)
+{
+ u16 mode;
+ u16 mode2;
+ u16 attribute;
+ u16 mode3;
+
+ u16 x16;
+ u16 y16;
+
+ if (IsInvalidBg32(bg) == FALSE && IsTileMapOutsideWram(bg) == FALSE)
+ {
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+ mode = GetBgMetricTextMode(bg, 0x1) * 0x20;
+ mode2 = GetBgMetricTextMode(bg, 0x2) * 0x20;
+ switch (GetBgType(bg))
+ {
+ case 0:
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ CopyTileMapEntry(&firstTileNum, &((u16*)gGpuBgConfigs2[bg].tilemap)[(u16)GetTileMapIndexFromCoords(x16, y16, attribute, mode, mode2)], paletteSlot, 0, 0);
+ firstTileNum = (firstTileNum & 0xFC00) + ((firstTileNum + tileNumDelta) & 0x3FF);
+ }
+ }
+ break;
+ case 1:
+ mode3 = GetBgMetricAffineMode(bg, 0x1);
+ for (y16 = y; y16 < (y + height); y16++)
+ {
+ for (x16 = x; x16 < (x + width); x16++)
+ {
+ ((u8*)gGpuBgConfigs2[bg].tilemap)[(y16 * mode3) + x16] = firstTileNum;
+ firstTileNum = (firstTileNum & 0xFC00) + ((firstTileNum + tileNumDelta) & 0x3FF);
+ }
+ }
+ break;
+ }
+ }
+}
+
+u16 GetBgMetricTextMode(u8 bg, u8 whichMetric)
+{
+ u8 attribute;
+
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+
+ switch (whichMetric)
+ {
+ case 0:
+ switch (attribute)
+ {
+ case 0:
+ return 1;
+ case 1:
+ case 2:
+ return 2;
+ case 3:
+ return 4;
+ }
+ break;
+ case 1:
+ switch (attribute)
+ {
+ case 0:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 1;
+ case 3:
+ return 2;
+ }
+ break;
+ case 2:
+ switch (attribute)
+ {
+ case 0:
+ case 1:
+ return 1;
+ case 2:
+ case 3:
+ return 2;
+ }
+ break;
+ }
+ return 0;
+}
+
+u32 GetBgMetricAffineMode(u8 bg, u8 whichMetric)
+{
+ u8 attribute;
+
+ attribute = GetBgControlAttribute(bg, BG_CTRL_ATTR_SCREENSIZE);
+
+ switch (whichMetric)
+ {
+ case 0:
+ switch (attribute)
+ {
+ case 0:
+ return 0x1;
+ case 1:
+ return 0x4;
+ case 2:
+ return 0x10;
+ case 3:
+ return 0x40;
+ }
+ break;
+ case 1:
+ case 2:
+ return 0x10 << attribute;
+ }
+ return 0;
+}
+
+u32 GetTileMapIndexFromCoords(s32 x, s32 y, s32 screenSize, u32 screenWidth, u32 screenHeight)
+{
+ x = x & (screenWidth - 1);
+ y = y & (screenHeight - 1);
+
+ switch (screenSize)
+ {
+ case 0:
+ case 2:
+ break;
+ case 3:
+ if (y >= 0x20)
+ y += 0x20;
+ case 1:
+ if (x >= 0x20)
+ {
+ x -= 0x20;
+ y += 0x20;
+ }
+ }
+ return (y * 0x20) + x;
+}
+
+#ifdef NONMATCHING // This one has some weird switch statement cases that refuse to cooperate
+void CopyTileMapEntry(u16 *src, u16 *dest, s32 palette1, u32 tileOffset, u32 palette2)
+{
+ u16 test;
+ switch (palette1)
+ {
+ default:
+ if (palette1 > 0x10 || palette1 < 0)
+ test = *src + tileOffset + (palette2 << 12);
+ else
+ test = ((*src + tileOffset) & 0xFFF) + ((palette1 + palette2) << 12);
+ break;
+ case 0x10:
+ test = ((*dest & 0xFC00) + (palette2 << 12)) | ((*src + tileOffset) & 0x3FF);
+ break;
+ }
+
+ *dest = test;
+}
+#else
+__attribute__((naked))
+void CopyTileMapEntry(u16 *src, u16 *dest, s32 palette1, u32 tileOffset, u32 palette2)
+{
+ asm("push {r4-r6,lr}\n\
+ add r4, r0, #0\n\
+ add r6, r1, #0\n\
+ ldr r5, [sp, #0x10]\n\
+ cmp r2, #0x10\n\
+ beq _08002B14\n\
+ cmp r2, #0x10\n\
+ bgt _08002B34\n\
+ cmp r2, #0\n\
+ blt _08002B34\n\
+ ldrh r0, [r4]\n\
+ add r0, r3\n\
+ ldr r3, =0x00000fff\n\
+ add r1, r3, #0\n\
+ and r0, r1\n\
+ add r1, r2, r5\n\
+ lsl r1, #12\n\
+ b _08002B3A\n\
+ .pool\n\
+_08002B14:\n\
+ ldrh r1, [r6]\n\
+ mov r0, #0xFC\n\
+ lsl r0, #8\n\
+ and r1, r0\n\
+ lsl r2, r5, #12\n\
+ add r2, r1, r2\n\
+ ldrh r0, [r4]\n\
+ add r0, r3\n\
+ ldr r3, =0x000003ff\n\
+ add r1, r3, #0\n\
+ and r0, r1\n\
+ orr r0, r2\n\
+ b _08002B3C\n\
+ .pool\n\
+_08002B34:\n\
+ ldrh r0, [r4]\n\
+ add r0, r3\n\
+ lsl r1, r5, #12\n\
+_08002B3A:\n\
+ add r0, r1\n\
+_08002B3C:\n\
+ lsl r0, #16\n\
+ lsr r1, r0, #16\n\
+ strh r1, [r6]\n\
+ pop {r4-r6}\n\
+ pop {r0}\n\
+ bx r0\n");
+}
+#endif // NONMATCHING
+
+u32 GetBgType(u8 bg)
+{
+ u8 mode;
+
+ mode = GetBgMode();
+
+
+ switch (bg)
+ {
+ case 0:
+ case 1:
+ switch (mode)
+ {
+ case 0:
+ case 1:
+ return 0;
+ }
+ break;
+ case 2:
+ switch (mode)
+ {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ return 1;
+ }
+ break;
+ case 3:
+ switch (mode)
+ {
+ case 0:
+ return 0;
+ case 2:
+ return 1;
+ }
+ break;
+ }
+
+ return 0xFFFF;
+}
+
+bool32 IsInvalidBg32(u8 bg)
+{
+ if (bg > 3)
+ return TRUE;
+ return FALSE;
+}
+
+bool32 IsTileMapOutsideWram(u8 bg)
+{
+ if (gGpuBgConfigs2[bg].tilemap > (void*)IWRAM_END)
+ return TRUE;
+ if (gGpuBgConfigs2[bg].tilemap == 0x0)
+ return TRUE;
+ return FALSE;
+}
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 5317565dc..ccb2f7d20 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..fdfdd961a
--- /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 ScriptContext1_Stop(void);
+extern void warp_in(void);
+extern void GetXYCoordsOneStepInFrontOfPlayer(s16* x, s16* y);
+extern void PlayerGetDestCoords(s16* x, s16* y);
+
+EWRAM_DATA u8 gNumSafariBalls = 0;
+EWRAM_DATA static u16 sSafariZoneStepCounter = 0;
+EWRAM_DATA static u8 sSafariZoneCaughtMons = 0;
+EWRAM_DATA static u8 sSafariZoneFleedMons = 0;
+EWRAM_DATA static struct PokeblockFeeder sPokeblockFeeders[NUM_POKEBLOCK_FEEDERS] = {0};
+
+static void ClearAllPokeblockFeeders(void);
+static void DecrementFeederStepCounters(void);
+
+bool32 GetSafariZoneFlag(void)
+{
+ return FlagGet(SYS_SAFARI_MODE);
+}
+
+void SetSafariZoneFlag(void)
+{
+ FlagSet(SYS_SAFARI_MODE);
+}
+
+void ResetSafariZoneFlag(void)
+{
+ FlagReset(SYS_SAFARI_MODE);
+}
+
+void EnterSafariMode(void)
+{
+ IncrementGameStat(GAME_STAT_ENTERED_SAFARI_ZONE);
+ SetSafariZoneFlag();
+ ClearAllPokeblockFeeders();
+ gNumSafariBalls = 30;
+ sSafariZoneStepCounter = 500;
+ sSafariZoneCaughtMons = 0;
+ sSafariZoneFleedMons = 0;
+}
+
+void ExitSafariMode(void)
+{
+ sub_80EE44C(sSafariZoneCaughtMons, sSafariZoneFleedMons);
+ ResetSafariZoneFlag();
+ ClearAllPokeblockFeeders();
+ gNumSafariBalls = 0;
+ sSafariZoneStepCounter = 0;
+}
+
+bool8 SafariZoneTakeStep(void)
+{
+ if (GetSafariZoneFlag() == FALSE)
+ {
+ return FALSE;
+ }
+
+ DecrementFeederStepCounters();
+ sSafariZoneStepCounter--;
+ if (sSafariZoneStepCounter == 0)
+ {
+ ScriptContext1_SetupScript(gUnknown_082A4B8A);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void SafariZoneRetirePrompt(void)
+{
+ ScriptContext1_SetupScript(gUnknown_082A4B6F);
+}
+
+void sub_80FC190(void)
+{
+ sSafariZoneFleedMons += gBattleResults.field_1F;
+ if (gBattleOutcome == BATTLE_CAUGHT)
+ sSafariZoneCaughtMons++;
+ if (gNumSafariBalls != 0)
+ {
+ SetMainCallback2(c2_exit_to_overworld_2_switch);
+ }
+ else if (gBattleOutcome == 8)
+ {
+ ScriptContext2_RunNewScript(gUnknown_082A4B4C);
+ warp_in();
+ gUnknown_03005DAC = sub_80AF6F0;
+ SetMainCallback2(c2_load_new_map);
+ }
+ else if (gBattleOutcome == BATTLE_CAUGHT)
+ {
+ ScriptContext1_SetupScript(gUnknown_082A4B9B);
+ ScriptContext1_Stop();
+ SetMainCallback2(c2_exit_to_overworld_1_continue_scripts_restart_music);
+ }
+}
+
+static void ClearPokeblockFeeder(u8 index)
+{
+ memset(&sPokeblockFeeders[index], 0, sizeof(struct PokeblockFeeder));
+}
+
+static void ClearAllPokeblockFeeders(void)
+{
+ memset(sPokeblockFeeders, 0, sizeof(sPokeblockFeeders));
+}
+
+static void GetPokeblockFeederInFront(void)
+{
+ s16 x, y;
+ u16 i;
+
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+
+ for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
+ {
+ if (gSaveBlock1Ptr->location.mapNum == sPokeblockFeeders[i].mapNum
+ && sPokeblockFeeders[i].x == x
+ && sPokeblockFeeders[i].y == y)
+ {
+ gScriptResult = i;
+ StringCopy(gStringVar1, gPokeblockNames[sPokeblockFeeders[i].pokeblock.color]);
+ return;
+ }
+ }
+
+ gScriptResult = -1;
+}
+
+void GetPokeblockFeederWithinRange(void)
+{
+ s16 x, y;
+ u16 i;
+
+ PlayerGetDestCoords(&x, &y);
+
+ for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
+ {
+ if (gSaveBlock1Ptr->location.mapNum == sPokeblockFeeders[i].mapNum)
+ {
+ //Get absolute value of x and y distance from Pokeblock feeder on current map
+ x -= sPokeblockFeeders[i].x;
+ y -= sPokeblockFeeders[i].y;
+ if (x < 0)
+ x *= -1;
+ if (y < 0)
+ y *= -1;
+ if ((x + y) <= 5)
+ {
+ gScriptResult = i;
+ return;
+ }
+ }
+ }
+
+ gScriptResult = -1;
+}
+
+// unused
+struct Pokeblock *SafariZoneGetPokeblockInFront(void)
+{
+ GetPokeblockFeederInFront();
+
+ if (gScriptResult == 0xFFFF)
+ return NULL;
+ else
+ return &sPokeblockFeeders[gScriptResult].pokeblock;
+}
+
+struct Pokeblock *SafariZoneGetActivePokeblock(void)
+{
+ GetPokeblockFeederWithinRange();
+
+ if (gScriptResult == 0xFFFF)
+ return NULL;
+ else
+ return &sPokeblockFeeders[gScriptResult].pokeblock;
+}
+
+void SafariZoneActivatePokeblockFeeder(u8 pkblId)
+{
+ s16 x, y;
+ u8 i;
+
+ for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
+ {
+ // Find free entry in sPokeblockFeeders
+ if (sPokeblockFeeders[i].mapNum == 0
+ && sPokeblockFeeders[i].x == 0
+ && sPokeblockFeeders[i].y == 0)
+ {
+ // Initialize Pokeblock feeder
+ GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
+ sPokeblockFeeders[i].mapNum = gSaveBlock1Ptr->location.mapNum;
+ sPokeblockFeeders[i].pokeblock = gSaveBlock1Ptr->pokeblocks[pkblId];
+ sPokeblockFeeders[i].stepCounter = 100;
+ sPokeblockFeeders[i].x = x;
+ sPokeblockFeeders[i].y = y;
+ break;
+ }
+ }
+}
+
+static void DecrementFeederStepCounters(void)
+{
+ u8 i;
+
+ for (i = 0; i < NUM_POKEBLOCK_FEEDERS; i++)
+ {
+ if (sPokeblockFeeders[i].stepCounter != 0)
+ {
+ sPokeblockFeeders[i].stepCounter--;
+ if (sPokeblockFeeders[i].stepCounter == 0)
+ ClearPokeblockFeeder(i);
+ }
+ }
+}
+
+// unused
+bool8 GetInFrontFeederPokeblockAndSteps(void)
+{
+ GetPokeblockFeederInFront();
+
+ if (gScriptResult == 0xFFFF)
+ {
+ return FALSE;
+ }
+
+ ConvertIntToDecimalStringN(gStringVar2,
+ sPokeblockFeeders[gScriptResult].stepCounter,
+ STR_CONV_MODE_LEADING_ZEROS, 3);
+
+ return TRUE;
+}
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/script.c b/src/script.c
new file mode 100644
index 000000000..b2809a137
--- /dev/null
+++ b/src/script.c
@@ -0,0 +1,434 @@
+#include "global.h"
+#include "script.h"
+#include "event_data.h"
+#include "util.h"
+
+#define RAM_SCRIPT_MAGIC 51
+
+extern u8* gUnknown_020375C0;
+
+extern bool32 sub_801B27C(void);
+
+// ewram bss
+IWRAM_DATA static u8 sScriptContext1Status;
+IWRAM_DATA static u32 sUnusedVariable1;
+IWRAM_DATA static struct ScriptContext sScriptContext1;
+IWRAM_DATA static u32 sUnusedVariable2;
+IWRAM_DATA static struct ScriptContext sScriptContext2;
+IWRAM_DATA static bool8 sScriptContext2Enabled;
+
+extern ScrCmdFunc gScriptCmdTable[];
+extern ScrCmdFunc gScriptCmdTableEnd[];
+extern void *gNullScriptPtr;
+
+void InitScriptContext(struct ScriptContext *ctx, void *cmdTable, void *cmdTableEnd)
+{
+ s32 i;
+
+ ctx->mode = 0;
+ ctx->scriptPtr = 0;
+ ctx->stackDepth = 0;
+ ctx->nativePtr = 0;
+ ctx->cmdTable = cmdTable;
+ ctx->cmdTableEnd = cmdTableEnd;
+
+ for (i = 0; i < 4; i++)
+ ctx->data[i] = 0;
+
+ for (i = 0; i < 20; i++)
+ ctx->stack[i] = 0;
+}
+
+u8 SetupBytecodeScript(struct ScriptContext *ctx, const u8 *ptr)
+{
+ ctx->scriptPtr = ptr;
+ ctx->mode = 1;
+ return 1;
+}
+
+void SetupNativeScript(struct ScriptContext *ctx, bool8 (*ptr)(void))
+{
+ ctx->mode = 2;
+ ctx->nativePtr = ptr;
+}
+
+void StopScript(struct ScriptContext *ctx)
+{
+ ctx->mode = 0;
+ ctx->scriptPtr = 0;
+}
+
+bool8 RunScriptCommand(struct ScriptContext *ctx)
+{
+ if (ctx->mode == 0)
+ return FALSE;
+
+ switch (ctx->mode)
+ {
+ case 0:
+ return FALSE;
+ case 2:
+ if (ctx->nativePtr)
+ {
+ if (ctx->nativePtr() == TRUE)
+ ctx->mode = 1;
+ return TRUE;
+ }
+ ctx->mode = 1;
+ case 1:
+ while (1)
+ {
+ u8 cmdCode;
+ ScrCmdFunc *func;
+
+ if (!ctx->scriptPtr)
+ {
+ ctx->mode = 0;
+ return FALSE;
+ }
+
+ if (ctx->scriptPtr == gNullScriptPtr)
+ {
+ while (1)
+ asm("svc 2"); // HALT
+ }
+
+ cmdCode = *(ctx->scriptPtr);
+ ctx->scriptPtr++;
+ func = &ctx->cmdTable[cmdCode];
+
+ if (func >= ctx->cmdTableEnd)
+ {
+ ctx->mode = 0;
+ return FALSE;
+ }
+
+ if ((*func)(ctx) == 1)
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+u8 ScriptPush(struct ScriptContext *ctx, const u8 *ptr)
+{
+ if (ctx->stackDepth + 1 >= 20)
+ {
+ return 1;
+ }
+ else
+ {
+ ctx->stack[ctx->stackDepth] = ptr;
+ ctx->stackDepth++;
+ return 0;
+ }
+}
+
+const u8 *ScriptPop(struct ScriptContext *ctx)
+{
+ if (ctx->stackDepth == 0)
+ return NULL;
+
+ ctx->stackDepth--;
+ return ctx->stack[ctx->stackDepth];
+}
+
+void ScriptJump(struct ScriptContext *ctx, u8 *ptr)
+{
+ ctx->scriptPtr = ptr;
+}
+
+void ScriptCall(struct ScriptContext *ctx, u8 *ptr)
+{
+ ScriptPush(ctx, ctx->scriptPtr);
+ ctx->scriptPtr = ptr;
+}
+
+void ScriptReturn(struct ScriptContext *ctx)
+{
+ ctx->scriptPtr = ScriptPop(ctx);
+}
+
+u16 ScriptReadHalfword(struct ScriptContext *ctx)
+{
+ u16 value = *(ctx->scriptPtr++);
+ value |= *(ctx->scriptPtr++) << 8;
+ return value;
+}
+
+u32 ScriptReadWord(struct ScriptContext *ctx)
+{
+ u32 value0 = *(ctx->scriptPtr++);
+ u32 value1 = *(ctx->scriptPtr++);
+ u32 value2 = *(ctx->scriptPtr++);
+ u32 value3 = *(ctx->scriptPtr++);
+ return (((((value3 << 8) + value2) << 8) + value1) << 8) + value0;
+}
+
+void ScriptContext2_Enable(void)
+{
+ sScriptContext2Enabled = TRUE;
+}
+
+void ScriptContext2_Disable(void)
+{
+ sScriptContext2Enabled = FALSE;
+}
+
+bool8 ScriptContext2_IsEnabled(void)
+{
+ return sScriptContext2Enabled;
+}
+
+bool8 ScriptContext1_IsScriptSetUp(void)
+{
+ if (sScriptContext1Status == 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void ScriptContext1_Init(void)
+{
+ InitScriptContext(&sScriptContext1, gScriptCmdTable, gScriptCmdTableEnd);
+ sScriptContext1Status = 2;
+}
+
+bool8 ScriptContext2_RunScript(void)
+{
+ if (sScriptContext1Status == 2)
+ return 0;
+
+ if (sScriptContext1Status == 1)
+ return 0;
+
+ ScriptContext2_Enable();
+
+ if (!RunScriptCommand(&sScriptContext1))
+ {
+ sScriptContext1Status = 2;
+ ScriptContext2_Disable();
+ return 0;
+ }
+
+ return 1;
+}
+
+void ScriptContext1_SetupScript(const u8 *ptr)
+{
+ InitScriptContext(&sScriptContext1, gScriptCmdTable, gScriptCmdTableEnd);
+ SetupBytecodeScript(&sScriptContext1, ptr);
+ ScriptContext2_Enable();
+ sScriptContext1Status = 0;
+}
+
+void ScriptContext1_Stop(void)
+{
+ sScriptContext1Status = 1;
+}
+
+void EnableBothScriptContexts(void)
+{
+ sScriptContext1Status = 0;
+ ScriptContext2_Enable();
+}
+
+void ScriptContext2_RunNewScript(const u8 *ptr)
+{
+ InitScriptContext(&sScriptContext2, &gScriptCmdTable, &gScriptCmdTableEnd);
+ SetupBytecodeScript(&sScriptContext2, ptr);
+ while (RunScriptCommand(&sScriptContext2) == TRUE);
+}
+
+u8 *mapheader_get_tagged_pointer(u8 tag)
+{
+ u8 *mapScripts = gMapHeader.mapScripts;
+
+ if (!mapScripts)
+ return NULL;
+
+ while (1)
+ {
+ if (!*mapScripts)
+ return NULL;
+ if (*mapScripts == tag)
+ {
+ mapScripts++;
+ return (u8 *)(mapScripts[0] + (mapScripts[1] << 8) + (mapScripts[2] << 16) + (mapScripts[3] << 24));
+ }
+ mapScripts += 5;
+ }
+}
+
+void mapheader_run_script_by_tag(u8 tag)
+{
+ u8 *ptr = mapheader_get_tagged_pointer(tag);
+ if (ptr)
+ ScriptContext2_RunNewScript(ptr);
+}
+
+u8 *mapheader_get_first_match_from_tagged_ptr_list(u8 tag)
+{
+ u8 *ptr = mapheader_get_tagged_pointer(tag);
+
+ if (!ptr)
+ return NULL;
+
+ while (1)
+ {
+ u16 varIndex1;
+ u16 varIndex2;
+ varIndex1 = ptr[0] | (ptr[1] << 8);
+ if (!varIndex1)
+ return NULL;
+ ptr += 2;
+ varIndex2 = ptr[0] | (ptr[1] << 8);
+ ptr += 2;
+ if (VarGet(varIndex1) == VarGet(varIndex2))
+ return (u8 *)(ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24));
+ ptr += 4;
+ }
+}
+
+void mapheader_run_script_with_tag_x1(void)
+{
+ mapheader_run_script_by_tag(1);
+}
+
+void mapheader_run_script_with_tag_x3(void)
+{
+ mapheader_run_script_by_tag(3);
+}
+
+void mapheader_run_script_with_tag_x5(void)
+{
+ mapheader_run_script_by_tag(5);
+}
+
+void mapheader_run_script_with_tag_x7(void)
+{
+ mapheader_run_script_by_tag(7);
+}
+
+void mapheader_run_script_with_tag_x6(void)
+{
+ mapheader_run_script_by_tag(6);
+}
+
+bool8 mapheader_run_first_tag2_script_list_match(void)
+{
+ u8 *ptr = mapheader_get_first_match_from_tagged_ptr_list(2);
+
+ if (!ptr)
+ return 0;
+
+ ScriptContext1_SetupScript(ptr);
+ return 1;
+}
+
+void mapheader_run_first_tag4_script_list_match(void)
+{
+ u8 *ptr = mapheader_get_first_match_from_tagged_ptr_list(4);
+ if (ptr)
+ ScriptContext2_RunNewScript(ptr);
+}
+
+u32 CalculateRamScriptChecksum(void)
+{
+ return CalcCRC16WithTable((u8*)(&gSaveBlock1Ptr->ramScript.data), sizeof(gSaveBlock1Ptr->ramScript.data));
+}
+
+void ClearRamScript(void)
+{
+ CpuFill32(0, &gSaveBlock1Ptr->ramScript, sizeof(struct RamScript));
+}
+
+bool8 InitRamScript(u8 *script, u16 scriptSize, u8 mapGroup, u8 mapNum, u8 objectId)
+{
+ struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
+
+ ClearRamScript();
+
+ if (scriptSize > sizeof(scriptData->script))
+ return FALSE;
+
+ scriptData->magic = RAM_SCRIPT_MAGIC;
+ scriptData->mapGroup = mapGroup;
+ scriptData->mapNum = mapNum;
+ scriptData->objectId = objectId;
+ memcpy(scriptData->script, script, scriptSize);
+ gSaveBlock1Ptr->ramScript.checksum = CalculateRamScriptChecksum();
+ return TRUE;
+}
+
+u8 *GetRamScript(u8 objectId, u8 *script)
+{
+ struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
+ gUnknown_020375C0 = NULL;
+ if (scriptData->magic != RAM_SCRIPT_MAGIC)
+ return script;
+ if (scriptData->mapGroup != gSaveBlock1Ptr->location.mapGroup)
+ return script;
+ if (scriptData->mapNum != gSaveBlock1Ptr->location.mapNum)
+ return script;
+ if (scriptData->objectId != objectId)
+ return script;
+ if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum)
+ {
+ ClearRamScript();
+ return script;
+ }
+ else
+ {
+ gUnknown_020375C0 = script;
+ return scriptData->script;
+ }
+}
+
+bool32 sub_80991F8(void)
+{
+ struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
+ if (scriptData->magic != RAM_SCRIPT_MAGIC)
+ return FALSE;
+ if (scriptData->mapGroup != 0xFF)
+ return FALSE;
+ if (scriptData->mapNum != 0xFF)
+ return FALSE;
+ if (scriptData->objectId != 0xFF)
+ return FALSE;
+ if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum)
+ return FALSE;
+ return TRUE;
+}
+
+u8 *sub_8099244(void)
+{
+ struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data;
+ if (!sub_801B27C())
+ return NULL;
+ if (scriptData->magic != RAM_SCRIPT_MAGIC)
+ return NULL;
+ if (scriptData->mapGroup != 0xFF)
+ return NULL;
+ if (scriptData->mapNum != 0xFF)
+ return NULL;
+ if (scriptData->objectId != 0xFF)
+ return NULL;
+ if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum)
+ {
+ ClearRamScript();
+ return NULL;
+ }
+ else
+ {
+ return scriptData->script;
+ }
+}
+
+void sub_80992A0(u8 *script, u16 scriptSize)
+{
+ if (scriptSize > sizeof(gSaveBlock1Ptr->ramScript.data.script))
+ scriptSize = sizeof(gSaveBlock1Ptr->ramScript.data.script);
+ InitRamScript(script, scriptSize, 0xFF, 0xFF, 0xFF);
+}
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/util.c b/src/util.c
new file mode 100644
index 000000000..27b7c5ee5
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,503 @@
+#include "global.h"
+#include "util.h"
+#include "sprite.h"
+
+const u32 gBitTable[] =
+{
+ 1 << 0,
+ 1 << 1,
+ 1 << 2,
+ 1 << 3,
+ 1 << 4,
+ 1 << 5,
+ 1 << 6,
+ 1 << 7,
+ 1 << 8,
+ 1 << 9,
+ 1 << 10,
+ 1 << 11,
+ 1 << 12,
+ 1 << 13,
+ 1 << 14,
+ 1 << 15,
+ 1 << 16,
+ 1 << 17,
+ 1 << 18,
+ 1 << 19,
+ 1 << 20,
+ 1 << 21,
+ 1 << 22,
+ 1 << 23,
+ 1 << 24,
+ 1 << 25,
+ 1 << 26,
+ 1 << 27,
+ 1 << 28,
+ 1 << 29,
+ 1 << 30,
+ 1 << 31,
+};
+
+static const struct SpriteTemplate sInvisibleSpriteTemplate =
+{
+ .tileTag = 0,
+ .paletteTag = 0,
+ .oam = &gDummyOamData,
+ .anims = gDummySpriteAnimTable,
+ .images = NULL,
+ .affineAnims = gDummySpriteAffineAnimTable,
+ .callback = SpriteCallbackDummy,
+};
+
+static const u8 sSpriteDimensions[3][4][2] =
+{
+ // square
+ {
+ {1, 1},
+ {2, 2},
+ {4, 4},
+ {8, 8},
+ },
+
+ // horizontal rectangle
+ {
+ {2, 1},
+ {4, 1},
+ {4, 2},
+ {8, 4},
+ },
+
+ // vertical rectangle
+ {
+ {1, 2},
+ {1, 4},
+ {2, 4},
+ {4, 8},
+ },
+};
+
+static const u16 sCrc16Table[] =
+{
+ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
+ 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
+ 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
+ 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
+ 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
+ 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
+ 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
+ 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
+ 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
+ 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
+ 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
+ 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
+ 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
+ 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
+ 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
+ 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
+ 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
+ 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
+ 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
+ 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
+ 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
+ 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
+ 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
+ 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
+ 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
+ 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
+ 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
+ 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
+ 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
+ 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
+ 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
+ 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78,
+};
+
+const u8 gMiscBlank_Gfx[] = INCBIN_U8("graphics/interface/blank.4bpp"); // unused in Emerald
+
+u8 CreateInvisibleSpriteWithCallback(void (*callback)(struct Sprite *))
+{
+ u8 sprite = CreateSprite(&sInvisibleSpriteTemplate, 248, 168, 14);
+ gSprites[sprite].invisible = TRUE;
+ gSprites[sprite].callback = callback;
+ return sprite;
+}
+
+void StoreWordInTwoHalfwords(u16 *h, u32 w)
+{
+ h[0] = (u16)(w);
+ h[1] = (u16)(w >> 16);
+}
+
+void LoadWordFromTwoHalfwords(u16 *h, u32 *w)
+{
+ *w = h[0] | (s16)h[1] << 16;
+}
+
+void SetBgAffineStruct(struct BgAffineSrcData *src, u32 texX, u32 texY, s16 scrX, s16 scrY, s16 sx, s16 sy, u16 alpha)
+{
+ src->texX = texX;
+ src->texY = texY;
+ src->scrX = scrX;
+ src->scrY = scrY;
+ src->sx = sx;
+ src->sy = sy;
+ src->alpha = alpha;
+}
+
+void DoBgAffineSet(struct BgAffineDstData *dest, u32 texX, u32 texY, s16 scrX, s16 scrY, s16 sx, s16 sy, u16 alpha)
+{
+ struct BgAffineSrcData src;
+
+ SetBgAffineStruct(&src, texX, texY, scrX, scrY, sx, sy, alpha);
+ BgAffineSet(&src, dest, 1);
+}
+
+#ifdef NONMATCHING
+
+// Functionally equivalent.
+// Only the two yflip loops don't match.
+void CopySpriteTiles(u8 shape, u8 size, u8 *tiles, u16 *tilemap, u8 *output)
+{
+ u8 x, y;
+ s8 i, j;
+ u8 xflip[32];
+ u8 h = sSpriteDimensions[shape][size][1];
+ u8 w = sSpriteDimensions[shape][size][0];
+
+ for (y = 0; y < h; y++)
+ {
+ int filler = 32 - w;
+
+ for (x = 0; x < w; x++)
+ {
+ int tile = (*tilemap & 0x3ff) * 32;
+ int attr = *tilemap & 0xc00;
+
+ if (attr == 0)
+ {
+ void *src = tiles + tile;
+ void *dest = output;
+ int length = 32;
+ DmaCopy32(3, src, dest, length);
+ }
+ else if (attr == 0x800) // yflip
+ {
+ for (i = 0; i < 8; i++)
+ {
+ void *src = tiles;
+ void *dest = output;
+ int length = 4;
+ // this is likely wrong, but makes it closer to matching
+ src += tile + (7 - i) * 4;
+ dest += i * 4;
+ DmaCopy32(3, src, dest, length);
+ }
+ }
+ else // xflip
+ {
+ for (i = 0; i < 8; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ u8 i2 = i * 4;
+ xflip[i2 + (3-j)] = (tiles[tile + i2 + j] & 0xf) << 4;
+ xflip[i2 + (3-j)] |= tiles[tile + i2 + j] >> 4;
+ }
+ }
+ if (*tilemap & 0x800) // yflip
+ {
+ for (i = 0; i < 8; i++)
+ {
+ void *src = xflip + (7-i) * 4;
+ void *dest = output + i*4;
+ int length = 4;
+ DmaCopy32(3, src, dest, length);
+ }
+ }
+ else
+ {
+ void *src = xflip;
+ void *dest = output;
+ int length = 32;
+ DmaCopy32(3, src, dest, length);
+ }
+ }
+ tilemap++;
+ output += 32;
+ }
+ tilemap += filler;
+ }
+}
+
+#else
+__attribute__((naked)) void CopySpriteTiles(u8 shape, u8 size, u8 *tiles, u16 *tilemap, u8 *output)
+{
+ asm("\n\
+ .syntax unified\n\
+ push {r4-r7,lr}\n\
+ mov r7, r10\n\
+ mov r6, r9\n\
+ mov r5, r8\n\
+ push {r5-r7}\n\
+ sub sp, 0x38\n\
+ str r2, [sp, 0x20]\n\
+ adds r4, r3, 0\n\
+ ldr r7, [sp, 0x58]\n\
+ lsls r0, 24\n\
+ lsls r1, 24\n\
+ ldr r2, =sSpriteDimensions\n\
+ lsrs r1, 23\n\
+ lsrs r0, 21\n\
+ adds r1, r0\n\
+ adds r0, r2, 0x1\n\
+ adds r0, r1, r0\n\
+ ldrb r0, [r0]\n\
+ str r0, [sp, 0x24]\n\
+ adds r1, r2\n\
+ ldrb r1, [r1]\n\
+ str r1, [sp, 0x28]\n\
+ movs r0, 0\n\
+ b _0806F88C\n\
+ .pool\n\
+ _0806F740:\n\
+ movs r5, 0\n\
+ adds r0, 0x1\n\
+ str r0, [sp, 0x30]\n\
+ b _0806F874\n\
+ _0806F748:\n\
+ ldrh r0, [r4]\n\
+ ldr r2, =0x000003ff\n\
+ adds r1, r2, 0\n\
+ ands r1, r0\n\
+ lsls r1, 5\n\
+ mov r8, r1\n\
+ movs r2, 0xC0\n\
+ lsls r2, 4\n\
+ adds r1, r2, 0\n\
+ ands r1, r0\n\
+ mov r2, sp\n\
+ strh r0, [r2, 0x34]\n\
+ cmp r1, 0\n\
+ bne _0806F788\n\
+ ldr r0, [sp, 0x20]\n\
+ add r0, r8\n\
+ adds r1, r7, 0\n\
+ ldr r2, =0x04000008\n\
+ bl CpuSet\n\
+ adds r4, 0x2\n\
+ str r4, [sp, 0x2C]\n\
+ adds r7, 0x20\n\
+ mov r10, r7\n\
+ adds r5, 0x1\n\
+ mov r9, r5\n\
+ b _0806F86A\n\
+ .pool\n\
+ _0806F788:\n\
+ movs r0, 0x80\n\
+ lsls r0, 4\n\
+ cmp r1, r0\n\
+ bne _0806F7CC\n\
+ movs r1, 0\n\
+ adds r4, 0x2\n\
+ str r4, [sp, 0x2C]\n\
+ movs r2, 0x20\n\
+ adds r2, r7\n\
+ mov r10, r2\n\
+ adds r5, 0x1\n\
+ mov r9, r5\n\
+ _0806F7A0:\n\
+ lsls r4, r1, 24\n\
+ asrs r4, 24\n\
+ movs r0, 0x7\n\
+ subs r0, r4\n\
+ lsls r0, 2\n\
+ add r0, r8\n\
+ ldr r1, [sp, 0x20]\n\
+ adds r0, r1, r0\n\
+ lsls r1, r4, 2\n\
+ adds r1, r7, r1\n\
+ ldr r2, =0x04000001\n\
+ bl CpuSet\n\
+ adds r4, 0x1\n\
+ lsls r4, 24\n\
+ lsrs r1, r4, 24\n\
+ asrs r4, 24\n\
+ cmp r4, 0x7\n\
+ ble _0806F7A0\n\
+ b _0806F86A\n\
+ .pool\n\
+ _0806F7CC:\n\
+ movs r1, 0\n\
+ adds r4, 0x2\n\
+ str r4, [sp, 0x2C]\n\
+ movs r2, 0x20\n\
+ adds r2, r7\n\
+ mov r10, r2\n\
+ adds r5, 0x1\n\
+ mov r9, r5\n\
+ movs r0, 0xF\n\
+ mov r12, r0\n\
+ _0806F7E0:\n\
+ movs r2, 0\n\
+ lsls r4, r1, 24\n\
+ lsls r0, r4, 2\n\
+ lsrs r0, 24\n\
+ adds r6, r0, 0x3\n\
+ mov r1, r8\n\
+ adds r5, r1, r0\n\
+ _0806F7EE:\n\
+ lsls r1, r2, 24\n\
+ asrs r1, 24\n\
+ subs r0, r6, r1\n\
+ mov r2, sp\n\
+ adds r3, r2, r0\n\
+ adds r0, r5, r1\n\
+ ldr r2, [sp, 0x20]\n\
+ adds r0, r2, r0\n\
+ ldrb r2, [r0]\n\
+ mov r0, r12\n\
+ ands r0, r2\n\
+ lsls r0, 4\n\
+ lsrs r2, 4\n\
+ orrs r0, r2\n\
+ strb r0, [r3]\n\
+ adds r1, 0x1\n\
+ lsls r1, 24\n\
+ lsrs r2, r1, 24\n\
+ asrs r1, 24\n\
+ cmp r1, 0x3\n\
+ ble _0806F7EE\n\
+ movs r1, 0x80\n\
+ lsls r1, 17\n\
+ adds r0, r4, r1\n\
+ lsrs r1, r0, 24\n\
+ asrs r0, 24\n\
+ cmp r0, 0x7\n\
+ ble _0806F7E0\n\
+ mov r2, sp\n\
+ ldrh r0, [r2, 0x34]\n\
+ movs r2, 0x80\n\
+ lsls r2, 4\n\
+ ands r0, r2\n\
+ cmp r0, 0\n\
+ beq _0806F860\n\
+ movs r1, 0\n\
+ _0806F836:\n\
+ lsls r4, r1, 24\n\
+ asrs r4, 24\n\
+ movs r0, 0x7\n\
+ subs r0, r4\n\
+ lsls r0, 2\n\
+ add r0, sp\n\
+ lsls r1, r4, 2\n\
+ adds r1, r7, r1\n\
+ ldr r2, =0x04000001\n\
+ bl CpuSet\n\
+ adds r4, 0x1\n\
+ lsls r4, 24\n\
+ lsrs r1, r4, 24\n\
+ asrs r4, 24\n\
+ cmp r4, 0x7\n\
+ ble _0806F836\n\
+ b _0806F86A\n\
+ .pool\n\
+ _0806F860:\n\
+ mov r0, sp\n\
+ adds r1, r7, 0\n\
+ ldr r2, =0x04000008\n\
+ bl CpuSet\n\
+ _0806F86A:\n\
+ ldr r4, [sp, 0x2C]\n\
+ mov r7, r10\n\
+ mov r1, r9\n\
+ lsls r0, r1, 24\n\
+ lsrs r5, r0, 24\n\
+ _0806F874:\n\
+ ldr r2, [sp, 0x28]\n\
+ cmp r5, r2\n\
+ bcs _0806F87C\n\
+ b _0806F748\n\
+ _0806F87C:\n\
+ movs r0, 0x20\n\
+ ldr r1, [sp, 0x28]\n\
+ subs r0, r1\n\
+ lsls r0, 1\n\
+ adds r4, r0\n\
+ ldr r2, [sp, 0x30]\n\
+ lsls r0, r2, 24\n\
+ lsrs r0, 24\n\
+ _0806F88C:\n\
+ ldr r1, [sp, 0x24]\n\
+ cmp r0, r1\n\
+ bcs _0806F894\n\
+ b _0806F740\n\
+ _0806F894:\n\
+ add sp, 0x38\n\
+ pop {r3-r5}\n\
+ mov r8, r3\n\
+ mov r9, r4\n\
+ mov r10, r5\n\
+ pop {r4-r7}\n\
+ pop {r0}\n\
+ bx r0\n\
+ .pool\n\
+ .syntax divided");
+}
+
+#endif // NONMATCHING
+
+int CountTrailingZeroBits(u32 value)
+{
+ u8 i;
+
+ for (i = 0; i < 32; i++)
+ {
+ if ((value & 1) == 0)
+ value >>= 1;
+ else
+ return i;
+ }
+ return 0;
+}
+
+u16 CalcCRC16(u8 *data, s32 length)
+{
+ u16 i, j;
+ u16 crc = 0x1121;
+
+ for (i = 0; i < length; i++)
+ {
+ crc ^= data[i];
+ for (j = 0; j < 8; j++)
+ {
+ if (crc & 1)
+ crc = (crc >> 1) ^ 0x8408;
+ else
+ crc >>= 1;
+ }
+ }
+ return ~crc;
+}
+
+u16 CalcCRC16WithTable(u8 *data, u32 length)
+{
+ u16 i;
+ u16 crc = 0x1121;
+ u8 byte;
+
+ for (i = 0; i < length; i++)
+ {
+ byte = crc >> 8;
+ crc ^= data[i];
+ crc = byte ^ sCrc16Table[(u8)crc];
+ }
+ return ~crc;
+}
+
+u32 CalcByteArraySum(const u8* data, u32 length)
+{
+ u32 sum, i;
+ for (sum = 0, i = 0; i < length; i++)
+ sum += data[i];
+ return sum;
+}
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;