#pragma save_binary inherit "/std/living/handle"; inherit "/std/living/mon_actions"; inherit "/std/living/living"; inherit "/std/living/response_mon"; inherit "/std/living/goals"; inherit "/global/communicate"; inherit "/global/drunk"; inherit "/global/guild-race"; inherit "/global/spells"; #include "monster.h" #define MOVE_DEFAULT ({ 300, 300 }) #define SOUL_OBJECT "/obj/handlers/soul" void set_move_after( int after, int rand ); void do_move_after( int bing ); string cap_name; mixed *chat_string, *achat_string, *attack_spells; mixed move_after, *throw_out; int chat_chance, attack_everyone, aggressive, follow_speed, join_fight_type, alignment, achat_chance; string race, class, *move_zones, *enter_commands, join_fight_mess; static mixed *doing_story; static object last_attacked; int query_monster() { return 1; } /* Added by Newstyle, 26/01/94 */ int second_life() { return 0; } void create() { race_ob = "/std/races/unknown"; cur_lang = "common"; follow_speed = 3; response_mon::create(); doing_story = ({ ({ }), ({ }) }); chat_string = ({ 0, ({ }) }); achat_string = ({ 0, ({ }) }); move_zones = ({ }); attack_spells = ({ }); languages = ({ }); enter_commands = ({ }); gr_commands = ([ ]); known_commands = ({ }); goals::create(); living::create(); reset_get(); add_property( "determinate", "" ); add_property( "npc", 1 ); enable_commands(); living_commands(); handle_commands(); communicate_commands(); add_action( "soul_commqz", "*" ); add_action( "do_teach", "teach" ); add_action( "init_race", "init_race" ); mon_actions::create(); spells::create(); race_guild_commands(); } int query_cols() { return 80; } int soul_commqz( string str ) { string verb, bit; if( sscanf( str, "%s %s", verb, bit ) == 2 ) return( int ) SOUL_OBJECT->soul_command( verb, bit ); return( int ) SOUL_OBJECT->soul_command( str, "" ); } string query_cap_name() { return cap_name; } void set_cap_name( string s ) { cap_name = s; } /* Is this not handled internally by the soul object? */ int soul_com_force( string str ) { if( file_name( previous_object() ) != SOUL_OBJECT ) return 0; command( str ); return 1; } int init_race() { race_guild_commands(); return 1; } void set_name( string n ) { if( name && name != "object" ) return; name = n; cap_name = capitalize( name ); add_plural( pluralize( name ) ); set_short( capitalize( name ) ); set_long( "You see nothing special.\n" ); set_living_name( n ); } string long( string str, int dark ) { return query_long() + capitalize( query_pronoun() ) + " " + health_string() + ".\n" + calc_extra_look() + query_living_contents( 0 ); } int set_race( string str ) { race = str; return 1; } /* Bit of overkill having 3 'query_class' functions */ string query_race() { return race; } string query_class() { return class; } string query_guild() { return class; } string query_profession() { return class; } int set_class( string str ) { class = str; } int set_guild( string str ) { class = str; } int set_profession( string str ) { class = str; } varargs void init_command( string str, int tim ) { call_out( "do_command", tim, str ); } void init_equip() { call_out( "do_equip", 0 ); } int do_command( string str ) { return command( str ); } void init() { set_heart_beat( 1 ); attack(); if( aggressive ) if( aggressive >= 2 ) { if( !this_player()->query_property( "no attack" ) ) attack_ob( this_player() ); } else if( interactive( this_player() ) && !this_player()->query_property( "no attack" ) ) attack_ob( this_player() ); } int check_anyone_here() { object *arr; int i; /* No environment did return 1. Why I wonder? */ if( !environment() ) return 0; arr = all_inventory( environment() ); for( i = 0; i < sizeof( arr ); i++ ) if( interactive( arr[ i ] ) && arr[ i ] != this_object() ) return 1; return 0; } void set_attack_everyone( int i ) { attack_everyone = i; } int query_attack_everyone() { return attack_everyone; } void set_throw_out( int hps, int chance, string their_mess, string everyone_mess ) { throw_out = ({ hps, chance, their_mess, everyone_mess }); } int * query_throw_out() { return throw_out; } varargs void run_away( int bing ) { do_move_after( bing + 1 ); } string expand_string( string in_str, object on, object attacker ) { string *str, ret; int i, j, q, add_dollar; object liv, *obs, ob; str = explode( in_str, "$" ); ret = ""; for( i = 0; i < sizeof( str ); i++ ) switch( str[ i ][ 0 ] ) { case 'm': ob = this_object(); case 'l': if( !ob ) { if( !liv ) { obs = all_inventory( environment() ) - ({ this_object() }); if( sizeof( obs ) ) { j = q = random( sizeof( obs ) ); while( !living( obs[ q++ ] ) && j != q ) q = q % sizeof( obs ); liv = obs[ q - 1 ]; } } if( !liv ) break; ob = liv; } case 'a': if( !ob ) { if( !sizeof( attacker_list ) ) break; if( !attacker ) attacker = attacker_list[ random( sizeof( attacker_list ) ) ]; ob = attacker; } case 'o': if( !ob ) { if( !on ) { obs = all_inventory( environment() ); if( sizeof( obs ) ) { j = q = random( sizeof( obs ) ); while( living( obs[ q++ ] ) && j != q ) q = q % sizeof( obs ); on = obs[ q - 1 ]; } } ob = on; } switch( str[ i ][ 1..1000 ] ) { case "name": ret += (string)ob->query_name(); add_dollar = 0; break; case "cname": ret += (string)ob->query_cap_name(); add_dollar = 0; break; case "gender": ret += (string)ob->query_gender_string(); add_dollar = 0; break; case "poss": ret += (string)ob->query_possessive(); add_dollar = 0; break; case "obj": ret += (string)ob->query_objective(); add_dollar = 0; break; case "gtitle": ret += (string)ob->query_gender_title(); add_dollar = 0; break; case "pronoun": ret += (string)ob->query_pronoun(); add_dollar = 0; break; default: if( add_dollar ) ret += "$"; ret += str[ i ]; add_dollar = 1; break; } ob = 0; break; default: if( add_dollar ) ret += "$"; ret += str[ i ]; add_dollar = 1; ob = 0; break; } if( strlen( ret ) && ret[ strlen( ret ) - 1 ] == '$' ) return ret[ 0..strlen( ret ) - 2 ]; return ret; } void expand_mon_string( string str ) { switch( str[ 0 ] ) { case ':': say( this_player()->query_cap_name() + " " + expand_string( str[ 1..1000 ], 0, 0 ) + "\n" ); break; case '\'': case '"': command( expand_string( str, 0, 0 ) ); break; case '@': soul_commqz( expand_string( str[ 1..10000 ], 0, 0 ) ); break; default: say( expand_string( str, 0, 0 ) + "\n" ); break; } } void heart_beat() { object ob; int i, j; if( sizeof( attacker_list ) ) { for( i = 0; i < sizeof( attack_spells ); i += 3 ) if( random( 100 ) < attack_spells[ i ] ) call_other( attack_spells[ i + 2 ][ 0 ], attack_spells[ i + 2 ][ 1 ] ); if( throw_out ) for( i = 0; i < sizeof( attacker_list ); i++ ) if( attacker_list[ i ] && attacker_list[ i ]->query_hp() < throw_out[ 0 ] && environment( attacker_list[ i ] ) == environment() && random( 100 ) < throw_out[ 1 ] ) { if( throw_out[ 2 ] ) tell_object( attacker_list[ i ], expand_string( throw_out[ 2 ], 0, attacker_list[ i ] ) ); if( throw_out[ 3 ] ) say( expand_string( throw_out[ 3 ], 0, attacker_list[ i ] ), attacker_list[ i ] ); attacker_list[ i ]->run_away( 1 ); } if( (random( 1000 ) < achat_chance) && sizeof( achat_string[ 1 ] ) ) if( sizeof( doing_story[ 1 ] ) ) { expand_mon_string( doing_story[ 1 ][ 0 ] ); doing_story[ 1 ] = doing_story[ 1 ][ 1..sizeof( doing_story ) ]; } else { i = random( achat_string[ 0 ] + 1 ); while( (i -= achat_string[ 1 ][ j ]) > 0 ) j += 2; if( pointerp( achat_string[ 1 ][ j + 1 ] ) ) { doing_story[ 1 ] = achat_string[ 1 ][ j + 1 ]; expand_mon_string( doing_story[ 1 ][ 0 ] ); doing_story[ 1 ] = doing_story[ 1 ][ 1..sizeof( doing_story ) ]; } else expand_mon_string( achat_string[ 1 ][ j + 1 ] ); } if( attack_everyone ) { ob = first_inventory( environment() ); while( ob ) { ob->attack_by( this_object() ); ob = next_inventory( ob ); } } } else { if( hp == max_hp && gp == max_gp && !sizeof( achat_string ) && !sizeof( chat_string ) ) set_heart_beat( 0 ); if( random( 1000 ) < chat_chance && sizeof( chat_string[ 1 ] ) ) if( sizeof( doing_story[ 0 ] ) ) { expand_mon_string( doing_story[ 0 ][ 0 ] ); doing_story[ 0 ] = doing_story[ 0 ][ 1..sizeof( doing_story[ 0 ] ) ]; } else { i = random( chat_string[ 0 ] + 1 ); while( (i -= chat_string[ 1 ][ j ]) > 0 ) j += 2; if( pointerp( chat_string[ 1 ][ j + 1 ] ) ) { doing_story[ 0 ] = chat_string[ 1 ][ j + 1 ]; expand_mon_string( doing_story[ 0 ][ 0 ] ); doing_story[ 0 ] = doing_story[ 0 ][ 1..sizeof( doing_story[ 0 ] ) ]; } else expand_mon_string( chat_string[ 1 ][ j + 1 ] ); } if( !check_anyone_here() ) set_heart_beat( 0 ); } if( drunk_heart_beat( query_volume( 0 ) ) ) attack(); do_spell_effects( attackee ); remove_property( "done follow" ); if( sizeof( attacker_list ) && wimpy && (max_hp * wimpy / 100 > hp) ) run_away(); race_ob->player_heart_beat( race ); if(guild_ob) guild_ob->player_heart_beat(); } int rand_num( int no, int type ) { int i, val; for( i = 0; i < no; i++ ) val = random( type ) + 1; return val; } void set_random_stats( int no, int type ) { set_str( rand_num( no, type ) ); set_dex( rand_num( no, type ) ); set_int( rand_num( no, type ) ); set_con( rand_num( no, type ) ); set_wis( rand_num( no, type ) ); } void set_level( int i ) { if( i > 0 ) adjust_xp( i * 250 + 100 ); else adjust_xp( 350 ); hp = 10000; RACE_OB->set_level( i, race, class ); command( "init_race" ); } int give_money( int base, int rand, string type ) { if( !type ) type = "copper"; return adjust_money( base + random( rand ), type ); } void load_chat( int chance, string *c_s ) { int i; for( i = 0; i < sizeof( c_s ); i += 2 ) { chat_string[ 1 ] += ({ c_s[ i ], c_s[ i + 1 ] }); chat_string[ 0 ] += c_s[ i ]; } chat_chance = chance; } void set_chat_chance( int i ) { chat_chance = i; } int query_chat_chance() { return chat_chance; } void set_chat_string( string *chat ) { chat_string = chat; } string *query_chat_string() { return chat_string; } void add_chat_string( mixed weight, mixed chat ) { int i; if( pointerp( weight ) ) for( i = 0; i < sizeof( weight ); i += 2 ) add_chat_string( weight[ i ], weight[ i + 1 ] ); else if( member_array( chat, chat_string[ 1 ] ) == -1 ) { chat_string[ 1 ] += ({ weight, chat }); chat_string[ 0 ] += weight; } } void remove_chat_string( mixed chat ) { int i; if( pointerp( chat ) ) for( i = 0; i < sizeof( chat ); i++ ) remove_chat_string( chat[ i ] ); else if( (i = member_array( chat, chat_string[ 1 ] )) != -1 ) { chat_string[ 0 ] -= chat_string[ 1 ][ i - 1 ]; chat_string[ 1 ] = delete( chat_string[ 1 ], i - 1, 2 ); } } void load_a_chat( int chance, string *c_s ) { int i; for( i = 0; i < sizeof( c_s ); i += 2 ) { achat_string[ 1 ] += ({ c_s[ i ], c_s[ i + 1 ] }); achat_string[ 0 ] += c_s[ i ]; } achat_chance = chance; } void set_achat_chance( int i ) { achat_chance = i; } int query_achat_chance() { return achat_chance; } void set_achat_string( string *chat ) { achat_string = chat; } string *query_achat_string() { return achat_string; } void add_achat_string( mixed weight, mixed chat ) { int i; if( pointerp( weight ) ) for( i = 0; i < sizeof( weight ); i += 2 ) add_achat_string( weight[ i ], weight[ i + 1 ] ); else if( member_array( chat, achat_string[ 1 ] ) == -1 ) { achat_string[ 1 ] += ({ chat }); achat_string[ 0 ] += weight; } } void remove_achat_string( mixed chat ) { int i; if( pointerp( chat ) ) for( i = 0; i < sizeof( chat ); i++ ) remove_achat_string( chat[ i ] ); else if( (i = member_array( chat, achat_string[ 1 ] )) != -1 ) { achat_string[ 0 ] -= achat_string[ 1 ][ i - 1 ]; achat_string[ 1 ] = delete( achat_string[ 1 ], i - 1, 1 ); } } void add_move_zone( mixed zone ) { int i; if( pointerp( zone ) ) for( i = 0; i < sizeof( zone ); i++ ) add_move_zone( zone[ i ] ); else if( member_array( zone, move_zones ) != -1 ) return; else move_zones += ({ zone }); if( !move_after ) set_move_after( MOVE_DEFAULT[ 0 ], MOVE_DEFAULT[ 1 ] ); } void set_move_zones( string *zones ) { int i; for( i = 0; i < sizeof( zones ); i++ ) add_move_zone( zones[ i ] ); } void remove_move_zone( mixed zone ) { int i; if( pointerp( zone ) ) for( i = 0; i < sizeof( zone ); i++ ) remove_move_zone( zone[ i ] ); else { if( (i = member_array( zone, move_zones )) == -1 ) return; move_zones = delete( move_zones, i, 1 ); } } string *query_move_zones() { return move_zones; } void set_move_after( int after, int rand ) { move_after = ({ after, rand }); remove_call_out( "do_move_after" ); if( after != 0 && rand != 0 ) call_out( "do_move_after", after + random( rand ) ); } mixed query_move_after() { return move_after; } int add_enter_commands( mixed str ) { if( stringp( str ) ) enter_commands += ({ str }); else if( pointerp( str ) ) enter_commands += str; return 1; } string *query_enter_commands() { return enter_commands; } int reset_enter_commands() { enter_commands = ({ }); } int move_player( string dir, string dest, mixed message, object followee, mixed enter ) { int j; mixed i; i =::move_player( dir, dest, message, followee, enter ); if( i ) { for( j = 0; j < sizeof( enter_commands ); j++ ) init_command( enter_commands[ j ] ); return i; } return 0; } void do_move_after( int bing ) { mixed * direcs; int i, bong; string zone; if( !environment() || !bing && sizeof( attacker_list ) ) { call_out( "do_move_after", move_after[ 0 ] + random( move_after[ 1 ] ) ); return; } direcs = (string *)environment()->query_dest_dir(); while( !bong && sizeof( direcs ) ) { i = random( sizeof( direcs ) / 2 ) * 2; bong = 0; if( bing > 1 ) bong = (int)direcs[ i + 1 ]->query_property( "no throw out" ); zone = (string)direcs[ i + 1 ]->query_zone(); if( sizeof( move_zones ) || bong ) if( bong || (member_array( zone, move_zones ) == -1) ) { direcs = delete( direcs, i, 2 ); continue; } bong = command( direcs[ i ] ); if( !bong ) direcs = delete( direcs, i, 2 ); } if( !bing ) call_out( "do_move_after", move_after[ 0 ] + random( move_after[ 1 ] ) ); } void event_fight_in_progress( object me, object him ) { if( !join_fight_mess || !me || !him ) return; if( him == this_object() || me == this_object() ) return; if( !join_fight_type ) { if( member_array( me, attacker_list ) == -1 && member_array( him, attacker_list ) == -1 ) say( join_fight_mess ); if( !me->query_property( "no attack" ) ) attack_by( me ); if( !him->query_property( "no attack" ) ) attack_by( him ); } /* These did test for a user by query_ip_number() */ if( interactive( me ) ) { if( member_array( me, attacker_list ) == -1 ) say( join_fight_mess ); attack_by( me ); } if( interactive( him ) ) { if( member_array( him, attacker_list ) == -1 ) say( join_fight_mess ); attack_by( him ); } } void set_join_fights( string str ) { join_fight_mess = str; } string query_join_fights() { return join_fight_mess; } void set_join_fight_type( int i ) { join_fight_type = i; } int query_fight_type() { return join_fight_type; } /* Again, a serious overkill of functions here */ void set_al( int i ) { alignment = i; } int query_al() { return alignment; } int query_align() { return alignment; } void set_align( int i ) { alignment = i; } void set_alignment( int i ) { alignment = i; } int query_alignment() { return alignment; } void event_exit( object me, string mess, mixed ob ) { mixed * bing; int i; string zone; if( !move_after ) return; if( member_array( me, attacker_list ) != -1 ) { bing = (mixed *)environment()->query_dest_dir(); if( (i = member_array( ob, bing )) == -1 ) { if( !objectp( ob ) ) ob = find_object( ob ); else ob = file_name( ob ); if( (i = member_array( ob, bing )) == -1 ) return; } zone = (string)ob->query_move_zone(); if( move_zones && sizeof( move_zones ) ) if( member_array( zone, move_zones ) == -1 ) return; remove_call_out( "do_follow_move" ); call_out( "do_follow_move", 2 + random( follow_speed ), bing[ i - 1 ] ); } } void do_follow_move( string dir ) { command( dir ); } int add_attack_spell( int chance, string name, mixed obj, string func ) { int i; if( (i = member_array( name, attack_spells )) == -1 ) attack_spells += ({ chance, name, ({ obj, func }) }); else { attack_spells[ i - 1 ] = chance; attack_spells[ i + 1 ] = ({ obj, func }); } return 1; } int remove_attack_spell( string name ) { int i; if( (i = member_array( name, attack_spells )) == -1 ) return 0; attack_spells = delete( attack_spells, i - 1, 3 ); return 1; } mixed query_race_ob() { return race_ob; } void set_race_ob( mixed r ) { race_ob = r; } mixed query_guild_ob() { return guild_ob; } void set_guild_ob( mixed g ) { guild_ob = g; } int query_follow_speed() { return follow_speed; } void set_follow_speed( int f ) { follow_speed = f; } int query_aggressive() { return aggressive; } void set_aggressive( int a ) { aggressive = a; } int query_level() { if( !guild_ob ) return 1; return( int ) guild_ob->query_level( this_object() ); } int do_teach( string str ) { string bing; object *obs; notify_fail( "Syntax: teach <spell/command> to <person>\n" ); if( !str || str == "" ) return 0; if( sscanf( str, "%s to %s", str, bing ) != 2 ) return 0; obs = find_match( bing, environment() ); if( !sizeof( obs ) ) return 0; if( !command_teach( obs, str ) && !spell_teach( obs, str ) && !teach_skill( obs, str ) ) return 0; return 1; } mixed * stats() { mixed * zones; int i; zones = ({ }); for( i = 0; i < sizeof( move_zones ); i++ ) zones += ({ ({ "move zone " + i, move_zones[ i ] }) }); if( !query_move_after() ) return ::stats() + ({ ({ "guild", query_guild() }), ({ "guild ob", query_guild_ob() }), ({ "race", query_race() }), ({ "race ob", query_race_ob() }), ({ "join_fights", query_join_fights() }), ({ "follow speed", query_follow_speed() }), ({ "level", query_level() }), ({ "chat chance", query_chat_chance() }), ({ "achat chance", query_achat_chance() }), ({ "alignment", query_al() }), ({ "aggressive", query_aggressive() }), })+zones; return ::stats() + ({ ({ "race", query_race() }), ({ "race ob", query_race_ob() }), ({ "guild", query_guild() }), ({ "guild ob", query_guild_ob() }), ({ "join fights", query_join_fights() }), ({ "follow_speed", query_follow_speed() }), ({ "level", query_level() }), ({ "chat chance", query_chat_chance() }), ({ "achat chance", query_achat_chance() }), ({ "alignment", query_al() }), ({ "aggressive", query_aggressive() }), ({ "move after-fix", query_move_after()[ 0 ] }), ({ "move after-rand", query_move_after()[ 1 ] }), })+zones; } string expand_nickname( string str ) { return str; }