Champion's Max Load question

Discuss anything about the original Dungeon Master on any of the original platforms (Amiga, Atari, etc.).
This forum may contain spoilers.

Moderator: Ameena

Forum rules
Please read the Forum rules and policies before posting.
Post Reply
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Champion's Max Load question

Post by Erik Bauer »

There is something I can't understand reguarding the Max Load and how it is handled.
It seems that whenever a champion gains a level up that increases his strength, the max load value increases exceeding the strength boost, and then decreases over time reaching the correct number. Is that correct, or am I missing something?

Thank you
Don't let a closed door stop you
User avatar
Jan
Mighty Pirate
Posts: 2760
Joined: Tue Sep 23, 2008 4:55 pm
Location: Scumm Bar, Czech Republic

Re: Champion's Max Load question

Post by Jan »

I've never noticed that. I don't know but Max Load is influenced not only by current strength but also by current and maximum stamina (see http://dmweb.free.fr/?q=node/691) so maybe the answer lies there. Dunno.
Finally playing and immensely enjoying the awesome Thimbleweed Park-a-reno!
User avatar
Saumun
High Lord
Posts: 2238
Joined: Fri Feb 20, 2009 3:03 am
Location: The Ether

Re: Champion's Max Load question

Post by Saumun »

Never noticed it either. I usually see the opposite due to stamina not being at max, then the max load increases when the stamina is regained.
Maybe Paul S or Sophia could explain it.
“Grynix Ernum Quey Ki Skebow Rednim U Os Dey Wefna Enocarn Aquantana” - Anon
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Re: Champion's Max Load question

Post by Erik Bauer »

It's even stranger than I tought... watching my videos I'm seeing this:
Stamm can load 52Kg... I fight against a rock monster, suddenly Stamm hits the Rock Monster and deals a huge amount of damage, reequipping him I can see he can load 75Kg without gaining levels, then a few minutes later, his max load is back to 52.
I'm starting to think there is some item he is wearing that has some hidden effect. Maybe the Berzerker helm (In most RPG games the Berserker skill increases strength and fighting related skills of the character using it trading off with a decrease in defensive skills, making him a fearsome opponent). I'll investigate and report back.
Don't let a closed door stop you
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Re: Champion's Max Load question

Post by Erik Bauer »

Nope... Berzerker helm is not influencing it, I've seen the same thing happening to Zed, and he is wearing a regular helmet.
Both times the champions had their stamina vaule near the half of it's maximum. If the math formula contained in the link provided by Saumun is correct, then there must be another thing that is able to change max load. Otherwise there is a small bug in the code handling the formula.
Don't let a closed door stop you
User avatar
Sophia
Concise and Honest
Posts: 4239
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Champion's Max Load question

Post by Sophia »

What version are you playing?

This post by Gambit mentions what you seem to be encountering (in the DOS version of DM, I think?) but doesn't go into detail. I took a quick look at the source code to CSBwin and it seems like it does the right thing, so if you're playing an original version it could be a compiler problem or something.

EDIT: Looking at Christophe's source code, which is the closest to the original source code we're ever going to get, there's this line (line 2043 of CHAMPION.C):

Code: Select all

return (P641_i_Value >>= 1) + (int)(((long)P641_i_Value * (long)L0925_i_CurrentStamina) / L0926_i_HalfMaximumStamina);
There may be some sort of order of operations issue here, and/or the compiler doing something wrong... because if P641_i_Value gets used in the stamina calculation before the new halved value is stored, this would produce the bug you're seeing.
User avatar
Paul Stevens
CSBwin Guru
Posts: 4318
Joined: Sun Apr 08, 2001 6:00 pm
Location: Madison, Wisconsin, USA

Re: Champion's Max Load question

Post by Paul Stevens »

I am not sure that there is any requirement that the operands
of commutative operations such as addition are guaranteed to be
evaluated in any particular order.
But I confess ignorance of the rules governing this.
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Re: Champion's Max Load question

Post by Erik Bauer »

I'm playing Amiga version, the one republished by Psygnosis after CSB went out, emulated through WinUae. I'm not 100% sure, but I recall noticing the same thing back in the days when I played it unemulated. Can't recall if it happens also in the vanilla Amiga version
Don't let a closed door stop you
User avatar
ChristopheF
Encyclopedist
Posts: 1537
Joined: Sun Oct 24, 1999 2:36 pm
Location: France
Contact:

Re: Champion's Max Load question

Post by ChristopheF »

Congratulations, you have found a new bug in Dungeon Master!
Sophia and Paul are correct. The order of evaluation of the operands depends on the compiler implementation and is not guaranteed by the C language.
I have checked the machine code produced by the various compilers and I have added the following comment in my source code next to the line quoted by Sophia:

BUG: In order to compute the correct adjusted value, the first operand of the addition must be executed first so that its updated value is used in the second operand. However, there is no guarantee that the code produced by the compiler will execute the operands in this particular order. The following compilers produce 'correct' code where the first operand of the addition is executed first: Megamax C (DM 1.x and CSB 2.x for Atari ST), High C (DM 2.0 and CSB 3.1 for FM-Towns), THINK C 4.0 (CSB 3.x for Amiga and X68000, DM 3.0 for X68000). The following compilers produce 'incorrect' code where the second operand of the addition is executed first: Aztec C 3.6a (DM 2.x for Amiga), APW (DM 2.x for Apple IIGS), Turbo C 2.0 (DM 2.0 and CSB 3.1 for PC-98), Turbo C++ 1.01 (DM 3.4 for PC), THINK C 5.0 (DM 3.6 Amiga)
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Re: Champion's Max Load question

Post by Erik Bauer »

Whew! I'm a bit ahsamed in speaking this, as I spent the last 30 years learning computer programming and then programming by job (not much C and C++ tho), but I did not know that different C compilers could handle operations order in different ways.
I confirm I'm using version 3.6 of DM for my current walktrough, so this must be as you say.

Thank you all for your time and your kind explanations, it's a pleasure to be part of this community :)
Don't let a closed door stop you
User avatar
Paul Stevens
CSBwin Guru
Posts: 4318
Joined: Sun Apr 08, 2001 6:00 pm
Location: Madison, Wisconsin, USA

Re: Champion's Max Load question

Post by Paul Stevens »

Christophe:

I know you put the words 'correct' and 'incorrect' in quotes. But I think
it would be better to use words such as 'expected' or 'unexpected' so as
to emphasize the fact that either result is 'correct'.

Wow! You have all those compilers at your disposal? That is impressive
all by itself. Thanks and Great Work!
User avatar
ChristopheF
Encyclopedist
Posts: 1537
Joined: Sun Oct 24, 1999 2:36 pm
Location: France
Contact:

Re: Champion's Max Load question

Post by ChristopheF »

You are quite right that "expected/unexpected" is a better choice of words because there is no issue on the compiler side.
The C language does not specify an order of evaluation, therefore each compiler does it in its own way (and all are correct as there is no specification to follow). It is the developer's responsibility to avoid such ambiguous expressions when writing code that is expected to be portable. But it is so easy to write non portable code withoug noticing: even after testing the program on Atari ST, the results were correct as the compiler does things as expected. Because the bug only has minor consequences, they probably never noticed it on other platforms and we had to wait until 2016 for someone to notice and report it! (I personnaly never noticed this while playing the PC version years ago).

About compilers: I don't have the APW compiler for Apple IIGS (not even sure to this day which version/variant was used). I also don't have the FM-Towns compiler (although I have one version that is not the exact one that FTL used).
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Re: Champion's Max Load question

Post by Erik Bauer »

ChristopheF wrote:You are quite right that "expected/unexpected" is a better choice of words because there is no issue on the compiler side.
The C language does not specify an order of evaluation, therefore each compiler does it in its own way (and all are correct as there is no specification to follow). It is the developer's responsibility to avoid such ambiguous expressions when writing code that is expected to be portable. But it is so easy to write non portable code withoug noticing: even after testing the program on Atari ST, the results were correct as the compiler does things as expected. Because the bug only has minor consequences, they probably never noticed it on other platforms and we had to wait until 2016 for someone to notice and report it! (I personnaly never noticed this while playing the PC version years ago). [...]
Uh, in my ignorance about ANSI (and not ANSI) C standards I'd expect the compiler to use the same order of evaluation that is used in Math, as it should be an universal standard, AFAIK.
But as a computer programmer I'm quite fascinated about this
Don't let a closed door stop you
User avatar
Paul Stevens
CSBwin Guru
Posts: 4318
Joined: Sun Apr 08, 2001 6:00 pm
Location: Madison, Wisconsin, USA

Re: Champion's Max Load question

Post by Paul Stevens »

universal standard
I've heard that in a far-away galaxy creatures think backwards.
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Re: Champion's Max Load question

Post by Erik Bauer »

Paul Stevens wrote: I've heard that in a far-away galaxy creatures think backwards.
LOL that made my day! :D
Don't let a closed door stop you
User avatar
terkio
Mon Master
Posts: 937
Joined: Tue Jul 10, 2012 8:24 pm

Re: Champion's Max Load question

Post by terkio »

http://en.cppreference.com/w/c/language ... precedence

As is the rule in maths, * / has higher priority than + -, and evaluation is left to right at a same level priority.
"You can be on the right track and still get hit by a train!" Alfred E. Neuman
User avatar
ChristopheF
Encyclopedist
Posts: 1537
Joined: Sun Oct 24, 1999 2:36 pm
Location: France
Contact:

Re: Champion's Max Load question

Post by ChristopheF »

terkio, the first note on the page you mention leads here: http://en.cppreference.com/w/c/language/eval_order
User avatar
Erik Bauer
Adept
Posts: 252
Joined: Thu Jan 11, 2007 1:44 pm

Re: Champion's Max Load question

Post by Erik Bauer »

So there is an important yet (at least to me) subtle difference between operand priority and expression evaluation order in C and C++... now my mind seems to start remembering some info I studied while at school more than 20 years ago and then never used (as I mostly programmed in Visual Basic and VB.Net).
Well, cross compiling a videogame must have been a fascinating yet frustrating hell of a job right in the '80s and '90s :D


EDIT:
Gosh... that grows more fascinating as I think about it... somehow I Wish I had learnt how to program an Amiga back then... well... why not? Retro Programming is an hobby as good as anyother :D
Don't let a closed door stop you
User avatar
Paul Stevens
CSBwin Guru
Posts: 4318
Joined: Sun Apr 08, 2001 6:00 pm
Location: Madison, Wisconsin, USA

Re: Champion's Max Load question

Post by Paul Stevens »

compiling a videogame must have been ...hell of a job
One quickly learns that when evaluation has side-effects that
you force the compiler to do things in the order you want them
done. One does not do things like

Code: Select all

a = (b++) + c - 2 * b
Whoever wrote that line of code in the Dungeon Master engine
must have forgotten this.
User avatar
Sophia
Concise and Honest
Posts: 4239
Joined: Thu Sep 12, 2002 9:50 pm
Location: Nowhere in particular
Contact:

Re: Champion's Max Load question

Post by Sophia »

What I find most interesting and fascinating about this is how the source code we had to work with was close enough to the original source code that we can use it to explain bugs, because the original code almost certainly contained a similar construction that caused a similar bug!

Just for fun I wrote two test programs, which were identical except one featured the lines:

Code: Select all

a >>= 1;
c = a + ((a * b) / b+1);
And the other was:

Code: Select all

c = (a >>= 1) + ((a * b) / b+1);
When I compiled them with clang, they produced identical assembly language code except if I told it to compile without any optimizations whatsoever. The Atari ST compiler used by the DM team must not have optimized particularly much, either, or done something else that wasn't too clever. Of course, the compiler I'm using now is much newer, so I'd certainly hope that C compilers had gotten better in the last 30 years.

Still, it makes the reverse engineering all the more amazing. Christophe, how did you know to write the line that way? :shock:
User avatar
Paul Stevens
CSBwin Guru
Posts: 4318
Joined: Sun Apr 08, 2001 6:00 pm
Location: Madison, Wisconsin, USA

Re: Champion's Max Load question

Post by Paul Stevens »

I, too, was surprised.
Christophe, how did you know to write the line that way?
You must have had some mechanical code generation. Was it able to do
this particular line without any help? If so, I will add 'amazed' to my
list of adjectives.
User avatar
ChristopheF
Encyclopedist
Posts: 1537
Joined: Sun Oct 24, 1999 2:36 pm
Location: France
Contact:

Re: Champion's Max Load question

Post by ChristopheF »

I did not use any mechanical code generation, I did it all manually. Luckily, and as Sophia suspects, the Megamax C compiler on Atari ST does not perform any kind of optimization at all. The resulting machine code is then really straightforward in almost all cases, so it was relatively easy to understand what it did and write the corresponding C code. There is no reordering of statements, no automatic removal of redundant instructions, etc. so it is quite easy to identify each set of machine instructions that correspond to a single C statement/expression (or even a subexpression).
I check (and fix as necessary) the C code I write so that once compiled, it produces the same machine code as in the original. This step is very important as it ensures my source code is close enough to the original source code. This is a trial and error process. Tedious and time consuming, but really not that hard.
While working on other platforms/compilers, I had to make lots of little changes to the source code to ensure it would work with multiple compilers. One simple example: with Megamax C, most 'while' and 'for' loops produce the same machine code: you can use while or for interchangeably in the source code and it will produce exactly the same machine code. However, this is not true with the Aztec C compiler on Amiga. So when working on the Amiga versions I had to replace some 'while' statements by 'for' statements, and some 'for' by 'while' so that the same source code works fine with both compilers. In a way, this helped me ensure which type of loop the original developers have used.
In the particular case of the function we discuss in this thread, the C code I wrote from the Atari ST machine code just compiled fine without any change for all other versions I've studied. That is why I did not notice this bug: I never compared the machine code on any other version with the Atari ST one, as long as it compiled identically to all the original executables.
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Champion's Max Load question

Post by Gambit37 »

Interesting thread. I don't understand all the tech speak, but I had forgotten about reporting this bug all those years ago. I can't remember if I wrote that based on personal experience, or if it was something Doug told me about when I interviewed him. I'll see if I can find the original interview...!
User avatar
Paul Stevens
CSBwin Guru
Posts: 4318
Joined: Sun Apr 08, 2001 6:00 pm
Location: Madison, Wisconsin, USA

Re: Champion's Max Load question

Post by Paul Stevens »

I did not use any mechanical code generation, I did it all manually....... Tedious and time consuming
Having done something similar but less difficult, I can say that this
is quite an understatement. Good grief; what a task.
User avatar
ChristopheF
Encyclopedist
Posts: 1537
Joined: Sun Oct 24, 1999 2:36 pm
Location: France
Contact:

Re: Champion's Max Load question

Post by ChristopheF »

I'll see if I can find the original interview
Will you share it after all those years? ;-)
User avatar
Gambit37
Should eat more pies
Posts: 13714
Joined: Wed May 31, 2000 1:57 pm
Location: Location, Location
Contact:

Re: Champion's Max Load question

Post by Gambit37 »

Yes, if I can find it, but they would still need some work as there was personal stuff in there that Doug didn't want me to share.
User avatar
Sphenx
On Master
Posts: 566
Joined: Sun Sep 09, 2001 11:23 am
Contact:

Re: Champion's Max Load question

Post by Sphenx »

Just for reference, here is the corresponding code from SkWin (STAMINA_ADJUSTED_ATTR function). I can't tell how close it is from original DM2 code, but at least this adaptation does not contain the bug, since the 'halve and assign' operation is done separately.

Code: Select all

	i16 si = quantity;
	i16 bp02 = ref->curStamina();
	U16 di = ref->maxStamina() >> 1;
	if (bp02 < di) {
		si >>= 1;
		return (i32(si) * i32(bp02)) / i32(di) +si;
	}
	return si;
Post Reply