/* -*- LPC -*- */
/*
* $Id: weapon.c,v 1.24 2003/03/12 22:15:58 ceres Exp $
*/
inherit "/std/object";
inherit "/std/weapon_logic";
inherit "/std/basic/condition";
inherit "/std/basic/holdable";
#include "weapon.h"
#include "money.h"
#include <move_failures.h>
#include <virtual.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/weapon_handler
* please see that file for more details
*
* Modified 18/5/93 by Piecemaker to remove octarine descriptions for non
* wizards.
*/
string *un_modifyable;
mixed *wield_func;
void create() {
set_damage_chance( 25 );
un_modifyable = ({ });
weapon_logic::create();
holdable::create();
condition::create();
object::create();
add_alias("weapon");
add_plural("weapons");
if (!query_property("shop type")) {
add_property("shop type", "armoury");
}
add_help_file("weapon");
} /* create() */
/** @ignore yes */
string short(int dark) {
string str;
str = "";
return ::short(dark)+str;
} /* short() */
/**
* This method sets the wield function of the object. This will be
* called when the object is wielded and unwielded.
* @param func the function to call
* @param ob the object to call the method on
*/
void set_wield_func(string func, mixed ob) {
if (!func) {
wield_func = 0;
} else {
wield_func = ({ func, ob });
}
} /* set_wield_func() */
/**
* This method return true if it is a weapon.
* @return always returns 1
*/
int query_weapon() { return 1; }
/** @ignore yes */
string long(string s, int dark) {
return ::long(s, dark)+cond_string();
} /* long() */
/**
* This method setups the weapon with the new condition. It sets the
* maximum and lowest conditions to the specified condition.
* @param new_condition the condition value of the weapon
*/
void new_weapon( int new_condition ) {
set_cond( new_condition );
set_max_cond( new_condition );
set_lowest_cond( new_condition );
} /* new_weapon() */
/** @ignore yes */
int held_this_item(int held, object holder, mixed arg) {
int weight;
object weapon;
// Let them know if they aren't dexterous or strong enough to hold
// this weapon effectively.
if(held == 1 && interactive(holder)) {
weight = this_object()->query_weight();
foreach(weapon in holder->query_weapons())
weight += weapon->query_weight();
weight -= holder->query_str();
switch(weight) {
case 76..10000:
tell_object(holder, "You struggle to hold " +
query_multiple_short(holder->query_holding() +
({ this_object() }) - ({ 0 })) +
".\n");
break;
case 50..75:
tell_object(holder, "You struggle slightly to hold " +
query_multiple_short(holder->query_holding() +
({ this_object() }) - ({ 0 })) +
".\n");
break;
default:
}
}
if (wield_func) {
if (!held) {
/* Unwield first.... */
return call_other(wield_func[1], wield_func[0], 0);
} else if (held == 1) {
return call_other(wield_func[1], wield_func[0], holder);
}
}
return 1;
}
/** @ignore yes */
varargs int move( mixed dest, string messin, string messout ) {
int ret;
int limb;
object holder;
//
// Make sure we revert back to how we were before the move. If the
// move fails we should not be changing our state.
//
limb = query_my_limb();
holder = query_holder();
ret = holdable::move(dest);
if (ret != MOVE_OK) {
return ret;
}
ret = object::move( dest, messin, messout );
if (ret != MOVE_OK && holder) {
holder->set_hold(this_object(), limb);
}
return ret;
} /* move() */
void dest_me() {
holdable::dest_me();
object::dest_me();
} /* dest_me() */
int modify_damage(int val, string name) {
int tmp;
tmp = val + (val * query_enchant()) /
(query_max_enchant() + query_enchant());
if(member_array(name, un_modifyable) != -1)
return tmp;
tmp = ( tmp * query_cond() ) / query_max_cond();
if(tmp < val / 10)
return val / 10;
return tmp;
} /* modify_damage() */
void hit_weapon( int amount, string type ) {
if ( member_array( type, un_modifyable) != -1 )
return;
do_damage( type, amount );
} /* hit_weapon() */
/* immune to condtion loss */
int add_immune(string name) {
if (member_array(name, un_modifyable) != -1)
return 0;
un_modifyable += ({ name });
return 1;
} /* add_immune() */
int remove_immune(string name) {
int i;
if ((i = member_array(name, un_modifyable)) == -1)
return 0;
un_modifyable = delete(un_modifyable, i, 1);
return 1;
} /* remove_immune() */
int query_value() {
return ( ::query_value() * ( 10 + ( 90 * query_cond() ) /
query_max_cond() ) ) / 100;
} /* query_value() */
int query_full_value() { return ::query_value(); }
mixed *query_money_array() {
return (mixed *)MONEY_HAND->create_money_array(query_value());
} /* query_money_array() */
int query_money(string type) {
int i;
mixed *m_a;
m_a = (mixed *)MONEY_HAND->create_money_array(query_value());
if ((i=member_array(type, m_a)) == -1)
return 0;
return m_a[i+1];
} /* query_money() */
mixed *stats() {
return
object::stats() +
condition::stats() +
weapon_logic::stats();
} /* stats() */
void break_me() {
if ( query_holder() ) {
tell_object( query_holder(), "%^RED%^$C$"+ the_short() +" breaks!%^RESET%^\n" );
tell_room( environment( query_holder() ), poss_short() +
" breaks!\n", query_holder() );
query_holder()->set_unhold( this_object() );
}
::break_me();
} /* break_me() */
void player_wield(int pos) {
if (!environment()) {
return;
}
this_object()->hold_item( environment(), pos );
} /* player_wield() */
mapping query_static_auto_load() {
if ( base_name( this_object() ) == "/obj/weapon" )
return int_query_static_auto_load();
return 0;
} /* query_static_auto_load() */
mapping int_query_static_auto_load() {
mapping tmp;
tmp = object::int_query_static_auto_load();
return ([ "::" : tmp,
"attack names" : attack_names,
"attack data" : attack_data,
"attack types" : attack_types,
"hold" : holdable::query_static_auto_load(),
"condition" : condition::query_static_auto_load()
]);
} /* int_query_static_auto_load() */
mapping query_dynamic_auto_load() {
mapping map;
map = ([
"::" : object::query_dynamic_auto_load(),
"condition" : condition::query_dynamic_auto_load(),
"hold" : holdable::query_dynamic_auto_load(),
]);
return map;
} /* query_dynamic_auto_load() */
void init_static_arg( mapping map ) {
if ( !mapp( map ) ) return ;
if ( map[ "::" ] ) {
object::init_static_arg( map[ "::" ] );
}
if ( map[ "attack names" ] ) {
attack_names = map[ "attack names" ];
}
if ( map[ "attack data" ] ) {
attack_data = map[ "attack data" ];
}
if ( map[ "attack types" ] ) {
attack_types = map[ "attack types" ];
}
if ( !undefinedp( map[ "condition" ] ) ) {
condition::init_static_arg( map[ "condition" ] );
}
if (map["no limbs"]) {
//
// The new method handles it differently.
//
holdable::init_static_arg(map);
} else {
holdable::init_static_arg(map["hold"]);
}
} /* init_static_arg() */
void replace_me(){
object receipt;
receipt = clone_object( "/std/object" );
receipt->set_name( "receipt" );
receipt->set_short( "destructed item receipt" );
receipt->add_adjective( ({ "destructed", "item" }) );
receipt->set_long( "This seems to be a small piece of paper.\n" );
receipt->set_read_mess( "According to our sources, your "+query_short()+" was not "
"allowed to exist. Have a nice day." );
receipt->move( environment() );
receipt->set_weight( 1 );
destruct( this_object() );
} /* replace_me() */
void init_dynamic_arg( mapping map, object ) {
mapping stat_temp;
string virt_name, new_name;
if ( map[ "::" ] )
object::init_dynamic_arg( map[ "::" ] );
if ( !undefinedp( map[ "condition" ] ) ) {
condition::init_dynamic_arg( map[ "condition" ] );
}
holdable::init_dynamic_arg(map["hold"], 1);
if( virt_name = query_property( VIRTUAL_NAME_PROP) ) {
if( file_size( virt_name ) == -1 ) {
new_name = ( CLONER )->other_file( virt_name );
if( stringp( new_name ) && ( new_name != virt_name ) ) {
add_property( VIRTUAL_NAME_PROP, new_name );
virt_name = new_name;
} else {
if( VIRTUAL_HANDLER->query_forbidden( virt_name ) ) {
call_out( "replace_me", 1 );
} else {
VIRTUAL_HANDLER->add_missing( virt_name );
}
}
}
if( file_size( virt_name ) != -1 &&
query_property( "virtual time" ) < stat( virt_name )[1] ) {
stat_temp = ( VIRTUAL_HANDLER )->new_data( virt_name );
if( mapp( stat_temp ) ) {
init_static_arg( stat_temp );
add_property( "virtual time", time() );
}
}
}
} /* init_dynamic_arg() */