dsIIr4/bin/
dsIIr4/extra/creremote/
dsIIr4/extra/wolfpaw/
dsIIr4/lib/cmds/admins/
dsIIr4/lib/cmds/common/
dsIIr4/lib/cmds/creators/include/
dsIIr4/lib/cmds/creators/include/SCCS/
dsIIr4/lib/daemon/services/
dsIIr4/lib/doc/
dsIIr4/lib/domains/Ylsrim/
dsIIr4/lib/domains/Ylsrim/adm/
dsIIr4/lib/domains/Ylsrim/armor/
dsIIr4/lib/domains/Ylsrim/broken/
dsIIr4/lib/domains/Ylsrim/fish/
dsIIr4/lib/domains/Ylsrim/meal/
dsIIr4/lib/domains/Ylsrim/npc/
dsIIr4/lib/domains/Ylsrim/virtual/
dsIIr4/lib/domains/Ylsrim/weapon/
dsIIr4/lib/domains/campus/adm/
dsIIr4/lib/domains/campus/etc/
dsIIr4/lib/domains/campus/meals/
dsIIr4/lib/domains/campus/npc/
dsIIr4/lib/domains/campus/save/
dsIIr4/lib/domains/campus/txt/
dsIIr4/lib/domains/campus/txt/ai/charles/
dsIIr4/lib/domains/campus/txt/ai/charles/bak2/
dsIIr4/lib/domains/campus/txt/ai/charles/bak2/bak1/
dsIIr4/lib/domains/campus/txt/ai/charly/
dsIIr4/lib/domains/campus/txt/ai/charly/bak/
dsIIr4/lib/domains/campus/txt/jenny/
dsIIr4/lib/domains/default/creator/
dsIIr4/lib/domains/default/doors/
dsIIr4/lib/domains/default/etc/
dsIIr4/lib/domains/default/virtual/
dsIIr4/lib/domains/default/weap/
dsIIr4/lib/domains/town/virtual/
dsIIr4/lib/lib/comp/
dsIIr4/lib/lib/lvs/
dsIIr4/lib/lib/user/
dsIIr4/lib/lib/virtual/
dsIIr4/lib/log/
dsIIr4/lib/obj/book_source/
dsIIr4/lib/obj/include/
dsIIr4/lib/realms/template/
dsIIr4/lib/realms/template/adm/
dsIIr4/lib/realms/template/area/armor/
dsIIr4/lib/realms/template/area/npc/
dsIIr4/lib/realms/template/area/obj/
dsIIr4/lib/realms/template/area/room/
dsIIr4/lib/realms/template/area/weap/
dsIIr4/lib/realms/template/bak/
dsIIr4/lib/realms/template/cmds/
dsIIr4/lib/save/
dsIIr4/lib/save/kills/o/
dsIIr4/lib/secure/cfg/classes/
dsIIr4/lib/secure/cmds/creators/include/
dsIIr4/lib/secure/cmds/players/
dsIIr4/lib/secure/cmds/players/include/
dsIIr4/lib/secure/daemon/include/
dsIIr4/lib/secure/lib/
dsIIr4/lib/secure/lib/include/
dsIIr4/lib/secure/lib/net/include/
dsIIr4/lib/secure/lib/std/
dsIIr4/lib/secure/modules/
dsIIr4/lib/secure/npc/
dsIIr4/lib/secure/obj/include/
dsIIr4/lib/secure/room/
dsIIr4/lib/secure/save/
dsIIr4/lib/secure/save/boards/
dsIIr4/lib/secure/save/players/g/
dsIIr4/lib/secure/tmp/
dsIIr4/lib/secure/verbs/creators/
dsIIr4/lib/shadows/
dsIIr4/lib/spells/
dsIIr4/lib/std/board/
dsIIr4/lib/std/lib/
dsIIr4/lib/tmp/
dsIIr4/lib/verbs/admins/include/
dsIIr4/lib/verbs/common/
dsIIr4/lib/verbs/common/include/
dsIIr4/lib/verbs/creators/include/
dsIIr4/lib/verbs/players/include/SCCS/
dsIIr4/lib/verbs/rooms/
dsIIr4/lib/verbs/rooms/include/
dsIIr4/lib/www/
dsIIr4/v22.2b14-dsouls2/
dsIIr4/v22.2b14-dsouls2/ChangeLog.old/
dsIIr4/v22.2b14-dsouls2/Win32/
dsIIr4/v22.2b14-dsouls2/compat/
dsIIr4/v22.2b14-dsouls2/compat/simuls/
dsIIr4/v22.2b14-dsouls2/include/
dsIIr4/v22.2b14-dsouls2/mudlib/
dsIIr4/v22.2b14-dsouls2/testsuite/
dsIIr4/v22.2b14-dsouls2/testsuite/clone/
dsIIr4/v22.2b14-dsouls2/testsuite/command/
dsIIr4/v22.2b14-dsouls2/testsuite/data/
dsIIr4/v22.2b14-dsouls2/testsuite/etc/
dsIIr4/v22.2b14-dsouls2/testsuite/include/
dsIIr4/v22.2b14-dsouls2/testsuite/inherit/
dsIIr4/v22.2b14-dsouls2/testsuite/inherit/master/
dsIIr4/v22.2b14-dsouls2/testsuite/log/
dsIIr4/v22.2b14-dsouls2/testsuite/single/
dsIIr4/v22.2b14-dsouls2/testsuite/single/tests/compiler/
dsIIr4/v22.2b14-dsouls2/testsuite/single/tests/efuns/
dsIIr4/v22.2b14-dsouls2/testsuite/single/tests/operators/
dsIIr4/v22.2b14-dsouls2/testsuite/u/
dsIIr4/v22.2b14-dsouls2/tmp/
dsIIr4/win32/
/*    /secure/daemon/character.c
 *    from the Dead Souls V Object Library
 *    the multi-character management daemon
 *    created by Descartes of Borg 951216
 */

#include <lib.h>
#include <save.h>
#include <privs.h>
#include <link.h>
#include <config.h>
#include "include/character.h"

inherit LIB_DAEMON;

private mapping Links;

static void create() {
    daemon::create();
    SetNoClean(1);
    Links = ([]);
    if( unguarded( (: file_size(SAVE_CHARACTER __SAVE_EXTENSION__) :)) > 0 )
	unguarded((: restore_object, SAVE_CHARACTER :));
}

mixed eventConnect(string who) {
    class char_link c;
    string prime;
    int min_wait;

    if( base_name(previous_object()) != LIB_CONNECT ) return 0;
    if( !(c = Links[prime = who]) ) {
	foreach(string pl, class char_link cl in Links) {
	    if( member_array(who, cl->Secondaries) != -1 ) {
		prime = pl;
		c = cl;
		break;
	    }
	}
	if( !c ) return 1;
    }
    foreach(string ind in c->Secondaries + ({ prime })) {
	if( find_player(ind) )  {
	    if( who == ind ) return 1;
	    if(member_group(who, PRIV_SECURE) || member_group(who,PRIV_ASSIST))
		return 1;
	    else if( archp(find_player(ind)) ) return 1;
	    else return "You have a linked character currently logged in.\n";
	}
    }
    if( LINK_WAIT_PERIOD > uptime() ) min_wait = uptime();
    else min_wait = LINK_WAIT_PERIOD;
    if( c->LastOnDate > time() - min_wait ) {
	string tmp;
	int x;

	if( c->LastOnWith == who ) return 1;
	x = c->LastOnDate + min_wait - time();
	if( x < 60 ) tmp = consolidate(x, "a second");
	else tmp = consolidate(x/60, "a minute");
	if( !(member_group(who, PRIV_SECURE) || member_group(who,PRIV_ASSIST)))
	    return "\nYour character " + capitalize(c->LastOnWith) +
	    " recently logged in at " + ctime(c->LastOnDate) + ".\n" +
	    "You must wait another " + tmp + ".\n";
    }
    c->LastOnDate = time();
    c->LastOnWith = who;
    save_object(SAVE_CHARACTER);
    return 1;
}

mixed eventLink(string primary, string secondary, string email) {
    class char_link ch;

    if( !((int)master()->valid_apply(({ PRIV_LAW }))) )
	return "Permission denied.";
    if( !user_exists(primary = convert_name(primary)) )
	return "No such user: primary";
    if( !email ) return "Email is required for linking.";
    secondary = convert_name(secondary);
    if( Links[primary] ) {
	ch = Links[primary];
	if( Links[secondary] ) {
	    class char_link c2;

	    c2 = Links[secondary];
	    ch->Secondaries += ({ secondary });
	    ch->Secondaries += c2->Secondaries;
	    ch->Secondaries = distinct_array(ch->Secondaries);
	    ch->Email = email;
	    if( ch->LastOnDate < c2->LastOnDate ) {
		ch->LastOnDate = c2->LastOnDate;
		ch->LastOnWith = c2->LastOnWith;
	    }
	    Links[primary] = ch;
	    map_delete(Links, secondary);
	    if( !save_object(SAVE_CHARACTER) ) return "Error in saving.";
	    return 1;
	}
    }
    else if( Links[secondary] ) {
	ch = Links[secondary];
	map_delete(Links, secondary);
    }
    else ch = new(class char_link);
    if( ch->Secondaries ) ch->Secondaries += ({ secondary });
    else ch->Secondaries = ({ secondary });
    ch->Email = email;
    ch->LastOnDate = 0;
    ch->LastOnWith = primary;
    Links[primary] = ch;
    if( !save_object(SAVE_CHARACTER) ) return "Error in saving.";
    return 1;
}

mixed eventSaveTime() {
    class char_link c;
    object ob;
    string who;

    if( !userp(ob = previous_object()) ) return 0;
    who = (string)ob->GetKeyName();
    if( !(c = Links[who]) ) {
	foreach(string pl, class char_link cl in Links) {
	    if( member_array(who, cl->Secondaries) != -1 ) {
		c = cl;
		break;
	    }
	}
	if( !c ) return 1;
    }
    c->LastOnDate = time();
    c->LastOnWith = who;
    unguarded((: save_object, SAVE_CHARACTER :));
    return 1;
}

mixed eventUnlink(string primary, string who) {
    class char_link ch;

    if( !((int)master()->valid_apply(({ PRIV_ASSIST }))) )
	return "Permission denied.";
    primary = convert_name(primary);
    who = convert_name(who);
    if( !(ch = Links[primary]) ) return "No such primary character.";
    if( who == primary ) {
	if( sizeof(ch->Secondaries) < 2) {
	    map_delete(Links, primary);
	    save_object(SAVE_CHARACTER);
	    return 1;
	}
	primary = ch->Secondaries[0];
	ch->Secondaries = ch->Secondaries[1..];
	map_delete(Links, who);
	Links[primary] = ch;
	save_object(SAVE_CHARACTER);
	return 1;
    }
    if( member_array(who, ch->Secondaries) == -1 )
	return "Invalid secondary character for " + primary + ".";
    ch->Secondaries -= ({ who });
    Links[primary] = ch;
    save_object(SAVE_CHARACTER);
    return 1;
}

mapping GetLinks() {
    if( !((int)master()->valid_apply(({ PRIV_ASSIST }))) ) return ([]);
    else return Links;
}

mapping GetLink(string who) {
    class char_link ch;

    who = convert_name(who);
    if( Links[who] ) ch = Links[who];
    else {
	class char_link l;
	string pl;

	foreach(pl, l in Links) {
	    if( member_array(who, l->Secondaries) != -1 ) {
		ch = l;
		who = pl;
		break;
	    }
	}
	if( !ch ) return 0;
    }
    return ([ "primary" : who, "last char" : ch->LastOnWith,
      "secondaries" : ch->Secondaries, "last on" : ch->LastOnDate ]);
}