/
LIB3/
LIB3/D/ADMIN/
LIB3/D/ADMIN/OBJ/
LIB3/D/ADMIN/ROOM/W/
LIB3/D/HOME/
LIB3/D/HOME/CITY/ARENA/
LIB3/D/HOME/CITY/ITEMS/
LIB3/D/HOME/CITY/POSTOFFI/
LIB3/DOC/
LIB3/GLOBAL/SPECIAL/
LIB3/GLOBAL/VIRTUAL/
LIB3/NET/
LIB3/NET/CONFIG/
LIB3/NET/DAEMON/CHARS/
LIB3/NET/GOPHER/
LIB3/NET/INHERIT/
LIB3/NET/OBJ/
LIB3/NET/SAVE/
LIB3/NET/VIRTUAL/
LIB3/OBJ/B_DAY/
LIB3/OBJ/HANDLERS/TERM_TYP/
LIB3/PLAYERS/B/
LIB3/PLAYERS/N/
LIB3/ROOM/
LIB3/SAVE/
LIB3/SAVE/BOARDS/
LIB3/SAVE/ENVIRON/
LIB3/SAVE/POST/
LIB3/STD/COMMANDS/SHADOWS/
LIB3/STD/CREATOR/
LIB3/STD/DOM/
LIB3/STD/EFFECTS/
LIB3/STD/EFFECTS/HEALING/
LIB3/STD/EFFECTS/OTHER/
LIB3/STD/EFFECTS/POISONS/
LIB3/STD/ENVIRON/
LIB3/STD/GUILDS/
LIB3/STD/LIQUIDS/
LIB3/STD/ROOM/
LIB3/STD/TRIGGER/SHADOW/
LIB3/W/
LIB3/W/BANNOR/
LIB3/W/NEWSTYLE/
/*
   ** Spells can now be 'taught'.
   ** Spells/Commands taught automatically by guildmaster
 */

inherit "/std/room";

#include "skills.h"
#include "tune.h"
#include "money.h"

string  our_guild;
mixed  *spells, *commands;
object  teaching_person;

void    check_spells_commands( string *sk, int lvl );

void    create()
{
    ::create();
    set_short( "A guild" );
    set_long( "This is a standard guild.\n" );
    spells = ({ });
    commands = ({ });
}

void    init()
{
    ::init();
    add_action( "do_advance", "adv*ance" );
    add_action( "do_join", "join" );
    add_action( "do_info", "inf*o" );
    add_action( "do_cost", "co*st" );
    add_action( "do_leave", "leave" );
}

void    set_guild( string str )
{
    our_guild = str;
}

int     do_advance( string str )
{
    string  skill_name, sk, g_o;
    string *bits;
    int     cost, i, lvl, tmp, to, by, max_lvl, total_xp, total_cost, p_val;

    if( (g_o = (string)this_player()->query_guild_ob()) != our_guild && g_o )
    {
	notify_fail( "You cannot advance here! Go to your own guild.\n" );
	return 0;
    }
    if( !teaching_person )
    {
	notify_fail( "The guildmaster is not here to teach you right now.\n" );
	return 0;
    }
    if( member_array( this_player(), ( object * )teaching_person->query_attacker_list() ) != -1 )
    {
	notify_fail( "The guildmaster can't teach you while he is fighting!\n" );
	return 0;
    }
    if( !str )
    {
	notify_fail( sprintf( "Syntax: %-*#s\n", this_player()->query_cols(),
			      "advance <skill>\nadvance <skill> to <level>\n" +
			      "advance <skill> by <level>\n" ) );
	return 0;
    }
    if( (sscanf( str, "%s to %d", sk, to ) != 2) &&
	    (sscanf( str, "%s by %d", sk, by ) != 2) )
    {
	sk = str;
	by = 1;
    }
    bits = explode( implode( explode( sk, " " ), "." ), "." );
    if( !(skill_name = (string)SKILL_OB->query_skill( bits )) )
    {
	notify_fail( "Unknown skill : " + sk + ".\n" );
	return 0;
    }
    lvl = this_player()->query_skill( skill_name );
    if( !by && to )
	by = to - lvl;
    if( by == 0 )
    {
	notify_fail( "You are already level " + lvl
		     + " in " + skill_name + ".\n" );
	return 0;
    }
    if( by < 0 )
    {
	notify_fail( "You cannot unlearn skill levels!\n" );
	return 0;
    }
    if( (sizeof( explode( skill_name, "." ) ) - 1) * 5 > lvl )
    {
	notify_fail( "Not a high enough level in the outer skills to advance " +
		     "that yet.\n" );
	return 0;
    }
    if( !g_o )
	max_lvl = 5;
    else
	max_lvl = (int)our_guild->query_skill_max_level( skill_name );
    if( lvl >= max_lvl )
    {
	notify_fail( "You cannot advance in that skill any further here.\n" );
	return 0;
    }
    if( !g_o )
	cost = DEFAULT_COST;
    else
	cost = (int)our_guild->query_skill_cost( skill_name );
    cost *= (int)SKILL_OB->query_skill_cost( skill_name );
    cost *= STD_COST / 5;
    p_val = this_player()->query_value();
    total_xp = cost * ((lvl / LEVEL_DIV) + 1);
    if( this_player()->query_xp() < total_xp )
    {
	notify_fail( "You don't have enough experience to advance " + sk + ".\n" );
	return 0;
    }
    if( (total_xp / COST_DIV) > p_val )
    {
	notify_fail( "You can't afford to advance in " + sk + ".\n"
		     + "It would have cost you " +
		     MONEY_HAND->money_value_string( total_xp / COST_DIV ) + ".\n" );
	return 0;
    }
    total_cost = tmp / COST_DIV;
    for( i = 1; i < by; i++ )
    {
	tmp = cost * (((lvl + i) / LEVEL_DIV) + 1);
	if( this_player()->query_xp() < tmp + total_xp )
	{
	    write( "Your lack of experience prevents you taking all the " +
		   "advancement you requested.\n" );
	    break;
	}
	if( lvl + i >= max_lvl )
	{
	    write( "You cannot advance that far here.\n" );
	    break;
	}
	if( ((tmp / COST_DIV) + total_cost) > p_val )
	{
	    write( "You cannot afford training in " + sk + " to " + (i + lvl) +
		   ". It would have cost you " +
		   MONEY_HAND->money_value_string( tmp / COST_DIV ) + ".\n" );
	    break;
	}
	total_xp += tmp;
	total_cost += tmp / COST_DIV;
    }
    this_player()->adjust_xp( -total_xp );
    this_player()->pay_money( MONEY_HAND->create_money_array( total_cost ) );
    this_player()->add_skill_level( skill_name, i );
    this_player()->reset_all();
    event( this_object(), "guild_advance", bits, lvl, lvl + i );
    check_spells_commands( bits, lvl + i );
    write( "You advance your skill in " + sk + " from " + lvl + " to " +
	   (lvl + i) + " for " + total_xp + " xp and " +
	   MONEY_HAND->money_value_string( total_cost ) + ".\n" );
    say( this_player()->query_cap_name() + " advances " +
	 this_player()->query_possessive() + " skills.\n" );
    return 1;
}

int     do_join( string str )
{
    if( (string)this_player()->query_guild_ob() == our_guild )
    {
	notify_fail( "You are already a member of this guild!\n" );
	return 0;
    }
    if( this_player()->query_guild_ob() )
    {
	notify_fail( "You already belong to a guild!\n" );
	return 0;
    }
    write( "You will only ever get to join one guild.  Are you sure? " );
    input_to( "confirm_join" );
    return 1;
}

void    confirm_join( string str )
{
    mixed   skills;
    int     i;

    str = lower_case( str );
    if( str[ 0 ] != 'n' && str[ 0 ] != 'y' )
    {
	write( "Answer yes or no." );
	input_to( "confirm_join" );
	return;
    }
    if( str[ 0 ] == 'n' )
    {
	write( "Come back if you change your mind!\n" );
	return;
    }
    this_player()->set_guild_ob( our_guild );
    this_player()->race_guild_commands();
    write( "You are now a member of the " + our_guild->query_name() + " guild.\n" );
    write( "You may 'leave' the guild any time before you advance any "
	   + "of your skills beyond level 5. After that, you will not "
	   + "be allowed to change your guild.\n" );
    say( this_player()->query_cap_name() + " joins the " + our_guild->query_name() +
	 " guild.\n" );
    event( this_object(), "guild_join" );
    event( users(), "inform", "%^GREEN%^" + this_player()->query_cap_name() +
	   " is now a member of the " + our_guild->query_name() +
	   " guild.%^RESET%^" );

    skills = (mixed *)this_player()->query_skills();

/* Top level only, as the applicant must be < level 5 */
    for( i = 0; i < sizeof( skills ); i += SKILL_ARR_SIZE )
    {
	check_spells_commands( skills[ i + SKILL_NAM..i + SKILL_NAM ],
			       skills[ i + SKILL_LVL ] );
    }
    return;
}

int     do_leave( string str )
{
    if( str != "guild" )
    {
	notify_fail( "Syntax : leave guild\n" );
	return 0;
    }
    if( (string)this_player()->query_guild_ob() != our_guild )
    {
	notify_fail( "How can you leave a guild if you aren't in it.\n" );
	return 0;
    }
    if( (int)this_player()->query_level() > 5 )
    {
	notify_fail( "You are too high a level to leave this guild.\n" );
	return 0;
    }
    write( "Are you sure you want to leave the guild (Y/N) : " );
    input_to( "confirm_leave" );
    return 1;
}

void    confirm_leave( string str )
{
    str = lower_case( str );
    if( str[ 0 ] != 'n' && str[ 0 ] != 'y' )
    {
	write( "Answer yes or no." );
	input_to( "join2" );
	return;
    }
    if( str[ 0 ] != "y" )
    {
	write( "Okay, guild not left.\n" );
	return;
    }
    write( "You are no longer a member of the "
	   + our_guild->query_name() + " guild.\n" );
    say( this_player()->query_cap_name() + " leaves the "
	 + our_guild->query_name() + " guild.\n" );
    event( this_object(), "guild_join" );
    event( users(), "inform", "%^GREEN%^" + this_player()->query_cap_name() +
	   " has left the " + our_guild->query_name() +
	   " guild.%^RESET%^" );

    this_player()->set_start_pos( "d/am/am/mendeddrum" );
    this_player()->set_guild_ob( 0 );
    this_player()->set_guild_data( 0 );
    this_player()->guild_commands();
    this_player()->save_me();
}

string  rec_cost_old( mixed *arr, string path, int depth )
{
    int     i;
    int     cost;
    string  str, lpath;

    str = "";
    for( i = 0; i < sizeof( arr ); i += SKILL_ARR_SIZE )
    {
	lpath = path + "." + arr[ i ];
	cost = (int)SKILL_OB->query_skill_cost( (lpath)[ 1..500 ] );
	cost *= (int)our_guild->query_skill_cost( (lpath)[ 1..500 ] );
	str += sprintf( "%*'| 's%-*'.'s costs %d xp.\n", ( depth - 1 ) * 2, "",
			20 - (depth - 1) * 2, arr[ i ],
			cost * STD_COST * (((int)this_player()->query_skill( lpath )
					    / LEVEL_DIV) + 1) );
	if( this_player()->query_skill( lpath ) >= depth * 5 )
	    str += rec_cost_old( arr[ i + SKILL_BIT ], path + "." + arr[ i ], depth + 1 );
    }
    return str;
}				/* rec_cost_old() */

string  rec_cost( mixed *arr, string path, int depth, string g_o )
{
    int     i, depth_gap, ndots;
    int     cost, lvl, max_lvl;
    string  str, lpath;

    depth_gap = (depth - 1) * 2;
    ndots = 18 - depth_gap;

    for( i = 0; i < sizeof( arr ); i += SKILL_ARR_SIZE )
    {
	if( path != "" )
	    lpath = path + "." + arr[ i ];
	else
	    lpath = arr[ i ];
	lvl = (int)this_player()->query_skill( lpath );
	if( !g_o )
	    max_lvl = 5;
	else
	    max_lvl = (int)g_o->query_skill_max_level( lpath );
	if( lvl >= max_lvl )
	    str = sprintf( "%*'| 's%-*'.'s %3d/%3d  mastered\n", depth_gap, "",
			   ndots, arr[ i ], lvl, max_lvl );
	else
	{
	    if( !g_o )
		cost = DEFAULT_COST;
	    else
		cost = (int)g_o->query_skill_cost( lpath );
	    cost *= (int)SKILL_OB->query_skill_cost( lpath );
	    cost *= (STD_COST / 5) * ((lvl / LEVEL_DIV) + 1);
	    str = sprintf( "%*'| 's%-*'.'s %3d/%3d %6d xp\n", depth_gap, "",
			   ndots, arr[ i ], lvl, max_lvl, cost );
	}
	if( lvl >= depth * 5 )
	    str += rec_cost( arr[ i + SKILL_BIT ], lpath, depth + 1, g_o );
    }
    return str;
}

int     do_cost( string str )
{
    string *bits;
    mixed * arr;
    int     i, cost, lvl, max_lvl, tmp, by, to;
    string  skill_name, sk, g_o;

    if( !str )
    {
	notify_fail( sprintf( "Syntax: %-*#s\n", this_player()->query_cols(),
			      "cost all\ncost <skill>\ncost <skill> to <level>\n" +
			      "cost <skill> by <level>\n" ) );
	return 0;
    }
    if( (g_o = (string)this_player()->query_guild_ob()) != our_guild && g_o )
    {
	notify_fail( "You are not a member of this guild.\n" );
	return 0;
    }
    arr = (mixed *)SKILL_OB->query_skills();
/*
   if (!arr)
   {
   notify_fail("Error. Please report to a Lord immediately");
   return 0;
   }
 */
    if( str == "old" )
    {
	printf( "%#*-s\n", this_player()->query_cols(), rec_cost_old( arr, "", 1 ) );
    }
    else
	if( str == "all" )
	{
	    printf( "%-*'='s\n", this_player()->query_cols(),
		    "======SKILLS=======Cur/Max==For Next" );
	    printf( "%#*-s\n", this_player()->query_cols(), rec_cost( arr, "", 1, g_o ) );
	    printf( "%*'='|s\n", this_player()->query_cols(), "> You have " +
		    this_player()->query_xp() + " points to spend <" );
	}
	else
	{
	    if( (sscanf( str, "%s to %d", sk, to ) != 2) &&
		    (sscanf( str, "%s by %d", sk, by ) != 2) )
	    {
		sk = str;
		by = 1;
	    }
	    bits = explode( sk, "." );
	    if( !(skill_name = (string)SKILL_OB->query_skill( bits )) )
	    {
		notify_fail( "There is no such skill as " + sk + ".\n" );
		return 0;
	    }
	    lvl = (int)this_player()->query_skill( skill_name );
	    if( !by && to )
		by = to - lvl;
	    if( by <= 0 )
	    {
		notify_fail( "We can't give refund xp for regressing skills!\n" );
		return 0;
	    }
	    if( by == 0 )
	    {
		notify_fail( "It won't cost you anything to stay at the same level!\n" );
		return 0;
	    }
	    if( (sizeof( explode( skill_name, "." ) ) - 1) * 5 > lvl )
	    {
		notify_fail( "Not a high enough level in the outer skills to advance " +
			     "that yet.\n" );
		return 0;
	    }
	    if( !g_o )
		max_lvl = 5;
	    else
		max_lvl = (int)our_guild->query_skill_max_level( skill_name );
	    if( lvl >= max_lvl )
	    {
		notify_fail( "Your guild cannot teach you " + sk +
			     " above level " + max_lvl + ".\n" );
		return 0;
	    }
	    if( !g_o )
		cost = DEFAULT_COST;
	    else
		cost = (int)our_guild->query_skill_cost( skill_name );
	    cost *= (int)SKILL_OB->query_skill_cost( skill_name );
	    cost *= STD_COST / 5;
	    for( i = 0; i < by; i++ )
	    {
		if( lvl + i >= max_lvl )
		{
		    write( "Your guild cannot teach you " + sk + " to that level.\n" );
		    break;
		}
		tmp += cost * (((lvl + i) / LEVEL_DIV) + 1);
	    }
	    printf( "It would cost you %d xp to raise %s from level %d to %d.\n",
		    tmp, skill_name, lvl, ( lvl + i ) );
	}
    return 1;
}

int     do_info()
{
    mixed * arr;

    write( our_guild->long() + "\nSkill costs if you join this guild.\n" );

    arr = (mixed *)this_player()->query_skills();
    printf( "%-*'='s\n", this_player()->query_cols(),
	    "======SKILLS=======Cur/Max==For Next" );
    printf( "%#*-s\n", this_player()->query_cols(), rec_cost( arr, "", 1,
							      our_guild ) );
    printf( "%*'='|s\n", this_player()->query_cols(), "> You have " +
	    this_player()->query_xp() + " points to spend <" );
    return 1;
}

void    add_spell( string name, string *path, int lvl )
{
    spells += ({ name, path, lvl });
}

void    add_command( string name, string *path, int lvl )
{
    commands += ({ name, path, lvl });
}

query_spells()
{
    return spells + ({ });
}
query_commands()
{
    return commands + ({ });
}

void    set_teaching_person( object ob )
{
    teaching_person = ob;
}
object  query_teaching_person()
{
    return teaching_person;
}

void    check_spells_commands( string *path, int lvl )
{
    int     i, j;

    for( i = 0; i < sizeof( spells ); i += 3 )
	for( j = 0; j < sizeof( spells[ i + 1 ] ); j++ )
	    if( j >= sizeof( path ) )
	    {
		if( spells[ i + 2 ] <= lvl )
		    teaching_person->init_command( "teach " + spells[ i ] + " to " +
						   this_player()->query_name() );
	    }
	    else
		if( spells[ i + 1 ][ j ] != path[ j ] )
		    break;

    for( i = 0; i < sizeof( commands ); i += 3 )
	for( j = 0; j < sizeof( commands[ i + 1 ] ); j++ )
	    if( j >= sizeof( path ) )
	    {
		if( commands[ i + 2 ] <= lvl )
		    teaching_person->init_command( "teach " + commands[ i ] + " to " +
						   this_player()->query_name() );
	    }
	    else
		if( commands[ i + 1 ][ j ] != path[ j ] )
		    break;
}