Skeetendo

’Cause all games were better on the GBC

You are not logged in.

#1 2018-09-10 06:03:09

glodfinch
Member
Registered: 2018-09-10
Post 1/11

[pokered] Sketch implementation

Over the past few days I started some hacking, and I've been working on putting Smeargle into pokered. Naturally this meant implementing his Sketch move.
Now if I've learned anything since I started it's that small logical errors can lead to strange and hard to find bugs :)

With this being the first code I had to write that I couldn't find examples to follow (on the forums or in the disassembly), I was wondering if someone more experienced than me would be willing to glance over my Sketch implementation, and let me know if there's any glaring novice errors there. From my limited play testing it seems to work, but I could've easily made some mistake that I don't know enough yet to detect.

https://github.com/glodfinch/pokered/bl … effect.asm

I also couldn't really find much information about adding new move animations and had to work this out myself, is there any documentation about that out there? All I could find was docs for pokecrystal. It would be nice to confirm what I learned with another source.

Many thanks in advance if anyone can help me out!

Last edited by glodfinch (2018-09-10 07:07:34)

Offline

#2 2018-09-12 00:15:28

Danny-E 33
Administrator
Registered: 2012-06-09
Post 1,114/1,119

Re: [pokered] Sketch implementation

glodfinch wrote:

Now if I've learned anything since I started it's that small logical errors can lead to strange and hard to find bugs :)

That's what makes it so fun and rewarding :)

I haven't ran your code, but by just reading it I noticed a couple things

These few lines:

.checkIfAttacked
  and a ; opponent has attacked yet?
  jp z, .failed
.checkMoveSelected
  ld c, a ; store opponent move for check loop later
  and a ; opponent move invalid?
  jp z, .failed

can be simplified.

The 'and a' instruction will only set the z flag if the value in register a is 0. What this code is effectively doing is:
Jump to .failed if register a is 0
Load register a into register c
Jump to .failed if register a is 0

It can be simplified to this:

.checkIfAttacked
  and a ; opponent has attacked yet?
  jp z, .failed
  ld c, a ; store opponent move for check loop later


Also, you have these three lines:

.sketchEffect
  ld hl, PlayCurrentMoveAnimation ;trigger the animation
  ld b, BANK(PlayCurrentMoveAnimation)
  call Bankswitch

We have a macro to make this easier to type:

.sketchEffect
  callab PlayCurrentMoveAnimation ;trigger the animation

The 'callab' macro loads the address into hl, the bank into b, and then calls Bankswitch



You have this loop to calculate the address of the party mon data:

ld hl, wPartyMons
  ld a, [wPlayerMonNumber] ;amount of times to loop
  and a
  jr z, .loopDone2
  ld de, $2c ;amount to inc hl by
.findPartyMemberLoop ;interate over party members
  add hl, de
  dec a
  jr nz, .findPartyMemberLoop
.loopDone2

But there is a built in AddNTimes: routine in Pokemon Red, and it handles the case when register a is 0, so you don't need to code an extra check.
The AddNTimes: routine adds bc to hl, 'a' times
Also, you can use an expression for the size of a party mon data, instead of hard-coding $2c bytes (the expression is calculated at compile-time)
So you could change it to this:

; push and pop register bc
  push bc
  ld hl, wPartyMons
  ld a, [wPlayerMonNumber] ;amount of times to loop
  ld bc, wPartyMon2 - wPartyMon1 ;amount to inc hl by
  call AddNTimes
  pop bc

But you have to push/pop bc now because you were using b and c for something else
You were using de for adding to hl, but AddNTimes uses bc



You have this bit here:

ld a, NUM_MOVES
  sub b ;move slot to replace
  ld de, $8
  add hl, de ;jump to pokemon moves
  ld de, 0
  ld e, a
  add hl, de ;jump to move slot

I would personally change it to this:

ld a, 8 + NUM_MOVES
  sub b ;move slot to replace
  ld d, 0
  ld e, a
  add hl, de ;jump to move slot

or even better:

ld a, wPartyMon1Moves - wPartyMon1 + NUM_MOVES
  sub b ;move slot to replace
  ld d, 0
  ld e, a
  add hl, de ;jump to move slot

Don't load de with 0, then overwrite e. Only load d with 0, then load e
Only add to hl once. Prepare the whole value to be added (8 + (NUM_MOVES - b)), then add to hl
And '8' can be written as the expression: "wPartyMon1Moves - wPartyMon1"



But I don't notice any bugs. Very good code overall :)

Offline

#3 2018-09-12 06:05:06

glodfinch
Member
Registered: 2018-09-10
Post 2/11

Re: [pokered] Sketch implementation

Wow Danny, thank you for the in depth response!

Danny-E 33 wrote:

These few lines:

.checkIfAttacked
  and a ; opponent has attacked yet?
  jp z, .failed
.checkMoveSelected
  ld c, a ; store opponent move for check loop later
  and a ; opponent move invalid?
  jp z, .failed

can be simplified.

You're right! I think this redundancy occurred when I fixed a previous bug, prior to that a was loaded with different values at the time of each check.

Danny-E 33 wrote:

The 'callab' macro loads the address into hl, the bank into b, and then calls Bankswitch

That's really interesting, I wasn't aware of many macros. Is there any documentation out there on the macros available or should I suck it up and read through the files in the macros folder? Maybe I'm thinking too wishfully, asking for documentation all the time. :)

Danny-E 33 wrote:

But there is a built in AddNTimes: routine in Pokemon Red, and it handles the case when register a is 0, so you don't need to code an extra check.

Just to confirm, AddNTimes is a helper routine built into the game, and not a macro? Is there any particular file I can find routines like this?

Danny-E 33 wrote:
ld a, wPartyMon1Moves - wPartyMon1 + NUM_MOVES

Somehow, I had completely missed that you can do arithmetic like that in an ld instruction. I guess it's only with static values though and the compiler handles it, so the sub b instruction can't be integrated to the ld.

Danny-E 33 wrote:

Don't load de with 0, then overwrite e. Only load d with 0, then load e
Only add to hl once. Prepare the whole value to be added (8 + (NUM_MOVES - b)), then add to hl

Is this purely to save execution cycles?


It'd be great if you could answer me one more question, if you can.
I'm trying to replicate Sketch's attack animation as closely as possible:
https://youtu.be/oBMqOSxaLC8?t=1300

So far I was able to replicate the movements of the sketch pencil for the most part, without issues, though I see the sprite is drawn only black and white (I suspect this is just a limitation of the animation system). My next problem to solve is the lightening/darkening of the pokemon sprite. From what I understand the GBC can set palettes differently for each tile, so that's how it's achieved there, but we have no such luxury on the GB. I was able to add new back sprites for each lighter/darker frame and created a new version of LoadMonBackPic in core.asm that let me load in any back sprite I wanted at any time, but this took roughly a second for each frame - hardly an animation!

So my next idea is to read and write directly to VRAM, because the lighter version of the sprite can be calculated directly from the original 2bpp data, i.e.
colour == %01 || colour == %10 ? colour + 1 : colour

It's a lossy operation so how to undo this is a problem I'll have to solve later.. :) Maybe I could somehow wedge the entire original sprite into WRAM. (I just did some research on this and found the sprite buffers in SRAM - not sure if I can use one of those or have to create a new one)
Anyway, my attempt to do this was with a modified version of the CopyVideoData routine in copy2.asm, where I put the above calculation in between the source and destination. But all this seemed to do was crash the game, even with my modifications to that routine removed. From what I recall in BGB's debugger, I think all the memory was getting replaced with rst. Unfortunately I can't show you because I gave up and deleted my work, but hopefully that's detailed enough to understand what I was doing.

If you have any thoughts on this, or any information on directly modifying VRAM without screwing everything up, I'd really appreciate it.
Sorry for the lengthy question and thanks again for your help!

Last edited by glodfinch (2018-09-12 09:02:19)

Offline

Board footer

Powered by FluxBB