My last project was adding an online social editor to SaberMUD (mine) .. and it was a little more difficult than i imagined .. so for all those who are contemplating adding a social editor to their mud, I am going to sort of outline what it took .. that way you know what yer getting into :> First of all the command_info structure which is used in a variable named cmd_info in interpreter.c is a HARD CODED variable.. to have an editor which can dynamically add socials on line, you need to create another pointer to a command_info structure which you allocate enough space for at boot time (after figuring out how many socials you have in the social file and how many ACTUAL commands you have in cmd_info).. I used 'used_cmd_info' for this variable which was put in the place of cmd_info throughout the mud where a command like decision was based.: struct command_info *used_cmd_info; Then I had to add to the social file some more info ... (the command stuff which was going to get taken out of interpreter.c) like min position the char had to be in .. the minimum level for the command/social.. etc.. i decided on a firstline social format of this: ~accuse accuse 0 6 5 0 ^ the actual command name ^ the name I want to be used to decide WHERE to sort this command into the command listing.. (explained more later) ^ this number is the 'hide' flag (already in old file) ^ this is the minimum position the character has to be in to do the social. ^ this is the minimum position the victim has to be in to do the social. (already in old file) ^ this is the min. level that the character has to be to do the social. Then after working my way through the socials file.. i had to go into act.social.c and add all these extra fields to what the social_messg can handle.. and i also MOVED it from act.social.c to structs.h because more than just the socials handler file would need it (aedit.c in particular) here's what my structure ended up looking like (at the end of structs.h): /* used in the socials */ struct social_messg { int act_nr; char *command; /* holds copy of activating command */ char *sort_as; /* holds a copy of a similar command or * abbreviation to sort by for the parser */ int hide; /* ? */ int min_victim_position; /* Position of victim */ int min_char_position; /* Position of char */ int min_level_char; /* Minimum level of socialing char */ /* No argument was supplied */ char *char_no_arg; char *others_no_arg; /* An argument was there, and a victim was found */ char *char_found; char *others_found; char *vict_found; /* An argument was there, but no victim was found */ char *not_found; /* The victim turned out to be the character */ char *char_auto; char *others_auto; }; Of course you need to go into act.social.c and adjust how the boot_social_messages() routine loads the data from the file.. (include the new info). Then I took the sort out of that routine and placed it into a new routine after it .. which i named 'create_command_list()' and they ended up looking like this: void boot_social_messages(void) { FILE *fl; int nr = 0, hide, min_char_pos, min_pos, min_lvl, curr_soc = -1; char next_soc[MAX_STRING_LENGTH], sorted[MAX_INPUT_LENGTH]; /* open social file */ if (!(fl = fopen(SOCMESS_FILE, "r"))) { sprintf(buf, "Can't open socials file '%s'", SOCMESS_FILE); perror(buf); exit(1); } /* count socials & allocate space */ *next_soc = NULL; while (!feof(fl)) { fgets(next_soc, MAX_STRING_LENGTH, fl); if (*next_soc == '~') top_of_socialt++; } sprintf(buf, "Social table contains %d socials.", top_of_socialt); log(buf); rewind(fl); CREATE(soc_mess_list, struct social_messg, top_of_socialt + 1); /* now read 'em */ for (;;) { fscanf(fl, " %s ", next_soc); if (*next_soc == '$') break; if (fscanf(fl, " %s %d %d %d %d \n", sorted, &hide, &min_char_pos, &min_pos, &min_lvl) != 5) { fprintf(stderr, "Format error in social file near social '%s'\n", next_soc); exit(1); } /* read the stuff */ curr_soc++; soc_mess_list[curr_soc].command = str_dup(next_soc+1); soc_mess_list[curr_soc].sort_as = str_dup(sorted); soc_mess_list[curr_soc].hide = hide; soc_mess_list[curr_soc].min_char_position = min_char_pos; soc_mess_list[curr_soc].min_victim_position = min_pos; soc_mess_list[curr_soc].min_level_char = min_lvl; soc_mess_list[curr_soc].char_no_arg = fread_action(fl, nr); soc_mess_list[curr_soc].others_no_arg = fread_action(fl, nr); soc_mess_list[curr_soc].char_found = fread_action(fl, nr); soc_mess_list[curr_soc].others_found = fread_action(fl, nr); soc_mess_list[curr_soc].vict_found = fread_action(fl, nr); soc_mess_list[curr_soc].not_found = fread_action(fl, nr); soc_mess_list[curr_soc].char_auto = fread_action(fl, nr); soc_mess_list[curr_soc].others_auto = fread_action(fl, nr); } /* close file & set top */ fclose(fl); top_of_socialt = curr_soc; } /* this function adds in the loaded socials and assigns them a command # */ void create_command_list(void) { int i, j, k; struct social_messg temp; extern struct command_info *used_cmd_info; extern struct command_info cmd_info[]; /* free up old command list */ if (used_cmd_info) free(used_cmd_info); used_cmd_info = NULL; /* re check the sort on the socials */ for (j = 0; j < top_of_socialt; j++) { k = j; for (i = j + 1; i <= top_of_socialt; i++) if (str_cmp(soc_mess_list[i].sort_as, soc_mess_list[k].sort_as) < 0) k = i; if (j != k) { temp = soc_mess_list[j]; soc_mess_list[j] = soc_mess_list[k]; soc_mess_list[k] = temp; } } /* count the commands in the command list */ i = 0; while(*cmd_info[i].command != '\n') i++; i++; CREATE(used_cmd_info, struct command_info, top_of_socialt + i + 2); /* this loop sorts the socials and commands together into one big list */ i = 0; j = 0; k = 0; while ((*cmd_info[i].command != '\n') || (j <= top_of_socialt)) { if ((i < NUM_RESERVED_CMDS) || (j > top_of_socialt) || (str_cmp(cmd_info[i].sort_as, soc_mess_list[j].sort_as) < 1)) used_cmd_info[k++] = cmd_info[i++]; else { soc_mess_list[j].act_nr = k; used_cmd_info[k].command = soc_mess_list[j].command; used_cmd_info[k].sort_as = soc_mess_list[j].sort_as; used_cmd_info[k].minimum_position = soc_mess_list[j].min_char_position; used_cmd_info[k].command_pointer = do_action; used_cmd_info[k].minimum_level = soc_mess_list[j++].min_level_char; used_cmd_info[k].subcmd = 0; used_cmd_info[k++].show = 1; } } used_cmd_info[k].command = str_dup("\n"); used_cmd_info[k].sort_as = str_dup("zzzzzzz"); used_cmd_info[k].minimum_position = 0; used_cmd_info[k].command_pointer = 0; used_cmd_info[k].minimum_level = 0; used_cmd_info[k].subcmd = 0; used_cmd_info[k].show = 0; sprintf(buf, "Command info rebuilt, %d total commands.", k); log(buf); } Then.. in db.c i added a prototype at the top: void create_command_list(void); Then where it boots all the info up i added a line: log("Loading social messages."); boot_social_messages(); create_command_list(); /* newline */ This effectively read all the info from the socials file, then sorted it with what was already in the cmd_info variable (in interpreter.c) and ended up in used_cmd_info.. So this means you have to go back through interpreter.c and REMOVE any line with the do_action statement in it.. (its a social) and put the appropriate info into the socials file .. (ie. min level able to do the command, min position .. etc).. BUT there is ONE more slot which i added to retain the basic functionality of the cmd_info list.. and thats a "sort_as" variable.. which tells the create_command_info WHERE to place the command.. (for example many muds, want the tell command to trigger when you type 't person blah' .. henceforth they place the tell command at the beginning of the 't' commands. so .. here's an example of what i did to my command_info structure (in interpreter.h): struct command_info { char *command; char *sort_as; byte minimum_position; void (*command_pointer) (struct char_data *ch, char * argument, int cmd, int subcmd); sh_int minimum_level; int subcmd; int show; }; then here's an example of the 't' section of my interpreter.c's definition of cmd_info: { "tell" , "t" , POS_DEAD , do_tell , 0, 0, 1 }, { "take" , "take" , POS_RESTING , do_get , 0, 0, 1 }, { "taste" , "taste" , POS_RESTING , do_eat , 0, SCMD_TASTE, 1 }, { "teleport" , "teleport" , POS_DEAD , do_teleport , LVL_GOD, 0, 1 }, { "thaw" , "thaw" , POS_DEAD , do_wizutil , LVL_FREEZE, SCMD_THAW, 1 }, { "title" , "ti" , POS_DEAD , do_title , 0, 0, 1 }, { "time" , "time" , POS_DEAD , do_time , 0, 0, 1 }, { "toggle" , "toggle" , POS_DEAD , do_toggle , 0, 0, 1 }, { "transfer" , "transfer" , POS_SLEEPING, do_trans , LVL_GOD, 0, 1 }, { "typo" , "typo" , POS_DEAD , do_gen_write, 0, SCMD_TYPO, 1 }, notice that the first field (the actual command name) is NOT sorted into alphabetical order.. but the second field (the newly added sort_as field) IS sorted into alphabetical order.. this means that when the create_command_list() routine goes to add in the socials it will know where to place each social.. (note: the second field now back in the example of the 'socials' file .. is the same as the second field here in the command_info structure of cmd_info, it tells the social where to go in relation to the next ACTUAL command..) DO NOT make the sort_as field a value equivalent to 'LATER' than the original command .. this field is ONLY meant to tell the create_command_list() routine if a command was meant to be shifted before other commands.. (or else all the commands behind the command which you put a 'later than' sort_as field will be shifted too.) Hmm... then I'd guess you have your own dynamic command list.. which enables you to build a aedit..(pretty much copy redit.c then replace with the appropriate menu and defines in OLC.H .).. heres an example of my aedit.c (most important routines): ------------------------------------------------------------------ /* ** File: aedit.c ** Comment: OLC for MUDs -- this one edits socials */ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "interpreter.h" #include "handler.h" #include "comm.h" #include "utils.h" #include "db.h" #include "olc.h" #include "screen.h" extern int top_of_socialt; extern struct social_messg *soc_mess_list; extern char *edit_errors[]; extern char *position_types[]; #define RESERVE_CMDS 15 /* reserve these commands to come straight * from the cmd list then start sorting */ /* external functs */ void create_command_list(void); void free_action(struct social_messg *action); /* function protos */ void aedit_disp_menu(struct descriptor_data * d); void aedit_parse(struct descriptor_data * d, char *arg); void aedit_setup_new(struct descriptor_data *d); void aedit_setup_existing(struct descriptor_data *d, int real_num); void aedit_save_to_disk(struct descriptor_data *d); void aedit_save_internally(struct descriptor_data *d); /* ** Utils and exported functions. */ void aedit_setup_new(struct descriptor_data *d) { CREATE(OLC_ACTION(d), struct social_messg, 1); OLC_ACTION(d)->command = str_dup("newcmd"); OLC_ACTION(d)->sort_as = str_dup("newcmd"); OLC_ACTION(d)->hide = 0; OLC_ACTION(d)->min_victim_position = POS_STANDING; OLC_ACTION(d)->min_char_position = POS_STANDING; OLC_ACTION(d)->min_level_char = 0; OLC_ACTION(d)->char_no_arg = str_dup("This action is unfinished."); OLC_ACTION(d)->others_no_arg = str_dup("This action is unfinished."); OLC_ACTION(d)->char_found = NULL; OLC_ACTION(d)->others_found = NULL; OLC_ACTION(d)->vict_found = NULL; OLC_ACTION(d)->not_found = NULL; OLC_ACTION(d)->char_auto = NULL; OLC_ACTION(d)->others_auto = NULL; aedit_disp_menu(d); OLC_VAL(d) = 0; } /*------------------------------------------------------------------------*/ void aedit_setup_existing(struct descriptor_data *d, int real_num) { CREATE(OLC_ACTION(d), struct social_messg, 1); OLC_ACTION(d)->command = str_dup(soc_mess_list[real_num].command); OLC_ACTION(d)->sort_as = str_dup(soc_mess_list[real_num].sort_as); OLC_ACTION(d)->hide = soc_mess_list[real_num].hide; OLC_ACTION(d)->min_victim_position = soc_mess_list[real_num].min_victim_position; OLC_ACTION(d)->min_char_position = soc_mess_list[real_num].min_char_position; OLC_ACTION(d)->min_level_char = soc_mess_list[real_num].min_level_char; OLC_ACTION(d)->char_no_arg = ((soc_mess_list[real_num].char_no_arg != NULL)?str_dup(soc_mess_list[real_num].char_no_arg):NULL); OLC_ACTION(d)->others_no_arg = ((soc_mess_list[real_num].others_no_arg != NULL)?str_dup(soc_mess_list[real_num].others_no_arg):NULL); OLC_ACTION(d)->char_found = ((soc_mess_list[real_num].char_found != NULL)?str_dup(soc_mess_list[real_num].char_found):NULL); OLC_ACTION(d)->others_found = ((soc_mess_list[real_num].others_found != NULL)?str_dup(soc_mess_list[real_num].others_found):NULL); OLC_ACTION(d)->vict_found = ((soc_mess_list[real_num].vict_found != NULL)?str_dup(soc_mess_list[real_num].vict_found):NULL); OLC_ACTION(d)->not_found = ((soc_mess_list[real_num].not_found != NULL)?str_dup(soc_mess_list[real_num].not_found):NULL); OLC_ACTION(d)->char_auto = ((soc_mess_list[real_num].char_auto != NULL)?str_dup(soc_mess_list[real_num].char_auto):NULL); OLC_ACTION(d)->others_auto = ((soc_mess_list[real_num].others_auto != NULL)?str_dup(soc_mess_list[real_num].others_auto):NULL); OLC_VAL(d) = 0; aedit_disp_menu(d); } /*------------------------------------------------------------------------*/ void aedit_save_internally(struct descriptor_data *d) { struct social_messg *new_soc_mess_list = NULL; int i; /* add a new social into the list */ if (OLC_ZNUM(d) > top_of_socialt) { CREATE(new_soc_mess_list, struct social_messg, top_of_socialt + 2); for (i = 0; i <= top_of_socialt; i++) new_soc_mess_list[i] = soc_mess_list[i]; new_soc_mess_list[++top_of_socialt] = *OLC_ACTION(d); free(soc_mess_list); soc_mess_list = new_soc_mess_list; create_command_list(); } /* pass the editted action back to the list - no need to add */ else { free_action(&soc_mess_list[OLC_ZNUM(d)]); soc_mess_list[OLC_ZNUM(d)] = *OLC_ACTION(d); } olc_add_to_save_list(-1, OLC_SAVE_ACTION); } /*------------------------------------------------------------------------*/ void aedit_save_to_disk(struct descriptor_data *d) { FILE *fp; int i; if (!(fp = fopen(SOCMESS_FILE, "w+"))) { sprintf(buf, "Can't open socials file '%s'", SOCMESS_FILE); perror(buf); exit(1); } for (i = 0; i <= top_of_socialt; i++) { sprintf(buf, "~%s %s %d %d %d %d\n", soc_mess_list[i].command, soc_mess_list[i].sort_as, soc_mess_list[i].hide, soc_mess_list[i].min_char_position, soc_mess_list[i].min_victim_position, soc_mess_list[i].min_level_char); fputs(buf, fp); sprintf(buf, "%s\n%s\n%s\n%s\n", ((soc_mess_list[i].char_no_arg)?soc_mess_list[i].char_no_arg:"#"), ((soc_mess_list[i].others_no_arg)?soc_mess_list[i].others_no_arg:"#"), ((soc_mess_list[i].char_found)?soc_mess_list[i].char_found:"#"), ((soc_mess_list[i].others_found)?soc_mess_list[i].others_found:"#")); fputs(buf, fp); sprintf(buf, "%s\n%s\n%s\n%s\n\n", ((soc_mess_list[i].vict_found)?soc_mess_list[i].vict_found:"#"), ((soc_mess_list[i].not_found)?soc_mess_list[i].not_found:"#"), ((soc_mess_list[i].char_auto)?soc_mess_list[i].char_auto:"#"), ((soc_mess_list[i].others_auto)?soc_mess_list[i].others_auto:"#")); fputs(buf, fp); } fprintf(fp, "$\n"); fclose(fp); olc_remove_from_save_list(-1, OLC_SAVE_ACTION); } /*------------------------------------------------------------------------*/ /* Menu functions */ ... Anyways .. i am SURE that this is FAR from complete, but as for a quicky explanation of what it took to impl an aedit function.. i hope it covers all the basis. I for some reason i forgot a major portion of something, and you're still stumped, let me know. Michael Scott aka Manx! FLAMES == scottm@workcomm.net Ps. Sorry for the long post.. but the code examples I felt sortof added to the easability of understanding.
This archive was generated by hypermail 2b30 : 12/18/00 PST