/** * This is the effect skelton docs. This effect * has a classification of "body.drunk". * <p> * Describe the arguments in here. * <p> * This effect has a shadow associated with it. * @classification body.drunk * @see help::effects */ #include "path.h" #include <effect.h> #include <living.h> #include <position.h> /* The effects of being drunk */ /* The initial arg (to add_effect()) is roughly the alcohol volume * from the old system. It is converted to seconds of duration via * 2*arg/query_con(). For the other routines, the arg is a 2-element * array: the duration, and the max duration over the lifetime of the * effect (for use in end()). */ /** @ignore yes */ #define HANGOVER 1000 mapping compass = ([ "north" : 1, "northeast" : 1, "east" : 1, "southeast" : 1, "south" : 1, "southwest" : 1, "west" : 1, "northwest" : 1 ]); void come_around( object person ); /** @ignore yes */ string query_classification() { return "body.drunk"; } /** @ignore yes */ string query_shadow_ob() { return SHADOWS + "drunk"; } int counter( object person, int bonus ) { // This effect will counteract "knurd" and, to some extent, "hungover" // (note that since these effects don't yet exist, this function may // not be tested :). int i, *effnums, b; class effect *effs; if ( !person ) return 0; if ( !living( person ) ) return 0; b = bonus; effs = (class effect *)person->query_effs(); // Knurd effnums = (int *)person->effects_matching( "body.knurd" ); for ( i = sizeof( effnums ) - 1; i >= 0; i-- ) { b -= effs[ effnums[ i ] ]->ob_name->test_remove( person, effs[ effnums[ i ] ]->arg, effnums[ i ], b ); if ( !b ) { person->submit_ee( 0, 0, EE_REMOVE ); return 0; } } // Hungover effnums = (int *)person->effects_matching( "body.hungover" ); for ( i = sizeof( effnums ) - 1; i >= 0; i-- ) { b -= effs[ effnums[ i ] ]->ob_name->test_remove( person, effs[ effnums[ i ] ]->arg, effnums[ i ], b/10 ) * 10; if ( !b ) { person->submit_ee( 0, 0, EE_REMOVE ); return 0; } } return b; } /* counter() */ /** @ignore yes */ int *beginning( object person, int extent, int ) { int x, c; // The duration should be similar to the old /global/player drunk // effect, ie, time = 2*extent/query_con(). person->submit_ee( "drunk_behaviour", ({ 10, 60 }), EE_CONTINUOUS ); if (c = person->query_con()) x = 2 * extent / c; else x = 2 * extent; x = counter( person, x ); person->submit_ee( 0, x, EE_REMOVE ); return ({ x, x }); } /* beginning() */ /** @ignore yes */ int *merge_effect( object person, int *old_extent, int new_extent ) { int extent, c, m; if ( !(c = person->query_con()) ) c = 1; extent = 2*new_extent/c + person->expected_tt(); extent = counter( person, extent ); person->submit_ee( 0, extent, EE_REMOVE ); m = old_extent[1]; if( extent > m ) m = extent; return ({ extent, m }); } /* merge_effect() */ /** @ignore yes */ void end( object person, int *extent ) { if( person->query_property( PASSED_OUT ) ) come_around( person ); if( extent[1] > 60 ) tell_object( person, "As the features of the world become painfully " "clear, you realize you are once again sober.\n" ); if( ( extent[1] > HANGOVER) || ( extent[1] > random( HANGOVER ))) { // Put hangover effect here } } /* end() */ void drunk_behaviour( object person, int *) { int i, intox, damage, selector; object thing, *things, tp; intox = (int)person->expected_tt(); if( person->query_property( PASSED_OUT ) ) { switch ( random ( 4 ) ) { case 0 : tell_room( ENV(person), person->the_short()+" snores " "contentedly.\n", person ); break; case 1 : tell_room( ENV(person), person->the_short()+" mutters something " "about "+person->HIS+" mother.\n", person ); break; default : tell_room( ENV(person), person->the_short()+" opens "+ person->HIS+" eyes, looks around stupidly, and passes out" " again.\n", person ); } return; } selector = random( intox ) / person->query_con() / 5; tp = TP; set_this_player( person ); switch ( selector ) { case 0 : break; case 1 : case 2 : switch ( random( 4 ) ) { case 0 : person->new_parser("hiccup"); break; case 1 : person->new_parser("burp"); break; case 2 : person->new_parser("trip"); break; default : person->new_parser("stagger"); break; } break; case 3 : tell_object( person, "You trip over and fall on your "+ "face.\n" ); tell_room( ENV(person), person->the_short()+" trips over and "+ "falls on "+person->HIS+" face.\n", person ); break; case 4 : person->new_parser( "puke" ); break; case 5 : switch( random( 2 ) ) { case 0 : things = INV( person ); while( sizeof( things ) && !thing ) { i = random( sizeof( things ) ); if( !things[ i ]->short() || things[ i ]->query_worn() ) { things = delete( things, i, 1 ); continue; } if( things[ i ]->move( ENV(person) ) ) { things = delete( things, i, 1 ); continue; } thing = things[ i ]; } if( !thing ) break; tell_object( person, "Oops, butterfingers, you have dropped "+ thing->poss_short()+".\n"); tell_room( ENV(person), person->the_short()+" stumbles "+ "and drops "+thing->a_short()+".\n", person ); break; case 1 : tell_object( person, "You fall heavily, bruising yourself "+ "nicely.\n" ); tell_room( ENV(person), person->the_short()+" falls heavily. " "You wince in sympathy.\n", person ); damage = random( (int)person->query_weight() / 10 ); damage -= person->query_ac("blunt", damage ); person->adjust_hp( -damage ); break; } break; default : if( intox > 0 ) { switch ( random( 2 ) ) { case 0 : tell_object( person, "The world goes black. You have "+ "passed out.\n" ); tell_room( ENV(person), person->the_short()+" looks ill, " "then falls over and lies there with a blank look on "+ person->HIS+" face.\n", person ); person->add_property( PASSED_OUT, 1 ); person->submit_ee("come_around", ({ 50, 80 }), EE_ONCE ); // Silently make them lie down. LYING_CMD->position( person, 1 ); break; case 1 : person->submit_ee("wander_about", 3, EE_ONCE ); break; } } } set_this_player(tp); } /* drunk_behaviour() */ void come_around( object person ) { tell_object( person, "Something blurry appears before you. You "+ "realise it's the multiverse and pick yourself up.\n" ); tell_room( ENV(person), capitalize( (string)person->the_short() ) +" blinks "+ (string)person->query_possessive() +" eyes blearily and "+ "picks "+ (string)person->query_objective() +"self up.\n", person ); person->remove_property( PASSED_OUT ); } /* come_around() */ void wander_about( object person ) { int i, flag; string *direcs; if( person->query_property( PASSED_OUT ) || !ENV( person ) ) return; if( random( 4 ) ) person->submit_ee( "wander_about", ({ 5, 5 }), EE_ONCE ); direcs = (string *)ENV( person )->query_direc(); while ( sizeof( direcs ) && !flag ) { i = random( sizeof( direcs ) ); if( /* !ENV( person )->query_obvious_exit( direcs[ i ] ) || */ !ENV( person )->query_door_open( direcs[ i ] ) ) { direcs = delete( direcs, i, 1 ); continue; } person->add_property( UNKNOWN_MOVE, 1 ); if ( compass[direcs[i]] ) flag = person->exit_command( 0, ({ direcs[ i ], "$N stumble$s off towards the $T." }) ); else flag = person->exit_command( 0, ({ direcs[ i ], "$N stumble$s off." }) ); tell_object(person, "You stumble around a bit.\n"); person->remove_property( UNKNOWN_MOVE ); if ( !flag ) direcs = delete( direcs, i, 1 ); } } /* wander_about() */ int test_remove( object player, int, int enum, int bonus ) { // The return value is the amount used to counteract this effect. // Note that knurd and hungover will have to do the same thing. int narg, *extent; narg = player->expected_tt(1, enum); if ( narg <= bonus ) { player->submit_ee2( enum, 0, 0, EE_REMOVE ); return narg; } else { extent = player->arg_of( enum); player->set_arg_of( enum, ({ narg - bonus, extent[1] })); player->submit_ee2( enum, 0, narg - bonus, EE_REMOVE ); return bonus; } }