// Bug/typo/idea tracking system // Based, in part, on the interface idea at Tsunami. // Used in conjunction with the "bug", "idea", "typo", and "bugs" commands // Deathknight -- May 13, 1996 #include <mudlib.h> inherit DAEMON ; /* These are only used once, so we #define them */ #define RESTORE_BTI "/data/bugs" #define BTI_DATA_FILE "data/bugs" /* * Structure for this mapping: * int number : ({ int type, string location_filename, * string assigned_to, mixed * comment_array }) * * Where type is: 1-bug, 2-typo, 3-idea * * Where comment_array is: * ({ string name, int date, string comment, ... }) * * (bti stands for Bugs/Typos/Ideas) */ mapping bti; int next_number; void create() { ::create() ; next_number = 1; bti = ([]); restore_object (RESTORE_BTI); } void save_me () { save_object (BTI_DATA_FILE); } int add_new (string comment) { int bti_type; object env, tp; string env_str; tp = this_player(); if (!tp || !interactive (tp)) return 0; env = environment (tp); if (!env) env_str = "(Nowhere)"; else env_str = file_name (env); if (query_verb() == "bug") bti_type = 1; else if (query_verb() == "typo") bti_type = 2; else if (query_verb() == "idea") bti_type = 3; else return 0; if (bti[next_number]) { write ("Internal bug daemon error!\n"); return 0; } bti[next_number++] = ({ bti_type, env_str, 0, ({ tp->query("name"), time(), comment }) }); save_me(); return next_number-1; } string bug_type (int type) { switch (type) { case 1: return "bug"; case 2: return "typo"; case 3: return "idea"; default: return "internal error!"; } } void list_bug (int bug_num) { mixed *bug, *comments; int x; bug = bti[bug_num]; if (!bug) { if (bug_num >= next_number) write ("That number has not yet been reached.\n"); else write ("That bug has already been concluded.\n"); return; } comments = bug[3]; printf ("Number: %d\n" "Date: %s\n" "Type: %s\n" "Location: %s\n" "Originator: %s\n" "Assigned to: %s\n" "------------------------------------------------------------", bug_num, ctime (comments[1]), bug_type (bug[0]), bug[1], comments[0][0], (bug[2] ? bug[2]:"(unassigned)") ); for (x=0; x<sizeof (comments); x+=3) { printf ("%s: %s %s\n", ctime (comments[x+1]), comments[x], comments[x+2]); } } int add_comment (int bug_num, string comment) { object tp; tp = this_player(); if (!tp || !interactive (tp)) return 0; if (!bti[bug_num]) { write ("Invalid bug number.\n"); return 0; } bti[bug_num][3] += ({ tp->query("name"), time(), comment }); save_me(); return bug_num; } int assign_bug (int bug_num, string name) { object tp; tp = this_player(); if (!tp || (!adminp (tp) && name != 0)) return 0; if (!bti[bug_num]) { write ("Invalid bug number.\n"); return 0; } if (!name && bti[bug_num][2] != tp->query("name") && !adminp (tp)) { write ("You can only resolve your own bugs.\n"); return 0; } /* Should we check if name's a valid user? */ bti[bug_num][2] = name; bti[bug_num][3] += ({ tp->query("name"), time(), (name ? "assigned to "+name:"resolved") }); save_me(); return bug_num; }