5 function sp_init(cards, tmp0, tmp1)
8 cards ="As Ks Qs Js 10s 9s 8s 7s 6s 5s 4s 3s 2s "\
9 "Ah Kh Qh Jh 10h 9h 8h 7h 6h 5h 4h 3h 2h "\
10 "Ac Kc Qc Jc 10c 9c 8c 7c 6c 5c 4c 3c 2c "\
11 "Ad Kd Qd Jd 10d 9d 8d 7d 6d 5d 4d 3d 2d"
13 for (i=1; i<=length(tmp0); i++)
17 function sp_reset(type)
21 sp_from = "" # The speakers player name
22 sp_valid = "" # It is the speaker turn
27 sp_suit = "" # The lead suit {s,h,d,c}
28 sp_piles = "" # [x] Played cards this turn
29 delete sp_pile # [x] Played cards this turn
34 sp_state = "bid" # {new,join,bid,pass,play}
35 sp_broken = 0 # Whether spades are broken
36 delete sp_last # [x] The result of the last hand
37 delete sp_hands # [p] Each players cards
38 delete sp_looked # [i] Whether a player has looked a their cards
39 delete sp_bids # [i] Each players bid
40 delete sp_nil # [i] Nil multiplier 0=regular, 1=nil, 2=blind
41 delete sp_pass # [i] Cards to pass
42 delete sp_tricks # [i] Tricks this round
47 sp_state = "new" # {new,join,bid,pass,play}
48 sp_owner = "" # Who started the game
49 sp_playto = 0 # Score the game will go to
50 sp_dealer =-1 # Who is dealing this round
51 sp_turn = 0 # Index of who's turn it is
52 sp_player = "" # Who's turn it is
53 sp_limit = 10 # Bag out limit / nil bonus
54 delete sp_players # [p] Player names players["name"] -> i
55 delete sp_auths # [c] Player auth names auths["auth"] -> "name"
56 delete sp_share # [c] Player teammates share["friend"] -> "name"
57 delete sp_order # [i] Player order order[i] -> "name"
58 delete sp_scores # [i] Teams score
63 sp_channel = "" # channel to play in
64 sp_log = "" # Log file name
65 delete sp_notify # [p] E-mail notification address
69 function sp_acopy(dst, src, key)
74 json_copy(dst, key, src[key])
78 function sp_save(file, game)
81 game["suit"] = sp_suit;
82 game["piles"] = sp_piles;
83 json_copy(game, "pile", sp_pile);
86 game["state"] = sp_state;
87 game["broken"] = sp_broken;
88 json_copy(game, "last", sp_last);
89 json_copy(game, "looked", sp_looked);
90 json_copy(game, "bids", sp_bids);
91 json_copy(game, "nil", sp_nil);
92 json_copy(game, "pass", sp_pass);
93 json_copy(game, "tricks", sp_tricks);
96 game["owner"] = sp_owner;
97 game["playto"] = sp_playto;
98 game["dealer"] = sp_dealer;
99 game["turn"] = sp_turn;
100 game["player"] = sp_player;
101 game["limit"] = sp_limit;
102 json_copy(game, "hands", sp_hands);
103 json_copy(game, "players", sp_players);
104 json_copy(game, "auths", sp_auths);
105 json_copy(game, "share", sp_share);
106 json_copy(game, "order", sp_order);
107 json_copy(game, "scores", sp_scores);
110 game["channel"] = sp_channel;
111 game["log"] = sp_log;
112 json_copy(game, "notify", sp_notify);
115 json_save(file, game);
118 function sp_load(file, game)
121 if (!json_load(file, game))
125 sp_suit = game["suit"];
126 sp_piles = game["piles"];
127 sp_acopy(sp_pile, game["pile"]);
130 sp_state = game["state"];
131 sp_broken = game["broken"];
132 sp_acopy(sp_last, game["last"]);
133 sp_acopy(sp_looked, game["looked"]);
134 sp_acopy(sp_bids, game["bids"]);
135 sp_acopy(sp_nil, game["nil"]);
136 sp_acopy(sp_pass, game["pass"]);
137 sp_acopy(sp_tricks, game["tricks"]);
140 sp_owner = game["owner"];
141 sp_playto = game["playto"];
142 sp_dealer = game["dealer"];
143 sp_turn = game["turn"];
144 sp_player = game["player"];
145 sp_limit = game["limit"];
146 sp_acopy(sp_hands, game["hands"]);
147 sp_acopy(sp_players, game["players"]);
148 sp_acopy(sp_auths, game["auths"]);
149 sp_acopy(sp_share, game["share"]);
150 sp_acopy(sp_order, game["order"]);
151 sp_acopy(sp_scores, game["scores"]);
154 sp_channel = game["channel"];
155 sp_log = game["log"];
156 sp_acopy(sp_notify, game["notify"]);
161 print strftime("%Y-%m-%d %H:%M:%S | ") msg >> "logs/" sp_log
162 fflush("logs/" sp_log)
163 say(sp_channel, msg);
166 function sp_pretty(cards, who)
169 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
170 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
172 if (!nounicode[who]) {
173 gsub(/s/, "\002♠", cards)
174 gsub(/h/, "\002♥", cards)
175 gsub(/d/, "\002♦", cards)
176 gsub(/c/, "\002♣", cards)
181 function sp_next(who, prev)
184 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
185 if (length(sp_order) == 4)
186 sp_player = sp_order[sp_turn]
190 function sp_shuf(i, mixed)
192 sp_usort(sp_players, mixed)
194 sp_order[i-1] = mixed[i]
195 sp_players[mixed[i]] = i-1
199 function sp_deal( shuf)
201 sp_say("/me deals the cards")
202 sp_usort(sp_deck, shuf)
203 for (i=1; i<=52; i++)
204 sp_hands[sp_order[i%4]][shuf[i]] = 1
206 sp_dealer = (sp_dealer+1)%4
208 sp_player = sp_order[sp_turn]
209 sp_say(sp_player ": you bid first!")
212 function sp_hand(to, who, sort, str)
214 asorti(sp_hands[who], sort, "sp_csort")
215 for (i=0; i<length(sort); i++)
216 str = str "" sprintf("%4s", sort[i])
217 gsub(/^ +| +$/, "", str)
218 return sp_pretty(str, to)
221 function sp_hasa(who, expr)
223 for (c in sp_hands[who]) {
230 function sp_type(card)
232 return substr(card, length(card))
235 function sp_usort(list, out) {
238 asorti(out, out, "@val_num_asc")
241 function sp_csort(i1,v1,i2,v2) {
242 return sp_deck[i1] > sp_deck[i2] ? +1 :
243 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
246 function sp_winner( card, tmp)
248 for (card in sp_pile)
249 if (card !~ sp_suit && card !~ /s/)
251 asorti(sp_pile, tmp, "sp_csort")
252 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
258 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
259 return sp_order[i+0] "/" sp_order[i+2]
262 function sp_bags(i, bags)
264 bags = sp_scores[i] % sp_limit
272 return sp_nil[who] == 0 ? sp_bids[who] :
273 sp_nil[who] == 1 ? "nil" :
274 sp_nil[who] == 2 ? "blind" : "n/a"
277 function sp_passer(who)
279 return sp_nil[(who+0)%4] == 2 || sp_nil[(who+1)%4] != 0 ||
280 sp_nil[(who+2)%4] == 2 || sp_nil[(who+3)%4] != 0
283 function sp_bidders( i, turn, bid, bids)
285 for (i = 0; i < 4; i++) {
286 turn = (sp_dealer + i) % 4
287 if (bid = sp_bid(turn))
288 bids = bids " " sp_order[turn] ":" bid
290 gsub(/^ +| +$/, "", bids)
294 function sp_extra( n, s)
296 n = sp_bids[0] + sp_bids[1] + sp_bids[2] + sp_bids[3];
297 s = n == 12 || n == 14 ? "" : "s";
299 return n<13 ? "Playing with " 13-n " bag" s "!" :
300 n>13 ? "Fighting for " n-13 " trick" s "!" : "No bags!";
303 function sp_score( bids, times, tricks)
305 for (i=0; i<2; i++) {
306 bids = sp_bids[i] + sp_bids[i+2]
307 tricks = sp_tricks[i] + sp_tricks[i+2]
309 times = int((sp_bags(i) + bags) / sp_limit)
311 sp_say(sp_team(i) " bag" (times>1?" way ":" ") "out")
312 sp_scores[i] -= sp_limit * 10 * times;
314 if (tricks >= bids) {
315 sp_say(sp_team(i) " make their bid: " tricks "/" bids)
316 sp_scores[i] += bids*10 + bags;
318 sp_say(sp_team(i) " go bust: " tricks "/" bids)
319 sp_scores[i] -= bids*10;
322 for (i=0; i<4; i++) {
325 sp_say(sp_order[i] " " \
326 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
327 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
328 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
329 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
331 sp_scores[i%2] += sp_limit * 10 * sp_nil[i] * \
332 (sp_tricks[i] == 0 ? 1 : -1)
334 if (sp_scores[0] > sp_scores[1])
335 sp_say(sp_team(0) " lead " sp_scores[0] " to " sp_scores[1] " of " sp_playto)
336 else if (sp_scores[1] > sp_scores[0])
337 sp_say(sp_team(1) " lead " sp_scores[1] " to " sp_scores[0] " of " sp_playto)
339 sp_say("tied at " sp_scores[0] " of " sp_playto)
342 function sp_play(card, winner, pi)
344 delete sp_hands[sp_from][card]
345 sp_pile[card] = sp_player
346 sp_piles = sp_piles (sp_piles?",":"") card
353 if (length(sp_pile) == 1)
354 sp_suit = sp_type(card)
357 if (length(sp_pile) == 4) {
359 pi = sp_players[sp_pile[winner]]
361 sp_say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
362 " (" sp_pretty(sp_piles, FROM) ")")
363 sp_last["player"] = sp_pile[winner];
364 sp_last["pile"] = sp_piles;
365 sp_next(sp_pile[winner])
370 if (sp_tricks[0] + sp_tricks[1] + \
371 sp_tricks[2] + sp_tricks[3] == 13) {
372 sp_say("Round over!")
374 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
375 sp_scores[0] != sp_scores[1]) {
377 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
379 say(CHANNEL, sp_team(winner) " wins the game " \
380 sp_scores[winner] " to " sp_scores[looser])
381 say(CHANNEL, sp_order[winner+0] "++")
382 say(CHANNEL, sp_order[winner+2] "++")
386 if (sp_scores[0] == sp_scores[1] &&
387 sp_scores[0] >= sp_playto)
388 sp_say("It's tie! Playing an extra round!");
396 function sp_delay(sec)
398 return (sec > 60*60*24 ? int(sec/60/60/24) "d " : "") \
399 (sec > 60*60 ? int(sec/60/60)%24 "h " : "") \
403 function sp_max(list, i, max)
405 for (i=0; i<length(list); i++)
406 if (max == "" || list[i] > max)
411 function sp_avg(list, i, sum)
413 for (i=0; i<length(list); i++)
415 return sum / length(list)
418 function sp_stats(file, line, arr, time, user, turn, start, delay)
421 while ((stat = getline line < file) > 0) {
423 if (!match(line, /^([0-9\- \:]*) \| (.*)$/, arr))
425 gsub(/[:-]/, " ", arr[1])
426 time = mktime(arr[1])
429 if (!match(arr[2], /^([^:]*): (.*)$/, arr))
433 # Record user latency
435 delay[turn][length(delay[turn])] = time - start
438 if (match(arr[2], /^it is your.*$/, arr)) {
447 reply("File does not exist: " file);
450 for (user in delay) {
451 say("latency for " user \
452 ": " sp_delay(sp_avg(delay[user])) " (avg)" \
453 ", " sp_delay(sp_max(delay[user])) " (max)")
459 cmd = "od -An -N4 -td4 /dev/random"
465 sp_load("var/sp_cur.json");
467 # sp_say("Game restored.")
471 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : \
472 AUTH in sp_share ? sp_share[AUTH] : FROM
473 sp_valid = sp_from && sp_from == sp_player
479 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
484 sp_save("var/sp_save.json");
490 sp_load("var/sp_save.json");
496 say(".help spades -- play a game of spades")
499 /^\.help [Ss]pades$/ {
500 say("Spades -- play a game of spades")
501 say(".help game -- setup and administer the game")
502 say(".help play -- commands for playing spades")
503 say(".help auth -- control player authorization")
508 say(".newgame [score] -- start a game to <score> points, default 500")
509 say(".endgame -- abort the current game")
510 say(".savegame -- save the current game to disk")
511 say(".loadgame -- load the previously saved game")
516 say(".join -- join the current game")
517 say(".look -- look at your cards")
518 say(".bid [n] -- bid for <n> tricks")
519 say(".pass [card] -- pass a card to your partner")
520 say(".play [card] -- play a card")
521 say(".last -- show who took the previous trick")
522 say(".turn -- check whose turn it is")
523 say(".bids -- check what everyone bid")
524 say(".tricks -- check how many trick have been taken")
525 say(".score -- check the score")
530 say(".auth [who] -- display authentication info for a user")
531 say(".allow [who] -- allow another person to play on your behalf")
532 say(".deny [who] -- prevent a previously allowed user from playing")
533 say(".show -- display which users can play for which players")
534 say(".notify [addr] -- email user when it is their turn")
540 /^\.deal (\w+) (.*)/ {
541 sp_say(FROM " is cheating for " $2)
543 for (i=3; i<=NF; i++)
549 /^\.order (\w+) ([0-4])/ {
550 sp_say(FROM " is cheating for " $2)
553 sp_player = sp_order[sp_turn]
557 sp_state == "play" &&
558 /^\.force (\w+) (\S+)$/ {
559 sp_say(FROM " is cheating for " $2)
567 match($0, /^\.newgame ?([1-9][0-9]*) *- *([1-9][0-9]*)$/, _arr) {
568 if (_arr[2] > _arr[1])
569 $0 = $1 " " int(rand() * (_arr[2]-_arr[1])+_arr[1])
572 /^\.newgame ?([1-9][0-9]*)?$/ {
573 if (sp_state != "new") {
574 reply("There is already a game in progress.")
578 sp_playto = $2 ? $2 : 200
579 sp_limit = sp_playto > 200 ? 10 : 5;
582 sp_log = strftime("%Y%m%d_%H%M%S.log")
583 sp_say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
587 (sp_from == sp_owner || AUTH == OWNER) &&
589 if (sp_state == "new") {
590 reply("There is no game in progress.")
592 sp_say(FROM " ends the game")
598 if (sp_state == "new") {
599 reply("There is no game in progress")
601 else if (sp_state == "play") {
602 reply("The game has already started")
604 else if (sp_state == "join" && sp_from in sp_players) {
605 reply("You are already playing")
607 else if (sp_state == "join") {
611 sp_auths[AUTH] = FROM
613 sp_say(FROM " joins the game!")
615 if (sp_state == "join" && sp_turn == 0) {
622 _who = $2 in USERS ? USERS[$2]["auth"] : ""
623 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
624 if (sp_state ~ "new|join") {
625 reply("The game has not yet started")
627 else if (!(sp_from in sp_players)) {
628 reply("You are not playing")
631 reply(_str " is not logged in")
633 else if (_who in sp_players || _who in sp_auths) {
634 reply(_str " is a primary player")
636 else if (_who in sp_share) {
637 reply(_str " is already playing for " sp_share[_who])
640 sp_say(_str " can now play for " sp_from)
641 sp_share[_who] = sp_from
646 _who = $2 in USERS ? USERS[$2]["auth"] : $2
647 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
648 if (sp_state ~ "new|join") {
649 reply("The game has not yet started")
651 else if (!(sp_from in sp_players)) {
652 reply("You are not playing")
654 else if (_who in sp_players || _who in sp_auths) {
655 reply(_str " is a primary player")
657 else if (!(_who in sp_share) || sp_share[_who] != sp_from) {
658 reply(_str " is not playing for " sp_from)
661 sp_say(_str " can no longer play for " sp_from)
662 delete sp_share[_who]
667 if (sp_from in sp_notify)
668 reply("Your address is " sp_notify[sp_from])
670 reply("Your address is not set")
674 if (sp_from in sp_notify) {
675 reply("Removing address " sp_notify[sp_from])
676 delete sp_notify[sp_from]
678 reply("Your address is not set")
682 /^\.notify \S+@\S+.\S+$/ {
684 gsub(/[^a-zA-Z0-9_+@.-]/, "", _addr)
685 sp_notify[sp_from] = _addr
686 reply("Notifying you at " _addr)
689 sp_state ~ "(bid|pass|play)" &&
693 _lines[sp_share[_i]] = _lines[sp_share[_i]] " " _i
695 sp_say(_i " allowed:" _lines[_i])
699 (sp_state == "bid" || sp_state == "play") &&
701 if (sp_from in sp_players)
702 reply("It is not your turn.")
704 reply("You are not playing.")
709 /^\.bid (0|[1-9][0-9]*)$/ {
710 if ($2 < 0 || $2 > 13) {
711 reply("You can only bid from 0 to 13")
715 if ($2 == 0 && !sp_looked[i]) {
716 sp_say(FROM " goes blind nil!")
718 } else if ($2 == 0) {
719 sp_say(FROM " goes nil!")
724 if (sp_turn != sp_dealer) {
725 sp_say(sp_player ": it is your bid! (" sp_bidders() ")")
727 sp_say(sp_extra() " (" sp_bidders() ")")
728 for (p in sp_players)
729 say(p, "You have: " sp_hand(p, p))
731 for (i=0; i<2; i++) {
733 sp_say(sp_team(i) ": select a card to pass " \
734 "(/msg " NICK " .pass <card>)")
738 if (sp_state == "play")
739 sp_say(sp_player ": you have the opening lead!")
744 sp_state == "pass" &&
747 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
749 # check validity and pass
750 if (!(sp_from in sp_players)) {
751 reply("You are not playing.")
753 else if (!sp_passer(_team)) {
754 reply("Your team did not go blind")
756 else if (sp_pass[sp_players[sp_from]]) {
757 reply("You have already passed a card")
759 else if (!(_card in sp_deck)) {
760 reply("Invalid card")
762 else if (!(_card in sp_hands[sp_from])) {
763 reply("You do not have that card")
766 sp_pass[sp_players[sp_from]] = $2
767 sp_say(FROM " passes a card")
770 # check for end of passing
771 if ((!sp_passer(0) || (sp_pass[0] && sp_pass[2])) &&
772 (!sp_passer(1) || (sp_pass[1] && sp_pass[3]))) {
776 delete sp_hands[sp_order[i]][_card]
777 sp_hands[sp_order[_partner]][_card] = 1
779 sp_say("Cards have been passed!")
780 sp_say(sp_player ": you have the opening lead!")
781 for (p in sp_players)
782 say(p, "You have: " sp_hand(p, p))
787 sp_state ~ "(bid|pass|play)" &&
789 if (!(sp_from in sp_players)) {
790 reply("You are not playing.")
792 sp_looked[sp_players[sp_from]] = 1
793 say(FROM, "You have: " sp_hand(FROM, sp_from))
798 sp_state == "play" &&
801 gsub(/[^A-Za-z0-9]/, "", _card);
802 if (!(_card in sp_deck)) {
803 reply("Invalid card")
805 else if (sp_suit && _card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
806 reply("You must follow suit (" sp_suit ")")
808 else if (_card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
809 reply("You cannot trump on the first hand")
811 else if (_card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
812 reply("Spades have not been broken")
814 else if (!(_card in sp_hands[sp_from])) {
815 reply("You do not have that card")
819 if (sp_state == "play") {
820 if (length(sp_hands[sp_from]))
821 say(FROM, "You have: " sp_hand(FROM, sp_from))
823 sp_say(sp_player ": it is your turn! " \
824 "(" sp_pretty(sp_piles, sp_player) ")")
826 sp_say(sp_player ": it is your turn!")
831 /^\.last/ && sp_state == "play" {
832 if (!isarray(sp_last))
833 say("No tricks have been taken!");
835 say(sp_last["player"] " took " \
836 sp_pretty(sp_last["pile"], FROM));
839 /^\.bids/ && sp_state == "bid" ||
840 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
842 _pile = sp_pretty(sp_piles, FROM)
846 if (/!/ && sp_share[_i] == sp_player)
847 _extra = _extra " " _i "!"
849 if (sp_state == "bid" && !_bids)
850 say("It is " sp_player "'s bid!" _extra)
851 if (sp_state == "bid" && _bids)
852 say("It is " sp_player "'s bid!" _extra " (" _bids ")")
853 if (sp_state == "play" && !_pile)
854 say("It is " sp_player "'s turn!" _extra)
855 if (sp_state == "play" && _pile)
856 say("It is " sp_player "'s turn!" _extra " (" _pile ")")
858 for (_i=0; sp_state == "pass" && _i<4; _i++)
859 if (sp_passer(_i) && !sp_pass[_i])
860 say("Waiting for " sp_order[_i] " to pass a card!")
862 if (/!!/ && (sp_state == "bid" || sp_state == "play")) {
863 if (sp_player in sp_notify) {
864 _bids = _bids ? _bids : "none"
865 _pile = _pile ? sp_piles : "none"
866 mail_send(sp_notify[sp_player], \
867 "It is your " sp_state "!", \
868 "Bids so far: " _bids "\n" \
869 "Cards played: " _pile)
870 say("Notified " sp_player " at " sp_notify[sp_player])
872 say("No email address for " sp_player)
877 /^\.bids$/ && sp_state ~ "(pass|play)" {
878 say(sp_order[0] " bid " sp_bid(0) ", " \
879 sp_order[2] " bid " sp_bid(2) ", " \
880 "total: " sp_bids[0] + sp_bids[2])
881 say(sp_order[1] " bid " sp_bid(1) ", " \
882 sp_order[3] " bid " sp_bid(3) ", " \
883 "total: " sp_bids[1] + sp_bids[3])
886 /^\.tricks$/ && sp_state == "play" {
887 say(sp_order[0] " took " int(sp_tricks[0]) "/" sp_bid(0) ", " \
888 sp_order[2] " took " int(sp_tricks[2]) "/" sp_bid(2))
889 say(sp_order[1] " took " int(sp_tricks[1]) "/" sp_bid(1) ", " \
890 sp_order[3] " took " int(sp_tricks[3]) "/" sp_bid(3))
893 (TO == NICK || DST == sp_channel) &&
894 /^\.(score|status)$/ {
895 if (sp_state == "new") {
896 say("There is no game in progress")
898 if (sp_state ~ "join|bid|pass|play") {
900 sp_playto " points, " \
903 if (sp_state == "join") {
904 say("Waiting for players: " \
905 sp_order[0] " " sp_order[1] " " \
906 sp_order[2] " " sp_order[3])
908 if (sp_state ~ "bid|pass|play") {
909 say(sp_team(0) ": " \
910 int(sp_scores[0]) " points, " \
911 int(sp_bags(0)) " bags")
912 say(sp_team(1) ": " \
913 int(sp_scores[1]) " points, " \
914 int(sp_bags(1)) " bags")
918 (TO == NICK || DST == sp_channel) &&
920 say("http://pileus.org/andy/spades/" sp_log)
923 (TO == NICK || DST == sp_channel) &&
925 sp_stats("logs/" sp_log);
928 (TO == NICK || DST == sp_channel) &&
929 /^\.stats ([0-9]+_[0-9]+)(\.log)$/ {
930 gsub(/\.log$/, "", $2);
931 sp_stats("logs/" $2 ".log");
934 /^\.((new|end|load)game|join|look|bid|pass|play|notify)/ {
935 sp_save("var/sp_cur.json");