Last active
August 29, 2015 14:11
-
-
Save magical/bbd62ff7706af4a549b0 to your computer and use it in GitHub Desktop.
Pokémon X capture routine analysis
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; Pokemon X capture routine | |
; DllBattle.cro .text+0x2ee40 | |
; tl;dr everything is pretty much the same | |
; but with more floating point. | |
; there are four shake checks again instead of three | |
; and the fourth root is now a 16/3 root. | |
; looks like we're going to use a truly staggering number of registers | |
2ee40: e92d4fff push {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr} | |
2ee44: e1a04001 mov r4, r1 | |
2ee48: e3a09000 mov r9, #0 | |
2ee4c: e1a0a003 mov r10, r3 ; the pokemon | |
; push some floating point registers too | |
2ee50: ed2d8b0c vpush {d8-d13} | |
2ee54: e24dd004 sub sp, sp, #4 | |
2ee58: e28d106c add r1, sp, #108 ; = (13*4 + 6*8 + 4) + 4 | |
; r5 and r8 are our "out" pointers for shakes and crit | |
2ee5c: e8910120 ldm r1, {r5, r8} | |
; if using the master ball, or something mysterious is non-zero... | |
2ee60: e59d7068 ldr r7, [sp, #104] | |
2ee64: e3570001 cmp r7, #1 | |
2ee68: e5c89000 strb r9, [r8] | |
2ee6c: 0a000004 beq 0x2ee84 | |
2ee70: e5940004 ldr r0, [r4, #4] | |
2ee74: e5900010 ldr r0, [r0, #16] | |
2ee78: e5d000b2 ldrb r0, [r0, #178] | |
2ee7c: e3500000 cmp r0, #0 | |
2ee80: 0a000006 beq 0x2eea0 | |
; ...automatic success! | |
2ee84: e3a00003 mov r0, #3 | |
2ee88: e5c50000 strb r0, [r5] | |
2ee8c: e3a00001 mov r0, #1 | |
; we'll come back here later on because who wants to clean up twice | |
2ee90: e28dd004 add sp, sp, #4 | |
2ee94: ecbd8b0c vpop {d8-d13} | |
2ee98: e28dd010 add sp, sp, #16 | |
2ee9c: e8bd8ff0 pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} | |
2eea0: e3a0100e mov r1, #14 ; get max hp | |
2eea4: e1a00003 mov r0, r3 | |
2eea8: eb0114fc bl 0x742a0 | |
2eeac: e080b080 add r11, r0, r0, lsl #1 ; mul by 3 | |
2eeb0: e3a0100d mov r1, #13 ; get cur hp | |
2eeb4: e1a0000a mov r0, r10 | |
2eeb8: eb0114f8 bl 0x742a0 | |
2eebc: e2600000 rsb r0, r0, #0 ; negate | |
2eec0: ed9faaf2 vldr s20, [pc, #968] ; 0x2f290 = 0.5f | |
2eec4: e09b0080 adds r0, r11, r0, lsl #1 ; max*3 - cur*2 | |
2eec8: eddfaaf1 vldr s21, [pc, #964] ; 0x2f294 = 0 | |
2eecc: 0d9f0af1 vldreq s0, [pc, #964] ; 0x2f298 = -0.5f | |
2eed0: 0a000003 beq 0x2eee4 | |
2eed4: e1a00600 lsl r0, r0, #12 ; convert to fixed point | |
2eed8: ee000a10 vmov s0, r0 ; convert to float | |
2eedc: eeb80a40 vcvt.f32.u32 s0, s0 | |
2eee0: ee300a0a vadd.f32 s0, s0, s20 ; add 0.5 | |
; If a thing is true (something about terrain?)... | |
; [This, of course, is where the dark grass penalty was in B/W | |
; but there is no dark grass in X/Y | |
; is there?] | |
2eee4: e5940004 ldr r0, [r4, #4] | |
2eee8: e5900010 ldr r0, [r0, #16] | |
2eeec: e59010a8 ldr r1, [r0, #168] | |
2eef0: eebd0ac0 vcvt.s32.f32 s0, s0 | |
2eef4: e3110020 tst r1, #32 | |
2eef8: ee106a10 vmov r6, s0 | |
2eefc: 0a00001a beq 0x2ef6c | |
; get ye olde dex counte | |
2ef00: e5900084 ldr r0, [r0, #132] | |
2ef04: e3500000 cmp r0, #0 | |
2ef08: 0a000011 beq 0x2ef54 | |
2ef0c: e3a01000 mov r1, #0 | |
2ef10: ebff46bf bl 0xa14 | |
; 601+ - x1.0 | |
2ef14: e3500f96 cmp r0, #600 | |
2ef18: 83a00a01 movhi r0, #4096 ; 0x1000 | |
2ef1c: 8a00000d bhi 0x2ef58 | |
; 451-600 - x0.9 | |
2ef20: e59f1374 ldr r1, [pc, #884] ; 0x2f29c = 0x1c2 = 450 | |
2ef24: e1500001 cmp r0, r1 | |
2ef28: 859f0370 ldrhi r0, [pc, #880] ; 0x2f2a0 = 0xe66 | |
2ef2c: 8a000009 bhi 0x2ef58 | |
; 301-450 - x0.8 | |
2ef30: e3500f4b cmp r0, #300 | |
2ef34: 859f0368 ldrhi r0, [pc, #872] ; 0x2f2a4 = 0xccd | |
2ef38: 8a000006 bhi 0x2ef58 | |
; 151-301 - x0.7 | |
2ef3c: e3500096 cmp r0, #150 | |
2ef40: 859f0360 ldrhi r0, [pc, #864] ; 0x2f2a8 = 0xb33 | |
2ef44: 8a000003 bhi 0x2ef58 | |
; 31-150 - x0.5 | |
2ef48: e350001e cmp r0, #30 | |
2ef4c: 83a00b02 movhi r0, #2048 ; 0x800 | |
2ef50: 8a000000 bhi 0x2ef58 | |
; 0-30 - x0.3 | |
2ef54: e59f0350 ldr r0, [pc, #848] ; 0x2f2ac = 0x4cd | |
; factor the penalty in | |
2ef58: e0c10096 smull r0, r1, r6, r0 | |
; round | |
2ef5c: e2900b02 adds r0, r0, #2048 ; 0x800 | |
2ef60: e2a11000 adc r1, r1, #0 | |
2ef64: e1a00620 lsr r0, r0, #12 | |
2ef68: e1806a01 orr r6, r0, r1, lsl #20 | |
; Catch rate | |
2ef6c: e1da00bc ldrh r0, [r10, #12] | |
2ef70: e5da1153 ldrb r1, [r10, #339] | |
2ef74: e3a02008 mov r2, #8 | |
2ef78: e58d2000 str r2, [sp] | |
2ef7c: ebff46a6 bl 0xa1c ; load pokemon's base stats | |
2ef80: e59d0000 ldr r0, [sp] | |
2ef84: e320f000 nop {0} | |
2ef88: ebff46a5 bl 0xa24 ; get catch rate | |
2ef8c: e6ff0070 uxth r0, r0 | |
; Ball bonus | |
2ef90: e58d7000 str r7, [sp] ; the ball | |
2ef94: e0060096 mul r6, r6, r0 ; (factor catch rate in) | |
2ef98: e59d0034 ldr r0, [sp, #52] | |
2ef9c: e59d203c ldr r2, [sp, #60] | |
2efa0: e1a0300a mov r3, r10 ; pokemon | |
2efa4: e1a01004 mov r1, r4 | |
2efa8: eb00029f bl 0x2fa2c ; ball bonus routine, see below | |
; multiply, round | |
2efac: e0c10096 smull r0, r1, r6, r0 | |
2efb0: e2900b02 adds r0, r0, #2048 ; 0x800 | |
2efb4: e2a11000 adc r1, r1, #0 | |
2efb8: e1a00620 lsr r0, r0, #12 | |
2efbc: e1800a01 orr r0, r0, r1, lsl #20 | |
; divide by 3*Max HP | |
2efc0: e1a0100b mov r1, r11 ; r11 is 3*maxhp | |
2efc4: ebff44b4 bl 0x29c ; unsigned 32-bit division | |
; Status modifier | |
2efc8: e1a06000 mov r6, r0 | |
2efcc: e1a0000a mov r0, r10 | |
2efd0: eb00f9d5 bl 0x6d72c | |
; jump table | |
2efd4: e3500006 cmp r0, #6 | |
2efd8: 379ff100 ldrcc pc, [pc, r0, lsl #2] | |
2efdc: ea000012 b 0x2f02c | |
; not sure which entry is which, but it doesn't really matter | |
2efe0: 0002f02c | |
2efe4: 0002f014 | |
2efe8: 0002eff8 | |
2efec: 0002eff8 | |
2eff0: 0002f014 | |
2eff4: 0002f014 | |
; the large bonus is 2.5 | |
2eff8: e3a00b0a mov r0, #10240 ; 0x2800 | |
2effc: e0c01096 smull r1, r0, r6, r0 | |
2f000: e2911b02 adds r1, r1, #2048 ; 0x800 | |
2f004: e2a00000 adc r0, r0, #0 | |
2f008: e1a01621 lsr r1, r1, #12 | |
2f00c: e1816a00 orr r6, r1, r0, lsl #20 | |
2f010: ea000005 b 0x2f02c | |
; the small bonus is 1.5 | |
2f014: e3a00b06 mov r0, #6144 ; 0x1800 | |
2f018: e0c10096 smull r0, r1, r6, r0 | |
2f01c: e2900b02 adds r0, r0, #2048 ; 0x800 | |
2f020: e2a11000 adc r1, r1, #0 | |
2f024: e1a00620 lsr r0, r0, #12 | |
2f028: e1806a01 orr r6, r0, r1, lsl #20 | |
; Moving on. Lots of floating-point instructions ahead. | |
; Historically, this is where Entralink and Critical capture would be. | |
2f02c: e5940004 ldr r0, [r4, #4] | |
2f030: ed9fca9e vldr s24, [pc, #632] ; 0x2f2b0 (0x45800000 = 4096.0f) | |
2f034: ed9f9b9f vldr d9, [pc, #636] ; 0x2f2b8 (1/4096.0) | |
2f038: ed9f8ba0 vldr d8, [pc, #640] ; 0x2f2c0 (0) | |
; If wotsit is 0, skip this stuff | |
2f03c: e5900010 ldr r0, [r0, #16] | |
2f040: e59000b8 ldr r0, [r0, #184] | |
2f044: e3500000 cmp r0, #0 | |
2f048: 0a000012 beq 0x2f098 | |
; otherwise... | |
; convert our fixed-point intermediate catch rate into a floating point | |
; number to pass to the mysterious function below | |
2f04c: e1a01646 asr r1, r6, #12 ; r6 /= 4096 | |
2f050: ee001a10 vmov s0, r1 ; convert to fp | |
2f054: e1a01a06 lsl r1, r6, #20 ; get fractional part | |
2f058: e1b01a21 lsrs r1, r1, #20 | |
2f05c: eeb81bc0 vcvt.f64.s32 d1, s0 | |
2f060: 1e001a10 vmovne s0, r1 ; add frac back in | |
2f064: 1eb80bc0 vcvtne.f64.s32 d0, s0 | |
2f068: 1e200b09 vmulne.f64 d0, d0, d9 | |
2f06c: 0eb00b48 vmoveq.f64 d0, d8 | |
2f070: ee310b00 vadd.f64 d0, d1, d0 | |
2f074: eeb70bc0 vcvt.f32.f64 s0, d0 | |
2f078: ebff466b bl 0xa2c ; mysterious function | |
; here's what the mysterious function does: it takes its argument (s0), | |
; loads a mysterious number from somewhere based on its other argument (r0), | |
; multiplies them together and divides by 100 (well, multiplies by 0.01) | |
; all in double-precision floating point because why not! | |
; now of course we convert it back to 12-bit fixed point | |
2f07c: eeb40aea vcmpe.f32 s0, s21 ; s21 is 0.0 | |
2f080: eef1fa10 vmrs APSR_nzcv, fpscr | |
2f084: eef00a4a vmov.f32 s1, s20 ; s20 is 0.5 | |
2f088: ce400a0c vmlagt.f32 s1, s0, s24 ; s24 is 4096.0 | |
2f08c: de500a0c vnmlsle.f32 s1, s0, s24 | |
2f090: eebd0ae0 vcvt.s32.f32 s0, s1 | |
2f094: ee106a10 vmov r6, s0 | |
; whew | |
; Critical capture | |
2f098: e5940004 ldr r0, [r4, #4] | |
2f09c: e59fa224 ldr r10, [pc, #548] ; 0x2f2c8 | |
; copy capture chance to r7 for the following calculations | |
2f0a0: e1a07006 mov r7, r6 | |
2f0a4: e5900010 ldr r0, [r0, #16] | |
; dex count again | |
2f0a8: e5900084 ldr r0, [r0, #132] | |
2f0ac: e3500000 cmp r0, #0 | |
2f0b0: 0a000021 beq 0x2f13c | |
2f0b4: e3a01000 mov r1, #0 | |
2f0b8: ebff4655 bl 0xa14 | |
; 601+ - 2.5 | |
2f0bc: e3500f96 cmp r0, #600 | |
2f0c0: 83a00b0a movhi r0, #10240 ; 0x2800 | |
2f0c4: 8a00000c bhi 0x2f0fc | |
; 451-600 - 2.0 | |
2f0c8: e59f11cc ldr r1, [pc, #460] ; 0x2f29c (450) | |
2f0cc: e1500001 cmp r0, r1 | |
2f0d0: 83a00a02 movhi r0, #8192 ; 0x2000 | |
2f0d4: 8a000008 bhi 0x2f0fc | |
; 301-450 - 1.5 | |
2f0d8: e3500f4b cmp r0, #300 | |
2f0dc: 83a00b06 movhi r0, #6144 ; 0x1800 | |
2f0e0: 8a000005 bhi 0x2f0fc | |
; 151-300 - 1.0 | |
2f0e4: e3500096 cmp r0, #150 | |
2f0e8: 83a00a01 movhi r0, #4096 ; 0x1000 | |
2f0ec: 8a000002 bhi 0x2f0fc | |
; 31-150 - 0.5 | |
2f0f0: e350001e cmp r0, #30 | |
2f0f4: 83a00b02 movhi r0, #2048 ; 0x800 | |
; 0-30 - skip | |
2f0f8: 9a00000f bls 0x2f13c | |
; cap capture rate at 255.0 | |
2f0fc: e3570aff cmp r7, #1044480 ; 0xff000 | |
2f100: c3a07aff movgt r7, #1044480 ; 0xff000 | |
; multiply by bonus, round | |
2f104: e0c10097 smull r0, r1, r7, r0 | |
2f108: e2900b02 adds r0, r0, #2048 ; 0x800 | |
2f10c: e2a11000 adc r1, r1, #0 | |
2f110: e1a00620 lsr r0, r0, #12 | |
2f114: e1800a01 orr r0, r0, r1, lsl #20 | |
; magic signed division by 6 | |
2f118: e59f11ac ldr r1, [pc, #428] ; 0x2f2cc (0x2aaaaaab) | |
2f11c: e0c01091 smull r1, r0, r1, r0 | |
2f120: e3a01c01 mov r1, #256 | |
2f124: e0404fc0 sub r4, r0, r0, asr #31 | |
; roll the dice | |
; it's a crit if rand(256) < the crit. capture chance | |
; the chance is truncated for the comparison | |
2f128: e59a0054 ldr r0, [r10, #84] ; pointer to rand state | |
2f12c: ebff444a bl 0x25c ; rand | |
2f130: e1500644 cmp r0, r4, asr #12 | |
2f134: 33a00001 movcc r0, #1 | |
2f138: 3a000000 bcc 0x2f140 | |
2f13c: e1a00009 mov r0, r9 ; r9 is 0 | |
; If the capture rate is >= 255.0, automatic success. | |
; Set shakes to 3 (or 1 in case of crit) and return success | |
2f140: e3560aff cmp r6, #1044480 ; 0xff000 | |
2f144: e5c80000 strb r0, [r8] ; crit | |
2f148: ba000005 blt 0x2f164 | |
2f14c: e3500000 cmp r0, #0 | |
2f150: 13a00001 movne r0, #1 | |
2f154: 03a00003 moveq r0, #3 | |
2f158: e5c50000 strb r0, [r5] ; shakes | |
2f15c: e3a00001 mov r0, #1 | |
2f160: eaffff4a b 0x2ee90 ; jump back to the top to return | |
; OH MY GOD. THE VFP INSTRUCTIONS. THEY'RE BACK | |
; convert capture chance to fp | |
2f164: e1a00646 asr r0, r6, #12 | |
2f168: ee010a10 vmov s2, r0 | |
2f16c: e1a00a06 lsl r0, r6, #20 | |
2f170: ed9f0b56 vldr d0, [pc, #344] ; 0x2f2d0 (255.0f) | |
2f174: e1b00a20 lsrs r0, r0, #20 | |
2f178: 1e020a10 vmovne s4, r0 | |
2f17c: ed9fdb55 vldr d13, [pc, #340] ; 0x2f2d8 (4096.0f) | |
2f180: eeb81bc1 vcvt.f64.s32 d1, s2 | |
2f184: ed9fbb55 vldr d11, [pc, #340] ; 0x2f2e0 (0.5f) | |
2f188: 1eb82bc2 vcvtne.f64.s32 d2, s4 | |
2f18c: 1e222b09 vmulne.f64 d2, d2, d9 ; d9 is still 1/4096 | |
2f190: 0eb02b48 vmoveq.f64 d2, d8 ; d8 is still 0 | |
2f194: ee311b02 vadd.f64 d1, d1, d2 | |
2f198: eeb41b48 vcmp.f64 d1, d8 | |
2f19c: eef1fa10 vmrs APSR_nzcv, fpscr | |
2f1a0: 01a00009 moveq r0, r9 | |
2f1a4: 0a000007 beq 0x2f1c8 | |
; divide 255.0 by catch rate | |
2f1a8: ee802b01 vdiv.f64 d2, d0, d1 | |
; convert back to fixed point | |
2f1ac: eeb42bc8 vcmpe.f64 d2, d8 | |
2f1b0: eef1fa10 vmrs APSR_nzcv, fpscr | |
2f1b4: eeb00b4b vmov.f64 d0, d11 | |
2f1b8: ce020b0d vmlagt.f64 d0, d2, d13 | |
2f1bc: de120b0d vnmlsle.f64 d0, d2, d13 | |
2f1c0: eebd0bc0 vcvt.s32.f64 s0, d0 | |
2f1c4: ee100a10 vmov r0, s0 | |
; convert back to floating point | |
2f1c8: e1a01640 asr r1, r0, #12 | |
2f1cc: ee001a10 vmov s0, r1 | |
2f1d0: e1a00a00 lsl r0, r0, #20 | |
2f1d4: e1b00a20 lsrs r0, r0, #20 | |
2f1d8: eeb81bc0 vcvt.f64.s32 d1, s0 | |
2f1dc: 1e000a10 vmovne s0, r0 | |
2f1e0: 1eb80bc0 vcvtne.f64.s32 d0, s0 | |
2f1e4: 1e200b09 vmulne.f64 d0, d0, d9 | |
2f1e8: 0eb00b48 vmoveq.f64 d0, d8 | |
2f1ec: ee310b00 vadd.f64 d0, d1, d0 | |
2f1f0: eeb70bc0 vcvt.f32.f64 s0, d0 | |
; !!! | |
; call powf(x, 0.1875) | |
2f1f4: eddf0a3b vldr s1, [pc, #236] ; 0x2f2e8 (0.1875 = 3/16) | |
2f1f8: ebff460d bl 0xa34 ; powf | |
; convert back to fixed-point | |
2f1fc: eeb40aea vcmpe.f32 s0, s21 | |
2f200: eef1fa10 vmrs APSR_nzcv, fpscr | |
2f204: ed9f1b39 vldr d1, [pc, #228] ; 0x2f2f0 (65536.0) | |
2f208: ce00aa0c vmlagt.f32 s20, s0, s24 | |
2f20c: de10aa0c vnmlsle.f32 s20, s0, s24 | |
2f210: eebd0aca vcvt.s32.f32 s0, s20 | |
2f214: ee100a10 vmov r0, s0 | |
; convert back to floating point | |
2f218: e1a01640 asr r1, r0, #12 | |
2f21c: ee001a10 vmov s0, r1 | |
2f220: e1a00a00 lsl r0, r0, #20 | |
2f224: e1b00a20 lsrs r0, r0, #20 | |
2f228: eeb82bc0 vcvt.f64.s32 d2, s0 | |
2f22c: 1e000a10 vmovne s0, r0 | |
2f230: 1eb80bc0 vcvtne.f64.s32 d0, s0 | |
2f234: 1e200b09 vmulne.f64 d0, d0, d9 | |
2f238: 0eb00b48 vmoveq.f64 d0, d8 | |
2f23c: ee322b00 vadd.f64 d2, d2, d0 | |
2f240: eeb42b48 vcmp.f64 d2, d8 | |
2f244: eef1fa10 vmrs APSR_nzcv, fpscr | |
; (if zero, skip the next step) | |
2f248: 01a00009 moveq r0, r9 | |
2f24c: 0a000006 beq 0x2f26c | |
; divide 65536.0 by our twisted, mutilated value | |
2f250: ee810b02 vdiv.f64 d0, d1, d2 | |
; and convert back to fixed-point | |
2f254: eeb40bc8 vcmpe.f64 d0, d8 | |
2f258: eef1fa10 vmrs APSR_nzcv, fpscr | |
2f25c: ce00bb0d vmlagt.f64 d11, d0, d13 | |
2f260: de10bb0d vnmlsle.f64 d11, d0, d13 | |
2f264: eebd0bcb vcvt.s32.f64 s0, d11 | |
2f268: ee100a10 vmov r0, s0 | |
; now we're pretty much done | |
; let's call this final value the shake chance | |
; Figure out how many shakes to attempt. | |
; One for crit. | |
; Four(!) otherwise. | |
2f26c: e5c59000 strb r9, [r5] ; shakes = 0 | |
2f270: e3a04000 mov r4, #0 | |
2f274: e1a06640 asr r6, r0, #12 | |
2f278: e5d80000 ldrb r0, [r8] | |
2f27c: e3500000 cmp r0, #0 | |
2f280: 13a07001 movne r7, #1 | |
2f284: 03a07004 moveq r7, #4 | |
; The top of this loop is waaaay up here on top of all | |
; these constants that we've been loading like crazy. | |
2f288: e3a01801 mov r1, #65536 ; 0x10000 | |
2f28c: ea000019 b 0x2f2f8 | |
; ignore the following lines | |
2f290: 3f000000 | |
2f294: 00000000 | |
2f298: bf000000 | |
2f29c: 000001c2 | |
2f2a0: 00000e66 | |
2f2a4: 00000ccd | |
2f2a8: 00000b33 | |
2f2ac: 000004cd | |
2f2b0: 45800000 | |
2f2b4: 00000000 | |
2f2b8: 00000000 | |
2f2bc: 3f300000 | |
2f2c0: 00000000 | |
2f2c4: 00000000 | |
2f2c8: 00000000 | |
2f2cc: 2aaaaaab | |
2f2d0: 00000000 | |
2f2d4: 406fe000 | |
2f2d8: 00000000 | |
2f2dc: 40b00000 | |
2f2e0: 00000000 | |
2f2e4: 3fe00000 | |
2f2e8: 3e400000 | |
2f2ec: 00000000 | |
2f2f0: 00000000 | |
2f2f4: 40f00000 | |
; hello again | |
; if rand(65536) >= the shake chance, the pokemon breaks free | |
2f2f8: e59a0054 ldr r0, [r10, #84] ; load rand state | |
2f2fc: ebff43d6 bl 0x25c ; rand | |
2f300: e1500006 cmp r0, r6 | |
2f304: e320f000 nop {0} | |
2f308: 2a000008 bcs 0x2f330 ; goto failure | |
2f30c: e5d50000 ldrb r0, [r5] | |
2f310: e2844001 add r4, r4, #1 ; increment counter | |
2f314: e3500003 cmp r0, #3 ; increment shakes | |
2f318: 32800001 addcc r0, r0, #1 ; ...but not past 3! | |
2f31c: 35c50000 strbcc r0, [r5] | |
2f320: e1540007 cmp r4, r7 ; if counter < max shakes | |
2f324: 3affffd7 bcc 0x2f288 ; loop | |
; note that we make up to four checks, | |
; but the returned shake count (r5) | |
; is capped at three | |
; whether or not fourth last check succeeded | |
; can be determined by whether the capture as a whole succeeded | |
; that is, four successful checks returns success (shakes=3) | |
; three successful checks and a failure returns failure (shakes=3) | |
2f328: e3a00001 mov r0, #1 ; return success | |
2f32c: eafffed7 b 0x2ee90 | |
2f330: e3a00000 mov r0, #0 ; return failure | |
2f334: eafffed5 b 0x2ee90 | |
; the end | |
; Ball bonus routine | |
; push a much more reasonable set of registers | |
2fa2c: e92d4010 push {r4, lr} | |
2fa30: e1a04003 mov r4, r3 | |
2fa34: e59d0008 ldr r0, [sp, #8] | |
2fa38: e2400002 sub r0, r0, #2 | |
2fa3c: e350000e cmp r0, #14 | |
; jump table | |
2fa40: 379ff100 ldrcc pc, [pc, r0, lsl #2] | |
2fa44: ea00006c b 0x2fbfc | |
2fa48: 0002fa88 ; great | |
2fa4c: 0002fa80 ; ultra | |
2fa50: 0002fbfc ; poke | |
2fa54: 0002fbfc ; safari | |
2fa58: 0002fa90 ; net | |
2fa5c: 0002fac4 ; dive | |
2fa60: 0002fae0 ; nest | |
2fa64: 0002fb48 ; repeat | |
2fa68: 0002fb7c ; timer | |
2fa6c: 0002fbfc ; luxury | |
2fa70: 0002fbfc ; premier | |
2fa74: 0002fb98 ; dusk | |
2fa78: 0002fbfc ; heal | |
2fa7c: 0002fbec ; quick | |
; Great Ball | |
2fa80: e3a00b06 mov r0, #6144 ; 0x1800 | |
2fa84: e8bd8010 pop {r4, pc} | |
; Ultra Ball | |
2fa88: e3a00a02 mov r0, #8192 ; 0x2000 | |
2fa8c: e8bd8010 pop {r4, pc} | |
; Net Ball | |
2fa90: e3a0100a mov r1, #10 ; bug type | |
2fa94: e1a00003 mov r0, r3 | |
2fa98: eb00ff50 bl 0x6f7e0 | |
2fa9c: e3500000 cmp r0, #0 | |
2faa0: e320f000 nop {0} | |
2faa4: 1a000032 bne 0x2fb74 ; ->3.0 | |
2faa8: e3a01006 mov r1, #6 ; water type | |
2faac: e1a00004 mov r0, r4 | |
2fab0: eb00ff4a bl 0x6f7e0 | |
2fab4: e3500000 cmp r0, #0 | |
2fab8: e320f000 nop {0} | |
2fabc: 1a00002c bne 0x2fb74 ; -> 3.0 | |
2fac0: ea00004d b 0x2fbfc | |
; Dive Ball | |
2fac4: e5910004 ldr r0, [r1, #4] | |
2fac8: e5900010 ldr r0, [r0, #16] | |
2facc: e59000a8 ldr r0, [r0, #168] | |
2fad0: e3100001 tst r0, #1 | |
2fad4: 03100901 tsteq r0, #16384 ; 0x4000 | |
2fad8: 1a000041 bne 0x2fbe4 ; ->3.5 | |
2fadc: ea000046 b 0x2fbfc | |
; Nest Ball | |
2fae0: e3a0100f mov r1, #15 | |
2fae4: e1a00003 mov r0, r3 | |
2fae8: eb0111ec bl 0x742a0 | |
2faec: e6ff0070 uxth r0, r0 | |
; if level is >= 30, forgeddaboudit | |
2faf0: e350001e cmp r0, #30 | |
2faf4: 2a000040 bcs 0x2fbfc | |
; subtract level from 41 | |
2faf8: e2600029 rsb r0, r0, #41 | |
2fafc: e6ff0070 uxth r0, r0 | |
2fb00: e3500028 cmp r0, #40 | |
2fb04: 83a00028 movhi r0, #40 | |
2fb08: 8a000002 bhi 0x2fb18 | |
2fb0c: e3500000 cmp r0, #0 | |
; more botched rounding / convert to fixed-point | |
2fb10: 0d9f0a3b vldreq s0, [pc, #236] ; 0x2fc04 (-0.5) | |
2fb14: 0a000004 beq 0x2fb2c | |
2fb18: e1a00600 lsl r0, r0, #12 | |
2fb1c: ee000a10 vmov s0, r0 | |
2fb20: eddf0a38 vldr s1, [pc, #224] ; 0x2fc08 (0.5) | |
2fb24: eeb80a40 vcvt.f32.u32 s0, s0 | |
2fb28: ee300a20 vadd.f32 s0, s0, s1 | |
; magic division by 10 | |
2fb2c: e59f10d8 ldr r1, [pc, #216] ; 0x2fc0c (0x66666667) | |
2fb30: eebd0ac0 vcvt.s32.f32 s0, s0 | |
2fb34: ee100a10 vmov r0, s0 | |
2fb38: e0c01091 smull r1, r0, r1, r0 | |
2fb3c: e1a01140 asr r1, r0, #2 | |
2fb40: e0410fc0 sub r0, r1, r0, asr #31 | |
2fb44: e8bd8010 pop {r4, pc} | |
; Repeat Ball | |
2fb48: e5910004 ldr r0, [r1, #4] ; get dex count | |
2fb4c: e5900010 ldr r0, [r0, #16] | |
2fb50: e5900084 ldr r0, [r0, #132] | |
2fb54: e3500000 cmp r0, #0 ; be sure it's non-zero | |
2fb58: 0a000027 beq 0x2fbfc | |
2fb5c: e1d310bc ldrh r1, [r3, #12] ; caught? | |
2fb60: e3a02000 mov r2, #0 | |
2fb64: ebff43b4 bl 0xa3c | |
2fb68: e3500000 cmp r0, #0 | |
2fb6c: e320f000 nop {0} | |
2fb70: 0a000021 beq 0x2fbfc | |
2fb74: e3a00a03 mov r0, #12288 ; 0x3000 | |
2fb78: e8bd8010 pop {r4, pc} | |
; Timer Ball | |
2fb7c: e5910014 ldr r0, [r1, #20] | |
2fb80: e59f1088 ldr r1, [pc, #136] ; 0x2fc10 = 0x4cd | |
2fb84: e0000190 mul r0, r0, r1 | |
2fb88: e2800a01 add r0, r0, #4096 ; 0x1000 | |
2fb8c: e3500901 cmp r0, #16384 ; 0x4000 | |
2fb90: c3a00901 movgt r0, #16384 ; 0x4000 | |
2fb94: e8bd8010 pop {r4, pc} | |
; Dusk Ball | |
2fb98: e5910004 ldr r0, [r1, #4] | |
2fb9c: e5900010 ldr r0, [r0, #16] | |
2fba0: e2804004 add r4, r0, #4 | |
2fba4: e3a00001 mov r0, #1 | |
2fba8: ebff43a5 bl 0xa44 | |
2fbac: e5d41007 ldrb r1, [r4, #7] | |
; if r1 = 3, 17, 19, 20, 60, or 59 | |
; (OR/AS: 3, 14, 15, 41) | |
2fbb0: e3510003 cmp r1, #3 | |
2fbb4: 13510011 cmpne r1, #17 | |
2fbb8: 0a000009 beq 0x2fbe4 -> 3.5 | |
2fbbc: e3510013 cmp r1, #19 | |
2fbc0: 13510014 cmpne r1, #20 | |
2fbc4: 0a000006 beq 0x2fbe4 -> 3.5 | |
2fbc8: e351003c cmp r1, #60 | |
2fbcc: 1351003b cmpne r1, #59 | |
2fbd0: 0a000003 beq 0x2fbe4 -> 3.5 | |
; or if r0 = 2, 3, or 4 | |
2fbd4: e3500002 cmp r0, #2 | |
2fbd8: 13500003 cmpne r0, #3 | |
2fbdc: 13500004 cmpne r0, #4 | |
2fbe0: 1a000005 bne 0x2fbfc | |
2fbe4: e3a00b0e mov r0, #14336 ; 0x3800 | |
2fbe8: e8bd8010 pop {r4, pc} | |
; Quick Ball | |
2fbec: e5910014 ldr r0, [r1, #20] | |
2fbf0: e3500000 cmp r0, #0 | |
2fbf4: 03a00a05 moveq r0, #20480 ; 0x5000 | |
2fbf8: 0affffa1 beq 0x2fa84 | |
; Fallback | |
2fbfc: e3a00a01 mov r0, #4096 ; 0x1000 | |
2fc00: e8bd8010 pop {r4, pc} | |
2fc04: bf000000 | |
2fc08: 3f000000 | |
2fc0c: 66666667 | |
2fc10: 000004cd |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment