#pragma strict_types /* * Master File for HEAVEN7 mudlib */ #include "/include/config.h" #include "/include/mudlib.h" #include "/include/cfg/levels.h" #include "/include/cfg/master.cfg" #ifdef AMYLAAR321 #include "/include/cfg/driver_hook.h" #endif status debug_mode; /* * There are several occasions when the game driver wants to check if * a player has permission to specific things. * * These types are implemented so far: * * "error messages": player is allowed to see runtime error messages. * "trace": player is allowed to use tracing. * "wizard": player considered at least a "minimal" wizard * "create domain": player is allowed to create new domains * "snoop": player is allowed to snoop */ int query_player_level(string what) { int security_level; if(!this_player()) return 0; security_level = (int)this_player()->query_security_level(); switch(what) { case "wizard": return (security_level >= SEC1); case "error messages": return (security_level >= SEC1); case "trace": return (security_level >= SEC4); case "create domain": return (security_level >= SEC8); case "snoop": return (security_level >= SEC5); } return 0; } /* * Strip '/' from native mode file_name() */ #ifdef NATIVE_MODE string master_file_name(object ob) { string file; file = file_name(ob); if(file[0] == '/') file = file[1..(strlen(file)-1)]; return file; } #define file_name master_file_name #endif /* NATIVE */ /* * start-up flags */ void flag(string str) { string file, arg; if(sscanf(str, "echo %s", arg) == 1) { write(arg + "\n"); return; } if(sscanf(str, "call %s %s", file, arg) == 2) { arg = (string)call_other(file, arg); write("Call Flag: "+ arg +"\n"); return; } write("Master: Unknown flag " + str + "\n"); } /***************************************************************************/ /* object player is connected */ /* * This function is called every time a player connects. * input_to() can't be called from here. */ object connect() { write("\n"); #ifdef USE_DEBUG return clone_object(DEBUG); #endif /* force usuage of DEBUG-player */ #ifdef DEBUG /* attempt to load WIZARD, * loads "secure/security" * "inherit/base/base_obj", * "inherit/base/living", * "obj/player", * "obj/wizard" */ if(catch(call_other(SECURITY_FILE,"??")) || catch(call_other(WIZARD,"??"))) { write("FATAL: Switching to DEBUG Object!!\n"); debug_mode = 1; return clone_object(DEBUG); } else { debug_mode = 0; return clone_object(PLAYER); } #else return clone_object(PLAYER); #endif } /****************************************************************************/ /* where are error logs written */ /* * Get the owner of a file. This is called from the game driver, so as * to be able to know which wizard should have the error. */ string get_wiz_name(string file) { string name, domain, rest; if(file[0] != '/') file = "/"+ file; if(sscanf(file, WIZARD_DIR +"%s/%s", name, rest) == 2 || sscanf(file, DOMAIN_DIR +"%s/w/%s/%s", domain, name, rest) == 3) { return name; } return 0; } /* * Write an error message into a log file. The error occured in the object * 'file', giving the error message 'message'. */ void log_error(string file, string message) { string name; name = get_wiz_name(file); if(!name) name = "log"; write_file("/log/"+ name, message); } /****************************************************************************/ /* edit setup save */ /* * The wizard object 'who' wants to save his ed setup. It is saved in the * file /players/wiz_name/.edrc . A test should be added to make sure it is * a call from a wizard. * * Don't care to prevent unauthorized access of this file. Only make sure * that a number is given as argument. */ int save_ed_setup(object who, int code) { string file; if(!intp(code)) return 0; file = WIZARD_DIR+(string)who->query_name(1)+"/"+ ED_SAVE; rm(file); return write_file(file,code+""); } /* * Retrieve the ed setup. No meaning to defend this file read from * unauthorized access. */ int retrieve_ed_setup(object who) { string file; int code; file = WIZARD_DIR+(string)who->query_name(1)+"/"+ ED_SAVE; if (file_size(file) <= 0) return 0; sscanf(read_file(file), "%d", code); return code; } /***************************************************************************/ /* a number of fn() in master will accept calls only from specific objects */ /* they form the basis of the security of the mud */ nomask status valid_master_call(object ob) { return (debug_mode || (status)SECURITY_FILE->valid_master_object(ob)); } nomask status valid_player_call(object ob) { if(valid_master_call(ob)) return 1; return (debug_mode || (status)SECURITY_FILE->restricted_path_object(ob)); } /****************************************************************************/ /* * When an object is destructed, this function is called with every * item in that room. We get the chance to save players ! */ void destruct_environment_of(object ob) { if(!interactive(ob)) return; tell_object(ob, "Everything you see is disolved.\n"+ "Luckily, you are transported somewhere...\n"); ob->move_player("is transfered#"+ VOID,0,1); /* domain safe move */ } #ifndef MUDOS_DR /* mudos loads these at startup in config */ /**********************************************************************/ /* include directories */ /* * Define where the '#include' statement is supposed to search for files. * "." will automatically be searched first, followed in order as given * below. The path should contain a '%s', which will be replaced by the file * searched for. */ string *define_include_dirs() { return ({ "/include/%s", "/include/fn_specs/%s","/include/cfg/%s", "/include/fn/%s","/include/skills/%s", }); } #endif /* !MUDOS_DR */ /**********************************************************************/ /* * The master object is asked if it is ok to shadow object ob. Use * previous_object() to find out who is asking. * * In this example, we allow shadowing as long as the victim object * hasn't denied it with a query_prevent_shadow() returning 1. */ #ifdef MUSOS_DR int valid_shadow(object ob) { #else int query_allow_shadow(object ob) { #endif /* MUDOS_DR */ string file; #ifdef SHADOW_DIR file = file_name(previous_object()); if(file[0] != '/') file = "/"+ file; if(sscanf(file,SHADOW_DIR,file) != 1) { return 0; /* only shadows that have been inspected can be used */ } #endif /* do not allow shadows with our security fns in them */ if(function_exists("valid_read",previous_object()) || function_exists("valid_write",previous_object())) { return 0; } return !ob->query_prevent_shadow(previous_object()); } /************************************************************************/ /* where is file written if wizard goes net-dead during edit * * * Give a file name for edit preferences to be saved in. */ string get_ed_buffer_save_file_name(string file) { string *file_ar; if(!debug_mode && file && file != "") { SECURITY_FILE->remove_current_edit(((file[0] != '/') ? "/" : "")+ file); } file_ar = explode(file,"/"); file = file_ar[sizeof(file_ar)-1]; return WIZARD_DIR+(string)this_player()->query_name(1)+"/"+DEAD_ED+"/"+file; } #ifndef MUDOS_DR /* mudos loads simul efun before master */ /***************************************************************************/ /* * Give a path to a simul_efun file. Observe that it is a string returned, * not an object. But the object has to be loaded here. Return 0 if this * feature isn't wanted. */ static string get_simul_efun_file() { if(catch(call_other(SIMUL_EFUN, "??"))) { write("Failed to load " + SIMUL_EFUN + "\n"); if(catch(call_other(SPARE_SIMUL_EFUN_FILE, "??"))) { write("Failed to load spare " + SPARE_SIMUL_EFUN_FILE + "\n"); shutdown(); return 0; } return SPARE_SIMUL_EFUN_FILE; } return SIMUL_EFUN; } string get_simul_efun() { #ifdef AMYLAAR321 return "/"+ get_simul_efun_file(); #else return get_simul_efun_file(); #endif /* AMYLAAR321 */ } #endif /* !MUDOS_DR */ /****************************************************************************/ /* file_size that can be used by all objects */ int master_file_size(string file) { return file_size(file); } /**************************************************************************/ /* exec() is called in player.c */ /* * Function name: valid_exec * Description: Checks if a certain 'program' has the right to use exec() * Arguments: name: Name of the 'program' that attempts to use exec() * Note that this is different from file_name(), * Programname is what 'function_exists' returns. * NOTE, the absence of a leading slash in the name. * Returns: True if exec() is allowed. */ int valid_exec(string name) { if(name && name != "" && name[0] == '/') { name = name[1..(strlen(name)-1)]; } switch(name) { case PLAYER +".c": case WIZARD +".c": return 1; break; } write("Invalid Exec() call by object: "+ name +"\n"); return 0; } #ifdef AMYLAAR void runtime_error(string error, string program, string current_object, int line) { if(!this_player() || !query_ip_number(this_player())) return; if(!query_player_level("error messages") || !error) { #ifdef ADMIN_NAME write(ADMIN_NAME +" exclaims: You have found a Space-Time Anomaly.\n"); #else write("Driver says: You have found a Space-Time Anomaly.\n"); #endif /* ADMIN_NAME */ } else { write(error +"\n"); write(((current_object) ? "program: "+ program +", object: "+ current_object +" line "+ line +"\n" : "")); } } int heart_beat_error(object heart_beat, string error, string program, string current_object, int line) { string wiz_name; if(!heart_beat || !query_ip_number(heart_beat)) return 0; #ifdef ADMIN_NAME tell_object(heart_beat,ADMIN_NAME +" tells you: You have no heart beat !\n"); #else tell_object(heart_beat,"Driver tells you: You have no heart beat !\n"); #endif /* ADMIN_NAME */ if(query_player_level("error messages")) { tell_object(heart_beat, error +"\n"); tell_object(heart_beat, ((current_object) ? "program: "+program+", object: "+current_object+" line "+line+"\n" : "")); } #ifdef LOG_HB_ERROR if(environment(this_player())) { write_file(LOG_HB_ERROR,"Room: "+ file_name(environment(this_player())) + "\nError: "+ error + "Program: "+ program + "\nObject: "+ current_object + "\nLine: "+ line +"\n\n"); if(!(wiz_name = get_wiz_name(file_name(environment(this_player()))))) { if(!(wiz_name = get_wiz_name(current_object))) { return 0; } } write_file(WIZARD_DIR+ wiz_name +"/HB_ERRORS", "Room: "+ file_name(environment(this_player())) +"\n"+ "Error: "+ error + "Program: "+ program +"\n"+ "Object: "+ current_object +"\n"+ "Line: "+ line +"\n\n"); } #endif return 0; /* Don't restart */ } #endif /* AMYLAAR */ /*************************************************************************/ /* validates whether an object can be loaded */ /* in native it gives object its uid */ static mixed master_creator_file(string object_name) { string wiz_name, domain, trailer; if(sscanf("/"+object_name,WIZARD_DIR+"%s/%s",wiz_name,trailer)) { return wiz_name; } if(sscanf("/"+object_name,DOMAIN_DIR+"%s/w/%s/%s",domain,wiz_name,trailer)) { return wiz_name; } /* directories that should not have objects in them */ if(sscanf(object_name,"usr/%s", trailer)) return 0; if(sscanf(object_name,"doc/%s", trailer)) return 0; if(sscanf(object_name,"info/%s", trailer)) return 0; if(sscanf(object_name,"help/%s", trailer)) return 0; if(sscanf(object_name,"manuals/%s", trailer)) return 0; if(sscanf("/"+object_name,WIZARD_DIR+"%s",trailer)) return 0; if(sscanf("/"+object_name,DOMAIN_DIR+"%s/w/%s",domain,trailer)) return 0; if(sscanf(object_name,"open/%s", trailer)) return 0; if(sscanf(object_name,"log/%s", trailer)) return 0; return 1; /* else legal */ } mixed creator_file(string object_name) { mixed creator_status; if((creator_status = master_creator_file(object_name))) { #ifdef NATIVE_MODE return UID_ROOT; #else return creator_status; #endif } return 0; } void move_or_destruct(object what, object to) /* An error in this function can be very nasty. Note that unlimited recursion * is likely to cause errors when environments are deeply nested */ { #ifdef COMPAT_FLAG do { int res; if (catch( res = transfer(what, to) )) res = 5; if ( !(res && what) ) return; } while( (res == 1 || res == 4 || res == 5) && (to = environment(to)) ); #else /* !COMPAT_FLAG */ if ( !catch( what->move(to, 1) ) ) return; #endif /*COMPAT_FLAG */ /* * Failed to move the object. Then, it is destroyed. */ destruct(what); } /******************************************************************/ /* snoops must routed via simul_efun */ int valid_snoop(object snooper, object snoopee) { #ifndef MUDOS_DR if(file_name(previous_object()) == get_simul_efun()) return 1; #else if(file_name(previous_object()) == SIMUL_EFUN) return 1; #endif /* MUDOS_DR */ } /****************************************************************/ /* snoops are usable by priviledged people */ int valid_query_snoop(object wiz) { return query_player_level("snoop"); } #ifdef AMYLAAR #ifdef COMPAT_FLAG mixed *prepare_destruct1(object ob) { object super; super = environment(ob); if (super) { mixed error, *errors; mixed weight; object me; me = this_object(); set_this_object(ob); errors = ({}); if ( living(ob) ) { if (error = catch(super->exit(ob),0)) errors = ({"exit"+": "+error}); } if ( error = catch((weight = (mixed)ob->query_weight()),0) ) { set_this_object(me); return ({"query_weight"+": "+error}) + errors; } if (weight && intp(weight)) { if (error = catch(super->add_weight(-weight),0)) { set_this_object(me); return ({"add_weight"+": "+error}) + errors; } } set_this_object(me); } return ({}); } #endif /* COMPAT_FLAG */ mixed prepare_destruct(object ob) { object super; mixed *errors; int i; #if 6 * 7 != 42 || 6 * 9 == 42 return "Preprocessor error"; #endif #ifdef COMPAT_FLAG errors = prepare_destruct1(ob); for(i = sizeof(errors); i--; ) { write(errors[i]); } #endif /* COMPAT_FLAG */ super = environment(ob); if (!super) { object item; while ( item = first_inventory(ob) ) { destruct_environment_of(item); if (item && environment(item) == ob) destruct(item); } } else { while (first_inventory(ob)) move_or_destruct(first_inventory(ob), super); } return 0; /* success */ } /* privilege_violation is called when objects try to do illegal things, * or files being compiled request a privileged efun. * * return values: * 1: The caller/file is allowed to use the privilege. * 0: The caller was probably misleaded; try to fix the error. * -1: A real privilege violation. Handle it as error. */ int privilege_violation(string what, mixed who, mixed arg) { switch(what) { case "call_out_info": return (valid_player_call(who)) ? 1 : -1; #ifdef INTERMUD case "send_imp": case "wizlist_info": return (valid_player_call(who) || file_name(who) == INETD) ? 1 : -1; #else case "wizlist_info": return (valid_player_call(who)) ? 1 : -1; #endif /* INTERMUD */ case "shutdown": return (valid_player_call(who) || file_name(who) == SHUTD) ? 1 : -1; case "nomask simul_efun": case "set_auto_include_string": case "add_worth": case "bind_lambda": case "get_extra_wizinfo": case "rename_object": case "set_extra_wizinfo": case "set_extra_wizinfo_size": case "set_this_object": case "shadow_add_action": return (valid_master_call(who)) ? 1 : -1; default: return -1; } return -1; } #ifdef INTERMUD void receive_imp(string sender,string msg) { INETD->receive_udp(sender,msg); } #endif /* INTERMUD */ void dangling_lfun_closure() { raise_error("dangling lfun closure\n"); } #endif /* AMYLAAR */ void slow_shut_down(int minutes) { shout("Game driver shouts: The memory is getting low !\n"); SHUTD->shut(minutes); } void remove_player(object victim) { catch(victim->quit()); if(victim) destruct(victim); } #ifndef 312MASTER /************************************************************************/ /* I don't know anyone who uses it? * Parse_command() is a heavy load */ /* * Default language functions used by parse_command() in non -o mode */ string *parse_command_id_list() { return ({ "one", "thing" }); } string *parse_command_plural_id_list() { return ({ "ones", "things", "them" }); } string *parse_command_adjectiv_id_list() { return ({ "iffish" }); } string *parse_command_prepos_list() { return ({ "in", "on", "under", "behind", "beside" }); } string parse_command_all_word() { return "all"; } #endif /* 312MASTER */ UID_TYPE get_root_uid() { return UID_ROOT; } #ifdef NATIVE_MODE /* mudos/native master fns */ string get_bb_uid() { return UID_BACKBONE; } string domain_file(string str) { string nom, tmp; if(str[0] != '/') str = "/"+str; if(sscanf(str, DOMAIN_DIR+"%s/%s", nom, tmp) == 2) return nom; return 0; } string author_file(string str) { return get_wiz_name(str); } int valid_seteuid(object ob, string id) { return 1; } int valid_override(string file, string efun_call) { return 1; } #endif /* mudos */ /*********************************************/ /* file security */ static mixed valid_file_access(string path, object caller, string call_fun, string access) { mixed file; object ob; if(path[0] != '/') path = "/"+ path; ob = (debug_mode) ? this_player() : (object)SECURITY_FILE; file = (mixed)call_other(ob,"valid_"+ access, path, caller, call_fun); if(!file) { #if 1 if(query_player_level("error messages")) { write("Invalid "+ access +" Access:\t "+ path +"\n\t\tCaller:\t "+ file_name(caller) +"\n\t\tEfun:\t "+ call_fun +"\n"); } else { write("Bad file name.\n"); } #else write("Invalid "+ access +" Access:\t "+ path +"\n\t\tCaller:\t "+ file_name(caller) +"\n\t\tEfun:\t "+ call_fun +"\n"); #endif } return file; } #ifndef MUDOS_DR mixed valid_write(string path, string eff_user, string call_fun, object caller) { if(!objectp(caller)) caller = previous_object(); return valid_file_access(path, caller, call_fun, "write"); } mixed valid_read(string path, string eff_user, string call_fun, object caller) { if(!objectp(caller)) caller = previous_object(); return valid_file_access(path, caller, call_fun, "read"); } /************************************************************************/ /* used by ed() to resolve a full path name */ mixed make_path_absolute(string path) { return (string)this_player()->valid_read(path); } #else mixed valid_write(string path, mixed caller, string call_fun) { if(!objectp(caller)) caller = previous_object(); return valid_file_access(path, caller, call_fun, "write"); } mixed valid_read(string path, mixed caller, string call_fun) { if(!objectp(caller)) caller = previous_object(); return valid_file_access(path, caller, call_fun, "read"); } #endif /* mudos */ /**************************************************************************/ /* wizlist */ #if defined(AMYLAAR) #if HAVE_WIZLIST == 0 #include "/include/cfg/wizlist.h" static void wiz_decay() { mixed *wl; int i; wl = wizlist_info(); for (i=sizeof(wl); i--; ) { set_extra_wizinfo(wl[i][WL_NAME], wl[i][WL_EXTRA] * 99 / 100); } call_out("wiz_decay", 3600); } void save_wiz_file() { rm("/WIZLIST"); write_file( "/WIZLIST", implode( map_array(wizlist_info(), lambda(({'a}), ({#'sprintf, "%s %d %d\n", ({#'[, 'a, WL_NAME}), ({#'[, 'a, WL_COMMANDS}), ({#'[, 'a, WL_EXTRA}) }) ) ), "" ) ); } void notify_shutdown() { if(previous_object() && valid_master_call(previous_object())) return; save_wiz_file(); } #endif /* WIZLIST */ void inaugurate_master(int arg) { #if HAVE_WIZLIST == 0 if (!arg) set_extra_wizinfo(0, allocate(BACKBONE_WIZINFO_SIZE)); if (find_call_out("wiz_decay") < 0) call_out("wiz_decay", 3600); #endif /* HAVE_WIZLIST */ #if defined(AMYLAAR321) set_driver_hook( H_MOVE_OBJECT0, unbound_lambda( ({'item, 'dest}), ({#',, #ifdef NATIVE_MODE ({#'?, ({#'!=, 'item, ({#'this_object})}), ({#'raise_error, "Illegal to move other object than this_object()\n"}) }), #endif #ifdef COMPAT_FLAG ({#'&&, ({#'living, 'item}), ({#'environment, 'item}), ({#',, ({#'efun::set_this_player, 'item}), ({#'call_other, ({#'environment, 'item}), "exit", 'item}), }) }), #endif ({#'efun::efun308, 'item, 'dest}), ({#'?, ({#'living, 'item}), ({#',, ({#'efun::set_this_player, 'item}), ({#'call_other, 'dest, "init"}), ({#'?, ({#'!=, ({#'environment, 'item}), 'dest}), ({#'return})}), }) }), ({#'=, 'others, ({#'all_inventory, 'dest}) }), ({#'=, ({#'[, 'others, ({#'member, 'others, 'item}) }), 0}), ({#'filter_array, 'others, ({#'bind_lambda, unbound_lambda( ({'ob, 'item}), ({#'?, ({#'living, 'ob}), ({#',, ({#'efun::set_this_player, 'ob}), ({#'call_other, 'item, "init"}), }) }) ) }), 'item, }), ({#'?, ({#'living, 'item}), ({#',, ({#'efun::set_this_player, 'item}), ({#'filter_objects, 'others, "init"}), }) }), ({#'?, ({#'living, 'dest}), ({#',, ({#'efun::set_this_player, 'dest}), ({#'call_other, 'item, "init"}), }) }), }) ) ); #ifdef COMPAT_FLAG set_driver_hook( H_LOAD_UIDS, unbound_lambda( ({'object_name}), ({#'?, ({#'==, ({#'sscanf, 'object_name, "players/%s", 'wiz_name}), 1, }), ({#'?, ({#'==, ({#'sscanf, 'wiz_name, "%s/%s", 'start, 'trailer}), 2, }), ({#'&&, ({#'strlen, 'start}), 'start}), 'wiz_name }), ({#'&&, ({#'!=, ({#'[..], 'object_name, 0, 3}), "ftp/"}), ({#'!=, ({#'[..], 'object_name, 0, 4}), "open/"}), }) }) ) ); set_driver_hook( H_CLONE_UIDS, unbound_lambda( ({'blueprint, 'new_name}), ({ #'||, ({#'creator, 'blueprint}), ({#'creator, ({#'previous_object})}), 1 }) ) ); set_driver_hook(H_CREATE_SUPER, "reset"); set_driver_hook(H_CREATE_OB, "reset"); set_driver_hook(H_CREATE_CLONE, "reset"); #else /* the following closures illustrate how the 3.1.2 driver used to * set (e)uids. It should be usable for tests, but to get better * performance, you are encouraged to replace the function * calls to get_bb_uid() and creator_file() by the equivalent code, * even if you are satisfied with the current behaviour. */ set_driver_hook( H_LOAD_UIDS, unbound_lambda( ({'object_name}), ({ #'?, ({#'==, ({#'=, 'creator_name, ({#'creator_file, 'object_name})}), ({#'getuid, ({#'previous_object})}), }), ({#'geteuid, ({#'previous_object})}), ({#'==, 'creator_name, ({#'get_bb_uid})}), ({#'geteuid, ({#'previous_object})}), ({#'({, 'creator_name, 1}), }) ) ); set_driver_hook( H_CLONE_UIDS, unbound_lambda( ({ /* object */ 'blueprint, 'new_name}), ({ #'?, ({#'==, ({#'=, 'creator_name, ({#'creator_file, 'new_name})}), ({#'getuid, ({#'previous_object})}), }), ({#'geteuid, ({#'previous_object})}), ({#'==, 'creator_name, ({#'get_bb_uid})}), ({#'geteuid, ({#'previous_object})}), ({#'({, 'creator_name, 1}), }) ) ); #ifdef NATIVE_MODE set_driver_hook(H_CREATE_OB, "create"); set_driver_hook(H_CREATE_CLONE, "create"); #else set_driver_hook(H_CREATE_SUPER, unbound_lambda(0, ({#',, ({#'call_other, ({#'this_object}), "create"}), ({#'call_other, ({#'this_object}), "reset"}) }) ) ); set_driver_hook(H_CREATE_OB, unbound_lambda(0, ({#',, ({#'call_other, ({#'this_object}), "create"}), ({#'call_other, ({#'this_object}), "reset"}) }) ) ); set_driver_hook(H_CREATE_CLONE, unbound_lambda(0, ({#',, ({#'call_other, ({#'this_object}), "create"}), ({#'call_other, ({#'this_object}), "reset"}) }) ) ); #endif #endif set_driver_hook(H_RESET, "reset"); set_driver_hook(H_CLEAN_UP, "clean_up"); #endif /* AMYLAAR321 */ } #if defined(AMYLAAR321) mixed current_time; string *epilog(int eflag) { if (eflag) return ({}); debug_message(sprintf("Loading init file %s\n", INIT_FILE)); current_time = rusage(); current_time = current_time[0] + current_time[1]; return explode(read_file(INIT_FILE), "\n"); } void preload(string file) { int last_time; if (strlen(file) && file[0] != '#') { last_time = current_time; debug_message(sprintf("Preloading: %s", file)); call_other(file, ""); current_time = rusage(); current_time = current_time[0] + current_time[1]; debug_message(sprintf(" %.2f\n", (current_time - last_time)/1000.)); } } #endif /* AMYLAAR321 */ #endif /* AMYLAAR */ /***********************************************************************/ /* promote new wizards and domain wizards */ string master_create_wizard(string owner,string domain,object caller) { string txt, tmp1, tmp2; object access; int tmp; if(!owner) return 0; if(!valid_player_call(caller)) return 0; write_file("/log/WIZ", "Name: "+ owner +", By: "+ (string)this_player()->query_name(1) +" Time: "+ ctime(time()) +"\n"); /* promote wizard */ if(!domain) { if(file_size(WIZARD_DIR+ owner) != -2) { tell_object(caller,"Adding Wizard Directory...\n"); mkdir(WIZARD_DIR+ owner); } if(file_size(WIZARD_DIR+ owner +"/open") != -2) { tell_object(caller,"Adding Open directory, ~/open\n"); mkdir(WIZARD_DIR+ owner +"/open"); } if(file_size(WIZARD_DIR+ owner +"/private") != -2) { tell_object(caller,"Adding Private directory, ~/private\n"); mkdir(WIZARD_DIR+ owner +"/private"); } if(file_size(WIZARD_DIR+ owner +"/"+ DEAD_ED) != -2) { tell_object(caller,"Adding dead edit directory, ~/"+ DEAD_ED +"\n"); mkdir(WIZARD_DIR+ owner +"/"+ DEAD_ED); } if(file_size(INIT_ACCESS) > 0 && file_size(WIZARD_DIR+ owner +"/access.c") < 0) { tell_object(caller,"Adding Configurable Access Object...\n"); txt = "#define NAME \""+ owner +"\"\n"; write_file(WIZARD_DIR+ owner +"/access.c",txt); txt = read_file(INIT_ACCESS); write_file(WIZARD_DIR+ owner +"/access.c",txt); } if(file_size(INIT_WORKROOM) > 0 && file_size(WIZARD_DIR+ owner +"/workroom.c") < 0) { tell_object(caller,"Adding Workroom...\n"); txt = "#include <mudlib.h>\ninherit ROOM;\n\n"; write_file(WIZARD_DIR+ owner +"/workroom.c",txt); txt = read_file(INIT_WORKROOM); write_file(WIZARD_DIR+ owner +"/workroom.c",txt); } } else { /* Add wizard to domain */ if(file_size(DOMAIN_DIR+ domain) != -2) { if(catch(call_other(DOMAIN_DIR +"access","??"))) { write("Error In Loading Head Domain Access Object!\n"); } if(query_player_level("create domain")) { write("Adding New Domain...\nMaking "+ owner +" the High Lord.\n"); if(this_player() != caller) { tell_object(caller,"Adding New Domain...\n"+ "You are now High Lord over "+ domain +".\n"); } mkdir(DOMAIN_DIR+ domain); txt = read_bytes(DOMAIN_DIR +"access.c", 0, file_size(DOMAIN_DIR +"access.c")); rm(DOMAIN_DIR +"access.bak"); write_file(DOMAIN_DIR +"access.bak",txt); sscanf(txt, "%s});%s", tmp1, tmp2); txt = "\""+owner+"\", "; txt = extract(txt,0,15); txt += "\""+ domain +"\",\n"; txt = tmp1+txt +" });"+ tmp2; rm(DOMAIN_DIR +"access.c"); write_file(DOMAIN_DIR +"access.c",txt); if((access = find_object(DOMAIN_DIR +"access"))) { destruct(access); } if(catch(call_other(DOMAIN_DIR +"access","??"))) { write("Error In Reloading Head Domain Access Object!\n"); } } else { write("You cannot add a New Domain.\n"); return 0; } } if(file_size(DOMAIN_DIR+ domain +"/access.c") < 0) { txt = read_bytes(DOMAIN_ACCESS,0,file_size(DOMAIN_ACCESS)); write_file(DOMAIN_DIR+domain+"/access.c",txt); if(catch(call_other(DOMAIN_DIR+ domain +"/access","??"))) { write("Error In Reloading Domain Access Object!\n"); } } if(file_size(DOMAIN_DIR+ domain +"/w") != -2) { mkdir(DOMAIN_DIR+ domain +"/w"); } if(file_size(DOMAIN_DIR+ domain +"/w/"+ owner) != -2) { tell_object(caller,"Adding Domain directory...\n"); mkdir(DOMAIN_DIR+ domain +"/w/"+ owner); } if(file_size(DOMAIN_DIR+ domain +"/w/"+ owner +"/access.c") < 0) { tell_object(caller,"Adding Configurable Access Object...\n"); txt = read_bytes(PLAYER_DOMAIN_ACCESS,0,file_size(PLAYER_DOMAIN_ACCESS)); write_file(DOMAIN_DIR+ domain +"/w/"+ owner +"/access.c",txt); if(catch(call_other(DOMAIN_DIR+domain+"/w/"+owner+"/access","??"))) { write("Error In Reloading Domain Creator Access Object!\n"); } } } }