You are not logged in.
Total newb here! So I've brainstormed a few moves for my hack and I'd like some feedback on how "programmable"
they are in PokeCrystal Disassembly. I just started messing around with it so I don't really have an idea of any preexisting limitations.
I'd also like to know if there's some sort of TM or Move Tutor limit if that's alright.
CORRUPT - Target becomes disobedient to Trainer. Fails if it is a Wild Pokemon.
Effects wear off after switching like Attract or Confuse Ray.
PITFALL - Trap opponent underground for one turn (reverse Dig). Fails if used consecutively.
Ground types escape immediately.
DEVOLVE - Target's stats reduced to preevolution's. Fails if no preevolution or used on same target.
Wears off on switch or maybe randomly.
ASCENSION - Disappear for one turn, attack next turn with different move of choice.
Basically Fly but with a twist. Fails if you try to use another semi-invulnerable move.
ANTI HEAL - Any healing items (Berries, Potions) will now do damage equal to the amount that would have been healed if used on affected mon.
NITPICK - Target can only use moves of its own Type.
DOWNSIZE - Move does greater damage depending on level difference to target.
Base 60 damage of move x1 if equal or less, x1.5, x2.5, x5, x7.5, x10 max.
I haven't actually worked out the math yet so change if needed.
Move that's always Super Effective
Thanks for any help!
The nice thing about assembly is that there are technically no "preexisting limitations". It's just a matter of how much code you want to (re)write.
TMs are regular items, so to add more, you'll need to replace unused items in constants/item_constants.asm and items/*.asm. Then you assign moves to the TMs in engine/tmhm.asm, and edit the data/base_stats/*.asm files to make TMs learnable.
Some tricky parts to all of that:
• The TM and HM item constants are mostly sequential, using the very last item IDs. (IIRC, you shouldn't define any non-TM items after the TMs, since an item's "TM-ness" is checked by comparing its ID with TM01) However, ITEM_C3 and ITEM_DC are unused constants that interrupt the sequence. Moving them will simplify things, but you'll have to edit engine/items.asm:GetTMHMNumber and GetNumberedTMHM to not skip over those IDs. Also, HM_08 is unused, so you can go ahead and replace it.
• Pokémon base stats have an array of flags, one bit for whether each TM is learnable, declared with the "tmhm" macro. This is defined in macros/basestats.asm. It inserts 8 bytes, or 64 bits. 50 TMs + 8 HMs + 3 tutor moves = 61 bits used, so there's only room for 3 more. You can add another byte like this:
rept 2 ; make this "rept 3" db w & $ff w = w >> 8 endr
Then you'll have room for 11 more TMs, HMs, or tutor moves. If you need more than that I can help with editing the tmhm macro to allow it.
• The "add_mt" macro, used in constants/item_constants.asm and defined in macros/basestats.asm, makes space in the base stats for a learnable-move flag but does not declare a corresponding item. That's because those moves are taught by the the move tutor in Goldenrod City, not by a TM or HM (look at main.asm:Special_MoveTutor for the code). If you run out of item IDs, you can still add tutor moves, but you will have to make sure the tmhm macro inserts enough space for them.
As for your proposed new moves, they'll all require custom effects with varying amounts of special code. The ones that involve new volatile status conditions (corruption, devolution, nitpicking, etc, which all heal on switch) will be more complicated. Here's a guide to adding Downsize, which is simpler.
First, the move itself:
• Add "const DOWNSIZE" after "const BEAT_UP" in constants/move_constants.asm. (Note that there's only room for three more moves, with IDs $FC, $FD, and $FE, before you have to start replacing some. You can also use $FF, but that will require editing a few parts of the code that assume it's not a valid move ID. Let me know if you want to do that, but first, there are pretty many redundant moves that can be replaced. Detect == Protect, Spider Web == Mean Look, Mind Reader == Lock-On, Psywave == terrible, etc.)
• Update battle/move_names.asm, battle/moves/move_descriptions.asm, battle/moves/moves.asm, and battle/anims.asm with your new move. Put it right after Beat Up in all the tables (replacing the unused move 252 or $FC if necessary). It's mostly self-explanatory. Make sure that in moves.asm it has EFFECT_DOWNSIZE. In anims.asm just reuse some other move animation, putting the "BattleAnim_Downsize:" label along with an existing one.
Now the Downsize move effect:
• Find the "move effects" in constants/battle_constants.asm and add EFFECT_DOWNSIZE at the end (after EFFECT_DEFENSE_CURL).
• Add "dw Downsize" after "dw DefenseCurl" in battle/moves/move_effects_pointers.asm.
• Add this to battle/moves/move_effects.asm (it's almost identical to the Magnitude effect):
Downsize: checkobedience usedmovetext doturn critical damagestats ; this sets the register d to the base power getdownsize ; this will modify d depending on the level difference damagecalc stab damagevariation checkhit hittarget failuretext checkfaint criticaltext supereffectivetext checkdestinybond buildopponentrage kingsrock endmove
And finally the getdownsize effect command:
• Add "command getdownsize" after "command curl" in macros/move_effect.asm.
• Add "dw BattleCommand_GetDownsize" after "dw BattleCommand_Curl" in battle/effect_command_pointers.asm.
• Finally, declare a new routine called "BattleCommand_GetDownsize" in battle/effect_commands.asm. This is inefficient and untested, but here's what it might look like (based on BattleCommand_GetMagnitude):
BattleCommand_GetDownsize: ; getdownsize ; we're using the b register but it already has some important value, so save ; its current value on the stack push bc ; ld a, [hBattleTurn] and a jr z, .players_turn .enemys_turn ld a, [BattleMonLevel] ld b, a ld a, [EnemyMonLevel] jp .initial_level_check .players_turn ; same as enemys_turn, with the levels swapped ld a, [EnemyMonLevel] ld b, a ld a, [BattleMonLevel] jp .initial_level_check .initial_level_check cp b ; "cp X" compares register a with X, and sets the "carry flag" c if a is less than X jp c, .less_than_opponent jp .at_least_opponents_level .at_least_opponents_level sub b ; now a == level difference, and we know a >= 0 cp 10 jp c, .gap_0_to_9 cp 20 jp c, .gap_10_to_19 jp .gap_20_or_more ; the opponent is 0 to 9 levels below the user, so 60 * 1.5 = 90 BP .gap_0_to_9 ld d, 90 jp .done ; the opponent is 10 to 19 levels below the user, so 60 * 2 = 120 BP .gap_10_to_19 ld d, 120 jp .done ; the opponent is 20 or more levels below the user, so 60 * 3 = 180 BP .gap_20_or_more ld d, 180 jp .done .less_than_opponent ; leave d unmodified .done ; we're returning, so put back the old value of b pop bc ret
Last edited by Rangi (2016-12-02 01:19:13)
Thanks! You've given me a good starting point, or at least an idea of which .asm files to look at.
I should have enough room for all my proposed TMs/Moves to fit with your suggested macro solution for the time being.
As for Downsize, it's actually supposed to more damage when the enemy's level is greater than yours, but I'm sure some minor tweaking could fix that. I really like your damage scale btw. It's way more reasonable than 10x lol.
I tried making the changes described above to be sure they'll actually work. Here is a commit applied to a copy of the latest pokecrystal that adds Downsize as TM51, learnable by all the starters. Should help as a reference for adding other moves.
Just noticed the link to your hack plans. I like your sprites, and you've clearly put a lot of effort into the region design.
- Map Connection Help!
My process for making map connections is still to guess the number values and test-edit-compile a few times until the maps line up. :P
It's way more reasonable than 10x lol.
60 BP × 5 = 300, which wouldn't even fit in one byte. You could probably make it work anyway, but it would be more complicated and possibly way overpowered.
Doing more damage when you're lower-leveled makes sense. You're right, editing the effect should be pretty easy. To understand the individual assembly instructions like "cp" and "ld" and "jr" I sometimes refer to this summary (Google cache since it's offline right now). (It's a cheat sheet, not an introduction.)
Last edited by Rangi (2016-12-02 01:51:19)
EDIT: more permanent mirror for the opcode summary, it doesn't seem like it's coming back: http://home.fiq.se/dmg/opcodes.html
As for your romhack, have you considered Crystal as base to make it easier to do "special" stuff in it using the disassembly? Or are you too invested in your current base for it to be feasible?
Pitfall is basically Sky Drop in reverse without damage?
All your move effects seem fairly straightforward to implement except for Pitfall which would be more complicated and Devolve which would be significantly more so. Everything is obviously possible, it just depends on how much time you're willing to spend (and hardware limitations, but this isn't a factor here)
EDIT: Making Corrupt work on enemy trainers requires more or less a rewrite of how obediance works I think, which would make it a bit tricky too.
Last edited by FIQ (2016-12-02 21:09:00)
@Rangi nice! You sure work fast. Thanks for checking out my stuff btw.
@FIQ I should really update the other thread, but I've transitioned to Crystal for the reason you stated. I initially just wanted Gold because I didn't want to deal with the extra spriting work that'd come with animated sprites (which I guess I could just disable somehow) and rewriting dialogue for a gender-swap rival (I ended up doing some big story rewrites anyway)
For the moves, they're just conceptual at the moment so I'm not too beat up if they don't make the final cut. I'm prioritizing Corrupt, Pitfall, Anitheal, the Always super effective move, and Downsize though. The rest are just extra credit, so to speak.
Now that you mention it, Pitfall does share similarities to Skydrop but the Pitfall user isn't incapacitated for the next turn with the target. I pictured it as a kind of 1-2 combo. 1)Bury opponent 2)Use Earthquake or Magnitude. The opponent will be able to retaliate as soon as they're released.
You can disable animations by editing gfx/pics/*/anim0.asm and gfx/pics/*/anim1.asm to just contain "endanim", and edit gfx/pics/*/bitmask.asm and gfx/pics/*/frames.asm to just be empty.