Reading one struct from another

Posted by Zeno on Thu 19 Aug 2004 02:35 AM — 9 posts, 31,439 views.

USA #0
Alright, I've got the character struct working, so now I'm trying to link a skill/attack struct to the character struct.

In the load_character function:

      case 'A':
        SREAD( "Attack0", character->attacks[0]->name );


Reads an attack file:

ATTACK *load_attack(char *argument)
{
  FILE *fp;
  ATTACK *attack = NULL;
  char afile[256];
  char aName[20];
  int size, i;
  char *word;
  bool done = FALSE, found;

  aName[0] = toupper(argument[0]);
  size = strlen(argument);
  for (i = 1; i < size; i++)
    aName[i] = tolower(argument[i]);
  aName[i] = '\0';


  sprintf(afile, "../attacks/%s.atk", aName);
  if ((fp = fopen(afile, "r")) == NULL)
    return NULL;

    if ((attack = malloc(sizeof(*attack))) == NULL)
    {
      bug("Load_attack: Cannot allocate memory.");
      abort();
    }

  word = fread_word(fp);
  while (!done)
  {
    found = FALSE;
    switch (word[0])
    {
      case 'C':
        SREAD( "Cmd", attack->cmd );
        break;
      case 'N':
        SREAD( "Name", attack->name );
        break;
      case 'P':
        SREAD( "PreAttack", attack->preattack );
        break;
      case 'E':
        if (compares(word, "EOF")) {done = TRUE; found = TRUE; break;}
        break;
    }
    if (!found)
    {
      bug("Load_attack: unexpected '%s' in %s's afile.", word, argument);
      return NULL;
    }

    if (!done) word = fread_word(fp);
  }

  fclose(fp);
  return attack;
}


main.h

typedef struct  attack_data   ATTACK;

In char struct:

  ATTACK          * attacks[20];


struct attack_data
{
  char          * name;
  char          * cmd;
  char          * preattack;
};

Attack part of a char:

Attacks0       Slash~


The struct for attacks work, I can display the file in a cmd.

But when loading a char with an attack, it crashes, with this debug:


#0  0x0804edee in load_character (argument=0x805aae1 "cloud") at save.c:307
#1  0x0804d8f4 in cmd_showchar (dMob=0x805b0a0, arg=0x811db58 "Slash") at commands.c:706
#2  0x0804b823 in handle_cmd_input (dsock=0x811db58, arg=0x805aae1 "cloud") at interpret.c:33
#3  0x0804943f in game_loop (control=3) at socket.c:175
#4  0x0804925c in main (argc=3, argv=0xbffff954) at socket.c:77
#5  0x42015967 in __libc_start_main () from /lib/i686/libc.so.6


The character loads fine until it gets to attack.


302       {
303         found = FALSE;
304         switch (word[0])
305         {
306           case 'A':
307             SREAD( "Attack0", character->attacks[0]->name );
308             SREAD( "AfterAKill1", character->afterakill1 );
309             break;
310           case 'B':
311             SREAD( "BlockFail",  character->blockfail  );


character->attacks[0] is not loading, because its null.

Why is it not reading correctly?
Amended on Thu 19 Aug 2004 02:38 AM by Zeno
USA #1
Did you allocate space for attack? It may be easier to do this:

{
 char *var;
 SREAD( "Attack0", var );
 character->attack[0] = lookup_attack( var );
}

And have lookup_attack return a pointer to the right allocated attack structure with the name that matches var. Make sure you read in the attacks when the mud starts however.

Think of it this way. You used smaug. When a person connected, they start as a descriptor. The descriptor_data struct has a CHAR_DATA *char variable (or something similar), however, before its used you need to load the char. It is then assigned.

What you are trying to do is assign data to space that isnt there. You could probably accomplish the same affect by just allocating space for character->attack when you allocate for a character.

I think thats right, maybe I've got myself all switched around. Try it, see what happens.

Btw, you'll need a linked list or table of pointers to allocated attacks, if you dont have one.

EDIT:

Actually, SREAD allocates data since it uses fread_string instead of fread_word, so perhaps allocating for attack is your best bet?
Amended on Thu 19 Aug 2004 06:20 AM by Nick Cash
Canada #2
Are you sure that you have the same thing for aName after it uppers and lowers it when you do it manually as when its in a players file? That part returns null with no bug if it can't find the file, so there might be a slight difference in what argument is.
USA #3
Whiteknight, oddly enough, thats what I tried first.

Although your way worked.

Now, its appearing null on a char. (At least its not crashing anymore)

Characters and skills aren't to be saved though, er that is, written to file.

Here's my debug while loading a char:

[LOG: SREAD: Attack0, temp]
[LOG: Temp: …À‰Á…Àˆw[]
[LOG: load_attack...]
[LOG: aName: …À‰Á…Àˆw[]
[LOG: SREAD: Attack0, temp]

Moves:
(null)



        dprintf(dMob, "%s", chara->attacks[0] );


If its attacks[0]->name, it crashes.

Do I really need a linked list?
USA #4
Well, if your loading attacks from a file then you might as well as just throw them in a linked list and reference to them that way. No need in wasting space by loading them one time for each character. Just make a master list, and then when you load from characters just do as you did. Have the name, and look it up and just assign the value.

An alternative to a linked list would be a table. If you have SWR, just go into const.c and look at the race table. This might be a good alternative since you dont have to load any files to have it work correctly. Then it simplies everything. character_data's attack var would turn to int attack[20], and instead of all of this work with pointers and allocating you just do this:

IREAD( "Attack0", character->attacks[0] );

And then when you want to loop through their attacks, you do this:

for ( i = 0; i < 20; i++ )
{
  if ( attack_table[i]->name == something )
   do soemthing here;
}

If you dont want to deal with loading files and crap, table's are generally a good way to do it.
Amended on Thu 19 Aug 2004 07:54 PM by Nick Cash
USA #5
Oh, I guess I forgot to mention that.

I already have an attack.lst and char.lst, but I don't have a table of any sort.

Whats the cause for crashing then, if I already have a linked list?

Cloud.char has Slash.atk in his file, I can read the file with showattack, but the char can't load it, it turns out to be null. Both list files are correct.

Anyways, I'll double check the list after I get back from buying Tales of Symphonia. ;)
USA #6
Okay, did some debugging, here's the results: (showattack displays the attack file, example, Slash.atk)

showattack slash

[LOG: load_attack started, arg: slash]
[LOG: load_attack, aName: Slash]
[LOG: load_attack, fopen: ../attacks/Slash.atk]
[LOG: load_attack: file found: ../attacks/Slash.atk]
[LOG: load_attack: Could allocate memory.]
Name: Slash
Cmd: slash
PreAttack: $n goes to slash...


showchar cloud

[LOG: load_char: attack0: ¯¢Õ£t¤¾¥+¥Program starting.]
[LOG: load_attack started, arg: ¯¢Õ£t¤¾¥+¥Program starting.]
[LOG: load_attack, aName: ¯¢Õ£t¤¾¥+¥program starting.]
[LOG: load_attack, fopen: ../attacks/¯¢Õ£t¤¾¥+¥program star../attacks/.atk]
(Char data here)
Moves:
(null)
Accounts using this char: 


So load_char is the problem.

  char *temp;
...
307      case 'A':
308        SREAD( "Attack0", temp );
309        bug( "load_char: attack0: %s", temp );
310        character->attacks[0] = load_attack( temp );
311        SREAD( "AfterAKill1", character->afterakill1 );
312        break;


Only problem is if I make it ATTACK *temp, then it crashes because:

save.c:308: warning: assignment from incompatible pointer type
save.c:310: warning: passing arg 1 of `load_attack' from incompatible pointer type


Yeah, in the Cloud character, Attack0 is "Slash".
USA #7
I cant belive I didn't see it before. If you examine SREAD in mud.h it actually has break; in there, which would mess everything up how you have it.
Quote:

Only problem is if I make it ATTACK *temp, then it crashes because:

save.c:308: warning: assignment from incompatible pointer type
save.c:310: warning: passing arg 1 of `load_attack' from incompatible pointer type

Well, that makes perfect sense. Look at what you are trying to do. SREAD is a macro specifically designed to load in strings. If you use anything but a char variable, it is likely to produce a crash.

Quote:

307 case 'A':
308 SREAD( "Attack0", temp );
309 bug( "load_char: attack0: %s", temp );
310 character->attacks[0] = load_attack( temp );
311 SREAD( "AfterAKill1", character->afterakill1 );
312 break;

Try this:

      case 'A':
        if ( compares( "Attack0", word ) )
        {
         temp = fread_string(fp);

         bug( "load_char: attack0: %s", temp );
         character->attacks[0] = load_attack( temp );

         found = TRUE;
         break;
        }
        SREAD( "AfterAKill1", character->afterakill1 );
        break;

That SHOULD fix the problem. I think....
USA #8
Yep, it did. Thanks.

As for the crash, I wasn't really asking why or how to fix that, just stating. Didn't say the reason for the crash, because it was obvious.

Now to figure out how to interpret the account->character->attack->cmdname as a command that can be used.