/* -*- LPC -*- */
/*
* $Locker: $
* $Id: th_row.c,v 1.12 2003/01/30 06:21:28 pinkfish Exp $
* $Log: th_row.c,v $
* Revision 1.12 2003/01/30 06:21:28 pinkfish
* Make it cost gp.
*
* Revision 1.11 2000/09/30 17:26:57 taffyd
* Added item to thrown_at().
*
* Revision 1.10 2000/07/02 10:15:41 taffyd
* Added event notification when thrown successfully. :)
*
* Revision 1.9 1999/10/23 11:00:57 taffyd
* Recode to fix bugs that seem to have seeped in.
*
* Revision 1.8 1999/07/24 12:13:26 terano
* Added the ability to throw at inanimate objects!
*
* Revision 1.7 1999/04/05 23:01:34 ceres
* Modified to use perform_task
*
* Revision 1.6 1998/09/15 00:32:34 pinkfish
* Really fix up the pk_check().
*
* Revision 1.5 1998/08/25 10:52:13 pinkfish
* Make the messages use the_shrot();
*
* Revision 1.4 1998/06/23 03:41:26 sin
* Terano fixed the pk_check
*
* Revision 1.3 1998/03/28 06:28:47 ceres
* Added a repeat check since some people have been abusing this command.
*
* Revision 1.2 1998/02/08 22:15:57 ceres
* moved to new skill tree
*
* Revision 1.1 1998/01/06 05:28:43 ceres
* Initial revision
*
*/
//You can now throw items at inanimate objects that have the
//targetable property, the bonus for that object is counted
//as the value that this property is set to!
//IE: add_property( "targetable", 300 );
//When a player attempts to throw something, it calls thrown_at( object player,
//int switch ) on the target, with 1 being a hit, and 0 being a miss.
#define CREATOR "Ceres"
#include <player.h>
#include <move_failures.h>
#include <tasks.h>
#define ASKILL "fighting.combat.range.thrown"
#define DSKILL "fighting.combat.dodging.range"
#define PSKILL "fighting.combat.parry.range"
#define COMMAND_GP_COST 5
inherit "/cmds/base";
int valid_target( object target, object thrower, object item );
int cmd( mixed *indirect_obs ) {
object target, item;
int dchance, damage;
if ( sizeof( indirect_obs[ 0 ] ) > 1 ) {
add_failed_mess( "You can only throw one item at a time!\n" );
return 0;
}
item = indirect_obs[ 0 ][ 0 ];
if ( sizeof( indirect_obs[ 1 ] ) > 1 ) {
add_failed_mess( "You can only throw $I at one target at a time!\n",
({ item }) );
return 0;
}
target = indirect_obs[ 1 ][ 0 ];
if ( item->query_wielded() != this_player() ) {
add_failed_mess( "You must be holding $I to throw it.\n",
({ item }) );
return 0;
}
if ( this_player() == target ) {
add_failed_mess( "You cannot throw $I at yourself!\n", ({ item }) );
return 0;
}
if ( !living( target ) && !target->query_property( "targetable" ) ) {
add_failed_mess( "Why do you want to throw $I at " +
target->the_short() + "?\n", ({ item }) );
return 0;
}
if (this_player()->query_gp() < COMMAND_GP_COST) {
add_failed_mess( "You need " + COMMAND_GP_COST + " points to "
"throw " + item->the_short() + " at " + target->the_short() +
".\n");
return 0;
}
if ( !valid_target( target, this_player(), item ) ) {
add_failed_mess( "You decide against throwing $I at " +
target->the_short() + ".\n", ({ item }) );
return 0;
}
if ( living( target ) ) {
switch ( (string)target->query_combat_response() ) {
case "dodge" :
dchance = target->query_skill_bonus( DSKILL );
break;
default:
dchance = target->query_skill_bonus( PSKILL );
}
}
else {
dchance = target->query_property( "targetable" );
}
dchance += item->query_weight() / ( this_player()->query_str() / 2 );
if( !this_player()->query_visible( target ) ) {
dchance /= 2;
}
this_player()->adjust_gp(-COMMAND_GP_COST);
// lets see if they hit or not.
switch( TASKER->perform_task(this_player(), ASKILL, dchance, TM_FREE) ) {
case AWARD:
tell_object(this_player(), "%^YELLOW%^You feel that your "
"skill in throwing weapons has increased.%^RESET%^\n");
case SUCCEED:
tell_object( this_player(), "You throw " + item->the_short() +
" at " + target->the_short() + " and hit!\n" );
tell_room( environment( this_player() ),
this_player()->the_short() + " throws " + item->a_short() +
" at " + target->the_short() + " and hits!\n",
this_player() );
if ( living( target ) ) {
damage = ( item->query_weight() / 4 ) +
( this_player()->query_str() * 2) +
( this_player()->query_skill_bonus( ASKILL ) / 3 );
damage -= target->query_ac( "blunt", damage );
target->attack_by( this_player() );
target->adjust_hp( -damage, this_player() );
this_player()->attack_ob( target );
event( item, "thrown", this_player(), target );
this_player()->adjust_time_left(-(ROUND_TIME*2));
}
target->thrown_at( this_player(), 1, item );
if ( item->move( target ) != MOVE_OK ) {
item->move( environment( target ) );
}
break;
default:
tell_object( this_player(), "You throw " + item->the_short() +
" at " + target->the_short() + " but miss.\n" );
tell_room( environment( this_player() ),
this_player()->the_short() + " throws " + item->a_short() +
" at " + target->the_short() + " but misses.\n", this_player() );
item->move( environment( target ) );
if( !interactive( target ) && living( target ) ) {
this_player()->attack_ob( target );
target->attack_by( this_player() );
}
target->thrown_at( this_player(), 0 ); //They missed, but lets note that anyway
break;
}
return 1;
} /* cmd() */
int valid_target( object target, object thrower, object item ) {
mixed owner;
if ( target->query_property( "dead" ) || target->query_auto_loading() ) {
return 0;
}
if ( userp( target ) && !interactive( target ) ) {
return 0;
}
if ( pk_check( thrower, target ) )
return 0;
if ( ( owner = target->query_owner() ) && pk_check( thrower, owner ) ) {
return 0;
}
return 1;
} /* valid_target() */
mixed *query_patterns() {
return ({ "<indirect:object:me'weapon'> at <indirect:object'target'>",
(: cmd($1) :) });
} /* query_patterns() */