Welcome to the Builder Academy

Question Mob Extra Descriptions?

More
19 Oct 2017 19:48 #7024 by thomas
Replied by thomas on topic Mob Extra Descriptions?
This is interesting. Keep us posted :)
The following user(s) said Thank You: Papaya Pete

Please Log in or Create an account to join the conversation.

More
19 Oct 2017 20:21 - 19 Oct 2017 20:29 #7025 by Papaya Pete
Replied by Papaya Pete on topic Mob Extra Descriptions?
Latest work has been... a little fruitful? Sort of?

I've managed to get it to save onto the mob file AND medit will pull up the data. However... look at how it saves it.
Code:
#1 old man~ an old man~ Sitting on a small stool is an old man, who mumbles to himself quietly. ~ Dressed in old grey robes, this old man has only a few wisps of spindly white hair left on his head. His beard, though it reaches his chest, is thin and can be seen through. Wrinkles form creases on his face, and his eyes look like they are shut at first glance. However, they're just barely open, and he mumbles to himself in an incoherent manner. He slowly rocks back and forth on the stool, as if constantly shifting his weight to get more comfortable. ~ He nods approvingly. "@YWell done, well done indeed!@n" ~ 262154 0 0 0 0 0 0 0 0 E 0 20 10 1d1+0 1d1+0 0 0 8 8 1 E T 10 A A help~ giving ~ A A name~ higgins ~

For some reason it saves 2 As in a row. So, while it DOES read the keyword and desc properly... every single topic now has an A as one of the keywords.

I had to make a change in db.c and it MIGHT be part of the problem... see, objects and rooms had code for parsing extra descs but mobs? Nada. And the formatting for objects and rooms is different enough that you can't just copy and paste it. So... here is what I tried to do.
Code:
switch (UPPER(letter)) { case 'S': /* Simple monsters */ parse_simple_mob(mob_f, i, nr); break; case 'E': /* Circle3 Enhanced monsters */ parse_enhanced_mob(mob_f, i, nr); break; /* add new mob types here.. */ default: log("SYSERR: Unsupported mob type '%c' in mob #%d", letter, nr); exit(1); } letter = fread_letter(mob_f); ungetc(letter, mob_f); while ((letter =='E') || (letter == 'T')) { if (letter == 'E') { CREATE(new_descr, struct extra_descr_data, 1); new_descr->keyword = fread_string(mob_f, buf2); new_descr->description = fread_string(mob_f, buf2); new_descr->next = mob_proto[i].ex_description; mob_proto[i].ex_description = new_descr; } else if (letter == 'T') dg_read_trigger(mob_f, &mob_proto[i], MOB_TRIGGER); letter = fread_letter(mob_f); ungetc(letter, mob_f); } /* DG triggers -- script info follows mob S/E section letter = fread_letter(mob_f); ungetc(letter, mob_f); while (letter=='T') { dg_read_trigger(mob_f, &mob_proto[i], MOB_TRIGGER); letter = fread_letter(mob_f); ungetc(letter, mob_f); } */

The commented out portion is what was used before: on reading a line, if ungetc gets a letter that is T, that means it's a trigger and it will put the trigger number afterwards on the same line. I took the same principle but had it read lines from the file instead.
Code:
fprintf(fd, "%d %d %d %d %d %d %d %d %d E\n" "%d %d %d %dd%d+%d %dd%d+%d\n", MOB_FLAGS(mob)[0], MOB_FLAGS(mob)[1], MOB_FLAGS(mob)[2], MOB_FLAGS(mob)[3], AFF_FLAGS(mob)[0], AFF_FLAGS(mob)[1], AFF_FLAGS(mob)[2], AFF_FLAGS(mob)[3], GET_ALIGNMENT(mob), GET_LEVEL(mob), 20 - GET_HITROLL(mob), GET_AC(mob) / 10, GET_HIT(mob), GET_MANA(mob), GET_MOVE(mob), GET_NDD(mob), GET_SDD(mob), GET_DAMROLL(mob)); fprintf(fd, "%d %d\n" "%d %d %d\n", GET_GOLD(mob), GET_EXP(mob), GET_POS(mob), GET_DEFAULT_POS(mob), GET_SEX(mob) ); /* Do we have extra descriptions? These are used for the ask chain system */ if (write_mobile_espec(mvnum, mob, fd) < 0) log("SYSERR: GenOLC: Error writing E-specs for mobile #%d.", mvnum); script_save_to_disk(fd, mob, MOB_TRIGGER); if (mob->ex_description) { /* Yes, save them too. */ for (ex_desc = mob->ex_description; ex_desc; ex_desc = ex_desc->next) { /* Sanity check to prevent nasty protection faults. */ if (!ex_desc->keyword || !ex_desc->description || !*ex_desc->keyword || !*ex_desc->description) { mudlog(BRF, LVL_IMMORT, TRUE, "SYSERR: OLC: medit_save_to_disk: Corrupt ex_desc/ask_chain!"); continue; } strncpy(buf, ex_desc->description, sizeof(buf) - 1); strip_cr(buf); fprintf(fd, "A\n" "%s~\n" "%s~\n", ex_desc->keyword, buf); } }

In this section of genmob.c, I decided to add in the saving of extra_descs after saving scripts to file. So, I have the feeling it is here that there are two As written to the file. It might just be due to me having worked at it for a while and needing a break, but I'm not seeing why it writes two As like it does.

I'm glad someone is finding this interesting. :P This is a frustrating one for me; I really don't know that much about reading and writing files so it's hard for me.

Edit: Huh... it's the while loop I modded in db.c, I'm sure of it. Anyone see how I got it wrong?
Last edit: 19 Oct 2017 20:29 by Papaya Pete. Reason: Found the culprit... I think.

Please Log in or Create an account to join the conversation.

More
20 Oct 2017 07:05 #7026 by Papaya Pete
Replied by Papaya Pete on topic Mob Extra Descriptions?
So I did a little more digging, and now the problem seems to be solved.

The following while loop (now fixed) was treating the 'A' as part of the keywords and not skipping to the next line to get to the real keywords. I did a little bit of research, and I threw in an fgets in there to help skip a line like I wanted it to do.
Code:
letter = fread_letter(mob_f); ungetc(letter, mob_f); while ((letter =='A') || (letter == 'T')) { if (letter == 'A') { fgets(buf, sizeof(buf), mob_f); CREATE(new_descr, struct extra_descr_data, 1); new_descr->keyword = fread_string(mob_f, buf2); new_descr->description = fread_string(mob_f, buf2); new_descr->next = mob_proto[i].ex_description; mob_proto[i].ex_description = new_descr; } else if (letter == 'T') dg_read_trigger(mob_f, &mob_proto[i], MOB_TRIGGER); letter = fread_letter(mob_f); ungetc(letter, mob_f); }

I think I've gotten the hard part done. Now I'm going to work on adding the Talk and Ask commands to be able to access my Talk and Ask dialogs.

Please Log in or Create an account to join the conversation.

More
20 Oct 2017 17:48 #7027 by Papaya Pete
Replied by Papaya Pete on topic Mob Extra Descriptions?
Got it done.

Yeah, trying to pull out that info using ask and talk was a lot easier than saving and loading it properly...
Code:
ACMD(do_talk) { struct char_data *talk_to = NULL; char *talk; char arg[MAX_INPUT_LENGTH]; if (FIGHTING(ch)) { send_to_char(ch, "You're too busy concentrating on defending yourself!\r\n"); return; } one_argument(argument, arg); if (!*arg) send_to_char(ch, "Who did you want to talk to?\r\n"); else if (!(talk_to = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) send_to_char(ch, "There's no one by that name here."); else if (talk_to == ch) send_to_char(ch, "It looks a little wrong to others if you start talking with yourself...\r\n"); else if (!IS_NPC(talk_to)) send_to_char(ch, "Try using 'say' if you want to talk with a fellow player.\r\n"); else { talk = talk_to->player.talk; if (talk == NULL) { // Throw this in juuuust in case there's nothing there. act("$n doesn't seem to have much to say.", FALSE, ch, 0, talk_to, TO_CHAR); } else { act("$n has a nice little chat with $N.", FALSE, ch, 0, talk_to, TO_NOTVICT); page_string(ch->desc, talk, FALSE); } } } ACMD(do_ask) { struct char_data *ask_who = NULL; char *dialog; char topic[MAX_INPUT_LENGTH], target[MAX_INPUT_LENGTH]; bool found = TRUE; if (FIGHTING(ch)) { send_to_char(ch, "You're too busy concentrating on defending yourself!\r\n"); return; } two_arguments(argument, target, topic); /* Organizing: first, find the person we want to question. */ if (!*target) { send_to_char(ch, "Who did you want to question?\r\n"); return; } ask_who = get_char_vis(ch, target, NULL, FIND_CHAR_ROOM); if (!ask_who) { send_to_char(ch, "There's no one by that name here.\r\n"); found = FALSE; } else if (ask_who == ch) { send_to_char(ch, "You're not going to learn anything new by asking yourself a question out loud like that.\r\n"); found = FALSE; } else if (!IS_NPC(ask_who)) { send_to_char(ch, "If you're going to ask a player a question, just use 'say' and wait for them to respond.\r\n"); found = FALSE; } if (found == FALSE) return; /* Now we found an NPC in the room. What about the topic being asked about? */ if (!*topic) send_to_char(ch, "What topic did you want to ask about?\r\n"); else { dialog = find_exdesc(topic, ask_who->ex_description); if (dialog == NULL) { // Throw this in juuuust in case there's nothing there. act("$N doesn't seem to have much to say on that topic.", FALSE, ch, 0, ask_who, TO_CHAR); act("$n asks $N about a topic, but $E doesn't have much to say about it.", FALSE, ch, 0, ask_who, TO_ROOM); } else { act("$n questions $N about a topic...", FALSE, ch, 0, ask_who, TO_NOTVICT); page_string(ch->desc, dialog, FALSE); } } }

Done some testing with it and it seems to work fine. Trying to clear out what a mob says and then trying to "talk" to it will result in a default "an undefined string" message. This means that, even for animals, one should place some kind of response when attempting to talk with it.
As for do_ask... I've tried just typing "ask," "ask <insert a name of someone who isn't here> <topic>," and asking a mob about something he doesn't know about at all, and all appropriate messages are kicked back. I have it set up so you could talk and ask about stuff when invisible, but a simple check for that can fix that issue if one so desires. I might do that myself at a later time. I also had a test player in the room with me, and I made the code just give simple messages to let him know another character was "talking" and "asking" about stuff with an npc. I didn't want to spam everyone with whatever the NPC has to say, but I did want others to know that the player was busy with talking and reading.

Anyways, that was a fun adventure! Onto something else on my list...
The following user(s) said Thank You: thomas

Please Log in or Create an account to join the conversation.

More
21 Oct 2017 07:30 #7029 by Papaya Pete
Replied by Papaya Pete on topic Mob Extra Descriptions?
Found and fixed some small bugs that would crash the mud.

First one is in medit. Needs the following default case to keep... bad issues from happening.
Code:
case 3: if (OLC_DESC(d)->keyword == NULL || OLC_DESC(d)->description == NULL) { write_to_output(d, "You can't edit the next dialog without completing this one.\r\n"); medit_disp_extradesc_menu(d); } else { struct extra_descr_data *new_extra; if (OLC_DESC(d)->next) OLC_DESC(d) = OLC_DESC(d)->next; else { /* Make new extra description and attach at end. */ CREATE(new_extra, struct extra_descr_data, 1); OLC_DESC(d)->next = new_extra; OLC_DESC(d) = new_extra; } medit_disp_extradesc_menu(d); } return; /* Add in this case to keep the mud from crashing if user inputs anything that is not 0 - 3 */ default: write_to_output(d, "Invalid option, please try again!\r\n"); medit_disp_extradesc_menu(d); return; } break;

Second bug is one I missed when copying code. Only noticed it when I put a name in and not dialog before exiting the menu; crash occurs when trying to free pointers.
Code:
case 0: /* If something got left out, delete the extra description when backing out to the menu. */ if (OLC_DESC(d)->keyword == NULL || OLC_DESC(d)->description == NULL) { struct extra_descr_data *temp; if (OLC_DESC(d)->keyword) free(OLC_DESC(d)->keyword); if (OLC_DESC(d)->description) free(OLC_DESC(d)->description); /* Clean up pointers. */ REMOVE_FROM_LIST(OLC_DESC(d), OLC_MOB(d)->ex_description, next); // <<<--- Was OLC_ROOM, not OLC_MOB. free(OLC_DESC(d)); } break;

Last thing I noticed, and it's not a major bug, but in order to have ask chains pop up that you've just entered you need to reboot the mud. A quick copyover does the trick.

Please Log in or Create an account to join the conversation.

Time to create page: 0.206 seconds