11 Jan, 2013, Hades_Kane wrote in the 21st comment:
Have a quick question about integers and such.

The numerical value that I'm pulling the digit from is a long int, and so that actually does restrict the number of characters the string can be to 10. This isn't a huge deal, but is there something I can use or something I can do to expand how big this number can go?

I know on things like max buffer or whatever, you can set a specified number or multiply the existing number.

Is there something doable when working with a value that's declared as a long?

I am assuming not, and I figure that what I would need to do is instead use 'long long' instead which seems to give me 19 spaces to work instead.

Am I shooting in the right direction? Is there any problems I may encounter anyone may think of right off?

Am I right that anywhere that the value may be printed using %ld I will need to convert to %ll?

Just working on this last night and today, I've learned a lot of new things about C that I didn't know, and have a better grasp of some other things such as pointers and arrays.
11 Jan, 2013, Rarva.Riendf wrote in the 22nd comment:
Short answer:Use string to store your numbers if you don't know how much storage you will need, or if you dont want to be limited.
(this is how I store all the room visited by a player, 1 bit per room so you can store 8 per char used)
Unless you plan for millions of players and NPC the memory used by a 'quest string' wont kill you. Especially if you allow it dynaically and not as a fixed buffer. Most of your npc will never use it.

Quote
Basically what I did was grab the number that I'm trying to pull from and did a strlen on it and made it int length

Lazy version :p (you could divide by ten till you get 0). And I am pretty sure a smart guy could do that using bit magic like shifting or stuff like that
12 Jan, 2013, Hades_Kane wrote in the 23rd comment:
And hey, wouldn't you know it… I figured out how to pluck that value and change it with a different function too :p

I think I'm just gonna stick to the long int on these. The main reason for this was to avoid having multiple duplicates of more or less the same value on a player. Say there is a special type of chest I want to track if they've opened, for example, I can use this pseudo-array within this variable system to keep track that way, and even if I decide to do 40 chests, that's 4 variables instead of 40 individual ones. So, the limit of 10 characters isn't that big of a deal.

Thanks for all the help!
12 Jan, 2013, quixadhal wrote in the 24th comment:
Are you seriously making overly complex code and data that requires you to look up the code to see what it does, just to save a few bytes of space? Is this 1980? WTF man…..

I mean, for God's sake, if you insist on going down that path, why not just use bit fields? At least you can make the code more readable…

struct foo {
int blah : 3, // holds signed values from -4 to 3
unsigned int ack : 4, // unsigned from 0 to 15
};

I really don't get the mindset to make your code stupidly difficult to maintain, just to save a handful of bytes when the machine you're likely using could run 50 copies of your MUD without any issue…

But, whatever…. have fun!
14 Jan, 2013, Hades_Kane wrote in the 25th comment:
Are you seriously making overly complex code and data that requires you to look up the code to see what it does, just to save a few bytes of space? Is this 1980? WTF man…..

Which setup would you rather deal when listing the variable tracking for players?

`Variables for 'Diabtoo':             Name                  Value    Persist?——————————  ———-  ——–sealedchest1                             1       yessealedchest2                             1       yessealedchest3                             1       yessealedchest4                             1       yessealedchest5                             1       yessealedchest6                             1       yessealedchest7                             1       yessealedchest8                             1       yessealedchest9                             1       yessealedchest10                            1       yessealedchest11                            1       yessealedchest12                            1       yessealedchest13                            1       yessealedchest14                            1       yessealedchest15                            1       yessealedchest16                            1       yessealedchest17                            1       yessealedchest18                            1       yessealedchest19                            1       yessealedchest20                            1       yessealedchest21                            1       yessealedchest22                            1       yessealedchest23                            1       yessealedchest24                            1       yessealedchest25                            1       yessealedchest26                            1       yessealedchest27                            1       yessealedchest28                            1       yessealedchest29                            1       yessealedchest30                            1       yessealedchest31                            1       yessealedchest32                            1       yessealedchest33                            1       yessealedchest34                            1       yessealedchest35                            1       yessealedchest36                            1       yessealedchest37                            1       yessealedchest38                            1       yessealedchest39                            1       yessealedchest40                            1       yeshiddenimperialland                       1       yesprepromotionquest                       54       yesmacalaniafinalquestjacob                 7       yeseotnewbienot                             2       yeseotnewbienew                             1       yeslearncooking                             7       yesvicolanthunder                           1       yesdudefly                                  3       yestreechoppingquest                       10       yesnewyearsupplies                          2       yesnewyearsevelorana                        1       yesinscriber                                3       yes`

or

`Variables for 'Diabtoo':             Name                  Value    Persist?——————————  ———-  ——–sealedchest1                    1010011010       yessealedchest2                    1110010101       yessealedchest3                    1001011011       yessealedchest4                    1100111010       yeshiddenimperialland                       1       yesprepromotionquest                       54       yesmacalaniafinalquestjacob                 7       yeseotnewbienot                             2       yeseotnewbienew                             1       yeslearncooking                             7       yesvicolanthunder                           1       yesdudefly                                  3       yestreechoppingquest                       10       yesnewyearsupplies                          2       yesnewyearsevelorana                        1       yesinscriber                                3       yes`

Now let's say that there ends up being a handful of other sets of data like that a builder might want to be able to track as they are scripting, and you could easily see how a player's variable list could end up spanning pages. This was mostly a usability issue.

And… how was improving and adding options on how to track multiple data sets within this system going to make my code "stupidly difficult to maintain"? It actually wasn't that much additional code, at least not much more than any of the other program checks or commands I've added.

It might have given me some difficulty on getting it going because it dealt with programming techniques I wasn't very familiar with, but one of my main priorities if not my top priority since I started messing with code has been expanding, adding, and making the OLC and program systems more flexible. The more I can do for those building on the game to have a variety of different tools to accomplish whatever they might want or need, the better in my mind, even if it's a pain in the ass to add or if I have to spend a week learning more programming than I knew before.
14 Jan, 2013, quixadhal wrote in the 26th comment:
Ahhhh, now that you've posted the actual data, perhaps we can get down to business. :)

The assumption I was making, from the way you presented your questions, was that you were using integers to store some complex set of values, all in one int, rather than splitting it up into logical structures. The most common nonsense is the infamous DikuMUD bitflags, where they stuffed all kinds of booleans into ints to make things work back when 1MB of RAM was gigantic.

Having "mobflags = 5632" and then making the poor user go lookup 5632 == 4096 + 1024 + 512, and then go find the docs to see that means ACT_ASSASSIN, ACT_SCARED_PC, and ACT_HUNTING…. not fun. Pointless these days when you could just have a roomflag structure with member names for all those things.

So, in fact, you aren't doing that at all…. and instead you have a bunch of key/value pairs, some of which are boolean, some of which are not, which may be considered persistent, or not.

Your problem then, is two-fold. Either you need to store/lookup such values quickly, or you need to display them in a nice fashion.

Since your earlier stuff made me think it was a storage issue, I hacked up a bit of C hash code as an example of one way to store such key/value stuff that makes it easy to retrieve. If you're using C++, use std::map instead. That code is at the bottom, if you care. :)

Since I now think this is more a display problem than an actual data issue… a couple of suggestions.

First, data display and data storage are two entirely different problems, and you should NEVER let one drive the other. In your example, it looks like your problem is that you have a bunch of "sealedchest" variables which were poorly named. If the user simply had to open some number of them, you could make it a single variable with the value being a counter… but I assume each chest is tied to a particular quest/npc/item/whatever… and so you need to track each one individually.

So, your choices are, rename the variables so they actually describe what they do… IE: sealedchestorcroom, sealedchest3701 (where 3701 is the vnum of the room/npc/obj that the quest relates to – assuming DikuMUD).

Your other option, is to make the DISPLAY code group things and compact them accordingly. Don't just loop over your variables and dump them… analyze them for patterns, especially if you know some are going to be there. If you filtered all the "sealedchest*" things out, you could group them all and display it as:

sealedchest: 1 2 17 18 19 20 23 45 2881

Where if the number's there, it's true… if not, it's false. To me, that's a lot easier to read than some boolean string where I have to count and can easily miscount which column it's in.

While you can easily hard-code for just one or two groups, you could have code do it for you if you enforce a little bit of structure on your naming schemes. For example, if you used underscore as a meaningful token, you could group by similar substrings between underscores.

sealedchest_1
sealedchest_13
newyear_supplies
newyear_sevelorana
eotnewbie_not
eotnewbie_new

could become:

sealedchest: 1 13
newyear: supplies(2) sevelorana
eotnewbie: not(2) new

So, you'd not display things with a 0 value, and display the values if anything other than 1. That would be fairly easy to code, you'd just need to break the strings up by _ and build arrays for each substring. It would be a one-liner in perl, but C will require you to do some memory management and pointer nonsense.

My last remark is to your comment about maintainability. Many people here don't agree with many things I say, but most of the long-time coders will probably agree with me on this one point. The more clever you think your code is, the more likely nobody will be able to maintain it down the road, including yourself. People HAD to cram things together into stupidly complex encodings back in 1990, because they were trying to run their games on slow machines that only had 4MB of RAM. There's no reason to do that today. Take the time and memory to make structures that clearly show what you're doing, and 10 years later, you can actually look at the code and fix it.

`#include <stdio.h>#include <stdlib.h>#include <math.h>#include <ctype.h>#include <string.h>#define BUCKETS 100struct s_stringMap;typedef struct s_stringMap {    const char *key;    const char *value;    int persist;    struct s_stringMap *next;} stringMap;unsigned int hashmap( const char *s ){    unsigned int hash = 0;    if(!s || !*s) return 0;    do {        hash += *s;        hash *= 13;        s++;    } while (*s);    return hash % BUCKETS;}void hash_init( stringMap *map ){    int i;    for(i = 0; i < BUCKETS; i++)    {        map[i].key = NULL;        map[i].value = NULL;        map[i].persist = FALSE;        map[i].next = NULL;    }}void hash_add( stringMap *map, const char *k, const char *v, int persist ){    unsigned int hashcode;    stringMap *p;    hashcode = hashmap(k);    p = &map[hashcode];    while(p->key && strcmp(p->key, k) && p->next)        p = p->next;    if(!p->key) {        /* First node? */        p->key = (const char *)strdup(k);        p->value = (const char *)strdup(v);        p->persist = persist;        p->next = NULL;    } else if(!strcmp(p->key, k)) {        /* Found our match! */        if(p->value)            free((void *)p->value);        p->value = (const char *)strdup(v);        p->persist = persist;    } else {        /* New key */        p->next = (stringMap *)calloc(1, sizeof(stringMap));        p = p->next;        p->key = (const char *)strdup(k);        p->value = (const char *)strdup(v);        p->persist = persist;        p->next = NULL;    }}const char * hash_find(stringMap *map, const char *k){    unsigned int hashcode;    stringMap *p;    hashcode = hashmap(k);    p = &map[hashcode];    while(p->key && strcmp(p->key, k) && p->next)        p = p->next;    if(!p->key)        return NULL;    if(!strcmp(p->key, k))        return p->value;    return NULL;}int hash_is_persist(stringMap *map, const char *k){    if(hash_find(map, k) != NULL)        return TRUE;    else        return FALSE;}`
14 Jan, 2013, Rarva.Riendf wrote in the 27th comment:
Quote
Many people here don't agree with many things I say, but most of the long-time coders will probably agree with me on this one point. The more clever you think your code is, the more likely nobody will be able to maintain it down the road, including yourself.

Indeed clever/smart code should be restricted to part when you actually have a performance problem. And even then be heavily commented in how it actually works.
Like Quix I would separate the storage and the display. It is also a common pattern.
Take a basic Diku example when you mstat a mobs, does it show you the flag, like 5632 or does it show ACT_ASSASSIN, ACT_SCARED_PC, and ACT_HUNTING
(well mine show ACT_ASSASSIN, ACT_SCARED_PC, and ACT_HUNTING, because I am not a computer, and I coded so I never have to use or look at the flag value anywhere)

so you shoudl have a method that actually makes the thing readable like:

sealchest xxx key found/chest locked
sealchest xxx key found/chest opened/chest looted

And yeah using maps is a better idea if you can put(sealchestxxx, FOUND) put(sealchestxxx, CHESTLOCKED) and be done with it.
14 Jan, 2013, mangan wrote in the 28th comment:
The more clever you think your code is, the more likely nobody will be able to maintain it down the road, including yourself.

This is a core principle in any large scale system. Complexity should only ever be used as a necessity to meet a design requirement (such as Diku and their system/memory requirements back in the day).

In such cases, abstract out the complexity into it's own little module if feasible (assuming that it is likely to change in the future, such as memory becoming cheap) and comment the requirements it meets as well as the cleverness behind the complexity, so that in the future a programmer can maintain (simplify, remove, modify) the module as they see fit to meet the new requirements (or lack of prior requirements). The commenting should make it clear why the current version is complex, so that maintainers have a level of confidence that they understand the code and aren't making poor assumptions.

Then again, everything I just said is in regards to systems in general. I don't know your requirements, nor am I implying whether your current solution is complex or not.
15 Jan, 2013, Hades_Kane wrote in the 29th comment:
Thing is, it wasn't that complex, and I don't even know where that presumption came from.

It was just aspects of programming I wasn't sure how to do. I'm basically self taught on the ROM codebase, and learn new things as I run into stuff I can't figure out based on the existing ROM code.

The extent of it's complexity really exists in these two parts of the code:

`var1 = var->value / pow(10,length - posval);	lval2 = var1 % 10;`

`char result1 [MAX_INPUT_LENGTH];	int i = posval - 1;	sprintf(result1, "%ld", result);    xbuf[0] = '\0';    strcpy( xbuf, lval1 );	xbuf[i] = '\0';	strcat( xbuf, result1 );	strcat( xbuf, &lval1[(i+1)] );`

Those are opposite ends of the function, but you get the point. I have limited experience in messing with string manipulation, I've never used the % before, I never knew about the pow function, and I've never needed to convert an int into a char. The trick of truncating a string by dividing by powers was something I knew nothing of either.

These might seem like basic things to other people, which I'm sure it does and that's why I asked for a bit of help on being pointed in the right direction, but if you've never had the need to use anything like this before, it can be a pain to figure out.
15 Jan, 2013, quixadhal wrote in the 30th comment:
You're confusing code complexity with concept complexity.

The code is quite simple, trying to remember why special positions within a number have special meaning is not simple. It's a convoluted way to compress data for no real gain, other than thinking it clever, and making it so you can avoid having to rewrite the display side of your code.
15 Jan, 2013, Hades_Kane wrote in the 31st comment:
You're confusing code complexity with concept complexity.

The code is quite simple, trying to remember why special positions within a number have special meaning is not simple. It's a convoluted way to compress data for no real gain, other than thinking it clever, and making it so you can avoid having to rewrite the display side of your code.

No.

The gain has nothing to do with being clever.

The gain has to do with modifying an existing system that uses a single value associated with a string as defined by the person writing a script to be able to use that single value to represent up to 10 different values. The gain has to do with usability and the interface through which builders script on my game.

Using arrays like this is a pretty basic aspect of C, and even with the myriad aspects or concepts of C that I'm unfamiliar with, being able to define something in the code like array[5] and then be able to use a for loop with that as the boundaries or even pulling out a specific place in the array. At it's core, that's the concept behind the code, and I'd be surprised if anyone with an even elementary understanding of C would consider that a complex concept.

If might not be quite as intuitive as being able to just outright go "if sealedchest[4] == 1" or whatever (what in the mobprog system is as intuitive or flexible as C?), but within the existing variable system, which uses syntax such as:

`if var \$n s7questline == 5and carries \$n 345  say Ah, I see you have my ale!  Go talk to John and he will do that favor I asked!  var \$n s7questline = 6  breakendif`

Then something as simple as:
if varpos \$n sealedchest1 == 5 0
or
varpos \$n sealedchest1 = 5 1

is inline with the rest of the system, it's intuitive toward the system, as long as the person using it understands the first number is the position and the second is the value, then it's easy to use.

I've used the variable system in one quest to track specific mobs being killed, and keeping track of 15 different variables with unique names that correspond to the mob's vnum is a pain, and had I had this in place before hand, keeping track of all of that would have been a lot easier. Being able to reduce the display when checking a player's variable list is a big advantage too, but this is more for the usability and flexibility of the system.

The scripters on my game have responded very positively toward the change and seem excited about it and ultimately, that's more important to me than whether some stranger on a message board thinks that adding what amounts to array functionality to our variable/program system is a complex concept or designed only to be clever.
15 Jan, 2013, Rarva.Riendf wrote in the 32nd comment:
Quote
It's a convoluted way to compress data for no real gain

If I agree most of what you said before, I still see a gain in doing that. It is less complicated than go look into how to use maps in pure C.
As I said I store the rooms visited by a char using the binary power, sure it is more "complicated" than just using a map that can do it but the code behind it needs no maintenance in itself, and I will never go read the generated string as well. Everytime I have to sort a table in C makes me cringe, when I know I could jsut make an Array.sort() in another langage.
does he really need to diplay the value anyway ? I doubt it. He probably just needs that the values are accurate.
16 Jan, 2013, quixadhal wrote in the 33rd comment:
Using arrays like this is a pretty basic aspect of C, and even with the myriad aspects or concepts of C that I'm unfamiliar with, being able to define something in the code like array[5] and then be able to use a for loop with that as the boundaries or even pulling out a specific place in the array. At it's core, that's the concept behind the code, and I'd be surprised if anyone with an even elementary understanding of C would consider that a complex concept.

You have N quest completion tokens. You want to know if quest N has been completed. It makes sense to ask if quest N was completed by checking for that property. It does NOT make sense to calculate that quest N's token is in byte position X in quest-mapping-thing 3. What happens if you remove a quest? What if you add another quest in-between two existing ones? Now you have to hand-shuffle the data around to fit the new ordering. Now, worst case, all your mobprog code has to be modified to look at quest-string-thing 4, position 12 instead of quest-string-thing 4, position 11.

I feel for you, if you're coding to the limitations of your mobprog system, rather than extending that system to work in a more intuitive fashion. I can't know how difficult that would be, as my Diku pre-dates mobprogs (all my stuff was hard-coded as special procs in C).

In any case, I'm simply saying that encoding things like this is obfuscation, so if you feel you have to do it this way, be sure you document the hell out of it, both in code AND in help files, or in 2020 you'll remember me saying this and curse up a storm. :)

@Rarva – I hear you. I'm now used to cushy languages like ruby and perl, and hate having to mess with qsort() and arrays of pointers. :)
16 Jan, 2013, Ssolvarain wrote in the 34th comment:
be sure you document the hell out of it, both in code AND in help files

That he did.

But to be fair, this particular system won't be used over the variables we currently use for quest tracking. It was mostly meant as a one-off to compress a string of variables for one particular project.

Nit picking is kind of rude and unnecessary for a project like this.
16 Jan, 2013, Hades_Kane wrote in the 35th comment:
Quote
What happens if you remove a quest? What if you add another quest in-between two existing ones?

Who said anything about there having to be a linear order to the way the variables are mapped?

For most quests, a single, cohesive value works just fine. For example, in the quest that leads up to quest promotion, the "prepromotion" variable is what is used, and that goes from 1-54 to track progress. Anything other side values that need to be used throughout, such as whether or not you completed X task for mob Y in Z manner are tracked through alternate variables, and once all of those side things are wrapped up, those variables are closed out and the "master" variable of "prepromotion" is updated to reflect the quest's progress.

The specific purposes of using these values are an array aren't to track linear progress of something like a quest, they are to track non linear sets of data that can be completed in any manner of things.

I have 10 mobs that have to be killed to progress, each of them being unique. Rather than having 15 different variables to track, I have an "array" like this setup, where each digit represents a specific mob, who updates it once they have been killed. At the end, rather than a big check in the prog of whether 10 different variables have been set, I have one check for the overall value, and done. All of this is stored and checked in a single variable structure rather than 10 different ones.

Or in the case of these special treasure chests, the same kind of thing. They will be found at different points and in different orders by different players. There is no linear track to interrupt or have to reshuffle a whole bunch of data. If I use all digits of the variables I have in place and later decide I want to add more chests? It's simple, just add another variable. Same thing with any of the other variables or quests or anything that a builder may be working on. And any builder scripting anything more complex than a greet program should be keeping notes of what they are doing with a quest or set of variables. Knowing that X digit of a value equals a particular mob or chest or whatever a builder may be keeping track of should be kept in notes.

And besides, this is a tool available. Not every tool that I provide the people working on my game gets used by every person. If someone finds it easier to track things with individual values, they are welcome to do that, but speaking as someone who has done extensive scripting on my game and speaking for others who have voiced their opinion on this addition, it is a welcome addition that makes doing what we need/want to do in our scripts easier in every respect.

Stock mobprogs are in fact quite limited, and as a builder I "grew up" on a MUD where the coder had all but abandoned the game, and so I and my fellow builders became very, very creative with what we could do with the limited stock resources we had. We were able to add entire new "features" to the game based on our progs alone. They were jury rigged to hell and back sometimes, even to the point of sometimes having objects having to load mobs to do something the objects couldn't do, and then disappearing. I can't count the number of quests I tracked using invisible-to-the-player items that couldn't be dropped that would be collected at the end of a quest in order to track progress. We've added transportation systems, transforming items, random battles… all kinds of things. Most of those things are hard-coded or have better tools available to do those now on End of Time, but we had to be creative back when I got started building.

This is one reason why I dedicate myself so strongly to focusing very heavily on improving the framework we have so that the people who build on my game will never have to jump through such elaborate hoops just to accomplish something. I add pretty much anything that is requested, I add sometimes entirely new aspects of our OLC when I have the need for something small, but see the potential in a more wide spread and more powerful usage by the builders. Creativity can go a long way with builders and the scripts, and the more I can provide them to work with, the more creative and the more interesting things they can create. I strongly feel there is no such thing as too many tools in this respect.

Our OLC and program system has now reached a point where with a bit of creativity, we haven't ran across anything that we couldn't accomplish. In some respects, certain things have actually gotten easier to script in-game rather than add code for, and one of our staff members has an entire "hunts" system programmed, and we've even managed to script TVs with channeling changing, commercials, etc. Things that could have been coded, but the versatility that our program system now has made doing these in the program system easier.
Random Picks

20.0/35