15 Nov, 2012, Verias wrote in the 1st comment:
Votes: 0
So, some of you might know me from ages long past, posts on TMC from back when, or maybe, just maybe, you've stumbled over one of my snippets.
Who knows. But I vanished, as if without a trace, from the MUD scene in very very early 2003. With only a marginal resurgence in 2004 to tweak some of my code.

Bearing in mind, all that's good and well, but not the point of this little anecdote.

So, I found my old codebase I'd been reworking from back then last week. I pulled it out, and…after installing compilers on my system again…
I had to go correct lots of errors…and even more errors…and then a few more…then I had to download zlib…
It was a hilariously arduous process, because I'm a stubborn person and run Win7 x64.

Finally, after all of that, I get a compile in MSVS10. I launch…game crashes…
So, more hunting to find why the game is having issues. It kept dying while trying to load my org.lst file setup (I wrote together some stuff for organizations in the game). And…I was baffled….for a very long time…until it occurred to me, to add a hard return under the terminating $ in the .lst file.

Suddenly! The game runs, and I'm like a little kid, enthralled that I was able to do something so…'monumental'? Nah, but it reminded me of both the joy and frustration I always received from doing mud coding and development.

With that, I was off, completing things from a todo.txt file that was almost as old as my daughter, churning out changes, rebooting, doing more, rebooting… Then I decided to add in Erwin's esteemed copyover, and off I went again.

Everything was going splendidly…until I noticed an oddity. Even at creation, level 1….every playerfile included the spell Acid Blast….and to boot….it was inextricably linked to the player's Hunger/Thirst/Full condition…..so it was degrading over time.

I started digging through every line of code, every piece related to adding skills to the player. I tried seeing if there was a link to player conditions…
I found none. Nowhere in the code are the two linked, in any fashion. I wracked my brain over this for a full day, growing more and more frustrated.

My friend, who is no coder, tries to talk to me about the issue. He's rambling on in what is his attempt to think/talk coding, when suddenly, something he says spurs me into action. He makes a comment about writing character data. I'd already been over fwrite_char, load_char_obj, and fread_char and found nothing there, but it was when he said "character data" I knew where I failed to look.

I dive into merc.h and here is what I find.

#define MAX_COND  6


And down in the struct for pc_data

sh_int  cond[4];
sh_int learned[MAX_SKILL_GROUP];



I stared, and immediately began laughing like a lunatic. This, this was the problem, the entire time. When writing out pc conditions to the playerfile, it was calling for MAX_COND, but the struct only allowed for 4, and it was rolling over into the next piece of the struct, grabbing sn[0] (and ignoring as the for loop starts with 0), and printing to file, the first spell on the list (1) which is acid blast, and assigning the value of the last condition to the spell.

I felt both relieved and stupid, as this problem was one that predated finding my code. It was a booboo I made back in 2003, and never found, until now.


Sorry for the long read, but you coders out there might find it slightly amusing.

Regards,
Verias
aka Keith W.
15 Nov, 2012, Rarva.Riendf wrote in the 2nd comment:
Votes: 0
Nah not amusing, been there too when I started to change hard coded value by constant…I feel the pain :)
15 Nov, 2012, Verias wrote in the 3rd comment:
Votes: 0
It doesn't change how elated you feel when you finally find it. Like I said in the post. I had been through all of the loading, character creation, saving of pfiles, I even removed 'acid blast' from the table (which made it use 'armor' instead, as that was the next spell on the list).

Time to get back to work. Much to do (I have a new ToDo.lst file).
15 Nov, 2012, Rarva.Riendf wrote in the 4th comment:
Votes: 0
Well I dont feel stupid, just angry at the one that hard coded value in the first place and made me lose my time :p
18 Nov, 2012, triskaledia wrote in the 5th comment:
Votes: 0
I quit coding/MUDding regularly for about a year… Had a friend ask me to get our MUD back up… Scrolling through the spells the other day I realized I had a lot of double checks in spells that didn't need to be made.
Psuedocode:
if(!saves_spell(waterball))
{
damage = number_range(100, 200) + mod_stat[STAT_INT];
if(spell_percent > 99)
dam *= 1.25;
act_damage(Yadayadayda);
}
else
{
damage = number_range(50, 100);
if(spell_percent > 99)
dam *= 1.25;
act_damage(Ydayadayda);
}
return;

instead of just defining the damage for whether it was saved or not, and then checking the spell % and then damaging right above code… It'll take a while, but I plan on fixing all those over coding things I did.
18 Nov, 2012, Verias wrote in the 6th comment:
Votes: 0
I had another really good one. Back in the day I wrote a blood trail code. The idea was that if a player's health dropped below 75% of their max health, they would "bleed" and leave a trail of blood in the room, indicating which way they went (i.e. A trail of blood leading north).

The original formula was mathed in this manner.

int value = ((ch->hit/ch->max_hit)*100);

if(value < 75)
{
// do stuff
}


Ultimately, this led to strange things occuring. If the player lost a single hitpoint, they would leave a blood trail.

In the end, the code was changed to this.

if (ch->hit < (ch->max_hit/4)*3)
{
// do stuff
}


and it works as intended.

Go figure.

Speaking of which, now that it's working as it should. I might toss this up into the repository. It's simple, and silly, but mixed with tracking skills (or in my game's case, vampires) it was a fun little tool.

Vampires could sniff a blood trail and discern whose blood it is.
18 Nov, 2012, Rarva.Riendf wrote in the 7th comment:
Votes: 0
Heh the usual int cast that put all division to 0 depending on how the compiler decided to make it :) annoying to hell to detect as well :)
23 Nov, 2012, Sharmair wrote in the 8th comment:
Votes: 0
Verias said:
I had another really good one. Back in the day I wrote a blood trail code. The idea was that if a player's health dropped below 75% of their max health, they would "bleed" and leave a trail of blood in the room, indicating which way they went (i.e. A trail of blood leading north).

The original formula was mathed in this manner.

int value = ((ch->hit/ch->max_hit)*100);

if(value < 75)
{
// do stuff
}


Ultimately, this led to strange things occuring. If the player lost a single hitpoint, they would leave a blood trail.

In the end, the code was changed to this.

if (ch->hit < (ch->max_hit/4)*3)
{
// do stuff
}


and it works as intended.

Go figure.

Speaking of which, now that it's working as it should. I might toss this up into the repository. It's simple, and silly, but mixed with tracking skills (or in my game's case, vampires) it was a fun little tool.

Vampires could sniff a blood trail and discern whose blood it is.


This is an example of using integer division without either realizing it or understanding how it works
(which it does the same way and in the same conditions in all the C/C++ compilers I have seen). The
rules are pretty simple: if both arguments to a division are integers an integer division is done and the
result is the whole number rounded down.

Actually, though your 2nd way is much better then the first, it still can be off a couple points. To
get the most accurate result still using only integer math, do the multiply before the divide:
int value = ((ch->hit*100)/ch->max_hit);

or in your 2nd way:
if (ch->hit < (ch->max_hit*3)/4)

The one thing to watch for here is to make sure the multiply does not result in an integer overflow.
If overflow might be a problem, or you don't care if you use integer math, you can use floating point
math just by making one of the arguments floating point (note there are some accuracy issues with
floating point, though in the uses to replace integer math you probably will not have to worry about
them). To make a constant number floating, just add a decimal part like 100.0, you can also cast
the argument (make sure you cast the argument and not the result of an already done division).
24 Nov, 2012, Rarva.Riendf wrote in the 9th comment:
Votes: 0
Quote
which it does the same way and in the same conditions in all the C/C++ compilers I have seen


If I remind well that there is no rule on wich order a calculation is done 4 * ( x / 3) could be done 4 * x then result is / 3 or x / 3 then the result * 4. and those can give different results if x is an int.
I am not sure, but I think I experienced it in a perticular GCC version, and that is why I now know it.

I found this as well.
http://stackoverflow.com/questions/76561...

Basically..just do not trust anything and just 4 * (double) x / 3, that will work for sure. and also ensure you have the closest rounding result as well.
24 Nov, 2012, quixadhal wrote in the 10th comment:
Votes: 0
Unless gcc doesn't follow the language specs, multiplication and division are performed left-to-right, unless grouped by parens. Addition and subtraction are also done left-to-right. The multiplication/division operators have precedance over the addition/subtraction group.

So, 4*(x/3) will ALWAYS be 4*(x/3), because of the parens. 4*x/3 will be (4*x)/3. 4*x+3/10 will be (4*x)+(3/10).

Here's a table of precedence for C and C++.
24 Nov, 2012, Rarva.Riendf wrote in the 11th comment:
Votes: 0
Thx Quix it has been a long time ago so I don't remind well what exactly was the problem Maybe I was doing 4 / 3 * x then… I was pretty sure something changed either in compiler or compiling option that made the result change. Or maybe it was just my imagination and I changed something elsewhere. Anyway my advice still hold…cast your int as a double as soon as you make a division, and then your result will be way more accurate in the end anyway :)

(and the thread I linked still giving me doubt about trusting gcc about that anyway)
24 Nov, 2012, Rarva.Riendf wrote in the 12th comment:
Votes: 0
Another interesting thread about calculation and compiler flags changing the (human) expected result:

http://stackoverflow.com/questions/75175...
0.0/12