/* -*- LPC -*- */
/*
* $Locker: $
* $Id: player.c,v 1.184 2003/07/15 07:13:27 pinkfish Exp $
*/
/**
* The main player object. Does all the player related stuff.
* @author Pinkfish
* @started December 1991
*/
#include <config.h>
#include <board.h>
#include <bounty.h>
#ifndef __DISTRIBUTION_LIB__
#include <deity.h>
#endif
#include <drinks.h>
#include <library.h>
#include <living.h>
#include <login.h>
#include <login_handler.h>
#include <log.h>
#include <quest_handler.h>
#include <command.h>
#include <mail.h>
#include <player.h>
#include <skills.h>
#include <top_ten_tables.h>
#include <tune.h>
#include <weather.h>
#include <refresh.h>
#include <nroff.h>
#include <db.h>
#include <error_handler.h>
#include <player_handler.h>
#include <playerinfo.h>
#include <group_handler.h>
// Right now if you move this below the clubs include it will break due to
// mudos class lossage :(
// This class contains all the global, nosaving variables to reduce our
// variable usage.
class player_info {
int hb_num;
int level;
int level_time;
int save_inhibit;
int update_tmps_call_out;
int last_save;
object snoopee;
mapping titles;
}
#include <clubs.h>
inherit "/global/line_ed";
inherit "/global/events";
inherit "/global/log";
inherit "/global/spells";
inherit "/global/more_string";
inherit "/global/finger";
inherit "/global/pweath";
inherit "/std/living/living";
inherit "/global/psoul";
inherit "/global/guild-race";
inherit "/global/more_file";
inherit "/global/path";
inherit "/global/start_position";
inherit "/global/family";
#define MIN_TIME_TO_SAVE 1800
#define FORGOT_CO_ORD_TIME (840553267+(8*60*60))
#define LEVEL_CACHE 60
#define ITEM_TRACKER ("/obj/handlers/item_tracker")
/*
* Discworld stuff
*/
private nosave class player_info _pinfo;
private int time_on;
private int max_deaths;
private int monitor;
private int _refresh_time;
private int start_time;
private int creator;
private int deaths;
private int last_log_on;
private int no_logins;
private int activity_counter;
private int _flags;
private string cap_name;
private string last_on_from;
private nosave string my_file_name;
void start_player();
void public_commands();
int save();
void set_desc(string str);
void do_load_auto();
void set_name(string str);
int check_dark(int light);
void continue_start_player();
int restart_heart_beat();
int brief_verbose(string,
string);
int quit_alt(int verbose);
int review();
int toggle_wimpy(string);
int do_refresh(string);
int do_cap(string);
protected void set_invis(int level);
void set_player_killer(int);
int query_player_killer();
void finished_error_check( object player, string my_name, int status,
mixed data );
void check_error_count();
void check_approve_list();
void create()
{
if (query_name()) {
return;
}
living::create();
events::create();
psoul::create();
line_ed::create();
more_string::create();
start_position::create();
add_property("determinate", "");
spells::create();
time_on = time();
start_time = time();
seteuid("PLAYER");
Str = 13;
Dex = 13;
Int = 13;
Con = 13;
Wis = 13;
set_max_sp(50);
set_sp(50);
wimpy = 20;
max_deaths = 7;
set_desc(0);
add_ac("bing", "blunt", 15);
add_ac("bing2", "sharp", 15);
add_ac("bing3", "pierce", 15);
add_property("player", 1);
set_cols(79);
set_rows(24);
last_log_on = time();
race_ob = RACE_STD;
sscanf(file_name(this_object()), "%s#", my_file_name);
//add_language("common");
_pinfo = new (class player_info, titles: ([ ]), save_inhibit:1);
}
/**
* @ignore yes
*/
void dest_me()
{
if ((query_name() != "object") && objectp(this_player()) &&
(this_player() != this_object()) &&
(file_name(this_player()) != "/obj/shut") &&
(explode(file_name(this_player()), "#")[0] != "/secure/login") &&
(explode(file_name(this_player()), "#")[0] != "/secure/nlogin")) {
user_event(this_object(), "inform",
(string) this_player()->query_name() +
" dests " + query_name(), "dest");
tell_object(this_object(), "You were destructed by " +
capitalize((string) this_player()->query_name()) + ".\n");
}
if(file_size(PLAYER_HANDLER->query_player_file_name(query_name())+
".o.gz") > 0 &&
PLAYER_HANDLER->query_player_disk_file_name(query_name()) &&
PLAYER_HANDLER->query_player_file_name(query_name()) !=
PLAYER_HANDLER->query_player_disk_file_name(query_name())) {
unguarded((:rename,
PLAYER_HANDLER->query_player_file_name(query_name())+".o.gz",
PLAYER_HANDLER->query_player_disk_file_name(query_name())+
".o.gz" :));
}
::dest_me();
} /* dest_me() */
/**
* This method stops the player from being able to save. This is done while
* the inventory is regenerating to stop problems with inventory loss due
* to logging off before it has finished.
* @see allow_save()
* @see query_save_inhibit()
*/
void disallow_save()
{
_pinfo->save_inhibit = 1;
}
/**
* This method allows the player to save again after they have been
* disallowed.
* @see disallow_save()
* @see query_save_inhibit()
*/
void allow_save()
{
_pinfo->save_inhibit = 0;
}
/**
* This method returns the value of the disallowing save variable. If this
* is a non-zero value then the player must not be saved.
* @see allow_save()
* @see disallow_save()
*/
int query_save_inhibit()
{
return _pinfo->save_inhibit;
}
/**
* This is the date on which the character was started. The very first
* time the player ever logged on.
* @return the time at which the player first logged on
*/
int query_start_time()
{
return start_time;
}
/**
* This method returns the current capitalised name of the player.
* @return the current capitalised name
* @see set_cap_name()
*/
nomask string query_cap_name()
{
return cap_name;
}
/**
* This method is called from within the login code to start up the
* new player, set their name and move them into the correct
* location on the mud.
* @param bong the name of the player
* @param new_flag are the a new player?
* @param c_name their capital name
* @param ident the ident from the authorisation code
* @param go_invis go invsible on login
*/
void move_player_to_start(string bong,
int new_flag,
string c_name,
string ident,
int go_invis) {
string lang;
/* Only /secure/login can do this. */
if (file_name(previous_object())[0..12] != "/secure/login" &&
file_name(previous_object())[0..13] != "/secure/nlogin") {
write("You don't have clearance to do that.\n");
return;
}
seteuid("Root");
set_name(bong);
if (!new_flag) {
unguarded((: restore_object,
PLAYER_HANDLER->query_player_file_name(query_name()), 1 :));
if (go_invis) {
switch(go_invis) {
case -1:
set_invis(0);
break;
case 2:
if (this_object()->query_lord()) {
set_invis(2);
break;
}
case 1:
set_invis(1);
}
}
}
disallow_save(); /* don't allow saves until the autoload has started */
add_property("player", 1);
cap_name = c_name;
set_short(cap_name);
add_property("determinate", "");
no_logins++;
if (!query_cols()) {
set_cols(79);
}
remove_property("new player");
if (this_player()->query_creator()) {
seteuid(query_name());
if (file_size("/w/" + query_name() + "/cmds") == -2)
AddSearchPath(({ "/w/" + query_name() + "/cmds" }));
AddSearchPath(({ DIR_PLAYER_CMDS, DIR_SECURE_PLAYER_CMDS,
DIR_CREATOR_CMDS, DIR_SECURE_CREATOR_CMDS,
DIR_PLAYTESTER_CMDS }));
} else {
seteuid("PLAYER");
AddSearchPath(({ DIR_PLAYER_CMDS, DIR_SECURE_PLAYER_CMDS }));
}
if (!last_on_from) {
printf("You have never logged in before.\n");
} else {
printf("You last logged in from %s and are currently "
"logged in from %s (%s).\n", last_on_from,
query_ip_name(this_object()), query_ip_number(this_object()));
}
last_on_from = query_ip_name(this_object()) + " (" +
query_ip_number(this_object()) + ")";
//
// What the heck does this do?
//
/*
if ( time_on < -500 * 24 * 60 * 60 ) {
time_on += time();
}
*/
if (time_on > 0) {
time_on = 0;
}
time_on += time();
if (new_flag) {
add_property("new player!", 1);
}
LOGIN_HANDLER->player_logon(bong, query_property("guest"),
(query_ip_name()? query_ip_name() :
query_ip_number()));
if(query_property("guest")) {
this_player()->set_nationality(DEFAULT_NATIONALITY);
this_player()->
set_nationality_region(this_player()->find_region(DEFAULT_NATIONALITY,
DEFAULT_REGION));
lang = DEFAULT_NATIONALITY->query_language();
// Setup the default language correctly.
this_player()->add_language(lang);
this_player()->set_default_language(lang);
this_player()->set_language(lang);
}
write(LOGIN_HANDLER->get_message("/doc/NEWS"));
call_out((: continue_start_player :), 0);
// remove the previously cached entry.
PLAYER_HANDLER->remove_cache_entry(query_name());
} /* move_player_to_start() */
/** @ignore yes */
protected void move_to_start_pos()
{
::move_to_start_pos();
if (query_verbose("look"))
command("look");
else
command("glance");
if (!finger_set()) {
write
("%^BOLD%^Please set your finger information with 'chfn'.%^RESET%^\n");
//command("chfn");
}
if(no_logins == 1 && !query_property("guest")) {
write("\n%^BOLD%^" +
LOGIN_HANDLER->get_message("/doc/login/NEW_USER_START") +
"%^RESET%^\n");
}
no_time_left();
START_PLAYER->logged_on_times(no_logins);
// Try resolving hostname one last time.
if(query_ip_number(this_object()) == query_ip_name(this_object()))
resolve(query_ip_number(this_object()), "");
} /* move_to_start_pos() */
/**
* @ignore yes
*
* This function tracks a players activity to determine whether they're still
* active or not. Ceres
*/
protected void update_activity(int logon)
{
int time_on;
// Lower their activity score if they haven't been on for more than a week.
if (last_log_on > 0) {
time_on = last_command - last_log_on;
if (time_on > 0)
activity_counter -= (time_on / (3600 * 24 * 7)) * 10;
}
if (activity_counter <= -55) {
activity_counter = -55;
}
// when they logon give them a couple more activity points.
if (logon) {
activity_counter += 3;
} else { // when they leave give them some more for each hour they were on.
activity_counter += 2 * ((time() - last_log_on) / 3600);
}
// Set minima and maxima to the counter.
if (activity_counter >= 0)
activity_counter = 0;
}
/**
* Return the current value of this players activity_counter
* (used for debugging)
*/
int query_activity_counter()
{
return activity_counter;
}
/**
* THis method prints something if there are bug replies to see.
*/
private void display_bug_replies(int type, class error_replies* replies) {
if (type == DB_SUCCESS) {
if (sizeof(replies) > 0) {
tell_object(this_object(), "\n\nYou have %^YELLOW%^" +
sizeof(replies) + " NEW%^RESET%^ bug repl" +
(sizeof(replies) > 1?"ies ":"y ") +
"(read with 'bug replies').\n\n");
}
}
}
private void check_mccp() {
if(!compressedp(this_object())) {
write("\n%^BOLD%^%^RED%^You are logged in uncompressed!\n");
write("Use of an MCCP capable mud client will reduce your load on "
"the " + mud_name() + " system.%^RESET%^\n\n");
}
}
/**
* @ignore yes
*/
void continue_start_player()
{
string title;
mapping news_rc;
mixed *stuff;
object book;
// Set the cre flag for setting up commands etc.
if (this_object()->query_lord()) {
creator = 1;
}
start_player();
no_time_left();
/* Remove passed out property, unless the player is
* in a trance, e.g. when contemplating. */
if (query_property(PASSED_OUT) && !query_property(TRANCE)) {
call_out((: remove_property :), 10 + random(30), PASSED_OUT);
}
remove_property(UNKNOWN_MOVE);
remove_property(RUNNING_MOVE);
init_after_save(); /* for effects */
printf("%s", fix_string(MAILER->new_mail(query_name())));
news_rc = BOARD_HAND->query_newsrc(query_name());
if (!news_rc) {
news_rc = ([ ]);
}
stuff = BOARD_HAND->get_subjects("announcements");
if (sizeof(stuff)) {
if (stuff[<1][B_TIME] > news_rc["announcements"]) {
write("\nThere are %^YELLOW%^NEW%^RESET%^ announcements. ");
write("You can read them with \"news\".\n\n");
//"/cmds/player/news"->do_list();
//printf("You can read then with \"news\".\n\n");
}
}
call_out((: check_mccp :), 4);
if (query_property("dead")) {
(clone_object(DEATH_SHADOW))->setup_shadow(this_object());
// Give them a dead book too.
book = clone_object(DEAD_BOOK);
book->move(this_object());
}
if (query_property("noregen")) {
DEATH->person_died(query_name());
}
exec_alias("login", "");
update_activity(1);
last_log_on = time();
title = LIBRARY->query_title(query_name());
if (stringp(title)) {
_pinfo->titles += ([ "quest" : title ]);
}
if (my_file_name != "/global/player") {
check_error_count();
if(my_file_name != "/global/playtester") {
check_approve_list();
}
}
if (query_property("new player!")) {
// Clear the alt info.
PLAYERINFO_HANDLER->player_created(query_name());
user_event(this_object(), "inform",
capitalize(query_name()) +
" arrives on " + mud_name() + " for the first time!", "new-player");
remove_property("new player!");
set_last_pos(CONFIG_NEWBIE_START_LOCATION);
START_PLAYER->start_player(this_object());
}
//add_language("common");
check_family_name();
call_out((: move_to_start_pos :), 0);
call_out((: set_heart_beat(1) :), 1);
// Tell them about new error replies.
ERROR_HANDLER->do_error_replies(query_name(), 1, (: display_bug_replies :));
} /* continue_start_player() */
/**
* @ignore yes
*/
void check_error_count() {
string my_name;
my_name = query_name();
DB_HANDLER->make_sql_request( "errors", "atuin", "",
"SELECT COUNT(Id) AS idc FROM errors WHERE Directory = '/w/" +
my_name + "' AND Status = 'OPEN'",
(: finished_error_check, this_object(), my_name :) );
} /* check_error_count() */
/**
* @ignore yes
*/
void finished_error_check( object player, string my_name, int status,
mixed data ) {
int num;
int ret;
if ( file_size("/w/" + my_name + "/" + PLAYER_ERROR_LOG) > 0 ) {
num = file_length("/w/" + my_name + "/" + PLAYER_ERROR_LOG);
tell_object( player, "%^YELLOW%^You have %^RED%^" + num +
"%^YELLOW%^ director" + (num == 1 ? "y" : "ies") +
" with %^RED%^ERRORS%^YELLOW%^ in /w/" + my_name + "/" +
PLAYER_ERROR_LOG + ".%^RESET%^\n");
}
if ( status == DB_SUCCESS && sizeof( data ) > 0 ) {
if ( ( ret = data[0]["idc"] ) > 0 ) {
tell_object( player, "%^YELLOW%^You have %^RED%^" + ret +
" ERROR" + (ret == 1 ? "" : "S") + "%^YELLOW%^ in /w/" +
my_name + ".%^RESET%^\n");
}
}
} /* finished_error_check() */
/** @ignore yes */
void check_approve_list() {
string str;
mapping assignments;
int count;
assignments = master()->query_directory_assignments();
foreach(str in keys(assignments)) {
if(member_array(this_object()->query_name(), assignments[str]) != -1 &&
file_size(str + "/to_approve")) {
count = sizeof(get_dir(str + "/to_approve/*")) - 2;
if(count > 0)
tell_object(this_object(), "%^YELLOW%^" + str + " has %^RED%^" +
count + "%^YELLOW%^ item" + (count > 1 ? "s" : "") +
" awaiting approval.%^RESET%^\n");
}
}
}
/**
* @ignore yes
*/
void start_player()
{
if (this_object()->query_creator() && my_file_name != "/global/player") {
this_player()->all_commands();
this_player()->app_commands();
this_player()->wiz_commands();
}
call_out((: do_load_auto :), 1);
reset_get();
enable_commands();
public_commands();
command_commands();
parser_commands();
force_commands();
race_guild_commands();
soul_commands();
event_commands();
finger_commands();
communicate_commands();
living_commands();
logging_commands();
editor_commands();
if (this_player()->query_creator()) {
set_living_name(query_name());
}
set_no_check(1);
set_con(Con);
set_dex(Dex);
set_int(Int);
set_str(Str);
set_wis(Wis);
reset_all();
set_current_path(query_home_dir());
if (wimpy > 100) {
wimpy = 25;
}
if (contmp || dextmp || inttmp || strtmp || wistmp) {
_pinfo->update_tmps_call_out = call_out((: update_tmps :), 900);
}
}
/* added chrisy 6 june 93 to stop net-dead players getting killed */
/**
* @ignore yes
* This is an over ride of something in /std/living
*/
int adjust_hp(int number,
object attacker,
object weapon,
string attack)
{
if (!interactive(this_object()))
return query_hp();
return::adjust_hp(number, attacker, weapon, attack);
} /* adjust_hp() */
/**
* Starts the autoloading process. This is called just after a player
* logs in to start up the auto loading process.
*/
void do_load_auto()
{
load_auto_load_alt(query_auto_load_string(), this_object(), this_object(),
(: tell_object(this_object(),
"\n%^CYAN%^Inventory regeneration complete.%^RESET%^\n") :));
set_auto_load_string(0);
allow_save();
} /* do_load_auto() */
/**
* @ignore yes
*/
void public_commands()
{
add_command("restart", this_object(), "", (: restart_heart_beat() :));
add_command("save", this_object(), "", (: save() :));
add_command("quit", this_object(), "", (: quit_alt(-1) :));
add_command("quit", this_object(), "brief", (: quit_alt(0) :));
add_command("quit", this_object(), "verbose", (: quit_alt(1) :));
add_command("review", this_object(), "", (: review() :));
add_command("wimpy", this_object(), "", (: toggle_wimpy(0) :));
add_command("wimpy", this_object(), "<word'number'>",
(: toggle_wimpy($4[0]) :));
add_command("refresh", this_object(), "<word'totally'>",
(: do_refresh($4[0]) :));
add_command("cap", this_object(), "<word'name'>", (: do_cap($4[0]) :));
} /* public_commands() */
/**
* Force the player to glance. Forces the player to glance in a
* certain direction.
* @param str the direction to glance in
* @return 0 ifg the command failed, non zer if it succeeded
*/
int glance(string str)
{
return command("glance" + (str ? " " + str : ""));
} /* glance() */
/**
* Force the player to look. Forces the player to look at something
* or just around. If the input is set to "" then they look around.
* @param str what to look at
* @return 0 if it failed, non zero on success
* @see efun::command()
*/
int look_me(string str)
{
return command(str ? "look" + str : "look");
} /* look_me() */
/**
* @ignore yes
*/
int review()
{
write("Entry : " + query_msgin() + "\n");
write("Exit : " + query_msgout() + "\n");
write("MEntry : " + query_mmsgin() + "\n");
write("MExit : " + query_mmsgout() + "\n");
write("Editor : " + query_editor() + "\n");
return 1;
} /* review() */
/**
* Forces the player to examine something. This does the same as the look_me
* function.
* @see look_me()
* @return 0 on a failure, non zero on success.
* @param arg the thing to look at.
*/
int examine(string arg)
{
return look_me(arg ? " at " + arg : "");
} /* examine() */
/**
* @ignore yes
*/
varargs string short(int dark,
int verbose)
{
string str;
string family;
string title;
if (!interactive(this_object())) {
str = "the net dead statue of ";
} else {
str = "";
}
family = query_family_name();
if (!family) {
family = "";
} else {
family = " " + family;
}
if (verbose)
title = query_player_title();
if (!title) {
title = "";
} else {
title = title + " ";
}
return str + title + living::short(dark) + family;
} /* short() */
/**
* This method changes the current value of the wimpy variables.
* @param str the new value of the wimpy variable
* @return 0 on failure and 1 on success
*/
int toggle_wimpy(string str)
{
int number;
if (!str) {
if (this_object()->query_wimpy())
write("You are in wimpy mode, you will run away at " +
this_object()->query_wimpy() +
"% of your max hps.\n");
else
write("You are in brave mode.\n");
write("Usage: wimpy <num> (caution read help wimpy)\n");
return 1;
}
if (sscanf(str, "%d", number) != 1)
return notify_fail("You must set your wimpy to a number.\n");
if ((number < 0) || (number > 30))
return notify_fail("Your wimpy must be between 0 and 30%.\n");
this_object()->set_wimpy(number);
printf("Wimpy set to %d%%\n", wimpy);
return 1;
} /* toggle_wimpy() */
/**
* This method returns any extra information associated with the score. This
* method will mostly be overridden by shadows which wish to place more
* information into the score command.
* @return the extra information to place in the score
*/
string extra_score()
{
return "";
}
/**
* This method is deprecated.
*
* @return always returns 1
* @see save_me()
*/
nomask int save() {
#ifdef UNUSED
if(query_verb() == "save") {
if(_pinfo->last_save > time() - 900) {
tell_object(this_object(), "You saved only a few minutes ago.\n");
return 1;
}
_pinfo->last_save = time();
}
#endif
/*
* easier on me - Pinkfish.
* ..
*/
if (((time() - time_on) < MIN_TIME_TO_SAVE) &&
!LIBRARY->query_quest_points(query_name()) &&
!query_property("authorised player")) {
if (query_verb() == "save") {
tell_object(this_object(), "You're too young to save... sorry.\n");
}
return 1;
}
tell_object(this_object(), "Saving...\n");
this_object()->save_me();
return 1;
}
/**
* Saves the player. Saves the player to disc, doing all the autoload
* stuff and such like.
* @see save()
*/
void save_me() {
mixed old;
#ifdef NOT_SAVEING_PLAYERS
if (!this_object()->query_creator()) {
write("Not saving for players currently.\n");
return;
}
#endif
if (query_auto_loading())
return;
if (query_property("guest")) {
if (query_verb() == "save")
tell_object(this_object(), "But not saving for guests... Sorry.\n");
return;
}
/* If this is called before auto_loading has even started, log and abort
* Olorin 31-Mar-97
*/
if (query_save_inhibit()) {
return;
}
if (guild_ob) {
guild_ob->player_save(this_object());
}
if (race_ob) {
race_ob->player_save(this_object());
}
old = geteuid();
check_last_pos();
/* for effects */
effect_freeze();
effects_saving();
/* Recreating the autoload stuff. */
create_auto_load(all_inventory(), 1);
if (interactive(this_object())) {
last_on_from = query_ip_name(this_object()) + " (" +
query_ip_number(this_object()) + ")";
}
//
// Keep the time_on calculation as close to the saving as possible.
//
time_on -= time();
//if (query_creator()) {
catch(unguarded((: save_object,
PLAYER_HANDLER->query_player_file_name(query_name()), 3 :)));
/*
} else {
catch(unguarded((: save_object,
PLAYER_HANDLER->query_player_file_name(query_name()), 1 :)));
}
*/
time_on += time();
ITEM_TRACKER->save_all_item_states(this_object()->query_name());
effect_unfreeze();
// if (this_object()->query_creator()) {
/* Clear the autoload string after saving to save memroy. */
set_auto_load_string(0);
// }
} /* save_me() */
void save_with_auto_load(mixed al)
{
mixed old;
#ifdef NOT_SAVEING_PLAYERS
if (!this_object()->query_creator()) {
write("Not saving for players currently.\n");
return;
}
#endif
if (query_property("guest")) {
write("But not saving for guests... sorry.\n");
return;
}
if (((time() - time_on) < MIN_TIME_TO_SAVE) && query_verb() == "save") {
tell_object(this_object(), "You're too young to save... sorry.\n");
return;
}
/* If this is called before auto_loading has even started, log and abort
* Olorin 31-Mar-97
*/
if (query_save_inhibit()) {
return;
}
if (guild_ob) {
guild_ob->player_save(this_object());
}
if (race_ob) {
race_ob->player_save(this_object());
}
old = geteuid();
/* for effects */
effect_freeze();
effects_saving();
set_auto_load_string(al);
if (((time() - time_on) >= MIN_TIME_TO_SAVE) ||
LIBRARY->query_quest_points(query_name())) {
//
// Put the time_on calculation as close to the save as possible.
//
time_on -= time();
//if (query_creator()) {
catch(unguarded((: save_object,
PLAYER_HANDLER->query_player_file_name(query_name()),
3 :)));
/*
} else {
catch(unguarded((: save_object,
PLAYER_HANDLER->query_player_file_name(query_name()),
1 :)));
}
*/
time_on += time();
}
effect_unfreeze();
} /* save_with_auto_load() */
/**
* This is the quit code called by the command 'quit'
* @return 1 if successful, 0 if failed
* @see quit()
* @see do_quit()
*/
int quit_alt(int verbose)
{
object frog;
if (verbose == -1) {
verbose = query_verbose("quit");
}
if (query_auto_loading()) {
if (!interactive(this_object())) {
dest_me();
} else {
write
("You cannot quit yet: your inventory is still being generated.\n");
}
return 1;
}
if (sizeof(filter_array((object *) this_object()->query_attacker_list(),
(: living($1) :))) &&
this_player() == this_object() && interactive(this_object())) {
write
("You cannot quit while in combat. Use 'stop' to stop fighting.\n");
return 1;
}
check_last_pos();
update_activity(0);
last_log_on = time();
// Added to help people tell when the player quits.
catch(this_object()->event_quit(this_object()));
catch(environment(this_object())->event_quit(this_object()));
catch(editor_check_do_quit());
write("A small gecko takes your hand and rushes you to the departure "
"lounge.\n");
say(query_cap_name() + " leaves the game.\n");
catch(move("/room/departures"));
user_event(this_object(), "inform",
query_cap_name() + " leaves " + mud_name() + "", "logon", this_object());
catch(LOGIN_HANDLER->player_logout(query_name()));
if (race_ob) {
catch(race_ob->player_quit(this_object()));
}
if (guild_ob) {
catch(guild_ob->player_quit(this_object()));
}
frog = clone_object("/obj/monster/greco");
frog->move("/room/departures");
frog->get_rid_of(this_object(), verbose);
return 1;
} /* quit_alt() */
/**
* quits the player.
* @return zero if it failed, non zero on success
* @see quit()
* @see quit_alt()
*/
int do_quit()
{
return quit_alt(-1);
} /* do_quit() */
/**
* A forced quit.
* This is the function called by external objects to quit
* a player. It avoids checks for things like being in combat.
*
* @return 0 if it failed, non zero if it succeeded.
* @see do_quit()
* @see quit_alt()
* @see efun::command()
*/
int quit()
{
if (query_auto_loading() || query_save_inhibit()) {
tell_object(this_object(),
"Forced to quit whilst auto loading. Not saving.\n");
::dest_me();
return 1;
}
check_last_pos();
update_activity(0);
last_log_on = time();
catch(editor_check_do_quit());
// Added to help people tell when the player quits.
catch(this_object()->event_quit(this_object()));
catch(environment(this_object())->event_quit(this_object()));
tell_object(this_object(), "Thanks for playing. See you next time.\n");
say(query_cap_name() + " leaves the game.\n");
user_event(this_object(), "inform",
query_cap_name() + " leaves " + mud_name() + "", "logon", this_object());
catch(LOGIN_HANDLER->player_logout(query_name()));
if (race_ob) {
catch(race_ob->player_quit(this_object()));
}
if (guild_ob) {
catch(guild_ob->player_quit(this_object()));
}
catch(save_me());
foreach( object inv in all_inventory( this_object() ) ) {
reset_eval_cost();
catch( inv->set_tracked_item_status_reason("QUIT") );
catch( inv->dest_me() );
}
catch(ITEM_TRACKER->
save_all_item_states_delete_cache(this_object()->query_name()));
effects_quiting();
// One more for good luck.
reset_eval_cost();
if (catch(dest_me())) {
destruct(this_object());
}
return 1;
} /* quit() */
/**
* This method returns the mapping of all the title associated with this
* player.
* @return the current mapping of titles
* @see query_title()
* @see set_title()
* @see remove_title()
*/
mapping query_titles()
{
return copy(_pinfo->titles);
}
/**
* This method returns the list of titles associated with this player.
* @return the list of titles
* @see query_titles()
* @see set_title()
* @see remove_title()
*/
string query_title()
{
return implode(m_values(_pinfo->titles), ", ");
}
/**
* This method sets the current title type to be of a certain name.
* @param type the type of title to set
* @param title the string to set it to
* @see query_title()
* @see set_title()
* @see remove_title()
*/
void set_title(string type,
string title)
{
_pinfo->titles[type] = title;
}
/**
* This method removes the title of the given type from the title mapping.
* @param type the type of title to remove
* @see query_title()
* @see set_title()
* @see remove_title()
*/
void remove_title(string type)
{
map_delete(_pinfo->titles, type);
}
/**
* This method returns the number of times the player has died.
* @return the number of times the player has died
* @see adjust_deaths()
* @see adjust_max_deaths()
*/
int query_deaths()
{
return deaths;
}
/**
* This method changes the number of times the player has died. This
* can only be positive.
* @param i the amount of deaths to adjust by, must be +ve
* @see query_deaths()
* @see adjust_max_deaths()
*/
void adjust_deaths(int i)
{
if (i > 0) {
deaths += i;
}
}
/* nomask protected void set_name(string str) { */
/** @ignore yes */
nomask void set_name(string str) {
if (query_name() && query_name() != "object") {
return;
}
if (file_name(previous_object())[0..12] != "/secure/login" &&
file_name(previous_object())[0..13] != "/secure/nlogin") {
return;
}
::set_name(str);
set_living_name(query_name());
set_main_plural(query_name());
} /* set_name() */
/**
* @ignore yes
* No ide what this is doing here?
*/
void init_static_arg(mapping map)
{
return;
}
/**
* @ignore yes
*/
void init_dynamic_arg(mapping, object) {
return;
}
/** @ignore yes */
string long(string str,
int dark)
{
string s;
string tmp;
string title;
string nationality;
title = query_player_title();
if (!title) {
title = "";
} else {
title = title + " ";
}
s = "You see " + title + query_short();
tmp = query_family_name();
if (tmp) {
s += " " + query_family_name();
}
if (guild_ob) {
s += " " + (string) guild_ob->query_title(this_object()) + ".\n";
} else {
s += ".\n";
}
if (race_ob) {
s += (string) race_ob->query_desc(this_object());
}
nationality = query_nationality_description(this_player());
if (nationality && nationality != "") {
s += nationality + "\n";
}
if (dark == 2 || dark == -2) {
s += "It is too ";
if (dark == -2) {
s += "dark";
} else {
s += "bright";
}
s += " to see their description or what " +
query_pronoun() + " are wearing or carrying.\n";
s += calc_extra_look();
} else {
if (query_desc() && query_desc() != "") {
s += capitalize(query_pronoun()) + " " + query_desc() +
query_main_zone_desc(query_wearing()) + "\n";
}
s += capitalize(query_pronoun()) + " " +
this_object()->health_string() + ".\n";
s +=
capitalize(query_pronoun()) + " is " + query_position_short() +
".\n";
s += calc_extra_look();
s += weather_extra_look();
s += query_living_contents(0);
}
return s;
} /* long() */
/**
* This method is called when the player dies. It creates the corpse
* and handles all the bits and pieces that should be dealth with
* when a player dies.
* <p>
* If this method returns 0 then the automatic death handling code
* in the living object is used instead of this.
* @return always returns 1
*/
mixed second_life()
{
object corpse;
string death_mess;
add_property("dead", time());
if (!DEATH->someone_died(this_object())) {
deaths++;
}
effects_thru_death();
corpse = make_corpse();
reset_protectors();
if (deaths > max_deaths) {
death_mess = query_property ("death mess");
tell_object(this_object(), "You have died your final death. " +
"Your name will be inscribed in the Hall of Legends.\n");
if (death_mess && sizeof (death_mess)) {
death_mess = strip_colours (death_mess);
death_mess = replace (death_mess, ({"\n", "", "\a", ""}));
shout(capitalize(query_name()) + " has died for the last time. " +
death_mess + "\n");
}
else {
shout(capitalize(query_name()) + " has died for the last time. " +
capitalize(query_pronoun()) + " is mourned.\n");
}
LIBRARY->complete_death(query_name());
corpse->move(PLAYER_MORGUE);
} else
corpse->move(environment());
call_out((: save_me :), 0);
if (find_object(OFFLER) && (deaths <= max_deaths)) {
OFFLER->person_died(query_name());
} else {
DEATH->person_died(query_name());
}
clone_object(DEATH_SHADOW)->setup_shadow(this_object());
if (guild_ob) {
guild_ob->member_died(this_object());
}
gp = 0;
hp = 0;
set_sp(0);
set_max_sp(50);
xp = 0;
//spells = ([ ]);
reset_spells();
reset_processes();
contmp = dextmp = inttmp = strtmp = wistmp = 0;
remove_call_out(_pinfo->update_tmps_call_out);
adjust_tmp_con(-2);
adjust_tmp_dex(-2);
adjust_tmp_int(-2);
adjust_tmp_str(-2);
adjust_tmp_wis(-2);
return corpse;
} /* second_life() */
/**
* This method removes the ghost from the player. This stops them
* being a ghost and turns them back into a real person.
* @see second_life()
*/
void remove_ghost()
{
if (deaths > max_deaths) {
if (this_player() != this_object()) {
tell_object(this_object(), this_player()->query_cap_name() +
" tried to raise you, but you are completely dead.\n");
tell_object(this_player(), query_cap_name() +
" is completely dead, you cannot raise " +
query_objective() + ".\n");
} else {
tell_object(this_object(), "You are completely dead. You cannot " +
"be raised.\n");
say(query_cap_name() +
" struggles to appear in a solid form, but fails.\n");
return;
}
}
remove_property("dead");
tell_object(this_object(), "You reappear in a more solid form.\n");
if (guild_ob) {
guild_ob->member_resurrected(this_object());
}
say(query_cap_name() + " appears in more solid form.\n");
if (query_hp() < 0) {
set_hp(1);
}
set_personal_temp(0);
this_object()->dest_death_shadow();
save_me();
all_inventory()->recovery_from_death();
} /* remove_ghost() */
/**
* Called when the player goes net dead. This is called
* by the driver when a player goes net dead. Turns them into
* a statue and stuff.
*/
void net_dead()
{
if (!environment() || file_name(environment()) == "/room/departures") {
// Don't do anything here...
return;
}
if ((query_name() == "guest") || (query_name() == "root")) {
say(query_name() + " vanishes in a puff of logic.\n");
quit();
} else {
say(query_name() + " goes white, looks very chalky and turns into a " +
"statue.\n");
user_event(this_object(), "inform",
capitalize(query_name()) + " has lost " +
query_possessive() + " link", "link-death", this_object());
check_last_pos();
LOGIN_HANDLER->player_net_dead(query_name());
/* Called to save the player when they go net dead. */
save_me();
}
event(environment(), "net_dead", this_object());
} /* net_dead() */
/**
* Checks to see if they have idled out. This is called from within
* the heart beat code.
* @see heart_beat()
*/
void idle_out()
{
say(cap_name + " has been idle for too long; " + query_pronoun() +
" vanishes in a puff of boredom.\n");
write("You idled out, sorry.\n");
quit();
} /* idle_out() */
/**
* The main heart beat function. This is called by the driver
* every 2 seconds on the player. Does all the maintence
* stuff like fixing up hps and stuff like that.
*/
void heart_beat()
{
catch {
int idle_time;
events::print_messages();
flush_queue();
if (!interactive(this_object())) {
idle_time = time() - last_command;
} else {
idle_time = query_idle(this_object());
}
if (query_creator()) {
idle_time = idle_time / 3;
/* Time out for creators is 3 times that of players... */
}
if (idle_time > FULL_IDLE) {
if ((LOGIN_HANDLER->is_discworld_full() || idle_time > MAX_IDLE) &&
(!interactive(this_object())
|| my_file_name != "/global/lord")) {
call_out((: idle_out :), 2);
}
}
if (interactive(this_object())) {
living::heart_beat();
adjust_sp(1);
adjust_xp(3);
living::update_volumes();
this_object()->do_spell_effects(0);
// reset it every hour to stop it rolling over.
if (_pinfo->hb_num++ > 1800)
_pinfo->hb_num = 0;
// Do these checks less frequently.
if (!(_pinfo->hb_num % 120)) {
calc_personal_temp();
adjust_max_sp(1);
}
}
};
} /* heart_beat() */
/**
* Is rthe monitor turned on? The hit point monitor which is
* displyed during combat...
*
* @return 1 if it is on, 0 if not
*/
int query_monitor()
{
return monitor;
}
/**
* Set the hit point minitor. This sets the value of the hit point
* monitor flag. If it is set to 0, the monitor is turned off. If
* it is set to 1 the monitor is turned on, higher values cause the monitor
* to be displayed every N heartbeats.
*
* @param i the new value for the hit point monitor flag
*/
void set_monitor(int i) {
monitor = i;
}
protected void write_prompt()
{
efun::tell_object(this_object(), "> ");
return;
}
#ifdef UNUSED
protected void write_prompt()
{
string prompt;
int tmp,
i;
string stuff;
if (!(monitor & 2) || !this_object()->query_creator())
efun::tell_object(this_object(), "> ");
else {
prompt = "";
stuff = this_player()->query_property("prompt");
for (i = 0; i < strlen(stuff); i++) {
switch (stuff[i]) {
case 'h': // Hp %
tmp = ((query_hp() * 100) / query_max_hp());
prompt += "Hp:";
switch (tmp) {
case 50..100:
prompt += "%^GREEN%^";
break;
case 20..49:
prompt += "%^YELLOW%^";
break;
default:
prompt += "%^RED%^";
}
prompt += tmp + "%^RESET%^";
break;
case 'H': // Hp %
tmp = ((query_hp() * 100) / query_max_hp());
prompt += "Hp:";
switch (tmp) {
case 50..100:
prompt += "%^GREEN%^";
break;
case 20..49:
prompt += "%^YELLOW%^";
break;
default:
prompt += "%^RED%^";
}
prompt += query_hp() + "%^RESET%^";
break;
case 'g': // Gp %
tmp = (query_gp() * 100) / query_max_gp();
prompt += "Gp:";
switch (tmp) {
case 50..100:
prompt += "%^GREEN%^";
break;
case 20..49:
prompt += "%^YELLOW%^";
break;
default:
prompt += "%^RED%^";
}
prompt += tmp + "%^RESET%^";
break;
case 'G': // Gp
tmp = (query_gp() * 100) / query_max_gp();
prompt += "Gp:";
switch (tmp) {
case 50..100:
prompt += "%^GREEN%^";
break;
case 20..49:
prompt += "%^YELLOW%^";
break;
default:
prompt += "%^RED%^";
}
prompt += query_gp() + "%^RESET%^";
break;
case 's': // Sp %
tmp = (query_sp() * 100) / query_max_sp();
prompt += "Sp:";
switch (tmp) {
case 50..100:
prompt += "%^GREEN%^";
break;
case 20..49:
prompt += "%^YELLOW%^";
break;
default:
prompt += "%^RED%^";
}
prompt += tmp + "%^RESET%^";
break;
case 'S': // Sp
tmp = (query_sp() * 100) / query_max_sp();
prompt += "Sp:";
switch (tmp) {
case 50..100:
prompt += "%^GREEN%^";
break;
case 20..49:
prompt += "%^YELLOW%^";
break;
default:
prompt += "%^RED%^";
}
prompt += query_sp() + "%^RESET%^";
break;
case 'X':
case 'x':
prompt += "Xp:" + query_xp();
break;
default:
if (sizeof(prompt) > 0 && prompt[sizeof(prompt) - 1] != stuff[i])
prompt += sprintf("%c", stuff[i]);
}
}
prompt += "> ";
efun::tell_object(this_object(), fix_string(prompt));
}
}
#endif
/**
* Called when the player wimpys out of a place. This does all the run
* away stuff anfd things like that.
* @return 1 if succeeded in running away, 0 if not
*/
int run_away()
{
int number;
become_flummoxed();
number =::run_away();
if (number)
tell_object(this_object(), "Your feet run away with you!\n");
else
tell_object(this_object(), "You try to run away, but no matter how "
"you scrabble, you can't find any way out.\n");
return number;
} /* run_away() */
/**
* The amount of time on line. This is the total amount of time online
* in seconds from when they first started playing. The return from
* this method is *negative*, you will need to make it positive to use it
* most likely.
* @return the total log on time in seconds (the return value is *negative*)
*/
nomask int query_time_on()
{
return time_on - time();
}
/**
* This method determins if the player is mature or not yet. It is based
* on the amount of time on.
* @return 1 if the player is mature, 0 if they are not
*/
int query_mature()
{
return (MATURITY * 60 * 60 + time_on < time());
}
/**
* Can the player see? Checks to see if the player can see at the passed
* in light level.
* @return 1 if they can see, 0 if they cannot
*/
int check_dark(int light)
{
int i;
if (race_ob)
if (catch(i = (int) race_ob->query_dark(light)))
race_ob = RACE_STD;
else
return i;
return (int) RACE_STD->query_dark(light);
} /* check_dark() */
/**
* Returns the players level. Uses their current guild to determine their
* guild level.
* @return their guild level
*/
int query_level()
{
string tmp;
if (_pinfo->level_time < (time() - LEVEL_CACHE)) {
if (guild_ob) {
_pinfo->level = (int) guild_ob->query_level(this_object());
} else {
/*
* If they do not have a guild object, see if they have a backup
* set. Otherwise use the warriors guild as the level setter.
*/
tmp = query_property("backup guild");
if (tmp) {
_pinfo->level = tmp->query_level(this_object());
} else
_pinfo->level = CONFIG_DEFAULT_GUILD->query_level(this_object());
}
_pinfo->level_time = time();
}
return _pinfo->level;
} /* query_level() */
/**
* Restarts their heartbeat if it has got turned off for some reason.
* @return always returns 1
*/
int restart_heart_beat()
{
set_heart_beat(1);
write("Ok, heart_beat restarted.\n");
return 1;
}
/**
* @ignore yes
*/
nomask void set_snoopee(object ob)
{
_pinfo->snoopee = ob;
}
/**
* Returns the object snooping us. If someone is snooping the player it
* returns the object doing the snooping. If no one is snooping the player
* it returns 0.
* @return the object snooping the player
* @see efun::snoop()
*/
nomask object query_snoopee()
{
return _pinfo->snoopee;
}
/**
* @ignore yes
*/
void set_creator(int i)
{
if (previous_object() != master()) {
write("Illegal attempt to set creator!\n");
log_file("ILLEGAL", this_player(1)->query_name() + " (" +
file_name(this_player(1)) +
") Illegal attempt to set_creator " + "at " + ctime(time()) +
" from " + file_name(previous_object()) + "\n");
return; /* THIS WAS MISSING !!! Turrican 4-11-95 */
}
creator = i;
set_home_dir("/w/" + query_name());
save_me();
} /* set_creator() */
/**
* Prevent the object from shadowing us? This checks to see if we should
* prevent this object from shadowing the player.
* @return 1 if we are prventing the shadow
*/
int query_prevent_shadow(object ob)
{
if (function_exists("query_prevent_shadow", ob) ||
function_exists("query_name", ob) ||
function_exists("query_creator", ob) ||
function_exists("query_lord", ob) ||
function_exists("query_hidden", ob) ||
function_exists("dest_me", ob) ||
function_exists("query_object_type", ob) ||
function_exists("query_lord", ob) || function_exists("save_me", ob))
/* added by sojan to fix security holes */
return 1;
return 0;
}
/**
* Returns the maxium number of deaths. This is the maxium number of times they
* can die before they are totaly dead.
* @return the maxiumm number fo deaths
*/
int query_max_deaths()
{
return max_deaths;
}
/**
* Sets the maximum number of deaths. This sets the maximum number of times a player can
* die.
* @param i the nukber of deaths to set it to
* @see adjust_max_deaths()
*/
protected void set_max_deaths(int i)
{
max_deaths = i;
}
/**
* Changes the current number of maxium deaths. This adjust
* the number of times a player can die before they are totaly dead.
* @return the current total maximum deaths
* @param i the amount of deaths to adjust by, must be +ve
*/
int adjust_max_deaths(int i)
{
if (i > 0) {
return (max_deaths += i);
}
}
/**
* @ignore yes
*/
varargs int move(mixed dest,
string msgin,
string msgout)
{
int i;
object env = environment();
i = living::move(dest, msgin, msgout);
if (!i) {
me_moveing(env);
}
return i;
} /* move() */
/**
* @ignore yes
*/
nomask protected int do_refresh(string str) {
if (query_property("guest")) {
return notify_fail("Guests cannot refresh, sorry.\n");
}
if (!str || str != "totally") {
return notify_fail("Please read the docs before using this command.\n");
}
write("%^BOLD%^WARNING! This will restart your character.%^RESET%^\n\n" +
"Are you sure you wish to refresh yourself totally? ");
input_to("refresh_docs");
return 1;
}
/**
* @ignore yes
*/
protected int refresh_docs(string str) {
string helpfile = "";
str = lower_case(str);
if (str[0] != 'y') {
write("Ok, not refreshing.\n");
return 1;
}
NROFF_HAND->create_nroff( "/doc/helpdir/refresh", helpfile );
helpfile = NROFF_HAND->cat_file( helpfile );
write ( helpfile[0..670] );
write("\n\n%^BOLD%^Having read the documentation, are you still sure you "
"wish to refresh totally?%^RESET%^\n");
input_to("refresh3");
return 1;
}
/**
* @ignore yes
*/
protected int refresh2(string str, int noevent) {
object ob;
string group;
str = lower_case(str);
if (str[0] != 'n' && str[0] != 'y') {
write
("Pardon? I do not understand. Do you want to refresh yourself? ");
input_to("refresh2");
return 1;
}
if (str[0] == 'n') {
write("Ok, not refreshing.\n");
return 1;
}
write("Doing refresh.\n");
Str = 13;
Con = 13;
Int = 13;
Wis = 13;
Dex = 13;
inttmp = dextmp = wistmp = strtmp = contmp = 0;
race_ob = CONFIG_DEFAULT_RACE;
if (guild_ob)
catch(guild_ob->delete_member(query_name()));
if (!noevent) {
REFRESH_HANDLER->player_refreshed(this_object(), PARTIAL_REFRESH);
}
guild_ob = 0;
set_al(0);
if (query_deity()) {
#ifndef __DISTRIBUTION_LIB__
catch(DEITY->delete_worshipper(query_deity(), query_name()));
catch(DEITY->delete_priest(query_deity(), query_name()));
#endif
}
set_deity(0);
set_skills(0);
/* Remove them as a playtester. */
PLAYTESTER_HAND->remove_playtester(query_name());
//
// If they have a family, remove them from that too.
//
if (query_family_name()) {
CLUB_HANDLER->remove_member(query_family_name(), query_name());
set_family_name(0);
}
reset_effects();
reset_spells();
reset_processes();
setup_default_titles();
guild_ob = 0;
set_guild_data(0);
xp = 0;
deaths = 0;
max_deaths = 7;
_refresh_time = time();
totaly_zap_bonus_cache();
known_commands = ({ "skills", "rearrange", "gp", "newbie" });
reset_starts();
race_guild_commands();
totaly_zap_stat_cache();
drink_info = allocate(D_SIZEOF);
map_prop = ([ "determinate" : "",
"player" : 1,
"skills version" :
(string) "/obj/handlers/change_skills"->query_version() ]);
this_object()->remove_ghost();
set_nationality(0);
set_nationality_region(0);
set_language("general");
set_default_language("general");
reset_all();
group = this_player()->query_group();
if (group) {
GROUP->remove_member(group, this_player(), " refreshed themselves.");
}
set_last_pos(CONFIG_NEWBIE_START_LOCATION);
START_PLAYER->give_junk(this_object());
// Remove people from the hunting list.
foreach (ob in query_attacker_list()) {
catch(ob->stop_fight(this_object()));
catch(stop_fight(ob));
}
call_out((: move_to_start_pos :), 0);
if (!noevent) {
write("Done refreshing.\n");
say(cap_name + " refreshes " + query_objective() + "self.\n");
save_me();
}
return 1;
} /* refresh2() */
/**
* @ignore yes
*/
protected int refresh3(string str)
{
object *items,
*ritems,
item;
str = lower_case(str);
if (str[0] != 'n' && str[0] != 'y') {
write("Pardon? I do not understand. Do you want to refresh " +
"yourself totally? ");
input_to("refresh3");
return 1;
}
if (str[0] == 'n') {
write("Ok, not refreshing.\n");
return 1;
}
write("Ok, refreshing totally.\n");
ritems = filter(all_inventory(environment()),
(: $1->query_property("dropped") &&
$1->query_property("dropped")[0] == query_name() :));
move(CONFIG_NEWBIE_START_LOCATION);
refresh2("y", 1);
set_player_killer(0);
_pinfo->titles = ([ ]);
REFRESH_HANDLER->player_refreshed(this_object(), TOTAL_REFRESH);
"/secure/related_files"->delete_related_files(query_name(),
0, TOTAL_REFRESH);
items = ritems + all_inventory();
foreach(item in items) {
item->dest_me();
}
foreach(item in children("/obj/corpse")) {
if (item->query_owner() == this_object()->query_name()) {
item->move("/room/rubbish");
}
}
// Remove from clubs and families.
foreach (string club in query_player_clubs()) {
catch(CLUB_HANDLER->remove_member(club, this_player()->query_name()));
}
if (query_family_name()) {
catch(CLUB_HANDLER->remove_member(query_family_name(),
this_player()->query_name()));
call_out("check_family_name", 2);
}
write("Done refreshing.\n");
say(cap_name + " refreshes " + query_objective() + "self.\n");
save_me();
return 1;
}
/**
* This method returns the one letter object type which is used in the
* finger command to display the type of object.
* @return the one letter object type
*/
string query_object_type(object player)
{
if ("/obj/handlers/playtesters"->query_playtester(query_name())) {
return "p";
}
return " ";
} /* query_object_type() */
/**
* @ignore yes
* Sets the cap name, part of a command..
*/
int do_cap(string str)
{
if (!str)
return notify_fail("Syntax: " + query_verb() + " <cap_name>\n");
if (lower_case(str) != query_name())
return
notify_fail
("You must have the same letters in your capitalized name.\n");
cap_name = str;
write("Capitalized name set to " + cap_name + ".\n");
return 1;
} /* do_cap() */
/** @ignore yes */
void set_my_ident(string str)
{
return;
}
/** @ignore yes */
string query_my_ident()
{
return 0;
}
/**
* @ignore yes
*/
void event_enter(object thing,
string mess,
object from)
{
events::event_enter(thing, mess, from);
living::event_enter(thing, mess, from);
} /* event_enter() */
/**
* @ignore yes
*/
void event_exit(object thing,
string mess,
object to)
{
events::event_exit(thing, mess, to);
living::event_exit(thing, mess, to);
} /* event_exit() */
/**
* @ignore yes
*/
string *parse_command_id_list()
{
if (query_player_killer()) {
return ({ "killer" }) +
living::parse_command_id_list() + family::parse_command_id_list();
} else {
return living::parse_command_id_list() + family::parse_command_id_list();
}
} /* parse_command_id_list() */
/**
* @ignore yes
*/
string *parse_command_plural_id_list()
{
if (query_player_killer()) {
return ({ "killers" }) + living::parse_command_plural_id_list() +
family::parse_command_plural_id_list();
} else {
return living::parse_command_plural_id_list() +
family::parse_command_plural_id_list();
}
} /* parse_command_plural_id_list() */
/**
* @ignore yes
*/
string *parse_command_adjectiv_id_list()
{
return living::parse_command_adjectiv_id_list() +
family::parse_command_adjectiv_id_list();
} /* parse_command_adjectiv_id_list() */
/**
* This method returns the time at which the player last logged on.
* @return the last logged on time
*/
int query_last_log_on()
{
return last_log_on;
}
/* This is the time since the last refresh... */
/**
* This method returns the time at which the player last refreshed.
* @return the last refresh time
*/
int query_refresh_time()
{
return _refresh_time;
}
/**
* This method returns the number of times the player has logged onto
* Discworld.
* @return the number of logins
*/
int query_no_logins()
{
return no_logins;
} /* query_no_logins() */
/**
* This method returns if the object is a creator or not.
* @return 1 if the object is a creator, 0 if not
*/
int query_creator()
{
return 0;
}
/**
* @ignore yes
*/
int _living(){return 1;}
/**
* Used to set the invisibility level upon login.
* @param level the invisiblity level
*/
protected void set_invis(int level) {
} /* set_invis() */
/**
* This method checks to see if the person is a player killer or not.
* @return 1 if they are a player killer, 0 if not
*/
int query_player_killer() {
return _flags & PLAYER_KILLER_FLAG;
} /* query_player_killer() */
/**
* This method sets the player killer flag on the player.
* @param flag 1 for pker, 0 for not
*/
void set_player_killer(int flag) {
if (flag) {
_flags |= PLAYER_KILLER_FLAG;
} else {
_flags &= ~PLAYER_KILLER_FLAG;
}
}
/**
* This method puts the person into or out of role playing mode.
* @param i 1 sets role playing mode, 0 unsets it.
*/
void set_role_playing(int i) {
if(i)
add_property(RPMODE, 1);
else
remove_property(RPMODE);
}
/**
* This method checks to see if the person is in role playing mode or not.
* @return 1 if they are in role playing mode, 0 if not.
*/
int query_role_playing() {
return query_property(RPMODE);
}