/
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/
#include "weapon.h"

/* ok.... now we start thinking about the strange things...
 *   We have several points we want to implement... 
 *   1)  A much wider range of damages.
 *   2)  A "To hit" and "damage" rolls being seperate things
 *          But are still related.  ie a good hit will do more damage
 *  Implementation...
 *    Ok, here goes.   The being hit players ac is taken based on the
 *    attack type, the ac will be returned as a base (not randomised)
 *    and a randomised amount...  This will be used to calculate the
 *    cute number we need.  Once we have the number we create the
 *    "To hit" role for the weapon.  Subtracting of this from our 
 *    ac number tells us weather or not we hit...  If we have hit
 *    We take the amount we hit by (after subtracting off the
 *    "To hit bonus") and add it too the extra damge that is done
 *    All this is kept in an array, there can be more than one
 *    attack in the array.  They can be connected together in
 *    several ways, 1) follow on after attack one did more that x
 *    points of damage.  2) have a percentage chance of working
 *    each attack.
 *    A standard set of attacks are defined in /std/handlers/armoury
 *    please see that file for more details
 */
static mixed attack_name, attack_data;
static string skill;

void    create()
{
    attack_name = ({ });
    attack_data = ({ });
}

mixed   query_attack_name()
{
    return attack_name;
}
mixed   query_attack_data()
{
    return attack_data;
}

void    set_weap_skill( string str )
{
    skill = str;
}
string  query_weap_skill()
{
    return skill;
}

int     add_attack( string name, mixed flag, int chance, mixed base, mixed hit,
		    mixed dam, string type )
{
    if( member_array( name, attack_name ) != -1 )
	return 0;
/* values for flag---
 *      0 - chance as follows
 *      "name" if it follows on after attack name
 *            chance at this point... 0-100 percetage
 *            200-... amount over hit to be done on
 */
    attack_name += ({ name });
    attack_data += ({ flag, chance, base, hit, dam, type });
}

int     add_arr_attack( string name, mixed *arr )
{
    int     i;

    if( !pointerp( arr ) || sizeof( arr ) != W_ARRAY_SIZE )
	return 0;
    if( (i = member_array( name, attack_name )) != -1 )
    {
	attack_data = attack_data[ 0..i * W_ARRAY_SIZE - 1 ] +
	    arr + attack_data[ (i + 1) * W_ARRAY_SIZE + 1..sizeof( attack_data ) ];
	return 1;
    }
    attack_name += ({ name });
    attack_data += arr;
    return 1;
}

void    remove_attack( string name )
{
    int     i;

    if( (i = member_array( name, attack_name )) == -1 )
	return;

    attack_name = delete( attack_name, i, 1 );
    attack_data = delete( attack_data, i * W_ARRAY_SIZE, W_ARRAY_SIZE );
}

int     calc_value( mixed arg, int skill, string name )
{
    int     i, amt;

    if( intp( arg ) )
	return( int ) this_object()->modify_damage( (random( arg ) * (100 + skill)) / 300,
						    name );

    if( !pointerp( arg ) )
	return 0;
    switch( sizeof( arg ) )
    {
	case 1:
	    return( int ) this_object()->modify_damage( arg[ F_FIXED ], name );

	case 2:
	    return( int ) this_object()->modify_damage( arg[ F_FIXED ] +
							        ((random( arg[ F_RAND ] ) * (100 + skill)) / 300), name );

	case 3:
	    for( i = 0; i < arg[ F_NUM ]; i++ )
		amt += random( arg[ F_DIE ] );
	    return( int ) this_object()->modify_damage( arg[ F_FIXED ] + ((amt *
									           (100 + skill)) / 300),
							name );

	default:
	    return 0;
    }
}

static object target, me;

void    do_attack( int name )
{
    int     i, off, hit, base, ac, skill_val;
    string  our_name;

    our_name = attack_name[ name ];
    off = name * W_ARRAY_SIZE;
    if( skill )
	skill_val = (int)me->query_skill_bonus( skill );
    else
	skill_val = 200;
    base = calc_value( attack_data[ off + W_BASE ], skill_val, our_name );
    hit = calc_value( attack_data[ off + W_HIT ], skill_val, our_name );
    ac = (int)target->query_ac( attack_data[ off + W_TYPE ] );
    hit += base - ac;
    if( hit < 0 )
    {
	this_object()->write_message( 0, target, me, attack_data[ off + W_TYPE ], our_name );
	this_object()->hit_weapon( ac, our_name );
	return;
    }
    base -= ac;
    if( base < 0 )
	base = 0;
    base += calc_value( attack_data[ off + W_DAM ], skill_val, our_name );
    this_object()->write_message( base, target, me, attack_data[ off + W_TYPE ], our_name );
    this_object()->hit_weapon( ac, our_name );
    if( base > target->query_hp() )
	base = target->query_hp() + 1;
/* Changed by NS, 24/01/94 */
    target->adjust_hp( -base, me );
    me->adjust_xp( base / 10 );
    if( !target )
	return;
    for( i = 0; i < sizeof( attack_data ); i += W_ARRAY_SIZE )
	if( attack_data[ i + W_FLAG ] == our_name )
	    if( random( 100 ) < attack_data[ i + W_CHANCE ] )
		if( attack_data[ i + W_CHANCE ] > 200 )
		{
		    if( hit > attack_data[ i + W_CHANCE ] - 200 )
			do_attack( i / W_ARRAY_SIZE );
		}
		else
		    do_attack( i / W_ARRAY_SIZE );
}

int     weapon_attack( object targ, object ob )
{
    int     i, off;

    target = targ;
    me = ob;
    for( i = 0; i < sizeof( attack_name ); i++ )
    {
	off = i * W_ARRAY_SIZE;
	if( !target )
	    continue;
	if( !attack_data[ off + W_FLAG ] )
	    if( random( 100 ) < attack_data[ off + W_CHANCE ] )
		do_attack( i );
    }
}

void    write_message( int dam, object attack_ob, object attack_by, string type,
		       string name )
{
    string *message;

    message = (string *)"/std/weapon.mess"->query_message( dam, type,
							   attack_ob, attack_by, name );
    if( message && sizeof( message ) >= 3 )
    {
	tell_object( attack_by, message[ 0 ] );
	tell_object( attack_ob, message[ 1 ] );
	tell_room( environment( attack_ob ), message[ 2 ], ({ attack_ob, attack_by }) );
	return;
    }
    if( dam < 30 )
    {
	tell_object( attack_by, "You missed " + attack_ob->short() + ".\n" );
	tell_object( attack_ob, capitalize( (string)attack_by->short() ) +
		     " missed you.\n" );
	tell_room( environment( attack_ob ), capitalize( (string)attack_by->short() ) +
		   " misses " + attack_ob->short() + ".\n", ({ attack_ob, attack_by }) );
    }
    else
    {
	tell_object( attack_by, "You hit " + attack_ob->short() + ".\n" );
	tell_object( attack_ob, capitalize( (string)attack_by->short() ) +
		     " hits you.\n" );
	tell_room( environment( attack_ob ), capitalize( (string)attack_by->short() ) +
		   " hits " + attack_ob->short() + ".\n", ({ attack_ob, attack_by }) );
    }
}

string  calc_string( mixed b )
{
    if( intp( b ) )
	return "rand(" + b + ")";
    if( !pointerp( b ) )
	return "Dead";
    switch( sizeof( b ) )
    {
	case 1:
	    return "" + b[ 0 ];
	case 2:
	    return "" + b[ 0 ] + "+rand(" + b[ 1 ] + ")";
	case 3:
	    return "" + b[ 0 ] + "+" + b[ 1 ] + "d" + b[ 2 ];
	default:
	    return "Oh hell";
    }
}

mixed   weapon_stats()
{
    int     i, j;
    mixed * ret;

    ret = ({ });
    for( i = 0; i < sizeof( attack_data ); i += W_ARRAY_SIZE, j++ )
	ret += ({ ({ "ATT" + j + " name", attack_name[ i / W_ARRAY_SIZE ], }),
		  ({ "     flag", attack_data[ i + W_FLAG ], }),
		  ({ "   chance", attack_data[ i + W_CHANCE ], }),
		  ({ "     base", calc_string( attack_data[ i + W_BASE ] ), }),
		  ({ "      hit", calc_string( attack_data[ i + W_HIT ] ), }),
		  ({ "      dam", calc_string( attack_data[ i + W_DAM ] ), }),
		  ({ "     type", attack_data[ i + W_TYPE ], }),
		   });
    return ret;
}

mixed   stats()
{
    return weapon_stats();
}				/* stats() */

void    set_attack_name( mixed *bing )
{
    attack_name = bing;
}
void    set_attack_data( mixed *bing )
{
    attack_data = bing;
}

mixed * query_init_data()
{
    return({ "attack name", attack_name, "set_attack_name/p",
	     "attack data", attack_data, "set_attack_data/p",
	     "attack skill", skill, "set_weap_skill/p" });
}				/* query_init_data() */