zinx" wrote:If you could provide details, I can probably easily patch them back to 1.10 as well. I don't know the details of the differences between the versions, sadly.

I have located the main multiplication routines used in both Diablo 1.10 and 1.12a.

There are two different ones, and they are identical across versions, but the game uses different variants in different versions.

I repeat,

**the damage calculation between 1.10 and 1.12a differs**.

One is a fixed-point multiply with a scaling factor of 1/128 (7-bit precision),

the other is a fixed-point multiply with a scaling factor of 1/100.

The two different variants are used in different places in 1.10 vs 1.12a.

In particular, at the very least, some of the weapon damage is calculated with the 1/100 variant in version 1.10, while the 1/128 variant is used in 1.12a.

Code: Select all

```
/* Pseudo-code. If it's valid C, you got lucky. */
int div128_32(int a) {
if (a < 0) a += 127;
return a / 128;
}
int mul_div128(int a, int b) {
if (a <= 0x1000000) {
if (b <= 0x10000) {
/* Full precision 32-bit multiply/divide */
/* Wraps if log2(a) + log2(b) >= 31 */
return div128_32(a * b, 128);
} else if ((b & ~0xf) < 128*16) {
/* Full precision 64-bit multiply/divide */
unsigned long long la = a, lb = b;
return (int) ((la*lb) / 128ULL);
} else {
/* Reduced precision of b, 32-bit multiply/divide */
/* Wraps if log2(a) + log2(b/128) >= 31 */
b = div128_32(b);
return a * b;
}
} else if ((a & ~0xf) < 128*16) {
/* Full precision 64-bit multiply/divide */
unsigned long long la = a, lb = b;
return (int) ((la*lb) / 128ULL);
} else {
/* Reduced precision of a, 32-bit multiply/divide */
/* Wraps if log2(a/128) + log2(b) >= 31 */
a = div128_32(a);
return a * b;
}
/* NOT REACHED */
}
int mul_div100_32(int a, int b) {
/* From compiler optimized code */
/* 0.32 / 32 = 1/100 */
const unsigned long long _3point2 = 0x51eb851f; /* 0.32 << 32, rounded up */
unsigned long long la;
/* Multiply by b */
la = (int)(a * b); /* 32-bit multiply */
/* Multiply by 0.32 */
la = (la * _3point2) >> 32; /* upper 32-bits of 64-bit multiply */
a = (int)la; /* truncate */
/* Divide by 32 and adjust rounding if negative */
return ((a >> 5) /* shift */ + (a < 0) /* round towards zero */)
}
int div100_32(int a) {
return mul_div100_32(a, 1);
}
int mul_div100(int a, int b) {
if (a <= 0x1000000) {
if (b <= 0x10000) {
/* Full precision 32-bit multiply/divide */
return mul_div100_32(a, b);
} else if ((b & ~0xf) < 100*16) {
/* Full precision 64-bit multiply/divide */
unsigned long long la = a, lb = b;
return (int) ((la*lb) / 100ULL);
} else {
/* Reduced precision of b, 32-bit multiply */
b = div100_32(b);
return (int)(a * b);
}
} else if ((a & ~0xf) < 100*16) {
/* Full precision 64-bit multiply/divide */
unsigned long long la = a, lb = b;
return (int) ((la*lb) / 100ULL);
} else {
/* Reduced precision of a, 32-bit multiply */
a = div100_32(a);
return (int)(a * b);
}
/* NOT REACHED */
}
```

My initial solution to this may be to simply replace the routines with 64-bit ones that clamp properly.

Why blizzard doesn't do this, I may never know. I very much doubt the performance is that much of an issue.