/
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/
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()
{
    spells = ({ });
    commands = ({ });
    ::create();
}				/* create() */

void    init()
{
    ::init();
    add_action( "do_advance", "ad*vance" );
    add_action( "do_join", "join" );
    add_action( "do_info", "inf*o" );
    add_action( "do_cost", "co*st" );
}				/* init() */

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(teaching_person->query_cap_name()+" says: You are not a member here!\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( teaching_person->query_cap_name()+" says: I am sorry but the skill " + sk + " does not exist.\n" );
	return 0;
    }
    lvl = (int)this_player()->query_skill( skill_name );
    if( !by && to )
	by = to - lvl;
    if( by <= 0 )
    {
	if( by == 0 )
	    notify_fail( teaching_person->query_cap_name()+" says: You are already at level " + lvl + " at " +
			 skill_name + ".\n" );
	else
	    notify_fail( teaching_person->query_cap_name()+" says: You cannot regress below your current skill level!\n" );
	return 0;
    }
    if( (sizeof( explode( skill_name, "." ) ) - 1) * 5 > lvl )
    {
	notify_fail( teaching_person->query_cap_name()+" says: You are not 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( teaching_person->query_cap_name()+" says: You cannot advance in that skill any further here.\n" );
	return 0;
    }
    if( !g_o )
	cost = DEFAULT_COST;	/* The guild trains cheaper.  Better thingys */
    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 = (int)this_player()->query_value();
    for( i = 0; i < by; i++ )
    {
	tmp = cost * (((lvl + i) / LEVEL_DIV) + 1);
	if( this_player()->query_xp() < tmp + total_xp )
	{
	    if( !i )
	    {
		notify_fail( teaching_person->query_cap_name()+" says: Your lack of experience prevents you improving " +
			     sk + ".\n" );
		return 0;
	    }
	    else
	    {
		write( teaching_person->query_cap_name()+" says: Your lack of experience prevents you taking all the " +
		       "advancement you requested.\n" );
	    }
	    break;
	}
	if( lvl + i >= max_lvl )
	{
	    write( teaching_person->query_cap_name()+" says: Your guild hasn't the resources to train you as far as " +
		   "you requested.\n" );
	    break;
	}
	if( ((tmp / COST_DIV) + total_cost) > p_val )
	{
	    if( !i )
	    {
		notify_fail( teaching_person->query_cap_name()+" says: Due to your sad lack of money the guild cannot train " +
			     "you in " + sk + ", it would have cost you " +
			     MONEY_HAND->money_value_string( tmp / COST_DIV ) + ".\n" );
		return 0;
	    }
	    else
	    {
		write( teaching_person->query_cap_name()+" says: Due to your sad lack of money the guild cannot train " +
		       "you 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;
}				/* do_advance() */

int     do_join( string str )
{
    if( (string)this_player()->query_guild_ob() == our_guild )
    {
	notify_fail( teaching_person->query_cap_name()+" says: You're already member here.\n" );
	return 0;
    }
    if( this_player()->query_guild_ob() )
    {
	notify_fail( teaching_person->query_cap_name()+" says: You cannot join here while you are member somewhere else.\n" );
	return 0;
    }
    write( teaching_person->query_cap_name()+" says: You will only ever get to join once.  Are you sure? " );
    input_to( "join2" );
    return 1;
}				/* do_join() */


int     join2( string str )
{
    mixed   skills;
    int     i;

    str = lower_case( str );
    if( str[ 0 ] != 'n' && str[ 0 ] != 'y' )
    {
	write( teaching_person->query_cap_name()+" says: I do not understand.  Yes or no? " );
	input_to( "join2" );
	return 1;
    }
    if( str[ 0 ] == 'n' )
    {
	write( teaching_person->query_cap_name()+" says: Ok, not joining the " + our_guild->query_name() + ".\n" );
	return 1;
    }
    this_player()->set_guild_ob( our_guild );
    this_player()->race_guild_commands();
    write( teaching_person->query_cap_name()+" says: You are now a member of the " + our_guild->query_name() + ".\n" );
    say( this_player()->query_cap_name() + " joins the " + our_guild->query_name() +
         ".\n");
    event( this_object(), "guild_join" );
    event( users(), "inform", this_player()->query_cap_name() + " is now a member " +
	   "of the " + our_guild->query_name(), "guild" );
    skills = (mixed *)this_player()->query_skills();
    for( i = 0; i < sizeof( skills ); i += SKILL_ARR_SIZE )
    {
/* Only do the top level */
	check_spells_commands( skills[ i + SKILL_NAM..i + SKILL_NAM ],
			       skills[ i + SKILL_LVL ] );
    }
    return 1;
}				/* join2() */

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

void    confirm_leave( string str )
{
    str = lower_case( str );
    if( str != "y" )
    {
	write( teaching_person->query_cap_name()+" says: You are still member here.\n" );
	return;
    }
    write( teaching_person->query_cap_name()+" says: Goodbye.\n" );
    call_other( our_guild, "leaving_guild" );
    this_player()->set_start_pos( "d/home/city/newbiepub" );
    this_player()->set_guild_ob( 0 );
    this_player()->set_guild_data( 0 );
    this_player()->guild_commands();
    this_player()->save_me();
}				/* confirm_leave() */

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 )
{				/* use lots of variables...so we only work things out minimum times */
    int     i, depth_gap, ndots;
    int     cost, lvl, max_lvl;
    string  str, lpath;

    str = "";
    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;
}				/* rec_cost() */

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( teaching_person->query_cap_name()+" says: You are not a member here.\n" );
	return 0;
    }
    arr = (mixed *)SKILL_OB->query_skills();
    if( !arr )
    {
	notify_fail( teaching_person->query_cap_name()+" says: Hmmm, we appear to have an error here.\n" );
	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( teaching_person->query_cap_name()+teaching_person->query_cap_name()+" says:  says: 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 )
	    {
		if( by == 0 )
		    notify_fail( teaching_person->query_cap_name()+" says: It won't cost you anything to stay at the same level!\n" );
		else
		    notify_fail( teaching_person->query_cap_name()+" says: We can't give refund xp for regressing skills!\n" );
		return 0;
	    }
	    if( (sizeof( explode( skill_name, "." ) ) - 1) * 5 > lvl )
	    {
		notify_fail( teaching_person->query_cap_name()+" says: 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( teaching_person->query_cap_name()+" says: I am sorry but I can not 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( teaching_person->query_cap_name()+" says: Sorry but I can not teach you all the advancement you " +
			   "requested.\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;
}				/* do_cost() */


int     do_info()
{
    mixed * arr;

    arr = (mixed *)SKILL_OB->query_skills();
    write( our_guild->long() + "\nSkill costs if you join here.\n" );
	    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 <" );

/**************
    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;
}				/* do_info() */
/*
 * From here on are the changes to make level gaining hopefully more
 * realistic...  (Note the more :)
 */
void    add_spell( string name, string *path, int lvl )
{
    spells += ({ name, path, lvl });
}				/* add_spell() */

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

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;

    if( !teaching_person || member_array( this_player(),
					  (object *)teaching_person->query_attacker_list() ) != -1 )
	return;

    for( i = 0; i < sizeof( spells ); i += 3 )
	for( j = 0; j < sizeof( spells[ i + 1 ] ); j++ )
	    if( j >= sizeof( path ) )
	    {			/* got through the skill path ok */
		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 ) )
	    {			/* got through the skill path ok */
		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;
}				/* check_spell_commands() */

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