… | |
… | |
32 | "* " . $ob->name . "/" . $ob->level . " " . (length $pl->own_title ? $pl->own_title : "the " . $pl->title) |
32 | "* " . $ob->name . "/" . $ob->level . " " . (length $pl->own_title ? $pl->own_title : "the " . $pl->title) |
33 | . ($pl->gender ? " [f]" : " [m]") |
33 | . ($pl->gender ? " [f]" : " [m]") |
34 | . ($pl->peaceful ? " [peaceful]" : " [HOSTILE]") |
34 | . ($pl->peaceful ? " [peaceful]" : " [HOSTILE]") |
35 | . ($ns->afk ? " [AFK]" : "") |
35 | . ($ns->afk ? " [AFK]" : "") |
36 | . ($ob->flag (cf::FLAG_WIZ) ? " [WIZ]" : "") |
36 | . ($ob->flag (cf::FLAG_WIZ) ? " [WIZ]" : "") |
37 | . " [" . $pl->ns->version . "]" |
37 | . " [" . $pl->ns->{who_version} . "]" |
38 | . " [" . ($pl->peaceful || $privileged ? $ob->map->visible_name : $ob->region->name) . "]" |
38 | . " [" . ($pl->peaceful || $privileged ? $ob->map->visible_name : $ob->region->name) . "]" |
39 | . (sprintf " [rtt %.3fs]", $pl->ns->tcpi_rtt * 1e-6) |
39 | . (sprintf " [rtt %.3fs]", $pl->ns->tcpi_rtt * 1e-6) |
40 | . ($privileged ? " " . $pl->ns->host : "") |
40 | . ($privileged ? " " . $pl->ns->host : "") |
41 | } sort { (lc $a->ob->name) cmp (lc $b->ob->name) } @pl |
41 | } sort { (lc $a->ob->name) cmp (lc $b->ob->name) } @pl |
42 | ), |
42 | ), |
… | |
… | |
47 | cf::register_command who => sub { |
47 | cf::register_command who => sub { |
48 | my ($ob, $arg) = @_; |
48 | my ($ob, $arg) = @_; |
49 | |
49 | |
50 | $ob->speed_left ($ob->speed_left - 4); |
50 | $ob->speed_left ($ob->speed_left - 4); |
51 | |
51 | |
52 | $ob->send_msg ("c/who" => (join "\n\n", who_listing $ob->may ("extended_who"), $arg), cf::NDI_DK_ORANGE | cf::NDI_REPLY | cf::NDI_CLEAR | cf::NDI_DEF); |
52 | $ob->send_msg ("c/who" => (join "\r", who_listing $ob->may ("extended_who"), $arg), cf::NDI_DK_ORANGE | cf::NDI_REPLY | cf::NDI_CLEAR | cf::NDI_DEF); |
53 | }; |
53 | }; |
54 | |
54 | |
55 | cf::register_command seen => sub { |
55 | cf::register_command seen => sub { |
56 | my ($pl, $args) = @_; |
56 | my ($pl, $args) = @_; |
57 | |
57 | |
|
|
58 | cf::async { |
58 | if (my ($login) = $args =~ /(\S+)/) { |
59 | if (my ($login) = $args =~ /(\S+)/) { |
59 | if ($login eq $pl->name) { |
60 | if ($login eq $pl->name) { |
60 | $pl->message ("Very funny, $login. Ha. Ha.", cf::NDI_REPLY); |
61 | $pl->message ("Very funny, $login. Ha. Ha.", cf::NDI_REPLY); |
61 | } elsif (cf::player::find_active $login) { |
62 | } elsif (cf::player::find_active $login) { |
62 | $pl->message ("$login is right here on this server!", cf::NDI_REPLY); |
63 | $pl->message ("$login is right here on this server!", cf::NDI_REPLY); |
63 | } elsif (cf::player::exists $login |
64 | } elsif (cf::player::exists $login |
64 | and stat cf::player::path $login) { |
65 | and !Coro::AIO::aio_stat cf::player::path $login) { |
65 | my $time = (stat _)[9]; |
66 | my $time = (stat _)[9]; |
66 | |
67 | |
67 | $pl->message ("$login was last seen here " |
68 | $pl->message ("$login was last seen here " |
68 | . (POSIX::strftime "%Y-%m-%d %H:%M:%S +0000", gmtime $time) |
69 | . (POSIX::strftime "%Y-%m-%d %H:%M:%S +0000", gmtime $time) |
69 | . " which was " . (int +(time - $time) / 3600) . " hours ago.", cf::NDI_REPLY); |
70 | . " which was " . (int +(time - $time) / 3600) . " hours ago.", cf::NDI_REPLY); |
|
|
71 | } else { |
|
|
72 | $pl->message ("No player named $login is known to me.", cf::NDI_REPLY); |
|
|
73 | } |
70 | } else { |
74 | } else { |
71 | $pl->message ("No player named $login is known to me.", cf::NDI_REPLY); |
75 | $pl->message ("Usage: seen <player>", cf::NDI_REPLY); |
72 | } |
76 | } |
73 | } else { |
|
|
74 | $pl->message ("Usage: seen <player>", cf::NDI_REPLY); |
|
|
75 | } |
77 | }; |
76 | }; |
78 | }; |
77 | |
79 | |
78 | cf::register_command body => sub { |
80 | cf::register_command body => sub { |
79 | my ($ob) = @_; |
81 | my ($ob) = @_; |
|
|
82 | |
|
|
83 | my $observe = $ob->contr->observe; |
80 | |
84 | |
81 | # Too hard to try and make a header that lines everything up, so just |
85 | # Too hard to try and make a header that lines everything up, so just |
82 | # give a description. (comment from C++) |
86 | # give a description. (comment from C++) |
83 | my $reply = |
87 | my $reply = |
84 | "The first column is the name of the body location.\n\n" |
88 | "The first column is the name of the body location.\r" |
85 | . "The second column is how many of those locations your body has.\n\n" |
89 | . "The second column is how many of those locations your body has.\r" |
86 | . "The third column is how many slots in that location are available.\n\n"; |
90 | . "The third column is how many slots in that location are available.\r" |
|
|
91 | . "The last column shows the items currently using the slot\n\n"; |
87 | |
92 | |
|
|
93 | # first process all applied items and hash them into their slots |
|
|
94 | my @slot; |
|
|
95 | |
|
|
96 | for my $item (grep $_->flag (cf::FLAG_APPLIED), $observe->inv) { |
|
|
97 | $item->slot_info ($_) |
|
|
98 | and push @{ $slot[$_] }, $item |
|
|
99 | for 0 .. cf::NUM_BODY_LOCATIONS-1; |
|
|
100 | } |
|
|
101 | |
88 | $reply .= sprintf " %-20s %3s %5s\n", "Location", "You", "Avail"; |
102 | $reply .= sprintf " %-20s %3s %5s %s\n", "Location", "You", "Avail", "What"; |
89 | for (0 .. cf::NUM_BODY_LOCATIONS - 1) { |
103 | for (0 .. cf::NUM_BODY_LOCATIONS - 1) { |
90 | my $msg = cf::object::slot_nonuse_name $_; |
104 | my $msg = cf::object::slot_nonuse_name $_; |
91 | $msg =~ s/^.*? a //; |
105 | $msg =~ s/^.*? a //; |
92 | $reply .= sprintf " %-20s %3d %5d\n", $msg, $ob->slot_info ($_), $ob->slot_used ($_) |
106 | $reply .= sprintf " %-20s %3d %5d %s\n", |
|
|
107 | $msg, |
|
|
108 | $observe->slot_info ($_), |
|
|
109 | $observe->slot_used ($_), |
|
|
110 | join ", ", map $_->query_short_name, @{ $slot[$_] } |
93 | if $ob->slot_info ($_) or $ob->slot_used ($_); |
111 | if $observe->slot_info ($_) || $observe->slot_used ($_); |
94 | } |
112 | } |
95 | |
113 | |
96 | $reply .= "You are not allowed to wear armor\n\n" |
114 | $reply .= "You are not allowed to wear armor\r" |
97 | unless $ob->flag (cf::FLAG_USE_ARMOUR); |
115 | unless $observe->flag (cf::FLAG_USE_ARMOUR); |
98 | $reply .= "You are not allowed to use weapons\n\n" |
116 | $reply .= "You are not allowed to use weapons\r" |
99 | unless $ob->flag (cf::FLAG_USE_WEAPON); |
117 | unless $observe->flag (cf::FLAG_USE_WEAPON); |
100 | |
118 | |
101 | $ob->send_msg ("c/body" => $reply, cf::NDI_REPLY); |
119 | $ob->send_msg ("c/body" => $reply, cf::NDI_REPLY | cf::NDI_CLEAR); |
102 | }; |
120 | }; |
103 | |
121 | |
104 | cf::register_command mark => sub { |
122 | #cf::register_command mark => sub { |
105 | my ($pl, $arg) = @_; |
123 | # my ($pl, $arg) = @_; |
106 | |
124 | # |
107 | if (length $arg) { |
125 | # if (length $arg) { |
108 | my $ob = $pl->find_best_object_match ($arg); |
126 | # my $ob = $pl->find_best_object_match ($arg); |
109 | |
127 | # |
110 | return $pl->reply (undef, "Could not find an object that matches $arg") |
128 | # return $pl->reply (undef, "Could not find an object that matches $arg") |
111 | unless $ob; |
129 | # unless $ob; |
112 | |
130 | # |
113 | $pl->contr->mark ($ob); |
131 | # $pl->contr->mark ($ob); |
114 | $pl->reply (undef, (sprintf "Marked item %s", $ob->name, $ob->title)); |
132 | # $pl->reply (undef, (sprintf "Marked item %s", $ob->name, $ob->title)); |
115 | } else { |
133 | # } else { |
116 | my $ob = $pl->find_marked_object; |
134 | # my $ob = $pl->mark; |
117 | |
135 | # |
118 | $pl->reply (undef, $ob |
136 | # $pl->reply (undef, $ob |
119 | ? (sprintf "%s %s * is marked.", $ob->name, $ob->title) |
137 | # ? (sprintf "%s %s * is marked.", $ob->name, $ob->title) |
120 | : "You have no marked object."); |
138 | # : "You have no marked object."); |
121 | } |
139 | # } |
122 | }; |
140 | #}; |
123 | |
|
|
124 | for my $cmd ("run", "fire") { |
|
|
125 | my $oncmd = "${cmd}_on"; |
|
|
126 | cf::register_command $cmd => sub { |
|
|
127 | my ($ob, $arg) = @_; |
|
|
128 | |
|
|
129 | $ob->reply (undef, "Can't $cmd into a non adjacent square.") |
|
|
130 | if $arg < 0 or $arg >= 9; |
|
|
131 | |
|
|
132 | $ob->contr->$oncmd (1); |
|
|
133 | $ob->move_player ($arg); |
|
|
134 | }; |
|
|
135 | |
|
|
136 | cf::register_command "${cmd}_stop" => sub { |
|
|
137 | my ($ob) = @_; |
|
|
138 | |
|
|
139 | $ob->contr->$oncmd (0); |
|
|
140 | }; |
|
|
141 | } |
|
|
142 | |
141 | |
143 | cf::register_command mapinfo => sub { |
142 | cf::register_command mapinfo => sub { |
144 | my ($ob) = @_; |
143 | my ($ob) = @_; |
145 | |
144 | |
146 | my $observe = $ob->contr->observe; |
145 | my $observe = $ob->contr->observe; |
147 | |
146 | |
148 | my $map = $observe->map |
147 | my $map = $observe->map |
149 | or return; |
148 | or return; |
150 | |
149 | |
151 | my $msg = sprintf "%s (%s) %s", $map->name, $map->path, $observe->region->longname; |
150 | my $msg = ''; |
152 | $msg .= sprintf "\n\nplayers: %d difficulty: %d size: %d start: %dx%d timeout: %d", |
151 | |
153 | (scalar $map->players), $map->difficulty, $map->width, $map->height, $map->enter_x, $map->enter_y, $map->timeout |
152 | if ($map->name ne '') { |
|
|
153 | $msg .= sprintf "%s [%s] ", $map->name, $map->visible_name |
|
|
154 | } else { |
|
|
155 | $msg .= sprintf "%s ", $map->visible_name |
|
|
156 | } |
|
|
157 | |
|
|
158 | if ($map->visible_name ne $map->path) { |
|
|
159 | $msg .= sprintf "(%s) ", $map->path; |
|
|
160 | } |
|
|
161 | |
|
|
162 | $msg .= sprintf "\r%s", $observe->region->longname; |
|
|
163 | |
|
|
164 | $msg .= sprintf "\rplayers: %d difficulty: %d" |
|
|
165 | . "\rsize: %dx%d start: %dx%d position: (%d|%d) timeout: %d", |
|
|
166 | (scalar $map->players), |
|
|
167 | $map->difficulty, |
|
|
168 | $map->width, $map->height, |
|
|
169 | $map->enter_x, $map->enter_y, |
|
|
170 | $ob->x, $ob->y, |
|
|
171 | $map->timeout |
154 | if $ob->flag (cf::FLAG_WIZ); |
172 | if $ob->flag (cf::FLAG_WIZ); |
155 | |
173 | |
156 | $ob->send_msg ("c/mapinfo" => $msg, cf::NDI_REPLY | cf::NDI_CLEAR); |
174 | $ob->send_msg ("c/mapinfo" => $msg, cf::NDI_REPLY | cf::NDI_CLEAR); |
157 | }; |
175 | }; |
158 | |
176 | |
159 | cf::register_command whereami => sub { |
177 | cf::register_command whereami => sub { |
160 | my ($ob) = @_; |
178 | my ($ob) = @_; |
161 | |
179 | |
162 | my $reg = $ob->contr->observe->region; |
180 | my $reg = $ob->contr->observe->region; |
163 | $ob->send_msg ("c/who" => (sprintf "You are %s.\n%s", $reg->longname, $reg->msg), cf::NDI_REPLY | cf::NDI_CLEAR); |
181 | $ob->send_msg ("c/who" => (sprintf "You are %s.\n\n%s", $reg->longname, $reg->msg), cf::NDI_REPLY | cf::NDI_CLEAR); |
164 | }; |
182 | }; |
165 | |
183 | |
166 | cf::register_command whereabouts => sub { |
184 | cf::register_command whereabouts => sub { |
167 | my ($ob, $arg) = @_; |
185 | my ($ob, $arg) = @_; |
168 | |
186 | |
… | |
… | |
170 | |
188 | |
171 | for my $pl (cf::player::list) { |
189 | for my $pl (cf::player::list) { |
172 | ++$count{$pl->ob->region->longname}; |
190 | ++$count{$pl->ob->region->longname}; |
173 | } |
191 | } |
174 | |
192 | |
175 | my $msg = "In the world currently there are:\n\n" |
193 | my $msg = "T<In the world currently there are:>\n\n" |
176 | . join "", map "$count{$_} player(s) $_\n\n", sort keys %count; |
194 | . join "", map { sprintf " C<%3d >player(s) %s\r", $count{$_}, $_ } sort keys %count; |
177 | |
195 | |
178 | $ob->send_msg ("c/who" => $msg, cf::NDI_REPLY | cf::NDI_CLEAR); |
196 | $ob->send_msg ("c/who" => $msg, cf::NDI_REPLY | cf::NDI_CLEAR); |
179 | }; |
197 | }; |
180 | |
198 | |
181 | cf::register_command hiscore => sub { |
199 | cf::register_command hiscore => sub { |
… | |
… | |
225 | }; |
243 | }; |
226 | |
244 | |
227 | cf::register_command afk => sub { |
245 | cf::register_command afk => sub { |
228 | my ($ob, $arg) = @_; |
246 | my ($ob, $arg) = @_; |
229 | |
247 | |
230 | $ob->contr->ns->afk ($ob->contr->ns->afk ? 0 : 1); |
248 | $ob->contr->ns->afk (!(length $arg ? !$arg : $ob->contr->ns->afk)); |
231 | $ob->reply (undef, $ob->contr->ns->afk ? "You are now AFK" : "You are no longer AFK"); |
249 | $ob->reply (undef, $ob->contr->ns->afk ? "You are now AFK." : "You are no longer AFK."); |
|
|
250 | }; |
|
|
251 | |
|
|
252 | cf::register_command bumpmsg => sub { |
|
|
253 | my ($ob, $arg) = @_; |
|
|
254 | |
|
|
255 | $ob->contr->ns->bumpmsg (!(length $arg ? !$arg : $ob->contr->ns->bumpmsg)); |
|
|
256 | $ob->reply (undef, $ob->contr->ns->bumpmsg ? "Bumping into walls sounds more painful now." : "Bumping into walls will now be silent."); |
|
|
257 | }; |
|
|
258 | |
|
|
259 | cf::register_command brace => sub { |
|
|
260 | my ($ob, $arg) = @_; |
|
|
261 | |
|
|
262 | $ob->contr->braced (!(length $arg ? !$arg : $ob->contr->braced)); |
|
|
263 | $ob->reply (undef, $ob->contr->braced ? "You are braced." : "Not braced."); |
232 | }; |
264 | }; |
233 | |
265 | |
234 | cf::register_command sound => sub { |
266 | cf::register_command sound => sub { |
235 | my ($ob, $arg) = @_; |
267 | my ($ob, $arg) = @_; |
236 | |
268 | |
237 | $ob->contr->ns->sound ($ob->contr->ns->sound ? 0 : 1); |
269 | $ob->contr->ns->sound (!(length $arg ? !$arg : $ob->contr->ns->sound)); |
238 | $ob->reply (undef, $ob->contr->ns->sound ? "The sounds are enabled." : "Silence is golden..."); |
270 | $ob->reply (undef, $ob->contr->ns->sound ? "The sounds are enabled." : "Silence is golden..."); |
239 | }; |
|
|
240 | |
|
|
241 | cf::register_command brace => sub { |
|
|
242 | my ($ob, $arg) = @_; |
|
|
243 | |
|
|
244 | $ob->contr->braced ($ob->contr->braced ? 0 : 1); |
|
|
245 | $ob->reply (undef, $ob->contr->braced ? "You are braced." : "Not braced."); |
|
|
246 | }; |
271 | }; |
247 | |
272 | |
248 | cf::register_command 'output-rate' => sub { |
273 | cf::register_command 'output-rate' => sub { |
249 | my ($ob, $arg) = @_; |
274 | my ($ob, $arg) = @_; |
250 | |
275 | |
251 | return $ob->reply (undef, sprintf "Output rate is presently %dbps.", $ob->contr->ns->max_rate / $cf::TICK) |
276 | return $ob->reply (undef, sprintf "Output rate is presently %dbps.", $ob->contr->ns->max_rate / $cf::TICK) |
252 | unless $arg > 0; |
277 | unless $arg > 0; |
253 | |
278 | |
254 | # minimum is 5k/s |
279 | $ob->contr->ns->max_rate ((cf::clamp $arg, $OUTPUT_RATE_MIN, $OUTPUT_RATE_MAX) * $TICK); |
255 | # maximum is 100k/s, this should be configurable |
|
|
256 | $ob->contr->ns->max_rate ((List::Util::max 5000, List::Util::min 100000, $arg) * $cf::TICK); |
|
|
257 | $ob->reply (undef, sprintf "Output rate now set to %dbps.", $ob->contr->ns->max_rate / $cf::TICK); |
280 | $ob->reply (undef, sprintf "Output rate now set to %dbps.", $ob->contr->ns->max_rate / $TICK); |
258 | }; |
281 | }; |
259 | |
282 | |
260 | cf::register_command 'output-count' => sub { |
283 | cf::register_command 'output-count' => sub { |
261 | my ($ob, $arg) = @_; |
284 | my ($ob, $arg) = @_; |
262 | |
285 | |
… | |
… | |
322 | |
345 | |
323 | if (length $from) { |
346 | if (length $from) { |
324 | $item = $ob->find_best_object_match ($from) |
347 | $item = $ob->find_best_object_match ($from) |
325 | or return $ob->message ("rename: could not find a matching item to rename."); |
348 | or return $ob->message ("rename: could not find a matching item to rename."); |
326 | } else { |
349 | } else { |
327 | $item = $ob->find_marked_object |
350 | $item = $ob->mark |
328 | or return $ob->message ("rename: no from name and no marked item found to rename."); |
351 | or return $ob->message ("rename: no from name and no marked item found to rename."); |
329 | } |
352 | } |
330 | |
353 | |
331 | $item->custom_name (length $to ? $to : undef); |
354 | $item->custom_name (length $to ? $to : undef); |
332 | |
355 | |
… | |
… | |
373 | my $startup = POSIX::strftime "%Y-%m-%d %H:%M:%S %Z", localtime $cf::UPTIME; |
396 | my $startup = POSIX::strftime "%Y-%m-%d %H:%M:%S %Z", localtime $cf::UPTIME; |
374 | my $runtime = sprintf "%.1f", (time - $cf::UPTIME) / 86400; |
397 | my $runtime = sprintf "%.1f", (time - $cf::UPTIME) / 86400; |
375 | $ob->send_msg ("c/uptime" => "server started $startup, uptime ${runtime}\d", cf::NDI_REPLY | cf::NDI_CLEAR); |
398 | $ob->send_msg ("c/uptime" => "server started $startup, uptime ${runtime}\d", cf::NDI_REPLY | cf::NDI_CLEAR); |
376 | }; |
399 | }; |
377 | |
400 | |
378 | my %IN_MEMORY = ( |
401 | my %MAP_STATE = ( |
|
|
402 | cf::MAP_ACTIVE => "A", |
379 | cf::MAP_ACTIVE => "I", |
403 | cf::MAP_INACTIVE => "I", |
380 | cf::MAP_SWAPPED => "S", |
404 | cf::MAP_SWAPPED => "S", |
381 | cf::MAP_LOADING => "L", |
|
|
382 | ); |
405 | ); |
383 | |
406 | |
384 | cf::register_command maps => sub { |
407 | cf::register_command maps => sub { |
385 | my ($ob, $arg) = @_; |
408 | my ($ob, $arg) = @_; |
386 | |
409 | |
387 | no re 'eval'; $arg = qr<$arg>; |
410 | no re 'eval'; $arg = qr<$arg>; |
388 | |
411 | |
389 | my $format = "%2s %1s %3s %5s %.60s\n"; |
412 | my $format = " %2s %1s %3s %5s %.60s\n"; |
390 | |
413 | |
391 | $ob->send_msg ("c/mapinfo" => (sprintf $format, "Pl", "I", "Svd", "Reset", "Name"), cf::NDI_REPLY | cf::NDI_CLEAR); |
414 | my $msg = "\n" . sprintf $format, "Pl", "S", "Svd", "Reset", "Name"; |
392 | |
415 | |
393 | for (sort keys %cf::MAP) { |
416 | for (sort keys %cf::MAP) { |
394 | my $map = $cf::MAP{$_} |
417 | my $map = $cf::MAP{$_} |
395 | or next; |
418 | or next; |
396 | |
419 | |
… | |
… | |
398 | next if $map->{deny_list}; |
421 | next if $map->{deny_list}; |
399 | |
422 | |
400 | my $svd = int $cf::RUNTIME - $map->{last_save}; |
423 | my $svd = int $cf::RUNTIME - $map->{last_save}; |
401 | $svd = "++" if $svd > 99; |
424 | $svd = "++" if $svd > 99; |
402 | |
425 | |
403 | $ob->send_msg ("c/mapinfo" => |
426 | $msg .= sprintf $format, |
404 | (sprintf $format, |
|
|
405 | (scalar $map->players), |
427 | (scalar $map->players), |
406 | $IN_MEMORY{$map->in_memory} || "?", |
428 | $MAP_STATE{$map->state} || "?", |
407 | $svd, |
429 | $svd, |
408 | (int $map->reset_at - $cf::RUNTIME), |
430 | (int $map->reset_at - $cf::RUNTIME), |
409 | $map->visible_name) |
431 | $map->visible_name; |
410 | ); |
|
|
411 | } |
432 | } |
412 | }; |
|
|
413 | |
433 | |
|
|
434 | $ob->send_msg ("c/mapinfo" => $msg, cf::NDI_REPLY | cf::NDI_CLEAR); |
|
|
435 | }; |
|
|
436 | |