http://www.dungeon-master.com/forum/vie ... 27&t=27791
http://www.dungeon-master.com/forum/vie ... 46&t=23134
Today I can say I have the final explanation on this question. I am 100% positive that this bug is found in CSBwin only and not in the original game on Atari ST. Sophia identified this bug in the past but it was never fixed in CSBwin (except in a special test version).
The bug lies in the function named TAG016426, as found in the CSBwin 12.3 source code (in Character.cpp).
Paul, when converting the game you were confused by some strange machine code and added this comment in your source code: "They stored a word and fetch a byte!"
Here is a disassembly of the original machine code for this function as found in CSB 2.0 for Atari ST:
Code: Select all
link a6,#-$000A
move.w d7,-(a7)
move.w $000C(a6),d0
movea.l $0008(a6),a0
muls #$0003,d0
lea $0047(a0),a0
adda.w d0,a0
move.b (a0),d0 The byte containing the current value of the statistic (like Antifire or Antimagic) is copied to d0
move.w d0,-$000A(a6) A word is stored in a local variable, with the high byte not properly initialized. Stange, but in fact this is not an issue, see below.
move.w #$00AA,d0
clr.w d3 This high byte of d3 is set to 0
move.b -$000A(a6),d3 Only the low byte of the word is used from the local variable, so we don't care what the value of the high byte was
sub.w d3,d0
move.w d0,d7 d7 now contains 170 - CurrentStatisticValue. There is no division by 256 to be found anywhere.
cmpi.w #$0010,d0
bge.s L16460
move.w $000E(a6),d0
lsr.w #3,d0
bra.s L16470
L16460 move.w d7,-(a7)
move.w #$0007,-(a7)
move.w $000E(a6),-(a7)
jsr $0198(a5)
addq.l #6,a7
L16470 move.w (a7)+,d7
unlk a6
rts
Code: Select all
unsigned int F307_fzzz_CHAMPION_GetStatisticAdjustedAttack(P642_ps_Champion, P643_ui_StatisticIndex, P644_ui_Attack)
CHAMPION* P642_ps_Champion;
unsigned int P643_ui_StatisticIndex;
unsigned int P644_ui_Attack;
{
register int L0927_i_Factor;
if ((L0927_i_Factor = 170 - P642_ps_Champion->Statistics[P643_ui_StatisticIndex][INDEX1_CURRENT]) < 16) {
return P644_ui_Attack >> 3;
}
return F030_aaaW_MAIN_GetScaledProduct(P644_ui_Attack, 7, L0927_i_Factor);
}
As you see, there is only one local variable L0927_i_Factor, stored in a register (the compiler actually assigns d7 to store L0927_i_Factor).
The 10 bytes of local variable storage allocated by the instruction "link a6,#-$000A" are for an additional "hidden" variable added automatically by the compiler and in which the program stores a temporary value with instruction "move.w d0,-$000A(a6)".
Sometimes, when evaluating an expression, the compiler needs to store a temporary value somewhere. In this purpose, the compiler creates an additional local variable with a fixed size of 10 bytes (don't ask me why this size), even if the temporary value to store is smaller. That is why the code looks confusing. Note that there are many other functions in the game where such 10 bytes temporary local variables are present, all added by the compiler.
Consequently, the current code in CSBwin is wrong in function TAG016426:
Code: Select all
D7W = sw(170 - w_10/256);
Code: Select all
D7W = sw(170 - w_10);