diff options
author | PikalaxALT <pikalaxalt@gmail.com> | 2017-09-13 19:29:19 -0400 |
---|---|---|
committer | PikalaxALT <pikalaxalt@gmail.com> | 2017-09-13 19:29:19 -0400 |
commit | 64ffa8f9639c0dae2075d722fb12610e42b2129f (patch) | |
tree | abb297307bf48a399052aa0c6f7d1db7498b9cc3 /src | |
parent | c2e31f0618e19a1edad6bfface74901c8cd405f7 (diff) | |
parent | 78009a835f840864b3d30af00c65a745f75b80fa (diff) |
Merge branch 'master' into field_map_obj
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_4.c | 601 | ||||
-rw-r--r-- | src/battle_ai.c | 1505 | ||||
-rw-r--r-- | src/bg.c | 1642 | ||||
-rw-r--r-- | src/calculate_base_damage.c | 284 | ||||
-rw-r--r-- | src/coins.c | 77 | ||||
-rw-r--r-- | src/load_save.c | 114 | ||||
-rw-r--r-- | src/lottery_corner.c | 167 | ||||
-rw-r--r-- | src/main.c | 14 | ||||
-rw-r--r-- | src/malloc.c | 2 | ||||
-rw-r--r-- | src/money.c | 55 | ||||
-rw-r--r-- | src/new_game.c | 117 | ||||
-rw-r--r-- | src/palette.c | 8 | ||||
-rw-r--r-- | src/play_time.c | 10 | ||||
-rw-r--r-- | src/pokemon_1.c | 325 | ||||
-rw-r--r-- | src/pokemon_2.c | 4 | ||||
-rw-r--r-- | src/pokemon_size_record.c | 222 | ||||
-rw-r--r-- | src/rng.c | 5 | ||||
-rw-r--r-- | src/safari_zone.c | 268 | ||||
-rw-r--r-- | src/save.c | 5 | ||||
-rw-r--r-- | src/script.c | 434 | ||||
-rw-r--r-- | src/start_menu.c | 231 | ||||
-rw-r--r-- | src/task.c | 6 | ||||
-rw-r--r-- | src/text.c | 2 | ||||
-rw-r--r-- | src/util.c | 503 | ||||
-rw-r--r-- | src/window.c | 2 |
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); + } +} @@ -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; |