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 sp_sock = "" # UDP log socket
66 delete sp_notify # [p] E-mail notification address
70 function sp_acopy(dst, src, key)
75 json_copy(dst, key, src[key])
79 function sp_save(file, game)
82 game["suit"] = sp_suit;
83 game["piles"] = sp_piles;
84 json_copy(game, "pile", sp_pile);
87 game["state"] = sp_state;
88 game["broken"] = sp_broken;
89 json_copy(game, "last", sp_last);
90 json_copy(game, "looked", sp_looked);
91 json_copy(game, "bids", sp_bids);
92 json_copy(game, "nil", sp_nil);
93 json_copy(game, "pass", sp_pass);
94 json_copy(game, "tricks", sp_tricks);
97 game["owner"] = sp_owner;
98 game["playto"] = sp_playto;
99 game["dealer"] = sp_dealer;
100 game["turn"] = sp_turn;
101 game["player"] = sp_player;
102 game["limit"] = sp_limit;
103 json_copy(game, "hands", sp_hands);
104 json_copy(game, "players", sp_players);
105 json_copy(game, "auths", sp_auths);
106 json_copy(game, "share", sp_share);
107 json_copy(game, "order", sp_order);
108 json_copy(game, "scores", sp_scores);
111 game["channel"] = sp_channel;
112 game["log"] = sp_log;
113 json_copy(game, "notify", sp_notify);
116 json_save(file, game);
119 function sp_load(file, game)
122 if (!json_load(file, game))
126 sp_suit = game["suit"];
127 sp_piles = game["piles"];
128 sp_acopy(sp_pile, game["pile"]);
131 sp_state = game["state"];
132 sp_broken = game["broken"];
133 sp_acopy(sp_last, game["last"]);
134 sp_acopy(sp_looked, game["looked"]);
135 sp_acopy(sp_bids, game["bids"]);
136 sp_acopy(sp_nil, game["nil"]);
137 sp_acopy(sp_pass, game["pass"]);
138 sp_acopy(sp_tricks, game["tricks"]);
141 sp_owner = game["owner"];
142 sp_playto = game["playto"];
143 sp_dealer = game["dealer"];
144 sp_turn = game["turn"];
145 sp_player = game["player"];
146 sp_limit = game["limit"];
147 sp_acopy(sp_hands, game["hands"]);
148 sp_acopy(sp_players, game["players"]);
149 sp_acopy(sp_auths, game["auths"]);
150 sp_acopy(sp_share, game["share"]);
151 sp_acopy(sp_order, game["order"]);
152 sp_acopy(sp_scores, game["scores"]);
155 sp_channel = game["channel"];
156 sp_log = game["log"];
157 sp_acopy(sp_notify, game["notify"]);
164 print strftime("%Y-%m-%d %H:%M:%S | ") msg >> "logs/" sp_log
165 fflush("logs/" sp_log)
168 function sp_pretty(cards, who)
171 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
172 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
174 if (!nounicode[who]) {
175 gsub(/s/, "\002♠", cards)
176 gsub(/h/, "\002♥", cards)
177 gsub(/d/, "\002♦", cards)
178 gsub(/c/, "\002♣", cards)
183 function sp_next(who, prev)
186 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
187 if (length(sp_order) == 4)
188 sp_player = sp_order[sp_turn]
192 function sp_shuf(i, mixed)
194 sp_usort(sp_players, mixed)
196 sp_order[i-1] = mixed[i]
197 sp_players[mixed[i]] = i-1
201 function sp_deal( shuf)
203 sp_say("/me deals the cards")
204 sp_usort(sp_deck, shuf)
205 for (i=1; i<=52; i++)
206 sp_hands[sp_order[i%4]][shuf[i]] = 1
208 sp_dealer = (sp_dealer+1)%4
210 sp_player = sp_order[sp_turn]
211 sp_say(sp_player ": you bid first!")
214 function sp_hand(to, who, sort, str)
216 asorti(sp_hands[who], sort, "sp_csort")
217 for (i=0; i<length(sort); i++)
218 str = str "" sprintf("%4s", sort[i])
219 gsub(/^ +| +$/, "", str)
220 return sp_pretty(str, to)
223 function sp_hasa(who, expr)
225 for (c in sp_hands[who]) {
232 function sp_type(card)
234 return substr(card, length(card))
237 function sp_usort(list, out) {
240 asorti(out, out, "@val_num_asc")
243 function sp_csort(i1,v1,i2,v2) {
244 return sp_deck[i1] > sp_deck[i2] ? +1 :
245 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
248 function sp_winner( card, tmp)
250 for (card in sp_pile)
251 if (card !~ sp_suit && card !~ /s/)
253 asorti(sp_pile, tmp, "sp_csort")
254 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
260 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
261 return sp_order[i+0] "/" sp_order[i+2]
264 function sp_bags(i, bags)
266 bags = sp_scores[i] % sp_limit
274 return sp_nil[who] == 0 ? sp_bids[who] :
275 sp_nil[who] == 1 ? "nil" :
276 sp_nil[who] == 2 ? "blind" : "n/a"
279 function sp_passer(who)
281 return sp_nil[(who+0)%4] == 2 || sp_nil[(who+1)%4] != 0 ||
282 sp_nil[(who+2)%4] == 2 || sp_nil[(who+3)%4] != 0
285 function sp_bidders( i, turn, bid, bids)
287 for (i = 0; i < 4; i++) {
288 turn = (sp_dealer + i) % 4
289 if (bid = sp_bid(turn))
290 bids = bids " " sp_order[turn] ":" bid
292 gsub(/^ +| +$/, "", bids)
296 function sp_extra( n, s)
298 n = sp_bids[0] + sp_bids[1] + sp_bids[2] + sp_bids[3];
299 s = n == 12 || n == 14 ? "" : "s";
301 return n<13 ? "Playing with " 13-n " bag" s "!" :
302 n>13 ? "Fighting for " n-13 " trick" s "!" : "No bags!";
305 function sp_score( bids, times, tricks)
307 for (i=0; i<2; i++) {
308 bids = sp_bids[i] + sp_bids[i+2]
309 tricks = sp_tricks[i] + sp_tricks[i+2]
311 times = int((sp_bags(i) + bags) / sp_limit)
313 sp_say(sp_team(i) " bag" (times>1?" way ":" ") "out")
314 sp_scores[i] -= sp_limit * 10 * times;
316 if (tricks >= bids) {
317 sp_say(sp_team(i) " make their bid: " tricks "/" bids)
318 sp_scores[i] += bids*10 + bags;
320 sp_say(sp_team(i) " go bust: " tricks "/" bids)
321 sp_scores[i] -= bids*10;
324 for (i=0; i<4; i++) {
327 sp_say(sp_order[i] " " \
328 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
329 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
330 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
331 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
333 sp_scores[i%2] += sp_limit * 10 * sp_nil[i] * \
334 (sp_tricks[i] == 0 ? 1 : -1)
336 if (sp_scores[0] > sp_scores[1])
337 sp_say(sp_team(0) " lead " sp_scores[0] " to " sp_scores[1] " of " sp_playto)
338 else if (sp_scores[1] > sp_scores[0])
339 sp_say(sp_team(1) " lead " sp_scores[1] " to " sp_scores[0] " of " sp_playto)
341 sp_say("tied at " sp_scores[0] " of " sp_playto)
344 function sp_play(card, winner, pi)
346 delete sp_hands[sp_from][card]
347 sp_pile[card] = sp_player
348 sp_piles = sp_piles (sp_piles?",":"") card
355 if (length(sp_pile) == 1)
356 sp_suit = sp_type(card)
359 if (length(sp_pile) == 4) {
361 pi = sp_players[sp_pile[winner]]
363 sp_say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
364 " (" sp_pretty(sp_piles, FROM) ")")
365 sp_last["player"] = sp_pile[winner];
366 sp_last["pile"] = sp_piles;
367 sp_next(sp_pile[winner])
372 if (sp_tricks[0] + sp_tricks[1] + \
373 sp_tricks[2] + sp_tricks[3] == 13) {
374 sp_say("Round over!")
376 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
377 sp_scores[0] != sp_scores[1]) {
379 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
381 say(CHANNEL, sp_team(winner) " wins the game " \
382 sp_scores[winner] " to " sp_scores[looser])
383 say(CHANNEL, sp_order[winner+0] "++")
384 say(CHANNEL, sp_order[winner+2] "++")
388 if (sp_scores[0] == sp_scores[1] &&
389 sp_scores[0] >= sp_playto)
390 sp_say("It's tie! Playing an extra round!");
398 function sp_delay(sec)
400 return (sec > 60*60*24 ? int(sec/60/60/24) "d " : "") \
401 (sec > 60*60 ? int(sec/60/60)%24 "h " : "") \
405 function sp_max(list, i, max)
407 for (i=0; i<length(list); i++)
408 if (max == "" || list[i] > max)
413 function sp_avg(list, i, sum)
415 for (i=0; i<length(list); i++)
417 return sum / length(list)
420 function sp_cur(list)
422 return list[length(list)-1]
425 function sp_stats(file, line, arr, time, user, turn, start, delay, short, extra)
428 while ((stat = getline line < file) > 0) {
430 if (!match(line, /^([0-9\- \:]*) \| (.*)$/, arr))
432 gsub(/[:-]/, " ", arr[1])
433 time = mktime(arr[1])
436 if (!match(arr[2], /^([^:]*): (.*)$/, arr))
440 # Record user latency
442 delay[turn][length(delay[turn])] = time - start
445 if (match(arr[2], /^(it is your|you .*(first|lead)!$)/, arr)) {
452 # Add current latency
454 delay[turn][length(delay[turn])] = systime() - start
455 debug("time: " (systime() - start))
460 reply("File does not exist: " file);
463 for (user in delay) {
464 short = length(user) <= 4 ? user : substr(user, 0, 4)
465 extra = (user != turn) ? "" : \
466 ", " sp_delay(sp_cur(delay[user])) " (cur)";
467 say("latency for " short \
468 ": " sp_delay(sp_avg(delay[user])) " (avg)" \
469 ", " sp_delay(sp_max(delay[user])) " (max)" extra)
475 cmd = "od -An -N4 -td4 /dev/random"
481 sp_load("var/sp_cur.json")
482 sp_sock = "/inet/udp/0/localhost/6173"
483 print "starting rhawk" |& sp_sock
485 # sp_say("Game restored.")
489 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : \
490 AUTH in sp_share ? sp_share[AUTH] : FROM
491 sp_valid = sp_from && sp_from == sp_player
497 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
502 sp_save("var/sp_save.json");
508 sp_load("var/sp_save.json");
514 say(".help spades -- play a game of spades")
517 /^\.help [Ss]pades$/ {
518 say("Spades -- play a game of spades")
519 say(".help game -- setup and administer the game")
520 say(".help play -- commands for playing spades")
521 say(".help auth -- control player authorization")
526 say(".newgame [score] -- start a game to <score> points, default 500")
527 say(".endgame -- abort the current game")
528 say(".savegame -- save the current game to disk")
529 say(".loadgame -- load the previously saved game")
534 say(".join -- join the current game")
535 say(".look -- look at your cards")
536 say(".bid [n] -- bid for <n> tricks")
537 say(".pass [card] -- pass a card to your partner")
538 say(".play [card] -- play a card")
539 say(".last -- show who took the previous trick")
540 say(".turn -- check whose turn it is")
541 say(".bids -- check what everyone bid")
542 say(".tricks -- check how many trick have been taken")
543 say(".score -- check the score")
548 say(".auth [who] -- display authentication info for a user")
549 say(".allow [who] -- allow another person to play on your behalf")
550 say(".deny [who] -- prevent a previously allowed user from playing")
551 say(".show -- display which users can play for which players")
552 say(".notify [addr] -- email user when it is their turn")
558 /^\.deal (\w+) (.*)/ {
559 sp_say(FROM " is cheating for " $2)
561 for (i=3; i<=NF; i++)
567 /^\.order (\w+) ([0-4])/ {
568 sp_say(FROM " is cheating for " $2)
571 sp_player = sp_order[sp_turn]
575 sp_state == "play" &&
576 /^\.force (\w+) (\S+)$/ {
577 sp_say(FROM " is cheating for " $2)
585 match($0, /^\.newgame ?([1-9][0-9]*) *- *([1-9][0-9]*)$/, _arr) {
586 if (_arr[2] > _arr[1])
587 $0 = $1 " " int(rand() * (_arr[2]-_arr[1])+_arr[1])
590 /^\.newgame ?([1-9][0-9]*)?$/ {
591 if (sp_state != "new") {
592 reply("There is already a game in progress.")
596 sp_playto = $2 ? $2 : 200
597 sp_limit = sp_playto > 200 ? 10 : 5;
600 sp_log = strftime("%Y%m%d_%H%M%S.log")
601 sp_say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
605 (sp_from == sp_owner || AUTH == OWNER) &&
607 if (sp_state == "new") {
608 reply("There is no game in progress.")
610 sp_say(FROM " ends the game")
616 if (sp_state == "new") {
617 reply("There is no game in progress")
619 else if (sp_state == "play") {
620 reply("The game has already started")
622 else if (sp_state == "join" && sp_from in sp_players) {
623 reply("You are already playing")
625 else if (sp_state == "join") {
629 sp_auths[AUTH] = FROM
631 sp_say(FROM " joins the game!")
633 if (sp_state == "join" && sp_turn == 0) {
640 _who = $2 in USERS ? USERS[$2]["auth"] : ""
641 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
642 if (sp_state ~ "new|join") {
643 reply("The game has not yet started")
645 else if (!(sp_from in sp_players)) {
646 reply("You are not playing")
649 reply(_str " is not logged in")
651 else if (_who in sp_players || _who in sp_auths) {
652 reply(_str " is a primary player")
654 else if (_who in sp_share) {
655 reply(_str " is already playing for " sp_share[_who])
658 sp_say(_str " can now play for " sp_from)
659 sp_share[_who] = sp_from
664 _who = $2 in USERS ? USERS[$2]["auth"] : $2
665 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
666 if (sp_state ~ "new|join") {
667 reply("The game has not yet started")
669 else if (!(sp_from in sp_players)) {
670 reply("You are not playing")
672 else if (_who in sp_players || _who in sp_auths) {
673 reply(_str " is a primary player")
675 else if (!(_who in sp_share) || sp_share[_who] != sp_from) {
676 reply(_str " is not playing for " sp_from)
679 sp_say(_str " can no longer play for " sp_from)
680 delete sp_share[_who]
685 if (!(sp_from in sp_players))
686 reply("You are not playing")
687 else if (sp_from == FROM)
688 say(FROM " has an existential crisis")
690 reply("You are playing for " sp_from);
694 if (sp_from in sp_notify)
695 reply("Your address is " sp_notify[sp_from])
697 reply("Your address is not set")
701 if (sp_from in sp_notify) {
702 reply("Removing address " sp_notify[sp_from])
703 delete sp_notify[sp_from]
705 reply("Your address is not set")
709 /^\.notify \S+@\S+.\S+$/ {
711 gsub(/[^a-zA-Z0-9_+@.-]/, "", _addr)
712 sp_notify[sp_from] = _addr
713 reply("Notifying you at " _addr)
716 sp_state ~ "(bid|pass|play)" &&
720 _lines[sp_share[_i]] = _lines[sp_share[_i]] " " _i
722 say(_i " allowed:" _lines[_i])
726 (sp_state == "bid" || sp_state == "play") &&
728 if (sp_from in sp_players)
729 reply("It is not your turn.")
731 reply("You are not playing.")
736 /^\.bid (0|[1-9][0-9]*)$/ {
737 if ($2 < 0 || $2 > 13) {
738 reply("You can only bid from 0 to 13")
742 if ($2 == 0 && !sp_looked[i]) {
743 sp_say(FROM " goes blind nil!")
745 } else if ($2 == 0) {
746 sp_say(FROM " goes nil!")
751 if (sp_turn != sp_dealer) {
752 sp_say(sp_player ": it is your bid! (" sp_bidders() ")")
754 sp_say(sp_extra() " (" sp_bidders() ")")
755 for (p in sp_players)
756 say(p, "You have: " sp_hand(p, p))
758 for (i=0; i<2; i++) {
760 sp_say(sp_team(i) ": select a card to pass " \
761 "(/msg " NICK " .pass <card>)")
765 if (sp_state == "play")
766 sp_say(sp_player ": you have the opening lead!")
771 sp_state == "pass" &&
774 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
776 # check validity and pass
777 if (!(sp_from in sp_players)) {
778 reply("You are not playing.")
780 else if (!sp_passer(_team)) {
781 reply("Your team did not go blind")
783 else if (sp_pass[sp_players[sp_from]]) {
784 reply("You have already passed a card")
786 else if (!(_card in sp_deck)) {
787 reply("Invalid card")
789 else if (!(_card in sp_hands[sp_from])) {
790 reply("You do not have that card")
793 sp_pass[sp_players[sp_from]] = $2
794 sp_say(FROM " passes a card")
797 # check for end of passing
798 if ((!sp_passer(0) || (sp_pass[0] && sp_pass[2])) &&
799 (!sp_passer(1) || (sp_pass[1] && sp_pass[3]))) {
803 delete sp_hands[sp_order[i]][_card]
804 sp_hands[sp_order[_partner]][_card] = 1
806 sp_say("Cards have been passed!")
807 sp_say(sp_player ": you have the opening lead!")
808 for (p in sp_players)
809 say(p, "You have: " sp_hand(p, p))
814 sp_state ~ "(bid|pass|play)" &&
816 if (!(sp_from in sp_players)) {
817 reply("You are not playing.")
819 sp_looked[sp_players[sp_from]] = 1
820 say(FROM, "You have: " sp_hand(FROM, sp_from))
825 sp_state == "play" &&
828 gsub(/[^A-Za-z0-9]/, "", _card);
829 if (!(_card in sp_deck)) {
830 reply("Invalid card")
832 else if (sp_suit && _card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
833 reply("You must follow suit (" sp_suit ")")
835 else if (_card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
836 reply("You cannot trump on the first hand")
838 else if (_card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
839 reply("Spades have not been broken")
841 else if (!(_card in sp_hands[sp_from])) {
842 reply("You do not have that card")
846 if (sp_state == "play") {
847 if (length(sp_hands[sp_from]))
848 say(FROM, "You have: " sp_hand(FROM, sp_from))
850 sp_say(sp_player ": it is your turn! " \
851 "(" sp_pretty(sp_piles, sp_player) ")")
853 sp_say(sp_player ": it is your turn!")
858 /^\.last/ && sp_state == "play" {
859 if (!isarray(sp_last))
860 say("No tricks have been taken!");
862 say(sp_last["player"] " took " \
863 sp_pretty(sp_last["pile"], FROM));
866 /^\.bids/ && sp_state == "bid" ||
867 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
869 _pile = sp_pretty(sp_piles, FROM)
874 _notify[0] = sp_player
875 for (_i in sp_share) {
876 if (sp_share[_i] != sp_player)
879 _extra = _extra " " _i "!"
881 _notify[length(_notify)] = _i
884 if (sp_state == "bid" && !_bids)
885 say("It is " sp_player "'s bid!" _extra)
886 if (sp_state == "bid" && _bids)
887 say("It is " sp_player "'s bid!" _extra " (" _bids ")")
888 if (sp_state == "play" && !_pile)
889 say("It is " sp_player "'s turn!" _extra)
890 if (sp_state == "play" && _pile)
891 say("It is " sp_player "'s turn!" _extra " (" _pile ")")
893 if (sp_state == "bid" || sp_state == "play") {
894 for (_i in _notify) {
895 if (_notify[_i] in sp_notify) {
896 _bids = _bids ? _bids : "none"
897 _pile = _pile ? sp_piles : "none"
898 mail_send(sp_notify[_notify[_i]], \
899 "It is your " sp_state "!", \
900 "Bids so far: " _bids "\n" \
901 "Cards played: " _pile)
902 say("Notified " _notify[_i] " at " sp_notify[_notify[_i]])
904 say("No email address for " _notify[_i])
909 for (_i=0; sp_state == "pass" && _i<4; _i++)
910 if (sp_passer(_i) && !sp_pass[_i])
911 say("Waiting for " sp_order[_i] " to pass a card!")
914 /^\.bids$/ && sp_state ~ "(pass|play)" {
915 say(sp_order[0] " bid " sp_bid(0) ", " \
916 sp_order[2] " bid " sp_bid(2) ", " \
917 "total: " sp_bids[0] + sp_bids[2])
918 say(sp_order[1] " bid " sp_bid(1) ", " \
919 sp_order[3] " bid " sp_bid(3) ", " \
920 "total: " sp_bids[1] + sp_bids[3])
923 /^\.tricks$/ && sp_state == "play" {
924 say(sp_order[0] " took " int(sp_tricks[0]) "/" sp_bid(0) ", " \
925 sp_order[2] " took " int(sp_tricks[2]) "/" sp_bid(2))
926 say(sp_order[1] " took " int(sp_tricks[1]) "/" sp_bid(1) ", " \
927 sp_order[3] " took " int(sp_tricks[3]) "/" sp_bid(3))
930 (TO == NICK || DST == sp_channel) &&
931 /^\.(score|status)$/ {
932 if (sp_state == "new") {
933 say("There is no game in progress")
935 if (sp_state ~ "join|bid|pass|play") {
937 sp_playto " points, " \
940 if (sp_state == "join") {
941 say("Waiting for players: " \
942 sp_order[0] " " sp_order[1] " " \
943 sp_order[2] " " sp_order[3])
945 if (sp_state ~ "bid|pass|play") {
946 say(sp_team(0) ": " \
947 int(sp_scores[0]) " points, " \
948 int(sp_bags(0)) " bags")
949 say(sp_team(1) ": " \
950 int(sp_scores[1]) " points, " \
951 int(sp_bags(1)) " bags")
955 (TO == NICK || DST == sp_channel) &&
957 say("http://pileus.org/andy/spades/" sp_log)
960 (TO == NICK || DST == sp_channel) &&
962 sp_stats("logs/" sp_log);
965 (TO == NICK || DST == sp_channel) &&
966 /^\.stats ([0-9]+_[0-9]+)(\.log)$/ {
967 gsub(/\.log$/, "", $2);
968 sp_stats("logs/" $2 ".log");
971 /^\.((new|end|load)game|join|look|bid|pass|play|notify)/ {
972 sp_save("var/sp_cur.json");