/* -*- LPC -*- */ /* * $Locker: $ * $Id: water.c,v 1.12 2002/08/03 22:27:04 ceres Exp $ * $Log: water.c,v $ * Revision 1.12 2002/08/03 22:27:04 ceres * Fixed skill names * * Revision 1.11 2002/03/09 20:20:04 tannah * Made add_property recognise the third parameter. * * Revision 1.10 2002/03/01 23:28:25 tannah * Made it check for use_base_stats before returning modified bonus, and checked * for query_verb() == "skills", too. * Made it recalculate bonus whenever query_skill_bonus() is called. * * Revision 1.9 2002/02/21 14:03:50 taffyd * Forced it to recalculate the burdening. * * Revision 1.8 2002/02/21 13:21:17 presto * Forcibly unlocked by taffyd * * Revision 1.7 2001/06/07 14:47:41 wobin * Added in cascading to do_soak for shadowed functions * * Revision 1.6 1999/05/25 23:39:50 pinkfish * Make it more error safe. * * Revision 1.5 1999/04/06 00:34:04 ceres * Modified to allow query_skill_bonus() to work for the swimming skill. * * Revision 1.4 1999/03/05 21:06:08 pinkfish * Fix up some errors that Mystic pointer out. * * Revision 1.3 1999/03/05 21:04:05 presto * Forcibly unlocked by pinkfish * * Revision 1.2 1998/05/14 00:43:52 presto * Slave work for Jeremy. :) * * Revision 1.1 1998/01/06 04:39:04 ceres * Initial revision * */ #include <move_failures.h> #define SWIMMING_SKILL "other.movement.swimming" #define STAMINA_SKILL "other.health" #define BUOYANT_PROP "buoyancy" #define ANCHOR_PROP "anchor" #define GILLS_PROP "gills" #define TROLL_RACE "troll" object swimmer; int bonus, buoyancy, drown_stage, swimming = 0, recheck_delay = -1; string sweep_dir = ""; void calc_swim_bonus(); int abs( int i ); void test_sweep(); void test_float(); void test_drown(); string sweep_string( mixed *dest_other_info, int pos ); varargs int exit_command( string word, mixed verb, object thing ); int abs( int i ) { return i < 0 ? -i : i; } int start_floating(); int start_swimming(); void setup_shadow( object this_swimmer ) { shadow( this_swimmer, 1 ); swimmer = this_swimmer; calc_swim_bonus(); } /* setup_shadow() */ void event_enter( object ob, string message, object from ) { int old_bonus, old_buoy; if (swimmer) { swimmer->event_enter( ob, message, from ); } old_bonus = bonus; old_buoy = buoyancy; calc_swim_bonus(); if ( bonus != old_bonus ) test_sweep(); if ( buoyancy != old_buoy ) { buoyancy += (int)ob->query_property( BUOYANT_PROP ); test_float(); } return; } /* event_enter() */ void event_exit( object ob, string message, object to ) { int old_bonus, old_buoy; if (swimmer) { swimmer->event_exit(ob, message, to); } old_bonus = bonus; old_buoy = buoyancy; calc_swim_bonus(); if ( bonus != old_bonus ) test_sweep(); if ( buoyancy != old_buoy ) { buoyancy -= (int)ob->query_property( BUOYANT_PROP ); test_float(); } return; } /* event_exit() */ void calc_swim_bonus() { float pct; object *held; if ( living( swimmer ) && ( held = (object *)swimmer->query_holding() ) ) { // Force a recalculation of their weight. swimmer->calc_burden(); bonus = (int)swimmer->query_skill_bonus( SWIMMING_SKILL ) / ( sizeof( held - (object *)({ 0 }) ) + 1 ); buoyancy = bonus - (int)swimmer->query_loc_weight() + (int)swimmer->query_property( BUOYANT_PROP ); if ( (string)swimmer->query_race() == TROLL_RACE ) buoyancy -= 300; if ( buoyancy < 0 && bonus ) { pct = -buoyancy / bonus; if ( pct < 1.0 ) { bonus += buoyancy; buoyancy = 0; } else { pct -= 1.0; buoyancy *= pct; bonus = 0; } } } else { if (swimmer) { bonus = (int)swimmer->query_property( ANCHOR_PROP ); buoyancy = (int)swimmer->query_property( BUOYANT_PROP ) - (int)swimmer->query_weight(); } } return; } /* calc_swim_bonus() */ void add_property( string prop, mixed val, int time ) { if (swimmer) { swimmer->add_property( prop, val, time ); } if ( prop == GILLS_PROP && val > 0 ) remove_call_out("do_drown"); if ( prop == BUOYANT_PROP && val ) { calc_swim_bonus(); test_float(); } return; } /* add_property() */ void remove_property( string prop ) { if (swimmer) { swimmer->remove_property( prop ); } if ( prop == GILLS_PROP ) test_drown(); else if ( prop == BUOYANT_PROP ) { calc_swim_bonus(); test_float(); } return; } /* remove_property() */ int add_skill_level( string skill, int lev ) { int lvl; if ( living(swimmer) ) { lvl = (int)swimmer->add_skill_level( skill, lev ); if ( skill == SWIMMING_SKILL && lev ) { calc_swim_bonus(); test_sweep(); test_float(); } return lvl; } else return 0; } /* add_skill_level() */ /* Added to allow the use of query_skill_bonus directly and still * obtain the correct result. -- Ceres */ varargs int query_skill_bonus( string skill, int use_base_stats ) { if( ( skill == SWIMMING_SKILL ) && ( !use_base_stats ) && ( query_verb() != "skills" ) ) { calc_swim_bonus(); return bonus; } return swimmer->query_skill_bonus(skill, use_base_stats); } int query_swim_bonus() { return bonus; } int query_buoyancy() { return buoyancy; } void test_sweep() { mapping flows, possible; int total_flow, r, f, s, flow_rate; string *dirs, dir, *dest_dir_info; object room; s = find_call_out( "do_sweep" ); room = environment( swimmer ); flows = (mapping)room->query_flows(); dest_dir_info = (string *)room->query_dest_dir(); f = ( 300 - ( evaluate( flows[ sweep_dir ] ) - swimming * bonus ) ) / 30; if ( f < 0 ) f = 0; f += room->query_min_sweep_delay( sweep_dir ); if ( s > f ) { remove_call_out( "do_sweep" ); call_out( "do_sweep", f, dest_dir_info[ member_array( sweep_dir, dest_dir_info ) + 1 ] ); } else if ( s == -1 || (int)room->query_flow( sweep_dir ) - swimming * bonus <= 0 ) { remove_call_out( "do_sweep" ); dirs = keys( flows ); total_flow = 0; possible = ([ ]); foreach ( dir in dirs ) { flow_rate = evaluate( flows[ dir ] ); if ( ( f = flow_rate - swimming * bonus ) > 0 && flow_rate > 0) { total_flow += f; possible += ([ dir : f ]); } } r = random( total_flow ); dirs = keys( possible ); total_flow = 0; foreach ( dir in dirs ) { if ( r < total_flow + possible[ dir ] ) { sweep_dir = dir; f = ( 300 - possible[ dir ] ) / 30; if ( f < 0 ) f = 0; f += room->query_min_sweep_delay( dir ); //tell_object(swimmer, "Calling do sweep, delay = " + f + ", direction = " + dir + "\n" ); call_out( "do_sweep", f, dest_dir_info[ member_array( sweep_dir, dest_dir_info ) + 1 ] ); return; } else total_flow += possible[ dir ]; } } return; } /* test_sweep() */ void test_float() { object room; int s, t; room = environment( swimmer ); if ( buoyancy < 0 ) { remove_call_out( "do_rise" ); s = find_call_out( "do_sink" ); if ( !( room->query_bottom() ) ) { t = (300 + buoyancy) / 30; if ( s > t ) { remove_call_out( "do_sink" ); s = -1; } if ( s == -1 ) { call_out( "do_sink", t + room->query_min_sweep_delay( room-> query_down_dir() ) ); swimmer->add_property( "there", (string)room->query_nonfloat_mess() ); } } else { swimmer->add_property( "there", (string)room->query_bottom_mess() ); if ( s > -1 ) remove_call_out( "do_sink" ); } } else if ( buoyancy > bonus ) { remove_call_out( "do_sink" ); s = find_call_out( "do_rise" ); if ( !( room->query_surface() ) ) { t = (300 - buoyancy) / 30; if ( s > t ) { remove_call_out( "do_rise" ); s = -1; } if ( s == -1 ) { call_out( "do_rise", t + room->query_min_sweep_delay( room-> query_up_dir() ) ); swimmer->add_property( "there", (string)room->query_float_mess() ); } } else if ( s > -1 ) remove_call_out( "do_rise" ); } else { remove_call_out( "do_rise" ); remove_call_out( "do_sink" ); swimmer->add_property( "there", (string)room->query_float_mess() ); } return; } /* test_float() */ void test_drown() { int delay; if ( environment( swimmer )->query_surface() ) remove_call_out("do_drown"); else if ( find_call_out( "do_drown" ) == -1 && !( swimmer->query_property( GILLS_PROP ) ) ) { delay = (int)swimmer->query_skill_bonus( STAMINA_SKILL ) / 20; if ( delay < 15 ) delay = 15; call_out( "do_drown", delay ); drown_stage = 0; } return; } /* test_drown() */ void do_sweep( string dest ) { mixed *dest_other_info; object room; room = environment(swimmer); if ( environment( swimmer )->query_terrain() ) environment( swimmer )->set_destination( sweep_dir ); dest_other_info = (mixed *)room->query_dest_other(); if ( !( swimmer->query_property("player") ) ) swimmer->move( dest, replace_string( (string)room->query_sweep_in_mess(), "$F",sweep_string( dest_other_info, member_array( sweep_dir, dest_other_info ) + 1 ) ), replace_string( (string)room->query_sweep_out_mess(), "$T", sweep_dir ) ); else { tell_object( swimmer, "The current pulls you " + sweep_dir + ".\n" ); swimmer->move_with_look( dest, replace_string( (string)room-> query_sweep_in_mess(), "$F", sweep_string( dest_other_info, member_array( sweep_dir, dest_other_info ) + 1 ) ), replace_string( (string)room-> query_sweep_out_mess(), "$T", sweep_dir ) ); } return; } /* do_sweep() */ void do_sink() { string dir; mixed *dest_other_info; int i; object room; room = environment(swimmer); dir = (string)room->query_down_dir(); if ( environment( swimmer )->query_terrain() ) environment( swimmer )->set_destination( dir ); dest_other_info = (mixed *)room->query_dest_other(); if ( ( i = member_array( dir, dest_other_info ) ) > -1 ) { if ( !( swimmer->query_property("player") ) ) swimmer->move( dest_other_info[ i + 1 ][0], replace_string( (string)room->query_sink_in_mess(), "$F", sweep_string( dest_other_info, i + 1 ) ), replace_string( (string)room->query_sink_out_mess(), "$T", dir ) ); else { tell_object( swimmer, "You sink toward the bottom.\n" ); swimmer->move_with_look( dest_other_info[ i + 1 ][0], replace_string( (string)room-> query_sink_in_mess(), "$F", sweep_string( dest_other_info, i + 1 ) ), replace_string( (string)room-> query_sink_out_mess(), "$T", dir ) ); } } return; } /* do_sink() */ void do_rise() { string dir; mixed *dest_other_info; int i; object room; room = environment( swimmer ); dir = (string)room->query_up_dir(); if ( environment( swimmer )->query_terrain() ) environment( swimmer )->set_destination( dir ); dest_other_info = (mixed *)room->query_dest_other(); if ( ( i = member_array( dir, dest_other_info ) ) > -1 ) { if ( !( swimmer->query_property("player") ) ) swimmer->move( dest_other_info[ i + 1 ][0], replace_string( (string)room->query_float_in_mess(), "$F", sweep_string( dest_other_info, i + 1 ) ), replace_string( (string)room->query_float_out_mess(), "$T", dir ) ); else { tell_object( swimmer, "You drift toward the surface.\n" ); swimmer->move_with_look( dest_other_info[ i + 1 ][0], replace_string( (string)room-> query_float_in_mess(), "$F", sweep_string( dest_other_info, i + 1 ) ), replace_string( (string)room-> query_float_out_mess(), "$T", dir ) ); } } return; } /* do_rise() */ void do_drown() { string *exits, up; int delay; delay = (int)swimmer->query_skill_bonus( STAMINA_SKILL ) / 5; if ( delay < 15 ) delay = 15; switch ( drown_stage ) { case 0: tell_object( swimmer, "Your lungs start to feel a bit heavy.\n" ); tell_room( environment( swimmer ), (string)swimmer->query_short() + " begins to look a bit uncomfortable.\n", swimmer ); call_out( "do_drown", delay ); break; case 1: tell_object( swimmer, "Your lungs are starting to burn.\n" ); tell_room( environment( swimmer ), (string)swimmer->query_short() + " starts to look slightly blue.\n", swimmer ); call_out( "do_drown", delay ); break; case 2: tell_object( swimmer, "Your lungs are fairly bursting.\n" ); tell_room( environment( swimmer ), (string)swimmer->query_short() + " begins to look panicky.\n", swimmer); call_out( "do_drown", delay ); break; default: swimmer->adjust_hp( ( 2 - drown_stage ) * 5 * ( 30 - (int)swimmer->query_con() ) ); if ( swimmer->query_hp() > 0 ) { call_out( "do_drown", delay ); exits = (string *)environment( swimmer )->query_dest_dir(); if ( member_array( up = (string)environment( swimmer )-> query_up_dir(), exits ) > -1 ) { tell_object( swimmer, "You panic and try to flee for the " "surface.\n" ); tell_room( environment( swimmer ), (string)swimmer->query_short() + " panics and madly " "tries to flee for the surface.\n", swimmer ); swimmer->exit_command( up ); } else { up = exits[ random( sizeof( exits ) ) / 2 ]; tell_object( swimmer, "You panic and try to flee " + up + ".\n" ); tell_room( environment( swimmer ), (string)swimmer->query_short() + " panics and tries " "to flee " + up + ".\n", swimmer ); swimmer->exit_command( up ); } } else swimmer->attack_by( environment( swimmer ) ); break; } ++drown_stage; return; } /* do_drown() */ // Changed slightly by Ceres to make it simpler, if youre swimming it // makes you soaked immediately now. void do_soak() { swimmer->add_effect("/std/effects/other/wetness", swimmer->query_weight()); swimmer->do_soak(); } /* do_soak() */ void cancel_sweep() { remove_call_out( "do_sweep" ); sweep_dir = ""; return; } /* cancel_sweep() */ void dest_water_shadow() { remove_call_out( "do_sweep" ); remove_call_out( "do_rise" ); remove_call_out( "do_sink" ); remove_call_out( "do_drown" ); remove_call_out( "do_soak" ); remove_call_out( "test_again" ); if (swimmer) { swimmer->remove_property("there"); } destruct( this_object() ); return; } /* dest_water_shadow() */ object find_water_shadow() { return this_object(); } int command_shadowed( string verb, string args ) { string my_mess, others_mess; my_mess = 0; if ( !( environment( swimmer )->query_surface() ) ) { if ( verb == "say" || verb == "'" ) { my_mess = "You try to talk, but only generate some bubbles."; others_mess = (string)swimmer->query_short() + " emits a 'glub glub' " "noise."; if ( !( swimmer->query_property( GILLS_PROP ) ) ) { my_mess += " In the process you inhale some water.\n"; others_mess += " In the process, " + (string)swimmer->query_pronoun() + " inhales " "some water.\n"; ++drown_stage; } else { my_mess += "\n"; others_mess += "\n"; } } else if ( verb == "lsay" ) { my_mess = "You try to speak loudly, but can only produce a lot of " "bubbles."; others_mess = (string)swimmer->query_short() + " produces a sort " "of 'glooob gloob' sound."; if ( !( swimmer->query_property( GILLS_PROP ) ) ) { my_mess += " You also inhale a fair amount of water.\n"; others_mess += " " + (string)swimmer->query_pronoun() + "also " "inhales a fair amount of water.\n"; drown_stage += 2; } else { my_mess += "\n"; others_mess += "\n"; } } else if ( verb == "shout" ) { my_mess = "You try to shout, but your main effects are a muffled " "'arrrble' and a lot of bubbles."; others_mess = (string)swimmer->query_short() + " open " + (string)swimmer->query_possessive() + " mouth and " "emits a muffled 'arrrble' noise."; if ( !( swimmer->query_property( GILLS_PROP ) ) ) { my_mess += " You also inhale about a lungful of water.\n"; others_mess += " " + (string)swimmer->query_pronoun() + " sucks " "in a large amount of water in the process.\n"; drown_stage += 3; } else { my_mess += "\n"; others_mess += "\n"; } } } if ( my_mess ) { tell_object( swimmer, my_mess ); tell_object( environment( swimmer ), others_mess ); return 1; } else return (int)swimmer->command_shadowed( verb, args ); } /* command_shadowed() */ int *set_hold( object ob, int pos ) { int *other, old_bonus; old_bonus = bonus; other = (int *)swimmer->set_hold( ob, pos ); calc_swim_bonus(); if ( old_bonus != bonus ) { test_sweep(); test_float(); } return other; } /* set_hold() */ void do_death( object thing ) { if (swimmer) { swimmer->do_death( thing ); } remove_call_out( "do_sweep" ); remove_call_out( "do_rise" ); remove_call_out( "do_sink" ); remove_call_out( "do_drown" ); remove_call_out( "do_soak" ); swimmer->remove_property("there"); return; } /* do_death() */ void remove_ghost() { swimmer->remove_ghost(); environment( swimmer )->event_enter( swimmer, "", 0 ); return; } /* remove_ghost() */ int *set_unhold( object ob ) { int *other, old_bonus; old_bonus = bonus; other = (int *)swimmer->set_unhold( ob ); calc_swim_bonus(); if ( old_bonus != bonus ) { test_sweep(); test_float(); } return other; } /* set_unhold() */ int move( mixed dest, string messin, string messout ) { string where, *dest_dir_info; int pos; if ( !swimmer->query_property( "dead" ) && living( swimmer ) ) { if ( objectp( dest ) ) where = file_name( dest ); else where = dest; dest_dir_info = (string *)environment( swimmer )->query_dest_dir(); pos = member_array( where, dest_dir_info ) - 1; if ( pos > -1 && !(int)environment( swimmer )-> attempt_exit( dest_dir_info[ pos ], swimmer ) ) { notify_fail( "" ); return MOVE_NO_DROP; } } return swimmer->move( dest, messin, messout ); } /* move() */ int do_float() { if ( !swimming ) { tell_object( swimmer, "You are already drifting with the current.\n" ); } else { tell_object( swimmer, "You stop resisting the current.\n" ); swimming = 0; test_sweep(); } return 1; } /* do_float() */ int do_swim() { if ( swimming ) { tell_object( swimmer, "You are already fighting the current.\n" ); } else { tell_object( swimmer, "You start to resist the current.\n" ); swimming = 1; test_sweep(); } return 1; } /* do_swim() */ void test_again() { test_float(); test_sweep(); call_out( "test_again", recheck_delay ); } void update_recheck( int time_out ) { int t; //tell_object( swimmer, "Called update...\n" ); recheck_delay = time_out; if ( time_out == -1 ) { remove_call_out( "test_again" ); } else if ( ( t = find_call_out( "test_again" ) ) == -1 ) { call_out( "test_again", time_out ); } else if ( time_out < t ) { remove_call_out( "test_again" ); call_out( "test_again", time_out ); } return; } string sweep_string( mixed *dest_other_info, int pos ) { if ( pointerp( dest_other_info[pos][5] ) ) { return dest_other_info[pos][5][1]; } else { return dest_other_info[pos][5]; } }