Skeetendo

’Cause all games were better on the GBC

You are not logged in.

#1 2017-06-07 23:23:22

Noah
New member
Registered: 2017-06-07
Post 1/2

[Pokecrystal] Adding a new trainer bank

Hi,

I'm working on a hack and plan to have scaled gyms dependent on the number of badges the player has at the time of the battle.

I've split the trainers.asm up into two sections using the same tactic from Polished Crystal because there is not enough room to fit it all:

SECTION "Enemy Trainer Parties 1", ROMX, BANK[$E]

and

SECTION "Enemy Trainer Parties 2", ROMX

This is also declared in main.asm:

SECTION "Enemy Trainer Pointers", ROMX, BANK[$E]

The first bank works fine, but the second bank does not. Any trainer loaded will have all fainted and random Pokemon (plus a glitched name as well) so it seems that the data isn't even being loaded. Oddly enough, if I remove the BANK[$E] portion from trainers.asm and main.asm the second bank works fine but when battling a trainer from the first bank the game crashes.

So my question is, is there a particular class where the information is pulled from trainers.asm where I could make sure it checks through both sections and not just one or the other?

Thanks!

Offline

#2 2017-06-07 23:36:29

Rangi
Member
Registered: 2016-05-09
Post 708/870

Re: [Pokecrystal] Adding a new trainer bank

Look at the whole commit Modify read_party.asm (and a few other places that read party data like in wildmons.asm) to use GetFarByte instead of loading [hl] directly.


Pokémon Polished Crystal (GitHub) — version 2.2.0 released
Pokémon Red★ and Blue★: Space World Edition (GitHub) — updated August 19!
Polished Map: pokered+pokecrystal map, tileset, and palette editor — version 3.5.1 released!

Offline

#3 2017-06-08 00:37:58

Noah
New member
Registered: 2017-06-07
Post 2/2

Re: [Pokecrystal] Adding a new trainer bank

I've made all of the changes from the commit, and now the compiler outputs this:

ERROR:  main.asm(1705) -> trainers/read_party.asm(307) :
        PC-relative value must be 8-bit
rgbasm: Assembly aborted in pass 2 (1 errors)!
Makefile:50: recipe for target 'main.o' failed

In read_party.asm, line 307 is:

jr .loop

From this:

.copied_pp

    pop hl
    jr .loop
; 3991b

And in main.asm:

INCLUDE "trainers/read_party.asm"

I've tried changing jr to jp but no luck, the trainer battles will freeze upon entering.

Any suggestions?

Thanks! :D

Last edited by Noah (2017-06-08 00:38:24)

Offline

#4 2017-06-08 02:43:22

Rangi
Member
Registered: 2016-05-09
Post 709/870

Re: [Pokecrystal] Adding a new trainer bank

There are many reasons why it might freeze, including using the wrong version of RGBDS. Make sure to use release 0.2.5. Apart from that, BGB's debugger may help you. You can step through the code line by line and keep track of the registers, RAM values, etc.


Pokémon Polished Crystal (GitHub) — version 2.2.0 released
Pokémon Red★ and Blue★: Space World Edition (GitHub) — updated August 19!
Polished Map: pokered+pokecrystal map, tileset, and palette editor — version 3.5.1 released!

Offline

#5 2017-06-17 06:03:04

ShockSlayer
Member
Registered: 2017-06-17
Post 1/15

Re: [Pokecrystal] Adding a new trainer bank

Hello, I'm a friend of Noah's who's also working on the project.

He eventually got the second bank working about a week ago. The commit was very helpful, and the problem ended up being us having the trainer type line formatted incorrectly in trainers.asm.

So far scripted battles work and we're able to scale them just fine, similar to how the game handles the phone call re-battles. But as we've found out normal trainers are called a bit differently, so I'm looking for a bit of advice on how to keep moving forward with this.

To preface, I don't really know assembly at all. I can kinda follow by example, and with enough time maybe figure out how to do something simple, but that's about it. The forums have been very helpful as well, so if someone else comes across this, I'll try to lay it out as best I can.

Anyways, here's basically what our Falkner scripts look like:

FalknerScript_0x683c2:
    faceplayer
    opentext
    checkevent EVENT_BEAT_FALKNER
    iftrue .FightDone
    writetext UnknownText_0x68473
    waitbutton
    closetext
    checkcode VAR_BADGES
    if_equal 0, .Falkner0Badge
   (etc...)
    if_greater_than 14, .Falkner15Badge
.Falkner0Badge
    winlosstext UnknownText_0x6854a, 0
    loadtrainer FALKNER, 1
    startbattle
    reloadmapafterbattle
    jump .FalkerDefeated
    (etc...)

Everything's spread out pretty nice and it's easy to have it jump around based on the number of badges.

But a normal gym trainer's script is a single line like this:

TrainerBird_keeperAbe:
    trainer EVENT_BEAT_BIRD_KEEPER_ABE, BIRD_KEEPER, ABE16, Bird_keeperAbeSeenText, Bird_keeperAbeBeatenText, 0, Bird_keeperAbeScript

Granted I've changed "ABE" to "ABE16", as I've laid out the trainer_constants.asm that way(so the 0 badges team is ABE1, all the way up to ABE16.) Also recently figured out that the order that's in there needs to match the order of the TrainerGroups in trainers.asm, as I noticed a Birdkeeper on Route 44 was loading the wrong data. Anyways, it's all one line, and doesn't seem to like the same scripting format as before. As far as I can tell, "trainer" is some kind of macro. I tried looking at trainer.asm but I've never been more confused in my life.

Ideally I'd like to figure out if it's possible to append a variable to text, so we could just throw that in there and be done with it, but I've got no idea how to do that either. Any advice is appreciated.

Offline

#6 2017-06-17 06:31:12

Rangi
Member
Registered: 2016-05-09
Post 726/870

Re: [Pokecrystal] Adding a new trainer bank

So, you want a normal trainer NPC, the sort that sees you a certain distance away and automatically walks up and so on, but that loads a different trainer ID depending on some variable like the number of badges. Interesting! And not actually possible with the existing system.

You could fake a so-called "variable trainer" that sees N tiles ahead by putting a line of N "xy_triggers" in front of them. xy_triggers run a certain script when you step on them; it's how the lady stops you from leaving New Bark Town. However, this would be limited and unwieldy. It would be difficult to have more than one variable trainer on the same map, and even more difficult to allow fighting them in any order. And you would not be able to have variable trainers that spin.

Another way to do this would be to create a new PERSONTYPE. It could be very similar to PERSONTYPE_TRAINER, except it would add your number of badges to the trainer ID before loading it. So you'd have to make them always in order, like ABE0 to ABE16, and you'd need all seventeen possibilities for every variable trainer. Of course, you could make a more general system, like where you could specify a variable other than badges, but that would get more complex, and I'm guessing you just need badge-based ones anyway for some kind of nonlinear game.

Or, you could try a different trainer type. See how in trainers.asm, 0 is a normal trainer, 1 has moves, 2 has an item, and 3 has item + moves? You could add 4, 5, 6, and 7, which act like those types but skip ahead based on the number of badges. You would have to edit read_party.asm to implement it, but I think that would be the most flexible solution, and actually the simplest compared with the alternatives. Basically you'd need to add four more entries to the TrainerTypes table in read_party.asm, which check your number of badges, skip that many $fe values, and then act like the first four types but end on a $fe or a $ff.

Last edited by Rangi (2017-06-17 08:08:35)


Pokémon Polished Crystal (GitHub) — version 2.2.0 released
Pokémon Red★ and Blue★: Space World Edition (GitHub) — updated August 19!
Polished Map: pokered+pokecrystal map, tileset, and palette editor — version 3.5.1 released!

Offline

#7 2017-06-17 08:08:05

Rangi
Member
Registered: 2016-05-09
Post 727/870

Re: [Pokecrystal] Adding a new trainer bank

Alright, I got the variable trainer type working! Here's the code. Basically I added this trainer type:

TrainerType5:
; variable
    ld h, d
    ld l, e

    ; Get the number of badges in a, c, and [wd265]
    push hl
    ld hl, Badges
    ld b, 2
    call CountSetBits
    pop hl

    ; For each badge, skip up to an $fe delimiter
.outerloop
    ld a, c
    and a
    jr z, .continue
.innerloop
    ld a, [hli]
    cp $fe
    jr nz, .innerloop
    dec c
    jr .outerloop

.continue
    ; Get the actual trainer type of the variable stage for this badge count
    ld a, [hli]
    ld c, a
    ld b, 0
    ld d, h
    ld e, l
    ld hl, TrainerTypes
    add hl, bc
    add hl, bc
    ; Jump to it
    ld a, [hli]
    ld h, [hl]
    ld l, a
    ld bc, ComputeTrainerReward
    jp [hl]

Of course I added TrainerType5 to the end of the TrainerTypes table, and edited the other four trainer types so they return when they encounter $fe as well as $ff. (The exact lines to do that are in the commit I linked.)

I also edited Falkner and his two Gym Trainers to demonstrate how the format works. Here's an example:

; FALKNER (1)
    db "FALKNER@"
    db 4 ; variable

    ; stage 0
    db 1 ; moves
    ; party
    db 7, PIDGEY
        db TACKLE
        db MUD_SLAP
        db 0
        db 0
    db 9, PIDGEOTTO
        db TACKLE
        db MUD_SLAP
        db GUST
        db 0
    db $fe ; delimiter

    ...

    ; stage 6
    db 3 ; item + moves
    ; party
    db 33, PIDGEOTTO, NO_ITEM
        db MUD_SLAP
        db FLY
        db QUICK_ATTACK
        db WING_ATTACK
    db 35, PIDGEOT, SHARP_BEAK
        db MUD_SLAP
        db FLY
        db QUICK_ATTACK
        db WING_ATTACK
    db $fe ; delimiter

    ...

    ; stage 16
    db 3 ; item + moves
    ; party
    db 58, PIDGEOT, NO_ITEM
        db MUD_SLAP
        db FLY
        db QUICK_ATTACK
        db WING_ATTACK
    db 60, PIDGEOT, SHARP_BEAK
        db MUD_SLAP
        db FLY
        db QUICK_ATTACK
        db WING_ATTACK
    db $ff ; end

A few things to note about this:

• One trainer ID applies to all 17 parties, depending on your badge count. So you don't have to repeat the trainer's name 17 times.
• Each party can have its own actual type (normal, item, moves, or item+moves).
• Each stage ends in $fe, except the last one ends in $ff.
• It should be easy to add more trainer types that vary based on something other than badge count.

Last edited by Rangi (2017-06-17 09:21:39)


Pokémon Polished Crystal (GitHub) — version 2.2.0 released
Pokémon Red★ and Blue★: Space World Edition (GitHub) — updated August 19!
Polished Map: pokered+pokecrystal map, tileset, and palette editor — version 3.5.1 released!

Offline

#8 2017-06-17 08:27:40

ShockSlayer
Member
Registered: 2017-06-17
Post 2/15

Re: [Pokecrystal] Adding a new trainer bank

Oh wow, this is really awesome! Thank you so much! I'm a bit concerned because our read_party.asm is copied directly from polishedcrystal, as that was the only way we were able to get multiple banks working, plus the nickname feature was too good to pass up. Is it possible to adapt this to that?

EDIT: I don't mean to sound presumptuous, I really really appreciate all the help so far.

Last edited by ShockSlayer (2017-06-17 08:32:57)

Offline

#9 2017-06-17 08:48:18

Rangi
Member
Registered: 2016-05-09
Post 728/870

Re: [Pokecrystal] Adding a new trainer bank

ShockSlayer wrote:

Oh wow, this is really awesome! Thank you so much! I'm a bit concerned because our read_party.asm is copied directly from polishedcrystal, as that was the only way we were able to get multiple banks working, plus the nickname feature was too good to pass up. Is it possible to adapt this to that?

Definitely! Just replace this part of ReadTrainerParty:

call GetNextTrainerDataByte
    ld [OtherTrainerType], a

.loop2
; level
    call GetNextTrainerDataByte
    cp $ff
    ret z

    ld [CurPartyLevel], a

With this:

call GetNextTrainerDataByte
    ld [OtherTrainerType], a

; variable?
    bit TRNTYPE_VARIABLE, a
    jr z, .not_variable
    ; get badge count in c
    push hl
    ld hl, Badges
    ld b, 2
    call CountSetBits
    pop hl
    ; skip that many $fe delimiters
.outerloop
    ld a, c
    and a
    jr z, .continue
.innerloop
    call GetNextTrainerDataByte
    cp $fe
    jr nz, .innerloop
    dec c
    jr .outerloop
.continue
    ; get trainer type of variable stage
    call GetNextTrainerDataByte
    ld [OtherTrainerType], a
.not_variable

.loop2
; level
    call GetNextTrainerDataByte
    cp $ff
    ret z
    cp $fe
    ret z

    ld [CurPartyLevel], a

And of course define TRNTYPE_VARIABLE along with the rest. (I'm guessing you got rid of TRNTYPE_PERSONALITY and reduced TRNTYPE_DVS back down to two bytes instead of three.)

By the way, if you're using my code, have you encountered this bug? Try having a trainer class with low default DVs, and give a particular one high custom DVs. I think you'll see them missing HP. And if you do the opposite, custom low for default high, they'll have extra HP.

Also, note that since $ff is the end-of-trainer marker and $fe is the variable stage delimiter, you can't use either of those as data values. So be careful if you added a new move with ID $fe, or if "8" ($fe) or "9" ($ff) is in a nickname, etc.

EDIT: I don't mean to sound presumptuous, I really really appreciate all the help so far.

Don't worry, I'm doing this for fun. I do hope you're getting better at reading and writing asm yourselves. Porting my extended ReadTrainerParty and multiple-bank systems is already progress. I tried commenting this variable-party code, so see if you can understand how it works. Eventually you'll be writing your own custom systems. :)

(One that you'll probably need eventually: variable wild Pokémon. All you really need is to scale their levels by the badge count. No need to worry about evolutionary stages, a wild level 50 Pidgey is IMO "acceptable" whereas a trainer with a level 50 Pidgey is not.)

Last edited by Rangi (2017-06-17 09:06:35)


Pokémon Polished Crystal (GitHub) — version 2.2.0 released
Pokémon Red★ and Blue★: Space World Edition (GitHub) — updated August 19!
Polished Map: pokered+pokecrystal map, tileset, and palette editor — version 3.5.1 released!

Offline

#10 2017-06-17 10:03:10

ShockSlayer
Member
Registered: 2017-06-17
Post 3/15

Re: [Pokecrystal] Adding a new trainer bank

I'm so thrilled with this. I'm looking at it now and it looks like we only removed personality, but we didn't touch and haven't used DVs for anything so I've never seen the bug. I guess that also means that it's trying to load a 3rd byte that isn't there...I had no idea, so I guess we'll have to fix that.

Anyways, I tested out the code myself and it works great! Although I have a lot of data to go back and reformat, I'm so glad to finally be able to knock this out once and for all, and being able to cut down on the amount of scripting is a very nice bonus. I don't think I'll even need to modify most of the gym scripts now!

We never considered scaling the wild Pokémon; but then again I didn't think it was even possible. Plus I dunno how that'd work if you beat all the gyms, and wanted to train a freshly hatched Pokémon, but if it was a toggle-able option, that could work out really well, or maybe only certain areas could be scaled. I'll have to give it some thought.

Thanks again, this is a huge help!

Offline

Board footer

Powered by FluxBB