22 Jul, 2011, melopene wrote in the 1st comment:
Votes: 0
Apologies for the massive blocks of log and code, but I'd rather be thorough with the information from the start…


So in all my recent work on a crafting system I've likely driven my code-buddy crazy, so here's one last thing I can't figure out.

The support code for mining requires that each area have a variety of materials set, so players who use their mining skill in the appropriate places have a shot at finding a raw material.

I've been working on this for a while now without much of a break, and it's driving me crazy that this last little bit won't function properly - I know I'm doing something very stupid and incorrect, but I really don't understand flag handling well enough to see it. So, any advice would be appreciated.

tl;dr: I'm stupid, please do my homework for me. Or at least tell me where I'm being stupid.

The following is what is currently occurring:

Quote
[Melopene's Library - 400 | - Limbo]
aedit 0

[Melopene's Library - 400 | - Limbo]

Name: [ 0] Limbo
File: limbo.are
Vnums: [1-500]
Age: [1]
Players: [1]
Security: [0]
Builders: [None]
Credits : [[ IMM ] Immortal Realms]
Materials: [unknown]
Flags: [none]

[Melopene's Library - 400 | - Limbo]
material hemite

[Melopene's Library - 400 | - Limbo]

Name: [ 0] Limbo
File: limbo.are
Vnums: [1-500]
Age: [1]
Players: [1]
Security: [0]
Builders: [None]
Credits : [[ IMM ] Immortal Realms]
Materials: [glass blood food magical paper plantlife wood silk linen cloth dragonskin feather fur hide leather stone bone brae ceramic pynium braun cuprim maledrite gold micite hemite irium silver dolomel shell bisce yahalm verdil ibha aquine shoham naceril alstine roseale cerul]
Flags: [changed]

[Melopene's Library - 400 | - Limbo]
asave changed
Saved zones:
Limbo - 'limbo.are'

[Melopene's Library - 400 | - Limbo]
copyover

You find yourself feeling a little off, as if something is wrong.


You pause for a moment to reflect on what it might be…

You shake your head, returning your attention to reality.

[ Melopene's Library ] [ Room 400 ]
A lengthy hall, lined with chalkboards and computer terminals, expands
along a north-south axis. The chalkboards are covered with scribbled
notations and ideas, as well as a few bits of pseudo-code, and the computer
terminals display various outputs of regression and factor analysis models.
Along the length of the hall, the grayed marble floors are largely empty,
save for a heavy mahogany desk and accompanying chair at the front of the
room. The desk is littered with papers on various topics from volunteerism
and work motivation to implementation of new governmental forms.

[Exits: none]
TICK!

[Melopene's Library - 400 | - Limbo]
aedit 0

[Melopene's Library - 400 | - Limbo]

Name: [ 0] Limbo
File: limbo.are
Vnums: [1-500]
Age: [1]
Players: [1]
Security: [0]
Builders: [None]
Credits : [[ IMM ] Immortal Realms]
Materials: [unknown]
Flags: [none]


And the following is the related code.

From olc_act.c:
AEDIT( aedit_material )
{
AREA_DATA *pArea;

EDIT_AREA(ch, pArea);

if ( argument[0] == '\0' )
{
send_to_char( "Syntax: material [type]\n\r", ch );
return FALSE;
}
int x;

for (x=0; material_flags[x].name != NULL; x++)
{
if (!str_cmp(material_flags[x].name,argument))
{
int matnum = material_flags[x].bit;

SET_BIT( pArea->materials, matnum );
return TRUE;
}
}
send_to_char( "Syntax: material [type]\n\r"
"Type '? material' for a list of materials.\n\r", ch );
return FALSE;


}


also, olc_act.c:
AEDIT( aedit_show )
{
AREA_DATA *pArea;
char buf [MAX_STRING_LENGTH];

EDIT_AREA(ch, pArea);

sprintf( buf, "Name: [%5d] %s\n\r", pArea->vnum, pArea->name );
send_to_char( buf, ch );

#if 0 /* ROM OLC */
sprintf( buf, "Recall: [%5d] %s\n\r", pArea->recall,
get_room_index( pArea->recall )
? get_room_index( pArea->recall )->name : "none" );
send_to_char( buf, ch );
#endif /* ROM */

sprintf( buf, "File: %s\n\r", pArea->file_name );
send_to_char( buf, ch );

sprintf( buf, "Vnums: [%d-%d]\n\r", pArea->min_vnum, pArea->max_vnum );
send_to_char( buf, ch );

sprintf( buf, "Age: [%d]\n\r", pArea->age );
send_to_char( buf, ch );

sprintf( buf, "Players: [%d]\n\r", pArea->nplayer );
send_to_char( buf, ch );

sprintf( buf, "Security: [%d]\n\r", pArea->security );
send_to_char( buf, ch );

sprintf( buf, "Builders: [%s]\n\r", pArea->builders );
send_to_char( buf, ch );

sprintf( buf, "Credits : [%s]\n\r", pArea->credits );
send_to_char( buf, ch );
sprintf( buf, "Materials: [%s]\n\r", flag_string( material_flags, pArea->materials ) );
send_to_char( buf, ch );
sprintf( buf, "Flags: [%s]\n\r", flag_string( area_flags, pArea->area_flags ) );
send_to_char( buf, ch );

return FALSE;
}


from olc_save.c:
void save_area( AREA_DATA *pArea )
{
FILE *fp;
char buf[MSL];

fclose( fpReserve );
if ( !( fp = fopen( pArea->file_name, "w" ) ) )
{
bug( "Open_area: fopen", 0 );
perror( pArea->file_name );
}

fprintf( fp, "#AREADATA\n" );
fprintf( fp, "Name %s~\n", pArea->name );
fprintf( fp, "Builders %s~\n", fix_string( pArea->builders ) );
fprintf( fp, "VNUMs %d %d\n", pArea->min_vnum, pArea->max_vnum );
fprintf( fp, "Credits %s~\n", pArea->credits );
fprintf( fp, "Security %d\n", pArea->security );
fprintf( fp, "Materials %s\n", fwrite_flag( pArea->materials, buf ) );
fprintf( fp, "End\n\n" );

save_mobiles( fp, pArea );
save_objects( fp, pArea );
save_rooms( fp, pArea );
save_specials( fp, pArea );
save_resets( fp, pArea );
save_shops( fp, pArea );
save_mobprogs( fp, pArea );
save_objprogs( fp, pArea );
save_roomprogs( fp, pArea );

fprintf( fp, "#$\n" );

fclose( fp );
fpReserve = fopen( NULL_FILE, "r" );
return;
}


A glance at my material table structure:
const struct flag_type material_flags[] =
{
{ "unknown", MAT_UNKNOWN, TRUE },
{ "glass", MAT_GLASS, TRUE },
{ "blood", MAT_BLOOD, TRUE },
{ "food", MAT_FOOD, TRUE },
{ "liquid", MAT_LIQUID, TRUE },
{ "magical", MAT_MAGICAL, TRUE },
{ "paper", MAT_PAPER, TRUE },
{ "plantlife", MAT_PLANTLIFE, TRUE },
{ "wood", MAT_WOOD, TRUE },
{ "silk", MAT_SILK, TRUE },
{ "linen", MAT_LINEN, TRUE },

//etc etc etc…

}


Aaaand, for fun, load_area_new, from db.c:
void new_load_area( FILE *fp )
{
AREA_DATA *pArea;
char *word;
bool fMatch;

pArea = alloc_perm( sizeof(*pArea) );
pArea->age = 15;
pArea->nplayer = 0;
pArea->file_name = str_dup( strArea );
pArea->vnum = top_area;
pArea->name = str_dup( "New Area" );
pArea->builders = str_dup( "" );
pArea->security = 9; /* 9 – Hugin */
pArea->materials = 0;
pArea->min_vnum = 0;
pArea->max_vnum = 0;
pArea->area_flags = 0;
/* pArea->recall = ROOM_VNUM_TEMPLE; ROM OLC */

for ( ; ; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = FALSE;

switch ( UPPER(word[0]) )
{
case 'M':
KEY( "Materials", fread_flag(fp));
case 'N':
SKEY( "Name", pArea->name );
break;
case 'S':
KEY( "Security", pArea->security, fread_number( fp ) );
break;
case 'V':
if ( !str_cmp( word, "VNUMs" ) )
{
pArea->min_vnum = fread_number( fp );
pArea->max_vnum = fread_number( fp );
}
break;
case 'E':
if ( !str_cmp( word, "End" ) )
{
fMatch = TRUE;
if ( area_first == NULL )
area_first = pArea;
if ( area_last != NULL )
area_last->next = pArea;
area_last = pArea;
pArea->next = NULL;
top_area++;
return;
}
break;
case 'B':
SKEY( "Builders", pArea->builders );
break;
case 'C':
SKEY( "Credits", pArea->credits );
break;
}
}
}
22 Jul, 2011, Omega wrote in the 2nd comment:
Votes: 0
First thing I noticed in the load_new_area was the following:

case 'M':
KEY( "Materials", fread_flag(fp));


should be

case 'M':
KEY( "Materials", pArea->materials, fread_flag(fp));
break;



Second part is, when you set hemite as the flag, I'm seeing that it is setting what appears to be all flags, is this a catch-all flag that is supposed to do that, or is it something else all together.

Also, how many flags do you have? (A-FF) ? Or more, or are those flag types just an enum. If so, that would be another potential issue.

Perhaps showing the saved file as well will help in the diagnosis of this, as well as your definitions for the material flag types.
22 Jul, 2011, melopene wrote in the 3rd comment:
Votes: 0
Darien said:
First thing I noticed in the load_new_area was the following:
…..

should be

…..


Changed, thanks for the catch!


Darien said:
Second part is, when you set hemite as the flag, I'm seeing that it is setting what appears to be all flags, is this a catch-all flag that is supposed to do that, or is it something else all together.

Also, how many flags do you have? (A-FF) ? Or more, or are those flag types just an enum. If so, that would be another potential issue.

Perhaps showing the saved file as well will help in the diagnosis of this, as well as your definitions for the material flag types.


I have a ton of materials. But they're #defined in merc.h as ints - I figured that because area_flags (changed, added, etc) were done in such a way that I would be okay to do this.

From the new-code-saved limbo.are:
#AREADATA
Name Limbo~
Builders None~
VNUMs 1 500
Credits [ IMM ] Immortal Realms~
Security 0
Materials ABDE
End


I guess this might also help…

from merc.h:
/*material types*/
#define MAT_UNKNOWN 0
#define MAT_GLASS 1
#define MAT_BLOOD 2
#define MAT_FOOD 3
#define MAT_LIQUID 4
#define MAT_MAGICAL 5
#define MAT_PAPER 6
#define MAT_PLANTLIFE 7
#define MAT_WOOD 8
#define MAT_SILK 9
#define MAT_LINEN 10
#define MAT_CLOTH 11
#define MAT_DRAGONSKIN 12
#define MAT_FEATHER 13
#define MAT_FUR 14
#define MAT_HIDE 15
#define MAT_LEATHER 16
#define MAT_STONE 17
#define MAT_BONE 18
#define MAT_BRAE 19
#define MAT_CERAMIC 20
#define MAT_PYNIUM 21
#define MAT_BRAUN 22
#define MAT_CUPRIM 23
#define MAT_MALEDRITE 24
#define MAT_GOLD 25
#define MAT_MICITE 26
#define MAT_HEMITE 27
#define MAT_IRIUM 28
#define MAT_SILVER 29
#define MAT_DOLOMEL 30
#define MAT_SHELL 31
#define MAT_SEPOL 32
#define MAT_BISCE 33
#define MAT_YAHALM 34
#define MAT_VERDIL 35
#define MAT_GODSICE 36
#define MAT_IBHA 37
#define MAT_AQUINE 38
#define MAT_SHOHAM 39
#define MAT_NACERIL 40
#define MAT_ALSTINE 41
#define MAT_ROSEALE 42
#define MAT_CERUL 43
22 Jul, 2011, Omega wrote in the 4th comment:
Votes: 0
Just as I expected; your numbers that you have defined cannot work in the flag system supplied. They simply do not comply to the required forum in which the flags work.

See, flags will use things like:

#define MAT_UNKNOWN (A)
#define MAT_GLASS (B)


However, there are not that many bit-flags available to you in the stock systems (need an enhanced bit handler to go up, see your merc.h for the definitions of the A/B/C/etc)

Thats why when you set your flags, it sets everything, and why when you save, it saved wrong data. (ABDE)

You'll need to either make it so that your area can only have 1 material flag-value, or you will have to improve your bit-system immensely for it to work your current way.

Of course those material types are probably attached to another system, so you cannot exactly convert them without converting the other system too.

But I digress.

The point is, your going to need to take a moment and revisit your overall design and work it out, do you want multiple material types, or just 1. That is your simple solution for the moment. (change it to 1; other wise, you'll need to convert to actual bit flags and expand the bitflag system)
22 Jul, 2011, melopene wrote in the 5th comment:
Votes: 0
Darien said:
Just as I expected; your numbers that you have defined cannot work in the flag system supplied. They simply do not comply to the required forum in which the flags work.

See, flags will use things like:

#define MAT_UNKNOWN (A)
#define MAT_GLASS (B)


However, there are not that many bit-flags available to you in the stock systems (need an enhanced bit handler to go up, see your merc.h for the definitions of the A/B/C/etc)

Thats why when you set your flags, it sets everything, and why when you save, it saved wrong data. (ABDE)

You'll need to either make it so that your area can only have 1 material flag-value, or you will have to improve your bit-system immensely for it to work your current way.

Of course those material types are probably attached to another system, so you cannot exactly convert them without converting the other system too.

But I digress.

The point is, your going to need to take a moment and revisit your overall design and work it out, do you want multiple material types, or just 1. That is your simple solution for the moment. (change it to 1; other wise, you'll need to convert to actual bit flags and expand the bitflag system)


That's pretty much exactly what I figured. I would like to be able to mine a number of minerals per area, but would prefer NOT to have to change every other call to materials in the code (as materials and material-related tables are very pervasive in this implementation).

I suppose the best approach at this point would be to implement a value array similar to that within objects - say, up to five or six or whatever types of minerals available in a specific area. I think that would be an easier approach than extending bits, and would be more readily converted into a snippet should I choose to do so.

Thank you, dear. :)
22 Jul, 2011, Omega wrote in the 6th comment:
Votes: 0
No problem; I had a similar mining system on my mud back in the day. The way I handled it was by having several 'types' of materials if you will, metallics, gems, etc, etc, and assigned a percentage for the different types. So under gems, there was ruby's, diamonds, opals, etc, anyways, each one, the more expensive the item got, the lower percentage there would be of it being able to be mined. (plus skill/level played an effect on it)

A similar system to that can easily be created : OR you can create a whole new material table just for it, last time I checked, people don't exactly mine glass. ;) So you could create another set of materials that fit your scheme and fit into the actual bit-system (easily enough) A through FF (or EE, forget which one stock comes with) Anyways, yeah, A-FF of minable material types is still quite a lot of materials. And you can always assign a secondary materials flag, and just keep expanding, like the extra_flags, and extra2_flags that people made for diku/merc derived muds. I'm sure you can do it with your own brand just as easily, just not using those other numbered systems.

(your call)

but I know with what you have right now, you could have one done up the way I described (if your a fast coder) within a hour; maybe 2 pending your skill level.

With that said, hope it goes well for you nomatter what you decide!
22 Jul, 2011, melopene wrote in the 7th comment:
Votes: 0
Darien said:
No problem; I had a similar mining system on my mud back in the day. The way I handled it was by having several 'types' of materials if you will, metallics, gems, etc, etc, and assigned a percentage for the different types. So under gems, there was ruby's, diamonds, opals, etc, anyways, each one, the more expensive the item got, the lower percentage there would be of it being able to be mined. (plus skill/level played an effect on it)

A similar system to that can easily be created : OR you can create a whole new material table just for it, last time I checked, people don't exactly mine glass. ;) So you could create another set of materials that fit your scheme and fit into the actual bit-system (easily enough) A through FF (or EE, forget which one stock comes with) Anyways, yeah, A-FF of minable material types is still quite a lot of materials. And you can always assign a secondary materials flag, and just keep expanding, like the extra_flags, and extra2_flags that people made for diku/merc derived muds. I'm sure you can do it with your own brand just as easily, just not using those other numbered systems.

(your call)

but I know with what you have right now, you could have one done up the way I described (if your a fast coder) within a hour; maybe 2 pending your skill level.

With that said, hope it goes well for you nomatter what you decide!


The code is working beautifully now, many thanks :)

I will most likely create yet another large data table determining material chance by sector at some point. However, the way that my world is set up, 98% of most areas are of a single sector (small areas are built upon wilderness grids), so I don't really anticipate needing much more than a sector and area materials check for some time.

I knew this project would be a beast before I took it on, but it's become a beast of a whole different level. :)
22 Jul, 2011, Rarva.Riendf wrote in the 8th comment:
Votes: 0
Quote
I knew this project would be a beast before I took it on, but it's become a beast of a whole different level. :)

Wait till you actually are at the point to create items with your materials. Then the real problems arise :p Distributing materials is the easiest part.
22 Jul, 2011, melopene wrote in the 9th comment:
Votes: 0
Rarva.Riendf said:
Quote
I knew this project would be a beast before I took it on, but it's become a beast of a whole different level. :)

Wait till you actually are at the point to create items with your materials. Then the real problems arise :p Distributing materials is the easiest part.


Actually, I'm doing distribution last. I first tested my formulas with OLC autosets, then added in the smithing code, then refining of raw materials, then mining the raw materials. So when I say that I've turned it into a beast, I mean it.

I mean… my master spreadsheet that I used to create my various crafting tables has 62 fields per material, not including material name. This is by far the biggest project I've ever tackled, and I'm tickled to death that it seems to have turned out precisely as I wanted it to.

Edit: Oh, and I still have a bunch of the fight code to redo based upon object material and condition. Teehee.
22 Jul, 2011, Rarva.Riendf wrote in the 10th comment:
Votes: 0
To have like unlimited flags you can do bit bashing

This is what I do to see if a char has already visted a room or not as an example (basically storing vnum value as the bit position)

pcdata->visitedroom = (char *)malloc(8192 * sizeof(char));  //0 to 8192*8 possible value stored

//8 is for one byte (as sizeofchar is one byte)

bool_t is_room_visited(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex) {
return ch->pcdata->visitedroom[pRoomIndex->vnum / 8] & (1 << (pRoomIndex->vnum % 8)) ? TRUE : FALSE;
}

void set_room_visited(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex) {
ch->pcdata->visitedroom[pRoomIndex->vnum / 8] |= (1 << (pRoomIndex->vnum % 8));
}


There you now have quite enough flags for a lifetime.
22 Jul, 2011, Scandum wrote in the 11th comment:
Votes: 0
If you want up to 64 flags instead of 32 you can also switch from int to long long, which is easier than going for an infinite bit system. If you want more than 64 flags it'd probably be best to go for an unlimited system right away.

Each int flag exceeding 31 bits would be changed to long long, you'd have to switch all %d calls to %lld (as you can write an int as a long long, but not visa versa) and cast 64 bit flags using: #define BIT32 (1LL << 31), #define BIT33 (1LL << 32), etc.
22 Jul, 2011, Runter wrote in the 12th comment:
Votes: 0
Having successfully built low level solutions to this problem in the past (infinite bits), and weighing the headache vs the gains, I've opted to just use arrays of values as a rope bridge. They're human readable, they're easy to implement, they're reliable, and they're efficient enough. Furthermore, we can always refactor later once we have thousands of players online at all times since the concept of a bitmask can be put through a routine to get another format. :rolleyes:
23 Jul, 2011, David Haley wrote in the 13th comment:
Votes: 0
A well-written arbitrary-sized bit vector is easy to use. Any kind of fixed-size numeric bit system will limit you; you already have 43, it's not that crazy to think you'll go to 64+. As a shameless plug, it so happens that I uploaded a bitvector library that is, IMHO, fairly easy to use.
23 Jul, 2011, Rarva.Riendf wrote in the 14th comment:
Votes: 0
Just superficially looked at your lib, how do you save a bitvector in a player? (that is why I use a char to store the bit, a simple fprintf works)
23 Jul, 2011, Sharmair wrote in the 15th comment:
Votes: 0
Rarva.Riendf said:
How do you save a bitvector in a player? (that is why I use a char to store the bit, a simple fprintf works)

That really is not saying much as pretty much all code that uses text player files (or other files you
might save a bitvector in) will use fprintf. The real question is what format string do you use to
save your chars? you pretty much imply you save the char array out as a simple string, and that
will NOT work, as it would terminate the string at the first char with no bits set ie. your char array
is not a string, it is a fixed size buffer of bits that happen to be arranged as chars (a rather bad
choice BTW).
23 Jul, 2011, Rarva.Riendf wrote in the 16th comment:
Votes: 0
Sharmair said:
Rarva.Riendf said:
How do you save a bitvector in a player? (that is why I use a char to store the bit, a simple fprintf works)

That really is not saying much as pretty much all code that uses text player files (or other files you
might save a bitvector in) will use fprintf. The real question is what format string do you use to
save your chars? you pretty much imply you save the char array out as a simple string, and that
will NOT work, as it would terminate the string at the first char with no bits set ie. your char array
is not a string, it is a fixed size buffer of bits that happen to be arranged as chars (a rather bad
choice BTW).

Well actually I save it like that:
for (sn =0; sn <MAX_MAP_ROOM_SAVED ; sn++)
fprintf(fp, "%c", ch->pcdata->visitedroom[sn]);
But I should calloc now that I read it again.
24 Jul, 2011, David Haley wrote in the 17th comment:
Votes: 0
I didn't include that because I think it depends on your usage. Do you want to save the actual bits, 001100101, or a list of named flags, "mobile" "magic" "strong" etc.?

It's pretty easy to iterate over the bit vector, checking if each bit is set or not, and outputting a 0 or 1 accordingly.
24 Jul, 2011, Rarva.Riendf wrote in the 18th comment:
Votes: 0
David Haley said:
I didn't include that because I think it depends on your usage. Do you want to save the actual bits, 001100101, or a list of named flags, "mobile" "magic" "strong" etc.?

It's pretty easy to iterate over the bit vector, checking if each bit is set or not, and outputting a 0 or 1 accordingly.

Had a stupid moment, as I also iterate through my char buffer to save the values. For some reason I was thinking actually simply fprintf the string but as Sharmair said that could not work.
0.0/18