Skeetendo

’Cause all games were better on the GBC

You are not logged in.

  • Index
  • → Generation I
  • → [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

#1 2016-09-14 00:43:26

MechanicalPen
Member
Registered: 2016-06-22
Post 11/29

[pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

I'm sure you've all seen this video before Which shows off some unused text. Presumably it was left over from when losing to enemy trainers didn't end the game. But did you know that most of the functionality to restore it already exists in the game's code?

Today, I'm gonna show you how use the code left behind to give enemy trainers victory quotes if they win (in five minutes or less!)

We start with the code that makes the player black out once all their pokemon are fainted. Interestingly, this code DOES already display a win quote, but only for the first Rival fight. It looks like this:

; called when player is out of usable mons.
; prints approriate lose message, sets carry flag if player blacked out (special case for initial rival fight)
HandlePlayerBlackOut:
    ld a, [wLinkState]
    cp LINK_STATE_BATTLING
    jr z, .notSony1Battle
    ld a, [wCurOpponent]
    cp OPP_SONY1 ;is the current opponent Rival1?
    jr nz, .notSony1Battle ;if not, don't print our message.
    coord hl, 0, 0
    lb bc, 8, 21
    call ClearScreenArea ;clear the top-right of the screen in case there's a pokemon there.
    call ScrollTrainerPicAfterBattle
    ld c, 40
    call DelayFrames
    ld hl, Sony1WinText
    call PrintText
    ld a, [wCurMap]
    cp OAKS_LAB
    ret z            ; starter battle in oak's lab: don't black out
.notSony1Battle
    ld b, SET_PAL_BATTLE_BLACK
    call RunPaletteCommand
    ld hl, PlayerBlackedOutText2
    ld a, [wLinkState]
    cp LINK_STATE_BATTLING
    jr nz, .noLinkBattle
    ld hl, LinkBattleLostText
.noLinkBattle
    call PrintText
    ld a, [wd732]
    res 5, a
    ld [wd732], a
    call ClearScreen
    scf
    ret

This code slides in a trainer sprite, and prints a message but only if we are fighting SONY1. We want it to print a message if we are fighting any trainer! So let's change the check. We want something like:

; called when player is out of usable mons.
; prints approriate lose message, sets carry flag if player blacked out (special case for initial rival fight)
HandlePlayerBlackOut:
    ld a, [wLinkState]
    cp LINK_STATE_BATTLING
    jr z, .notSony1Battle
    ld a, [wIsInBattle]
    dec a ;is the battle a wild battle?
    jr z, .notSony1Battle ;if so, don't print our message.
    coord hl, 0, 0
    ;rest of method here...

We're getting there. When the player loses to a trainer the game will show the message "BLUE: Yeah! Am I great or what?" How could we change this so the game prints a unique message for every trainer? Let's go searching... How does the game print a unique message for every trainer beaten? Our search leads us to;

TrainerBattleVictory:
    call EndLowHealthAlarm
    ld b, MUSIC_DEFEATED_GYM_LEADER
    ld a, [wGymLeaderNo]
    and a
    jr nz, .gymleader
    ld b, MUSIC_DEFEATED_TRAINER
.gymleader
    ld a, [wTrainerClass]
    cp SONY3 ; final battle against rival
    jr nz, .notrival
    ld b, MUSIC_DEFEATED_GYM_LEADER
    ld hl, wFlags_D733
    set 1, [hl]
.notrival
    ld a, [wLinkState]
    cp LINK_STATE_BATTLING
    ld a, b
    call nz, PlayBattleVictoryMusic
    ld hl, TrainerDefeatedText
    call PrintText
    ld a, [wLinkState]
    cp LINK_STATE_BATTLING
    ret z
    call ScrollTrainerPicAfterBattle
    ld c, 40
    call DelayFrames
    call PrintEndBattleText ;<<<<<<<<<<<<<<<<<<<<<<WE FOUND IT!
; win money
    ld hl, MoneyForWinningText
    call PrintText
    ld de, wPlayerMoney + 2
    ld hl, wAmountMoneyWon + 2
    ld c, $3
    predef_jump AddBCDPredef

So, 'PrintEndBattleText' prints out text once a battle is over. If we go back to 'HandlePlayerBlackOut:' and call 'PrintEndBattleText' we'll have different text for every trainer! Let's do it;

; called when player is out of usable mons.
; prints approriate lose message, sets carry flag if player blacked out (special case for initial rival fight)
HandlePlayerBlackOut:
    ld a, [wLinkState]
    cp LINK_STATE_BATTLING
    jr z, .notSony1Battle
    ld a, [wIsInBattle]
    dec a ;is the battle a wild battle?
    jr z, .notSony1Battle ;if so, don't print our message.
    coord hl, 0, 0
    lb bc, 8, 21
    call ClearScreenArea ;clear the top-right of the screen in case there's a pokemon there.
    call ScrollTrainerPicAfterBattle
    ld c, 40
    call DelayFrames
    ;ld hl, Sony1WinText ;We don't need these two lines anymore.
    ;call PrintText           ;feel free to delete!
    call PrintEndBattleText
    ld a, [wCurMap]
    cp OAKS_LAB
    ret z            ; starter battle in oak's lab: don't black out
.notSony1Battle
    ld b, SET_PAL_BATTLE_BLACK
    call RunPaletteCommand
    ld hl, PlayerBlackedOutText2
    ld a, [wLinkState]
    cp LINK_STATE_BATTLING
    jr nz, .noLinkBattle
    ld hl, LinkBattleLostText
.noLinkBattle
    call PrintText
    ld a, [wd732]
    res 5, a
    ld [wd732], a
    call ClearScreen
    scf
    ret

Surprisingly, that's all you have to do to restore (most if not all) the Rival win quotes from that youtube video at the top! It all has to do with this little method. Yes, the game does actually load lose battle quotes for trainers by default! If we search for all instances of 'SaveEndBattleTextPointers' We can see that lose quotes ([wEndBattleLoseTextPointer]) are set in various scripts and in TalkToTrainer:: but they are usually set to the same thing as win quotes. In the case TalkToTrainer, they are loaded from trainer headers but there is actually a bug which prevents them from loading correctly. So, let's fix ReadTrainerHeaderInfo::

; reads specific information from trainer header (pointed to at wTrainerHeaderPtr)
; a: offset in header data
;    0 -> flag's bit (into wTrainerHeaderFlagBit)
;    2 -> flag's byte ptr (into hl)
;    4 -> before battle text (into hl)
;    6 -> after battle text (into hl)
;    8 -> win battle text (into hl)
;    A -> lose battle text (into de)
ReadTrainerHeaderInfo::
    push de
    push af
    ld d, $0
    ld e, a
    ld hl, wTrainerHeaderPtr
    ld a, [hli]
    ld l, [hl]
    ld h, a
    add hl, de
    pop af
    and a
    jr nz, .nonZeroOffset
    ld a, [hl]
    ld [wTrainerHeaderFlagBit], a  ; store flag's bit
    jr .done
.nonZeroOffset
    cp $2
    jr z, .readPointer ; read flag's byte ptr
    cp $4
    jr z, .readPointer ; read before battle text
    cp $6
    jr z, .readPointer ; read after battle text
    cp $8
    jr z, .readPointer ; read end battle text
    cp $a
    jr nz, .done
    pop de           ;BUGFIX: we pushed de onto the stack at the top, so we have to pop it off the stack to keep things symmetrical.
    ld a, [hli]        ; read end battle text (2) but override the result afterwards (XXX why, bug?)
    ld d, [hl]
    ld e, a
    ret            ;BUGFIX: de contains the lose quote loaded from the trainer header. We are done here.  
    ;jr .done    ;BUGFIX: this replaces de (the value we just loaded) with the value on the top of the stack. That's not the behavior we want.
.readPointer
    ld a, [hli]
    ld h, [hl]
    ld l, a
.done
    pop de
    ret

That's everything! All that's left is to edit all the scripts and trainer headers to have lose quotes instead of two win quotes. (due to limitations, the win and lose quote pointers have to be in the same place. But you can TX_FAR to the actual text that is located anywhere). I hope this tutorial wasn't too confusing. Next time, we'll look at how to get Mimic's menu working over link cable.

Offline

#2 2016-10-09 19:24:49

Fotomac
Member
Registered: 2015-10-25
Post 241/332

Re: [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

That's actually fairly easy to understand. Except for the TX_FARing part, though.

Offline

#3 2016-10-10 17:07:16

MechanicalPen
Member
Registered: 2016-06-22
Post 25/29

Re: [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

TX_FAR is a macro in pokered for the text command that looks up text in any bank. just search for it in the pokered codebase and you can see how it is used. But, here is an example:

ViridianGymBattleLoseText:
    TX_FAR _ViridianGymBattleLoseText
    db "@"

ViridianGymBattleWinText:
    TX_FAR _ViridianGymBattleWinText
    db "@"

for win / lose quotes, ViridianGymBattleLoseText and ViridianGymBattleWinText have to be in the same bank (and they are the pointers you reference in the trainer's header.) But _ViridianGymBattleLoseText and _ViridianGymBattleWinText can be anywhere they'll fit. The text engine can look them up (because you told it to with TX_FAR.)

Offline

#4 2016-10-10 17:16:47

Fotomac
Member
Registered: 2015-10-25
Post 242/332

Re: [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

Which of the four pointer spots from the top would the "lose" text go, in relation to the "challenge" text, the "win" text, and the "post-battle" text?

Offline

#5 2016-10-11 18:37:47

MechanicalPen
Member
Registered: 2016-06-22
Post 26/29

Re: [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

This line right here is a hint. It appears to be in the order before, after, win, lose. But, try it and see!

Offline

#6 2016-11-04 18:34:42

lusentoj
Member
From: Sweden
Registered: 2016-02-29
Post 31/31

Re: [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

Thanks a ton, I used this to restore RIVAL's text in my hack!!

Offline

#7 2018-06-17 14:16:26

TRIFORCE89
Member
Registered: 2013-05-20
Post 22/29

Re: [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

This is pretty good. I've removed the printing of the trainer name because some of the text already has the Rival's name in it. I'm not using your code to apply it to all trainers either.

The only problem I'm encountering is that the battle music restarts when losing to a non-rival trainer. Any idea why or how to fix it?

Offline

  • Index
  • → Generation I
  • → [pokered Tutorial] 5 Minute Improvement #1 Restoring Trainer Lose Text

Board footer

Powered by FluxBB