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_cur(list)
420 return list[length(list)-1]
423 function sp_stats(file, line, arr, time, user, turn, start, delay, extra)
426 while ((stat = getline line < file) > 0) {
428 if (!match(line, /^([0-9\- \:]*) \| (.*)$/, arr))
430 gsub(/[:-]/, " ", arr[1])
431 time = mktime(arr[1])
434 if (!match(arr[2], /^([^:]*): (.*)$/, arr))
438 # Record user latency
440 delay[turn][length(delay[turn])] = time - start
443 if (match(arr[2], /^(it is your|you .*(first|lead)!$)/, arr)) {
450 # Add current latency
452 delay[turn][length(delay[turn])] = systime() - start
453 debug("time: " (systime() - start))
458 reply("File does not exist: " file);
461 for (user in delay) {
462 extra = (user != turn) ? "" : \
463 ", " sp_delay(sp_cur(delay[user])) " (cur)";
464 say("latency for " user \
465 ": " sp_delay(sp_avg(delay[user])) " (avg)" \
466 ", " sp_delay(sp_max(delay[user])) " (max)" extra)
472 cmd = "od -An -N4 -td4 /dev/random"
478 sp_load("var/sp_cur.json");
480 # sp_say("Game restored.")
484 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : \
485 AUTH in sp_share ? sp_share[AUTH] : FROM
486 sp_valid = sp_from && sp_from == sp_player
492 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
497 sp_save("var/sp_save.json");
503 sp_load("var/sp_save.json");
509 say(".help spades -- play a game of spades")
512 /^\.help [Ss]pades$/ {
513 say("Spades -- play a game of spades")
514 say(".help game -- setup and administer the game")
515 say(".help play -- commands for playing spades")
516 say(".help auth -- control player authorization")
521 say(".newgame [score] -- start a game to <score> points, default 500")
522 say(".endgame -- abort the current game")
523 say(".savegame -- save the current game to disk")
524 say(".loadgame -- load the previously saved game")
529 say(".join -- join the current game")
530 say(".look -- look at your cards")
531 say(".bid [n] -- bid for <n> tricks")
532 say(".pass [card] -- pass a card to your partner")
533 say(".play [card] -- play a card")
534 say(".last -- show who took the previous trick")
535 say(".turn -- check whose turn it is")
536 say(".bids -- check what everyone bid")
537 say(".tricks -- check how many trick have been taken")
538 say(".score -- check the score")
543 say(".auth [who] -- display authentication info for a user")
544 say(".allow [who] -- allow another person to play on your behalf")
545 say(".deny [who] -- prevent a previously allowed user from playing")
546 say(".show -- display which users can play for which players")
547 say(".notify [addr] -- email user when it is their turn")
553 /^\.deal (\w+) (.*)/ {
554 sp_say(FROM " is cheating for " $2)
556 for (i=3; i<=NF; i++)
562 /^\.order (\w+) ([0-4])/ {
563 sp_say(FROM " is cheating for " $2)
566 sp_player = sp_order[sp_turn]
570 sp_state == "play" &&
571 /^\.force (\w+) (\S+)$/ {
572 sp_say(FROM " is cheating for " $2)
580 match($0, /^\.newgame ?([1-9][0-9]*) *- *([1-9][0-9]*)$/, _arr) {
581 if (_arr[2] > _arr[1])
582 $0 = $1 " " int(rand() * (_arr[2]-_arr[1])+_arr[1])
585 /^\.newgame ?([1-9][0-9]*)?$/ {
586 if (sp_state != "new") {
587 reply("There is already a game in progress.")
591 sp_playto = $2 ? $2 : 200
592 sp_limit = sp_playto > 200 ? 10 : 5;
595 sp_log = strftime("%Y%m%d_%H%M%S.log")
596 sp_say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
600 (sp_from == sp_owner || AUTH == OWNER) &&
602 if (sp_state == "new") {
603 reply("There is no game in progress.")
605 sp_say(FROM " ends the game")
611 if (sp_state == "new") {
612 reply("There is no game in progress")
614 else if (sp_state == "play") {
615 reply("The game has already started")
617 else if (sp_state == "join" && sp_from in sp_players) {
618 reply("You are already playing")
620 else if (sp_state == "join") {
624 sp_auths[AUTH] = FROM
626 sp_say(FROM " joins the game!")
628 if (sp_state == "join" && sp_turn == 0) {
635 _who = $2 in USERS ? USERS[$2]["auth"] : ""
636 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
637 if (sp_state ~ "new|join") {
638 reply("The game has not yet started")
640 else if (!(sp_from in sp_players)) {
641 reply("You are not playing")
644 reply(_str " is not logged in")
646 else if (_who in sp_players || _who in sp_auths) {
647 reply(_str " is a primary player")
649 else if (_who in sp_share) {
650 reply(_str " is already playing for " sp_share[_who])
653 sp_say(_str " can now play for " sp_from)
654 sp_share[_who] = sp_from
659 _who = $2 in USERS ? USERS[$2]["auth"] : $2
660 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
661 if (sp_state ~ "new|join") {
662 reply("The game has not yet started")
664 else if (!(sp_from in sp_players)) {
665 reply("You are not playing")
667 else if (_who in sp_players || _who in sp_auths) {
668 reply(_str " is a primary player")
670 else if (!(_who in sp_share) || sp_share[_who] != sp_from) {
671 reply(_str " is not playing for " sp_from)
674 sp_say(_str " can no longer play for " sp_from)
675 delete sp_share[_who]
680 if (!(sp_from in sp_players))
681 reply("You are not playing")
682 else if (sp_from == FROM)
683 say(FROM " has an existential crisis")
685 reply("You are playing for " sp_from);
689 if (sp_from in sp_notify)
690 reply("Your address is " sp_notify[sp_from])
692 reply("Your address is not set")
696 if (sp_from in sp_notify) {
697 reply("Removing address " sp_notify[sp_from])
698 delete sp_notify[sp_from]
700 reply("Your address is not set")
704 /^\.notify \S+@\S+.\S+$/ {
706 gsub(/[^a-zA-Z0-9_+@.-]/, "", _addr)
707 sp_notify[sp_from] = _addr
708 reply("Notifying you at " _addr)
711 sp_state ~ "(bid|pass|play)" &&
715 _lines[sp_share[_i]] = _lines[sp_share[_i]] " " _i
717 sp_say(_i " allowed:" _lines[_i])
721 (sp_state == "bid" || sp_state == "play") &&
723 if (sp_from in sp_players)
724 reply("It is not your turn.")
726 reply("You are not playing.")
731 /^\.bid (0|[1-9][0-9]*)$/ {
732 if ($2 < 0 || $2 > 13) {
733 reply("You can only bid from 0 to 13")
737 if ($2 == 0 && !sp_looked[i]) {
738 sp_say(FROM " goes blind nil!")
740 } else if ($2 == 0) {
741 sp_say(FROM " goes nil!")
746 if (sp_turn != sp_dealer) {
747 sp_say(sp_player ": it is your bid! (" sp_bidders() ")")
749 sp_say(sp_extra() " (" sp_bidders() ")")
750 for (p in sp_players)
751 say(p, "You have: " sp_hand(p, p))
753 for (i=0; i<2; i++) {
755 sp_say(sp_team(i) ": select a card to pass " \
756 "(/msg " NICK " .pass <card>)")
760 if (sp_state == "play")
761 sp_say(sp_player ": you have the opening lead!")
766 sp_state == "pass" &&
769 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
771 # check validity and pass
772 if (!(sp_from in sp_players)) {
773 reply("You are not playing.")
775 else if (!sp_passer(_team)) {
776 reply("Your team did not go blind")
778 else if (sp_pass[sp_players[sp_from]]) {
779 reply("You have already passed a card")
781 else if (!(_card in sp_deck)) {
782 reply("Invalid card")
784 else if (!(_card in sp_hands[sp_from])) {
785 reply("You do not have that card")
788 sp_pass[sp_players[sp_from]] = $2
789 sp_say(FROM " passes a card")
792 # check for end of passing
793 if ((!sp_passer(0) || (sp_pass[0] && sp_pass[2])) &&
794 (!sp_passer(1) || (sp_pass[1] && sp_pass[3]))) {
798 delete sp_hands[sp_order[i]][_card]
799 sp_hands[sp_order[_partner]][_card] = 1
801 sp_say("Cards have been passed!")
802 sp_say(sp_player ": you have the opening lead!")
803 for (p in sp_players)
804 say(p, "You have: " sp_hand(p, p))
809 sp_state ~ "(bid|pass|play)" &&
811 if (!(sp_from in sp_players)) {
812 reply("You are not playing.")
814 sp_looked[sp_players[sp_from]] = 1
815 say(FROM, "You have: " sp_hand(FROM, sp_from))
820 sp_state == "play" &&
823 gsub(/[^A-Za-z0-9]/, "", _card);
824 if (!(_card in sp_deck)) {
825 reply("Invalid card")
827 else if (sp_suit && _card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
828 reply("You must follow suit (" sp_suit ")")
830 else if (_card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
831 reply("You cannot trump on the first hand")
833 else if (_card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
834 reply("Spades have not been broken")
836 else if (!(_card in sp_hands[sp_from])) {
837 reply("You do not have that card")
841 if (sp_state == "play") {
842 if (length(sp_hands[sp_from]))
843 say(FROM, "You have: " sp_hand(FROM, sp_from))
845 sp_say(sp_player ": it is your turn! " \
846 "(" sp_pretty(sp_piles, sp_player) ")")
848 sp_say(sp_player ": it is your turn!")
853 /^\.last/ && sp_state == "play" {
854 if (!isarray(sp_last))
855 say("No tricks have been taken!");
857 say(sp_last["player"] " took " \
858 sp_pretty(sp_last["pile"], FROM));
861 /^\.bids/ && sp_state == "bid" ||
862 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
864 _pile = sp_pretty(sp_piles, FROM)
868 if (/!/ && sp_share[_i] == sp_player)
869 _extra = _extra " " _i "!"
871 if (sp_state == "bid" && !_bids)
872 say("It is " sp_player "'s bid!" _extra)
873 if (sp_state == "bid" && _bids)
874 say("It is " sp_player "'s bid!" _extra " (" _bids ")")
875 if (sp_state == "play" && !_pile)
876 say("It is " sp_player "'s turn!" _extra)
877 if (sp_state == "play" && _pile)
878 say("It is " sp_player "'s turn!" _extra " (" _pile ")")
880 for (_i=0; sp_state == "pass" && _i<4; _i++)
881 if (sp_passer(_i) && !sp_pass[_i])
882 say("Waiting for " sp_order[_i] " to pass a card!")
884 if (/!!/ && (sp_state == "bid" || sp_state == "play")) {
885 if (sp_player in sp_notify) {
886 _bids = _bids ? _bids : "none"
887 _pile = _pile ? sp_piles : "none"
888 mail_send(sp_notify[sp_player], \
889 "It is your " sp_state "!", \
890 "Bids so far: " _bids "\n" \
891 "Cards played: " _pile)
892 say("Notified " sp_player " at " sp_notify[sp_player])
894 say("No email address for " sp_player)
899 /^\.bids$/ && sp_state ~ "(pass|play)" {
900 say(sp_order[0] " bid " sp_bid(0) ", " \
901 sp_order[2] " bid " sp_bid(2) ", " \
902 "total: " sp_bids[0] + sp_bids[2])
903 say(sp_order[1] " bid " sp_bid(1) ", " \
904 sp_order[3] " bid " sp_bid(3) ", " \
905 "total: " sp_bids[1] + sp_bids[3])
908 /^\.tricks$/ && sp_state == "play" {
909 say(sp_order[0] " took " int(sp_tricks[0]) "/" sp_bid(0) ", " \
910 sp_order[2] " took " int(sp_tricks[2]) "/" sp_bid(2))
911 say(sp_order[1] " took " int(sp_tricks[1]) "/" sp_bid(1) ", " \
912 sp_order[3] " took " int(sp_tricks[3]) "/" sp_bid(3))
915 (TO == NICK || DST == sp_channel) &&
916 /^\.(score|status)$/ {
917 if (sp_state == "new") {
918 say("There is no game in progress")
920 if (sp_state ~ "join|bid|pass|play") {
922 sp_playto " points, " \
925 if (sp_state == "join") {
926 say("Waiting for players: " \
927 sp_order[0] " " sp_order[1] " " \
928 sp_order[2] " " sp_order[3])
930 if (sp_state ~ "bid|pass|play") {
931 say(sp_team(0) ": " \
932 int(sp_scores[0]) " points, " \
933 int(sp_bags(0)) " bags")
934 say(sp_team(1) ": " \
935 int(sp_scores[1]) " points, " \
936 int(sp_bags(1)) " bags")
940 (TO == NICK || DST == sp_channel) &&
942 say("http://pileus.org/andy/spades/" sp_log)
945 (TO == NICK || DST == sp_channel) &&
947 sp_stats("logs/" sp_log);
950 (TO == NICK || DST == sp_channel) &&
951 /^\.stats ([0-9]+_[0-9]+)(\.log)$/ {
952 gsub(/\.log$/, "", $2);
953 sp_stats("logs/" $2 ".log");
956 /^\.((new|end|load)game|join|look|bid|pass|play|notify)/ {
957 sp_save("var/sp_cur.json");