C64 BTII: FILE0278460.PRG (CHAR DISK)

Any developer realated stuff
Weber G
Posts: 125
Joined: Tue Dec 15, 2020 9:58 am

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Weber G »

No problem.

Maybe it was done like I did in the attached file. I have decoded the combat engine and packed it back in the d64 file and added a file name 'combat'. Track 18 is very empty, so there is a lot of space for file names.

Now you have the disassembled combat engine and can go on to investigate the code.

Good luck! 8)
Attachments
Bard's Tale II (Character Disk)_combat.rar
(81.53 KiB) Downloaded 162 times
User avatar
Darendor
Posts: 1502
Joined: Wed Jan 14, 2009 1:53 am
Location: Red Deer, Alberta, Canada

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Darendor »

...

You know how I feel right now? I feel like I'm in 5th grade all over again, and I'm working hard on learning my multiplication tables...and here comes some guy in grade 8 and peers over my shoulder and says, "here let me help you with that", swipes my homework, and does it for me in 10 minutes, then hands it back to me and goes, "here ya go, hope you learned something", and then walks away.

That is more or less how I feel. Way to conpletely deflate me.
Weber G
Posts: 125
Joined: Tue Dec 15, 2020 9:58 am

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Weber G »

Oh, sorry! That wasn't my intention. Just wanted to speed up the analysis of the combat engine. It will be faster analysed when two work on it.
And I didn't need 10min but some hours to build that file.
User avatar
Darendor
Posts: 1502
Joined: Wed Jan 14, 2009 1:53 am
Location: Red Deer, Alberta, Canada

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Darendor »

It's fine, I'll get over it.

I think I mentioned at some point or another that I want to write a 'construction set' for the BTII game engine. That's kind of my whole motivation for doing this.
drifting
Posts: 153
Joined: Wed Dec 07, 2011 10:21 pm

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by drifting »

Weber G wrote: Thu Jan 07, 2021 9:08 am Oh, sorry! That wasn't my intention. Just wanted to speed up the analysis of the combat engine. It will be faster analysed when two work on it.
And I didn't need 10min but some hours to build that file.
Battle pseudocode from the DOS version. The functions seem to be pretty similar between the C64/Apple versions and the DOS version so this might help a little.

Code: Select all

battle_init(){
  saveActiveSongFlag;
  saveActiveSongNumber;

  // Initialize battle variables
  songMissileDamageFlag = 0;
  antiMagicBonus = 0;
  partySongDamageBonus = 0;
  partySongToHitBonus = 0;
  songHealHp = 0;
  party_extraAttacks = 0;
  party_acBonus = 0;

  // Convert song effects to battle effects
  if (song is active) {
    switch (activeSongNumber) {
    case ArchersTune:
      songMissileDamageFlag = 1;
    case SpellSong:
       antiMagicBonus = songBonus[dungeonLevel]
    case MeleeMarch:
       partySongDamageBonus = songBonus[dungeonLevel];
       partySongToHitBonus = songBonus[dungeonLevel];
    case ZanduvarCarack:
       songHealHp = songBonus[dungeonLevel];
    case RhymeOfDuotime:
       party_extraAttacks = 1;
    }
  }

  deactivateSong();
  getOpponents();
  printEncounter();

  do {
    updatePicture();
    getPlayerOptions();
    if (partyRan) {
      // Not a function call. This code is inline and can be called from a few different places
      // and I didn't want to clutter things up
      cleanupAndReturn();
    }

    getTurnPriorities();

    // Advance party
    if (partyAdvances) {
      foreach monsterGroup {
        monsterGroup.distance--
        if (monsterGroup.distance <= 1) {
          monsterGroup.distance = 1
        }
    }
    // Battle round loop
    for (priority == 0xff; priority != 0; priority--) {
      // Only check character actions when party is not advancing
      if (!partyAdvances) {
        foreach character {
          characterTurn();
          if (partyDied) {
            return -1;
          }
        }
      }

      foreach monsterGroup {
        foreach monster in group {
          if (monster.priority == priority) {
            monsterTurn();
            if (partyDied) {
              return -1;
            }
          }
        }
      }
    }

    partyDisbelieves();
    if (partyDied) {
      return -1;
    }

    if (monsterDisbelieveFlag) {
      foreach character {
        if character.isIllusion {
          if savingThrow().Fails {
            Print "Your foes see through your illusion"
            // Interestingly, in the DOS version, nothing happens other than the message is printed
          }
        }
      }
    }

    // Do post-round effects
    doPoisonEffect();
    doEquipmentEffects();
    if (songHealHp != 0) {
      foreach character {
        if player.isNotDisabled {
          character.Hp += songHealHp
          if character.Hp > character.MaxHp {
            character.Hp = character.MaxHp
          }
        }
      }
    postRoundCleanup();

    // The logic around continuing is very convoluted. This is the best representation
    // I can do.
    if monsterGroups.AreEmpty() {
      if party_active() {
        if partyAttack {
          Print "Do you wish to continue?"
          getYesNo();
          if (No) {
            cleanupAndReturn();
          }
        }
      }
    }
  }
}
User avatar
Darendor
Posts: 1502
Joined: Wed Jan 14, 2009 1:53 am
Location: Red Deer, Alberta, Canada

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Darendor »

Hi drifting, do you analyze the 8-bit version of the game too, or just the DOS version?

It seems that the DOS version is coded radically different, but then we know that the port from the 8-bit system wasn't all that spectacular.

Still, everything helps.
drifting
Posts: 153
Joined: Wed Dec 07, 2011 10:21 pm

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by drifting »

Darendor wrote: Fri Jan 08, 2021 12:53 am Hi drifting, do you analyze the 8-bit version of the game too, or just the DOS version?

It seems that the DOS version is coded radically different, but then we know that the port from the 8-bit system wasn't all that spectacular.

Still, everything helps.
I've done a bit with the 8 bit version. Mainly to fix the trap bug.

Coded radically different? Of course. They're completely different architectures. But they used mostly the same game logic between the ports. For example, the "monster to hit" code from Weber G's post viewtopic.php?p=7566#p7566. The DOS code is completely different but the logic is the same. The logic for the first bit of the BT2 function is this:

Code: Select all

Get character AC
Add target monster group's FEAR penalty to AC
If AC is greater than 1Fh then
  set AC to 1Fh
Get monster ToHit value
Add a random amount
Add a monster group spell penalty
If monster ToHit is greater than AC then
  Hit
The DOS code follows the same logic. Knowing the logic ahead of time could make it easier to figure out.
Darendor wrote: Fri Jan 08, 2021 12:53 am but then we know that the port from the 8-bit system wasn't all that spectacular.
The 1 & 2 ports were fine. Especially the Amiga version. BT3 was criminally bad.
User avatar
Darendor
Posts: 1502
Joined: Wed Jan 14, 2009 1:53 am
Location: Red Deer, Alberta, Canada

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Darendor »

drifting wrote: Fri Jan 08, 2021 3:08 am
Darendor wrote: Fri Jan 08, 2021 12:53 am Hi drifting, do you analyze the 8-bit version of the game too, or just the DOS version?

It seems that the DOS version is coded radically different, but then we know that the port from the 8-bit system wasn't all that spectacular.

Still, everything helps.
I've done a bit with the 8 bit version. Mainly to fix the trap bug.

Coded radically different? Of course. They're completely different architectures. But they used mostly the same game logic between the ports. For example, the "monster to hit" code from Weber G's post viewtopic.php?p=7566#p7566. The DOS code is completely different but the logic is the same. The logic for the first bit of the BT2 function is this:

Code: Select all

Get character AC
Add target monster group's FEAR penalty to AC
If AC is greater than 1Fh then
  set AC to 1Fh
Get monster ToHit value
Add a random amount
Add a monster group spell penalty
If monster ToHit is greater than AC then
  Hit
The DOS code follows the same logic. Knowing the logic ahead of time could make it easier to figure out.
Darendor wrote: Fri Jan 08, 2021 12:53 am but then we know that the port from the 8-bit system wasn't all that spectacular.
The 1 & 2 ports were fine. Especially the Amiga version. BT3 was criminally bad.

So the line "If AC is greater than 1Fh then - set AC to 1Fh" is the logic for preventing AC from getting any better than L+, I presume?
User avatar
Darendor
Posts: 1502
Joined: Wed Jan 14, 2009 1:53 am
Location: Red Deer, Alberta, Canada

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Darendor »

So I encountered a curiousity here.

Consider:

Code: Select all

824c 43  a9	LDA #$ff
824d 15  ff
824e 6f  85	STA $ac
824f 46  ac
8250 48  a2	LDX #$06
8251 ec  06
8252 43  a9	LDA #$02
8253 e8  02
8254 77  9d	STA $0390,x
8255 7a  90
8256 e9  03
8257 20  ca	DEX
8258 fa  10	BPL $fa
8259 10  fa
825a 8a  60	RTS
 825b eb  01	
 825c eb  01
 825d e8  02	
 825e e8  02
 825f e8  02
 8260 e9  03
 8261 e9  03
 8262 ee  04	
8263 43	 a9	LDA #$00
8264 ea  00
8265 6f  85	STA $f0
8266 a1  f0 
8267 4f  a5	LDA $e1
8268 0b  e1
8269 3a  d0	BNE $10
826a fa  10
826b 48  a2 	LDX #$00
826c ea  00
826d ca  20  	JSR $0902
826e e8  02
826f e3  09
8270 4a  a0	LDY #$14
8271 fe  14
8272 5b  b1	LDA ($67),y
Observe 825b to 8262; it looks to be a data field or table or somesuch in the middle of the executable code. Is this normal?
Weber G
Posts: 125
Joined: Tue Dec 15, 2020 9:58 am

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Weber G »

drifting, you are completely right. The DOS version with its texts could help a lot, since the logic behind seems to be similar to the C64 version.

I'm always wondering what's stored in the zeropage $F6/ $EA. Now I know it:

first lines of the C64 combat engine (finally with the knowing of $F6/ $EA):

Code: Select all

.C:9000  4C 09 90    JMP $9009		;bard not singing: $D404 = 0; $D40B = 0; bard singing (1): $D404 = 20; $D40B = 20; bard singing (3): $D404 = 41; $D40B = 41
.C:9003  4C DD 9E    JMP $9EDD
.C:9006  4C 05 A4    JMP $A405
.C:9009  20 93 08    JSR $0893		;initialise for random number creation
.C:900c  A5 F6       LDA $F6		;$F6 (bard is singing 0/1) => A
.C:900e  85 EA       STA $EA		;A => $EA (bard is singing 0/1)
.C:9010  20 14 09    JSR $0914		;clear $F6 $D404 $D40B
.C:9013  20 DC 95    JSR $95DC		;identify which monsters are attacking (#, hit point creation)	
.C:9016  20 D3 A7    JSR $A7D3		;sort monster groups by distance
.C:9019  20 A6 9C    JSR $9CA6		;text output which monsters attack (encounter text)
.C:901c  A9 00       LDA #$00		;0 => A
.C:901e  85 4D       STA $4D		;A => $4D
.C:9020  E6 C1       INC $C1		;increase $C1
Darendor, yes, sometines there are data flieds between the code:

Code: Select all

.C:4063  90 F1       BCC $4056		;Y < B8 => jump
.C:4065  E6 FA       INC $FA		;increase $FA
.C:4067  A6 FA       LDX $FA		;$FA => X
.C:4069  E0 78       CPX #$78
.C:406b  90 BA       BCC $4027		;X < 78h => jump
.C:406d  CE 76 40    DEC $4076		;decrease ######$4076
.C:4070  A0 0D       LDY #$0D		;0D => Y
.C:4072  20 5F 1D    JSR $1D5F		
.C:4075  A9 00       LDA #$00		;######$401A => A/ $406D
.C:4077  D0 AA       BNE $4023		;A <> 0 => jump
.C:4079  60          RTS

########## $407A - $4099
>C:407a  01 01 01 01  01 01 01 01  01 01 02 02  04 04 08 08   ................
>C:408a  08 08 08 08  08 08 08 08  08 08 04 04  02 02 01 01   ................
##############################################################################

###################################################################
########## clear text window
###################################################################
.C:409a  8E D1 40    STX $40D1		;X => ######$40D1
.C:409d  8C D3 40    STY $40D3		;Y => ######$40D3
.C:40a0  A2 18       LDX #$18		;18 => x
.C:40a2  BD 00 B6    LDA $B600,X	;B600,X => A
.C:40a5  18          CLC
.C:40a6  69 80       ADC #$80		;add 80h to A
.C:40a8  8D B8 40    STA $40B8		;A => ######$40B8
.C:40ab  BD 00 B7    LDA $B700,X	;B700,X => A
.C:40ae  69 00       ADC #$00		;add 0 to A
.C:40b0  8D B9 40    STA $40B9		;A => ######$40B9
User avatar
Darendor
Posts: 1502
Joined: Wed Jan 14, 2009 1:53 am
Location: Red Deer, Alberta, Canada

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Darendor »

How did you guys figure out what the code does and why/where?

I'm just curious. I haven't yet finished deciphering the file entirely yet, and am just wondering what you all look for.

Like for instance, this:

Code: Select all

.C:9000  4C 09 90    JMP $9009		;bard not singing: $D404 = 0; $D40B = 0; bard singing (1): $D404 = 20; $D40B = 20; bard singing (3): $D404 = 41; $D40B = 41
How did you know that was about the bard singing, and what does the "bard singing (1) mean vs bard singing (3)"? 2 different songs?
Weber G
Posts: 125
Joined: Tue Dec 15, 2020 9:58 am

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Weber G »

Which tool do you use? You don't have to decipher the code. There are tool which can do this in seconds. I didn't know this bard singing variables. But after I have taken a look at the DOS code from drifting, I tried it => let the bard sing, set a break point and check the variables and also the memory. That's all.
User avatar
Darendor
Posts: 1502
Joined: Wed Jan 14, 2009 1:53 am
Location: Red Deer, Alberta, Canada

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Darendor »

I'm not using any tool besides DirMaster and 2 copies of NotePad.

What do you think of this: https://c64preservation.com/files/EaLoader.txt

It's a documentation about Electronic Arts' loader back in the day. :shock:
Weber G
Posts: 125
Joined: Tue Dec 15, 2020 9:58 am

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by Weber G »

You will have no success if you only use DirMaster. Please use Vice!

These are two different things. The loader in your link is, as far as I can see in short, the autoloader which starts a game.

But to load from disk, BT2 has it's own 'loader' which loads from disk to the RAM.

The latter is of interest for us.

Here is the 'heart' of the loader (load modus):

Code: Select all

.C:fd87  20 CC FD    JSR $FDCC
.C:fd8a  2C 00 DD    BIT $DD00
.C:fd8d  50 FB       BVC $FD8A
.C:fd8f  38          SEC
.C:fd90  A6 02       LDX $02
.C:fd92  AD 12 D0    LDA $D012
.C:fd95  E9 32       SBC #$32		######6
.C:fd97  90 04       BCC $FD9D
.C:fd99  29 07       AND #$07
.C:fd9b  F0 F5       BEQ $FD92
.C:fd9d  8E 00 DD    STX $DD00
.C:fda0  8A          TXA
.C:fda1  09 20       ORA #$20
.C:fda3  AA          TAX
.C:fda4  EA          NOP
.C:fda5  EA          NOP
.C:fda6  A9 FF       LDA #$FF		######7 ######8
.C:fda8  AD 00 DD    LDA $DD00
.C:fdab  4A          LSR A
.C:fdac  4A          LSR A
.C:fdad  EA          NOP
.C:fdae  4D 00 DD    EOR $DD00
.C:fdb1  4A          LSR A
.C:fdb2  4A          LSR A
.C:fdb3  EA          NOP
.C:fdb4  24 80       BIT $80		#######9 #######10
.C:fdb6  4D 00 DD    EOR $DD00
.C:fdb9  4A          LSR A
.C:fdba  4A          LSR A
.C:fdbb  45 02       EOR $02
.C:fdbd  4D 00 DD    EOR $DD00
.C:fdc0  8E 00 DD    STX $DD00
.C:fdc3  49 FF       EOR #$FF
.C:fdc5  99 3E FB    STA $FB3E,Y
.C:fdc8  C8          INY
.C:fdc9  D0 C4       BNE $FD8F
.C:fdcb  60          RTS
As you can see, it loads directly from $DD00 (serial interface CIA) to the buffer $FB3E.
drifting
Posts: 153
Joined: Wed Dec 07, 2011 10:21 pm

Re: C64 BTII: FILE0278460.PRG (CHAR DISK)

Post by drifting »

Darendor wrote: Fri Jan 08, 2021 8:22 am So the line "If AC is greater than 1Fh then - set AC to 1Fh" is the logic for preventing AC from getting any better than L+, I presume?
Well, that's one place that prevents it. Really anywhere in the code where the AC is updated, the same code runs. So if you put on a piece of armor, the AC is recalculated and the same code is run.
Post Reply