/** * This is the base object for creating typo, bug, idea etc reporting * commands from. You should set the error type of the * object in its create function. The use_last_error flag should * be set for those error report types which will need to use the last * runtime error on the player object. * @example * inherit "/cmds/report_base"; * * void create() { * ::create(); * set_error_type("TYPO"); * } /\* create() *\/ */ #include <log.h> #include <command.h> #include <user_parser.h> class errors { int type; string file; string error; } #define ROOM_BUG 1 #define OBJECT_BUG 2 #define RITUAL_BUG 3 #define SPELL_BUG 4 #define HELP_BUG 5 #define COMMAND_BUG 6 #define GENERAL_BUG 7 #define SOUL_BUG 8 private nosave mapping _globals; private nosave string _error_type; private nosave int _use_last_error; void create() { _globals = ([ ]); } /* create() */ /** * This sets the error type name. The error type should be one * of "TYPO", "BUG", "IDEA". * @param type the type to set * @see query_verb() */ void set_error_type( string type ) { _error_type = type; } /** * This sets the use_last_error flag. If this flag is set to a non-zero * value then the last runtime error stored on the player object will * be attached to the error report. * @param error the new value of the last error flag */ void set_use_last_error( int error ) { _use_last_error = error; } /** * This method returns the currently set value of the last error flag. * @return the current value of the last error flag */ int query_use_last_error() { return _use_last_error; } /** @ignore yes */ int bug_room() { _globals[TP] = new( class errors, type : ROOM_BUG, error : "ROOM "+_error_type, file : file_name(ENV(TP)) ); TP->do_edit( 0, "end_of_edit"); return 1; } /* bug_room() */ /** @ignore yes */ int bug_general() { string dir, *bits, file; // For a general bug put it in the domains base directory. dir = file_name(ENV(TP)); bits = explode( dir, "/"); file = ( bits[0] == "d" ? implode(bits[0..1], "/")+"/general" : dir ); _globals[TP] = new( class errors, type : GENERAL_BUG, error : "GENERAL "+_error_type, file : file ); TP->do_edit( 0, "end_of_edit"); return 1; } /* bug_general() */ /** @ignore yes */ int bug_command( string str ) { mixed coms; class command cmd; class errors bing; bing = new( class errors ); cmd = new( class command, verb : str ); coms = ({ }); if( CMD_D->HandleStars(cmd) && sizeof( ( coms = (mixed)CMD_D->GetPaths(cmd->verb ) & (mixed)TP->GetSearchPath() ) ) ) { bing->file = coms[0]+"/"+cmd->verb; } else { if( coms = TP->query_parse_command(str) ) { bing->file = base_name(coms[0][OBJS]); } else { if( coms = SOUL_H->query_soul_command(str) ) { bing->file = SOUL_H; } else if( _error_type == "IDEA") { bing->file = "/cmds/IDEA"; } else { return notify_fail("Command "+str+" not found.\n"); } } } bing->error = "COMMAND "+_error_type+" "+str; bing->type = COMMAND_BUG; _globals[TP] = bing; TP->do_edit(0, "end_of_edit"); return 1; } /* bug_command() */ /** @ignore yes */ int bug_soul( string str ) { mixed coms; class errors bing; bing = new( class errors ); coms = ({ }); if( coms = SOUL_H->query_soul_command(str) ) { bing->file = SOUL_H; } else if( _error_type == "IDEA" ) { bing->file = "/std/soul/IDEA"; } else { return notify_fail("Soul command "+str+" not found.\n"); } bing->error = "SOUL "+_error_type+" "+str; bing->type = SOUL_BUG; _globals[TP] = bing; TP->do_edit( 0, "end_of_edit"); return 1; } /* bug_soul() */ /** @ignore yes */ int bug_help( string str ) { mixed stuff; class errors bing; string tmp; bing = new( class errors ); tmp = "/cmds/player/help"->query_synonym(str); if( strlen(tmp) ) str = tmp; stuff = "/cmds/player/help"->query_help_on(str); if( !sizeof(stuff) ) return notify_fail("Could not find the help file '"+str+"'.\n"); sscanf( stuff[0][0], "%*s (%s)", bing->file ); bing->error = "HELP "+_error_type+" "+str; bing->type = HELP_BUG; _globals[TP] = bing; TP->do_edit(0,"end_of_edit"); return 1; } /* bug_help() */ /** @ignore yes */ int bug_ritual( string str ) { mixed junk; class errors bing; if( !junk = TP->query_spell(str) ) { map_delete( _globals, TP ); return notify_fail("Ritual "+str+" not found.\n"); } bing = new( class errors ); bing->file = junk[0]; bing->error = "RITUAL "+_error_type+" "+str; bing->type = RITUAL_BUG; _globals[TP] = bing; TP->do_edit( 0, "end_of_edit"); return 1; } /* bug_ritual() */ /** @ignore yes */ int bug_spell( string str ) { mixed junk; class errors bing; if( !junk = TP->query_spell(str) ) { map_delete( _globals, TP ); return notify_fail("Spell "+str+" not found.\n"); } bing = new( class errors ); bing->file = junk[0]; bing->error = "SPELL "+_error_type+" "+str; bing->type = SPELL_BUG; _globals[TP] = bing; TP->do_edit( 0, "end_of_edit"); return 1; } /* bug_spell() */ /** @ignore yes */ int bug_object( object *obs, string str ) { object ob; string info, tmp; class errors bing; if( sizeof(obs) > 1 ) { notify_fail("More than one object can be identified with the name "+ str+". Please be more specific.\n"); map_delete( _globals, TP ); return 0; } ob = obs[0]; bing = new( class errors ); bing->file = base_name(ob); switch( bing->file ) { case "/std/room/basic/item" : bing->file = base_name(ENV(TP)); if( sizeof( tmp = ob->short() ) ) str = tmp; info = sprintf("Room item: %s.\n\n", str ); break; default: if( tmp = ob->query_property("virtual name") ) { bing->file = tmp; info = sprintf("VObject: %s, Object: %s\nName: %s, Short: %s\n\n", tmp, bing->file, ob->query_name(), ob->short() ); } else { info = sprintf("Name: %s, Short: %s\n\n", ob->query_name(), ob->short() ); } } bing->error = "OBJECT "+_error_type+" "+str; bing->type = OBJECT_BUG; _globals[TP] = bing; TP->do_edit( 0, "end_of_edit", 0, 0, info ); return 1; } /* bug_object() */ /** @ignore yes */ void end_of_edit( string body, string header ) { if( strlen(body) ) { int ending; string name, trace = 0; mapping last_error; class errors bing; bing = _globals[TP]; if( body[<1] != '\n') ending = 1; if( ENV(TP) && bing->type != ROOM_BUG ) { if( ending ) { body += "\n"; ending = 0; } body += sprintf("\nEnvironment: %s\n", file_name(ENV(TP)) ); } if( _use_last_error ) { last_error = (mapping)TP->get_last_error(); if( mapp(last_error) ) { trace = (string)master()->standard_trace( last_error, 1 ); TP->set_last_error(0); } } if( ending ) body += "\n"; name = (string)TP->query_name(); if( sizeof(header) ) body = header + body; if( _error_type == "REPORT" ) { BOARD_H->add_message("ptreports", CAP(name), bing->error+" by "+ CAP(name)+" ("+bing->file+")", body ); } else { SMART_LOG->smart_log( bing->error, name, body, trace, bing->file ); } PLAYTESTERS_H->report_made( name, bing->error, bing->file, body + (_use_last_error && trace ? "\nError:\n" + trace : "") ); printf("Thank you for your "+( _error_type == "REPORT" ? "" : "%s ")+ "report.\n", lower_case(_error_type) ); } else { printf("Not saving "+( _error_type == "REPORT" ? "" : "%s ")+ "report, aborting.\n", lower_case(_error_type) ); } map_delete(_globals, TP ); } /* end_of_edit() */ /** @ignore yes */ mixed query_patterns() { return ({ "command <string'name'>", (: bug_command($4[0]) :), "soul <string'name'>", (: bug_soul($4[0]) :), "spell <string'name'>", (: bug_spell($4[0]) :), "object <indirect:wiz-present'name of NPC or item'>", (: bug_object($1, $4[0]) :), "ritual <string'name'>", (: bug_ritual($4[0]) :), "help <string'subject'>", (: bug_help($4[0]) :), "room", (: bug_room() :), "general", (: bug_general() :), }); } /* query_patterns() */