#! perl #CONVERSION: PARTIAL # implement a replacement for the built-in say/chat/shout/tell/reply commands # adds ignore/unignore functionality use NPC_Dialogue; use POSIX (); # for strftime only sub clean_timeouts($) { my ($player) = @_; my $NOW = time; for my $hash (@$player{qw(ext_ignore_shout ext_ignore_tell)}) { while (my ($k, $v) = each %$hash) { if ($v < $NOW) { $player->message ("Your ignore on $k has expired.", cf::NDI_GREEN | cf::NDI_UNIQUE); delete $hash->{$k}; } elsif (!cf::player::exists $k) { $player->message ("Your ignore on $k is no longer valid (no such user).", cf::NDI_GREEN | cf::NDI_UNIQUE); delete $hash->{$k}; } } } } cf::player->attach ( prio => -1000, on_login => sub { my ($pl) = @_; clean_timeouts $pl->ob; }, 1 ); cf::register_command listen => sub { my ($who, $msg) = @_; my $player = cf::player::find_active $who->name; if ($msg ne "") { my $prev_listen = $player->listening; $player->listening ($msg); if ($prev_listen == $player->listening) { $who->message ("Your verbose level stayed $prev_listen.", cf::NDI_UNIQUE); } else { $who->message ("Your verbose level is now " . $player->listening . ". (previously: $prev_listen)", cf::NDI_UNIQUE); } } else { $who->message ("Your verbose level is " . $player->listening . ".", cf::NDI_UNIQUE); } 1 }; my $emotes = { growl => { noparams => { other => " growls." self => "Grrrrrrrrr...." }, params => { }, self => { }, }, giggle => { noparams => { other => " giggles." self => "You giggle." }, params => { }, self => { }, }, shiver => { noparams => { other => " shivers uncomfortably." self => "Brrrrrrrrr." }, params => { }, self => { }, }, chuckle => { noparams => { other => " chuckles politely." self => "You chuckle politely" }, params => { }, self => { }, }, sigh => { noparams => { other => " sighs loudly." self => "You sigh." }, params => { }, self => { }, }, scream => { noparams => { other => " screams at the top of his lungs!" self => "ARRRRRRRRRRGH!!!!!" }, params => { }, self => { }, }, puke => { noparams => { other => " pukes." self => "Bleaaaaaghhhhhhh!" }, params => { target => " pukes on your clothes!" other => " pukes on ." self => "You puke on ." }, self => { other => " pukes on his clothes." self => "You puke on yourself." }, }, strut => { noparams => { other => " struts proudly." self => "Strut your stuff." }, params => { }, self => { }, }, cringe => { noparams => { other => " cringes in terror!" self => "You cringe in terror." }, params => { target => " cringes away from in mortal terror." self => "You cringe away from ." }, self => { }, }, hiccup => { noparams => { other => " hiccups." self => "*HIC*" }, params => { }, self => { }, }, clap => { noparams => { other => " gives a round of applause." self => "Clap, clap, clap." }, params => { }, self => { }, }, kiss => { noparams => { other => " makes a weird facial contortion" self => "All the lonely people.." }, params => { target => " kisses you." other => " kisses ." self => "You kiss ." }, self => { }, }, wink => { noparams => { other => " winks suggestively." self => "Have you got something in your eye?" }, params => { target => " winks at ." self => "You wink suggestively at ." }, self => { other => " winks at himself - something strange is going on..." self => "You wink at yourself?? What are you up to?" }, }, pout => { noparams => { other => " pouts." self => "Aww, don't take it so hard." }, params => { }, self => { }, }, cackle => { noparams => { other => " throws back his head and cackles with insane glee!" self => "You cackle gleefully." }, params => { }, self => { }, }, sniff => { noparams => { other => " sniffs sadly." self => "You sniff sadly. *SNIFF*" }, params => { target => " sniffs you." other => " sniffs " self => "You sniff ." }, self => { other => " sniffs himself." self => "You sniff yourself." }, }, nod => { noparams => { other => " nods solemnly." self => "You nod solemnly." }, params => { target => " nods solemnly to you." other => " nods solemnly to ." self => "You nod solemnly to ." }, self => { }, }, frown => { noparams => { other => " frowns." self => "What's bothering you?" }, params => { target => " frowns darkly at you." other => " frowns darkly at ." self => "You frown darkly at ." }, self => { other => " frowns at himself." self => "You frown at yourself." }, }, snicker => { noparams => { other => " snickers softly." self => "You snicker softly." }, params => { }, self => { }, }, shrug => { noparams => { other => " shrugs helplessly." self => "You shrug." }, params => { target => " shrugs at you." other => " shrugs at ." self => "You shrug at ." }, self => { }, }, bleed => { noparams => { other => " is bleeding all over the carpet - got a spare tourniquet?" self => "You bleed all over your nice new armour." }, params => { target => " slashes his wrist and bleeds all over ." self => "You slash your wrist and bleed all over " }, self => { other => " performs some satanic ritual while wiping his blood on himself." self => "Very impressive! You wipe your blood all over yourself." }, }, twiddle => { noparams => { other => " patiently twiddles his thumbs." self => "You patiently twiddle your thumbs." }, params => { }, self => { }, }, spit => { noparams => { other => " spits over his left shoulder." self => "You spit over your left shoulder." }, params => { target => " spits in your face!" other => " spits in 's face." self => "You spit on ." }, self => { other => " drools all over himself." self => "You drool all over yourself." }, }, glare => { noparams => { other => " glares around him." self => "You glare at nothing in particular." }, params => { target => " glares icily at you, you feel cold to your bones." other => " glares at ." self => "You glare icily at ." }, self => { other => " glares at his feet, what is bothering him?" self => "You glare icily at your feet, they are suddenly very cold." }, }, bow => { noparams => { other => " bows deeply." self => "You bow deeply." }, params => { target => " bows before you." other => " bows before ." self => "You bow before ." }, self => { other => " folds up like a jackknife and kisses his own toes." self => "You kiss your toes." }, }, dance => { noparams => { other => " expresses himself through interpretive dance." self => "You dance with glee." }, params => { target => " grabs you, and begins dancing!" other => "Yipe! and are doing the Macarena!" self => "You grab and begin doing the Cha-Cha!" }, self => { other => " embraces himself and begins to dance!" self => "You skip and dance around by yourself." }, }, other => { noparams => { other => " dances with glee." self => "You are a nut." }, params => { target => "You get the distinct feeling that is nuts." other => " is eyeing quizzically." self => "You are still nuts." }, self => { other => "You look away from ." self => "My god! Is that LEGAL?" }, }, snore => { noparams => { other => " snores loudly." self => "Zzzzzzzzzzzzzzz." }, params => { }, self => { }, }, blush => { noparams => { other => " blushes." self => "Your cheeks are burning." }, params => { }, self => { }, }, snap => { noparams => { other => " snaps his fingers." self => "PRONTO! you snap your fingers." }, params => { }, self => { }, }, wave => { noparams => { other => " waves happily." self => "You wave." }, params => { target => " waves goodbye to you. Have a good journey." other => " waves goodbye to ." self => "You wave goodbye to ." }, self => { other => " waves goodbye to himself." self => "Are you going on adventures as well??" }, }, smile => { noparams => { other => " smiles happily." self => "You smile happily." }, params => { target => " smiles at you." other => " beams a smile at ." self => "You smile at ." }, self => { }, }, sneeze => { noparams => { other => " sneezes." self => "Gesundheit!" }, params => { target => " sneezes on you, you feel the snot cover you. EEEEEEW." other => " sneezes on and a film of snot covers him." self => "You sneeze at and a film of snot shoots onto him." }, self => { other => " sneezes, and covers himself in a slimy substance." self => "You sneeze on yourself, what a mess!" }, }, bounce => { noparams => { other => " bounces around." self => "BOIINNNNNNGG!" }, params => { target => " bounces around the room with you." other => " bounces around the room with ." self => "You bounce around the room with ." }, self => { }, }, shake => { noparams => { other => " shakes his head." self => "You shake your head." }, params => { target => " shakes your hand." other => " shakes 's hand." self => "You shake 's hand." }, self => { other => " shakes and quivers like a bowlful of jelly." self => "You are shaken by yourself." }, }, lick => { noparams => { other => " licks his mouth and smiles." self => "You lick your mouth and smile." }, params => { target => " licks you." other => " licks ." self => "You lick ." }, self => { other => " licks himself - YUCK." self => "You lick yourself." }, }, flip => { noparams => { other => " flips head over heels." self => "You flip head over heels." }, params => { }, self => { }, }, think => { noparams => { other => " closes his eyes and thinks really hard." self => "Anything in particular that you'd care to think about?" }, params => { }, self => { }, }, yawn => { noparams => { other => " yawns sleepily." self => "You open up your yap and let out a big breeze of stale air." }, params => { }, self => { }, }, laugh => { noparams => { other => " falls down laughing." self => "You fall down laughing." }, params => { target => " looks at you and falls down on the ground laughing." other => " looks at and falls down on the ground laughing." self => "You take one look at and fall down laughing." }, self => { other => " is laughing at something." self => "Laugh at yourself all you want, the others won't understand." }, }, burp => { noparams => { other => " burps loudly." self => "You burp loudly." }, params => { }, self => { }, }, gasp => { noparams => { other => " gasps in astonishment." self => "You gasp in astonishment." }, params => { }, self => { }, }, smirk => { noparams => { other => " smirks." self => "You smirk." }, params => { }, self => { }, }, cry => { noparams => { other => " bursts into tears." self => "Waaaaaaahhh.." }, params => { target => " cries on your shoulder." other => " cries on 's shoulder." self => "You cry on 's shoulder." }, self => { other => " sobs quietly to himself." self => "You cry to yourself." }, }, sulk => { noparams => { other => " sulks in the corner." self => "You sulk." }, params => { }, self => { }, }, whistle => { noparams => { other => " whistles appreciatively." self => "You whistle appreciatively." }, params => { target => " whistles at ." self => "You whistle at ." }, self => { other => " whistles to himself in boredom." self => "You whistle while you work." }, }, groan => { noparams => { other => " groans loudly." self => "You groan loudly." }, params => { }, self => { }, }, cough => { noparams => { other => " coughs loudly." self => "Yuck, try to cover your mouth next time!" }, params => { }, self => { }, }, grin => { noparams => { other => " grins evilly." self => "You grin evilly." }, params => { target => " grins evilly at you." other => " grins evilly at ." self => "You grin at ." }, self => { }, }, }; for my $emotion (keys %$emotes) { cf::register_command $emotion => sub { my ($ob, $tname) = @_; cf::async { my $name = $ob->name; if ($tname eq $name) { my $emote = $emotes->{$emotion}->{self}; $emote->{other} =~ s//$name/; for my $other ( grep { $ob->on_same_map_as ($_->ob) } cf::player::list ) { next if $other->ob == $ob; $other->ob->message ($emote->{other}, cf::NDI_GREY | cf::NDI_UNIQUE); } $ob->message ($emote->{self}, cf::NDI_GREY | cf::NDI_UNIQUE); } elsif ($tname) { my $target = cf::player::find $tname or return $ob->reply (undef, "$tname is not around."); my $emote = $emotes->{$emotion}->{params}; $emote->{self} =~ s//$tname/; $emote->{target} =~ s//$name/; $emote->{other} =~ s//$tname/; $emote->{other} =~ s//$name/; for my $other ( grep { $ob->on_same_map_as ($_->ob) } cf::player::list ) { next if $other->ob == $ob or $other == $target; $other->ob->message ($emote->{other}, cf::NDI_GREY | cf::NDI_UNIQUE); } $target->ob->message ($emote->{target}, cf::NDI_GREY | cf::NDI_UNIQUE); $ob->message ($emote->{self}, cf::NDI_GREY | cf::NDI_UNIQUE); } else { my $emote = $emotes->{$emotion}->{noparams}; $emote->{other} =~ s//$name/; for my $other ( grep { $ob->on_same_map_as ($_->ob) } cf::player::list ) { next if $other->ob == $ob; $other->ob->message ($emote->{other}, cf::NDI_GREY | cf::NDI_UNIQUE); } $ob->message ($emote->{self}, cf::NDI_GREY | cf::NDI_UNIQUE); } }; 1 }; } cf::register_command say => sub { my ($who, $msg) = @_; utf8::decode $msg; return if $who->contr->invoke (cf::EVENT_PLAYER_SAY, $msg); if ($msg) { my $name = $who->name; utf8::encode $msg; # ->message not yet utf8-ified $_->ob->message ("$name says: $msg", cf::NDI_GREY | cf::NDI_UNIQUE) for grep $who->on_same_map_as ($_->ob), cf::player::list; utf8::decode $msg; # npcs, magic_ears etc. # first find all objects and theirt-level inventories # within a 5x5 square # that have something resembling # dialogue or support on_say. my ($map, $x, $y) = ($who->map, $who->x - 2, $who->y - 2); for my $npc ( grep +($_->invoke (cf::EVENT_OBJECT_SAY, $who->contr, $msg) && return) || NPC_Dialogue::has_dialogue $_, map +($_, $_->inv), grep $_, map $map->at ($x + $_ % 5, $y + (int $_ / 5)), 0..24 ) { # if some listener teleported us somewhere else, stop right here last unless $map->path == $who->map->path; my $dialog = new NPC_Dialogue ob => $who, npc => $npc; my ($reply, @kw) = $dialog->tell ($msg); if (defined $reply) { if ($npc->type == cf::MAGIC_EAR) { if (length $reply) { $_->ob->message ($reply, cf::NDI_BROWN | cf::NDI_UNIQUE) for grep $who->on_same_map_as ($_->ob), cf::player::list; } $npc->use_trigger; } else { if (length $reply) { $_->ob->message ($npc->name . " says: $reply", cf::NDI_BROWN | cf::NDI_UNIQUE) for grep $who->on_same_map_as ($_->ob), cf::player::list; } } } if (@kw) { $_->ob->message ("[further topics: " . (join ", ", @kw) . "]", cf::NDI_BROWN | cf::NDI_UNIQUE) for grep $who->on_same_map_as ($_->ob), cf::player::list; } } } else { $who->message ("What do you want to say?", cf::NDI_UNIQUE); } 1 }; cf::register_command chat => sub { my ($who, $msg) = @_; utf8::decode $msg; return if $who->contr->invoke (cf::EVENT_PLAYER_CHAT, $msg); if ($msg) { my $name = $who->name; my $NOW = time; utf8::encode $msg; # ->message not yet utf8-ified cf::LOG cf::llevDebug, sprintf "QBERT [%s] %s\n", $name, $msg; ext::schmorp_irc::do_notice (sprintf "[%s] %s", $name, $msg); $_->ob->message ("$name chats: $msg", cf::NDI_BLUE) for grep { $_->ob->{ext_ignore_shout}{$name} < $NOW && $_->listening >= 10 } cf::player::list; } else { $who->message ("Chat what?", cf::NDI_UNIQUE); } 1 }; cf::register_command shout => sub { my ($who, $msg) = @_; utf8::decode $msg; return if $who->contr->invoke (cf::EVENT_PLAYER_SHOUT, $msg); if ($msg) { my $NOW = time; my $name = $who->name; cf::LOG cf::llevDebug, sprintf "QBERT {%s} %s\n", $name, $msg; ext::schmorp_irc::do_notice (sprintf "\007\0034{%s} %s\n", $name, $msg); utf8::encode $msg; # ->message not yet utf8-ified $_->ob->message ("$name shouts: $msg", cf::NDI_RED) for grep { $_->ob->{ext_ignore_shout}{$name} < $NOW && $_->listening >= 2 } cf::player::list; } else { $who->message ("Shout what?", cf::NDI_UNIQUE); } 1 }; cf::register_command tell => sub { my ($who, $args) = @_; my ($target, $msg) = split /\s+/, $args, 2; utf8::decode $msg; return if $who->contr->invoke (cf::EVENT_PLAYER_TELL, $target, $msg); my $name = $who->name; if ($target =~ /irc\//) { my (undef, $nick) = split /\//, $target, 2; $who->message ("You tell $target: $args"); ext::schmorp_irc::do_notice (sprintf "(%s) %s: %s\n", $name, $nick, $msg); } elsif (my $other = cf::player::find_active $target) { if ($msg) { if ($target eq $name) { $who->message ("You are talking to yourself, you freak!", cf::NDI_UNIQUE); } elsif ($other->ob->{ext_ignore_tell}{$name} >= time) { $who->message ("$target ignores what you say. Give up on it.", cf::NDI_UNIQUE); } else { utf8::encode $msg; # ->message not yet utf8-ified cf::LOG cf::llevDebug, sprintf "TELL [%s>%s] %s\n", $name, $target, $msg; $who->message ("You tell $target: $msg"); $other->ob->message ("$name tells you: $msg"); $other->ob->{ext_last_tell} = $name; } } else { $who->message ("What do you want to tell $target?", cf::NDI_UNIQUE); } } else { $who->message ("No such player. Your message: $msg", cf::NDI_UNIQUE); } 1 }; cf::register_command reply => sub { my ($who, $args) = @_; my $name = $who->name; utf8::decode $args; return if $who->contr->invoke (cf::EVENT_PLAYER_TELL, $who->{ext_last_tell}, $args); if ($who->{ext_last_tell} =~ /irc\//) { my (undef, $nick) = split /\//, $who->{ext_last_tell}, 2; $who->message ("You tell " . $who->{ext_last_tell} . ": $args"); ext::schmorp_irc::do_notice (sprintf "(%s) %s: %s\n", $name, $nick, $args); } elsif (my $other = cf::player::find_active $who->{ext_last_tell}) { if ($args) { $other->ob->{ext_ignore_tell}{$name} >= time or delete $other->ob->{ext_ignore_tell}{$name}; if ($other->ob->{ext_ignore_tell}{$name} < time) { utf8::encode $args; # ->message not yet utf8-ified cf::LOG cf::llevDebug, sprintf "TELL [%s>%s] %s\n", $name, $other->ob->name, $args; $who->message ("You tell " . $other->ob->name . ": $args"); $other->ob->message ("$name tells you: $args"); $who->{ext_last_tell} = $other->ob->name; } else { $who->message ($other->ob->name . " ignores what you say. Give up on it.", cf::NDI_UNIQUE); } } else { $who->message ("What do you want to tell ".$other->ob->name."?", cf::NDI_UNIQUE); } } else { $who->message ("Can't reply, player left. Your message: $args".$who->{ext_last_tell}, cf::NDI_UNIQUE); } 1 }; cf::register_command ignore => sub { my ($who, $args) = @_; my ($target, $type, $timeout) = split /\s+/, $args; if ($args eq "list") { clean_timeouts $who; if ((my @ignored_tell = sort keys %{$who->{ext_ignore_tell}}) + (my @ignored_shout = sort keys %{$who->{ext_ignore_shout}})) { $who->message ("Currently ignoring private messages from: ", cf::NDI_UNIQUE); $who->message ((join ", ", @ignored_tell), cf::NDI_UNIQUE); $who->message ("Currently ignoring shouts from: ", cf::NDI_UNIQUE); $who->message ((join ", ", @ignored_shout), cf::NDI_UNIQUE); $who->message ("To stop ignoring one, use unignore.", cf::NDI_UNIQUE); } else { $who->message ("Not ignoring anyone", cf::NDI_UNIQUE); } } elsif ($target && $type) { $timeout ne "" or $timeout = 24; my $absolute_timeout = time + $timeout * 3600; if (cf::player::exists $target) { if ($type eq "tell") { $who->message ("Now ignoring private messages from $target for $timeout hours.", cf::NDI_UNIQUE); $who->{ext_ignore_tell}{$target} = $absolute_timeout; } elsif ($type eq "shout") { $who->message ("Now ignoring shouts from $target for $timeout hours.", cf::NDI_UNIQUE); $who->{ext_ignore_shout}{$target} = $absolute_timeout; } elsif ($type eq "all") { $who->message ("Now ignoring everything from $target for $timeout hours.", cf::NDI_UNIQUE); $who->{ext_ignore_tell}{$target} = $absolute_timeout; $who->{ext_ignore_shout}{$target} = $absolute_timeout; } else { $who->message ("You need to specify tell, shout or all.", cf::NDI_UNIQUE); } } else { $who->message ("No such player: $target", cf::NDI_UNIQUE); } } else { $who->message ("Usage: ignore \n" . "will ignore a player for hours.\n" . "Usage: ignore list\n" . "will show you a list of players currently ignored.", cf::NDI_UNIQUE); } 1 }; cf::register_command unignore => sub { my ($who, $args) = @_; my ($target, $type) = split /\s+/, $args; if ($args eq "") { if ($who->{ext_ignore_tell}) { $who->message ("Currently ignoring private messages from: ", cf::NDI_UNIQUE); $who->message ((join ", ", sort keys %{ $who->{ext_ignore_tell} }), cf::NDI_UNIQUE); $who->message ("Currently ignoring shouts from: ", cf::NDI_UNIQUE); $who->message ((join ", ", sort keys %{ $who->{ext_ignore_shout} }), cf::NDI_UNIQUE); } else { $who->message ("Not ignoring anyone", cf::NDI_UNIQUE); } } else { if (cf::player::exists $target) { if ($type eq "tell") { $who->message ("Not ignoring private messages from $target anymore.", cf::NDI_UNIQUE); delete $who->{ext_ignore_tell} {$target}; } elsif ($type eq "shout") { $who->message ("Not ignoring shouts from $target anymore.", cf::NDI_UNIQUE); delete $who->{ext_ignore_shout}{$target}; } elsif ($type eq "all") { $who->message ("Not ignoring anything from $target anymore.", cf::NDI_UNIQUE); delete $who->{ext_ignore_tell} {$target}; delete $who->{ext_ignore_shout}{$target}; } else { $who->message ("You need to specify tell, shout or all.", cf::NDI_UNIQUE); } } else { $who->message ("No such player or ambiguous name: $target", cf::NDI_UNIQUE); } } 1 }; cf::register_command seen => sub { my ($who, $args) = @_; if (my ($login) = $args =~ /(\S+)/) { if ($login eq $who->name) { $who->message ("Very funny, $login. Ha. Ha.", cf::NDI_UNIQUE); } elsif (cf::player::find_active $login) { $who->message ("$login is right here on this server!", cf::NDI_UNIQUE); } elsif (cf::player::exists $login and stat sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($login) x 2) { my $time = (stat _)[9]; $who->message ("$login was last seen here " . (POSIX::strftime "%Y-%m-%d %H:%M:%S +0000", gmtime $time) . " which was " . (int +(time - $time) / 3600) . " hours ago.", cf::NDI_UNIQUE); } else { $who->message ("No player named $login is known to me.", cf::NDI_UNIQUE); } } else { $who->message ("Usage: seen ", cf::NDI_UNIQUE); } 1 };