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"]);
162 print strftime("%Y-%m-%d %H:%M:%S | ") msg >> "logs/" sp_log
163 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, 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 extra = (user != turn) ? "" : \
465 ", " sp_delay(sp_cur(delay[user])) " (cur)";
466 say("latency for " user \
467 ": " sp_delay(sp_avg(delay[user])) " (avg)" \
468 ", " sp_delay(sp_max(delay[user])) " (max)" extra)
474 cmd = "od -An -N4 -td4 /dev/random"
480 sp_load("var/sp_cur.json")
481 sp_sock = "/inet/udp/0/localhost/6173"
482 print "starting rhawk" |& sp_sock
484 # sp_say("Game restored.")
488 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : \
489 AUTH in sp_share ? sp_share[AUTH] : FROM
490 sp_valid = sp_from && sp_from == sp_player
496 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
501 sp_save("var/sp_save.json");
507 sp_load("var/sp_save.json");
513 say(".help spades -- play a game of spades")
516 /^\.help [Ss]pades$/ {
517 say("Spades -- play a game of spades")
518 say(".help game -- setup and administer the game")
519 say(".help play -- commands for playing spades")
520 say(".help auth -- control player authorization")
525 say(".newgame [score] -- start a game to <score> points, default 500")
526 say(".endgame -- abort the current game")
527 say(".savegame -- save the current game to disk")
528 say(".loadgame -- load the previously saved game")
533 say(".join -- join the current game")
534 say(".look -- look at your cards")
535 say(".bid [n] -- bid for <n> tricks")
536 say(".pass [card] -- pass a card to your partner")
537 say(".play [card] -- play a card")
538 say(".last -- show who took the previous trick")
539 say(".turn -- check whose turn it is")
540 say(".bids -- check what everyone bid")
541 say(".tricks -- check how many trick have been taken")
542 say(".score -- check the score")
547 say(".auth [who] -- display authentication info for a user")
548 say(".allow [who] -- allow another person to play on your behalf")
549 say(".deny [who] -- prevent a previously allowed user from playing")
550 say(".show -- display which users can play for which players")
551 say(".notify [addr] -- email user when it is their turn")
557 /^\.deal (\w+) (.*)/ {
558 sp_say(FROM " is cheating for " $2)
560 for (i=3; i<=NF; i++)
566 /^\.order (\w+) ([0-4])/ {
567 sp_say(FROM " is cheating for " $2)
570 sp_player = sp_order[sp_turn]
574 sp_state == "play" &&
575 /^\.force (\w+) (\S+)$/ {
576 sp_say(FROM " is cheating for " $2)
584 match($0, /^\.newgame ?([1-9][0-9]*) *- *([1-9][0-9]*)$/, _arr) {
585 if (_arr[2] > _arr[1])
586 $0 = $1 " " int(rand() * (_arr[2]-_arr[1])+_arr[1])
589 /^\.newgame ?([1-9][0-9]*)?$/ {
590 if (sp_state != "new") {
591 reply("There is already a game in progress.")
595 sp_playto = $2 ? $2 : 200
596 sp_limit = sp_playto > 200 ? 10 : 5;
599 sp_log = strftime("%Y%m%d_%H%M%S.log")
600 sp_say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
604 (sp_from == sp_owner || AUTH == OWNER) &&
606 if (sp_state == "new") {
607 reply("There is no game in progress.")
609 sp_say(FROM " ends the game")
615 if (sp_state == "new") {
616 reply("There is no game in progress")
618 else if (sp_state == "play") {
619 reply("The game has already started")
621 else if (sp_state == "join" && sp_from in sp_players) {
622 reply("You are already playing")
624 else if (sp_state == "join") {
628 sp_auths[AUTH] = FROM
630 sp_say(FROM " joins the game!")
632 if (sp_state == "join" && sp_turn == 0) {
639 _who = $2 in USERS ? USERS[$2]["auth"] : ""
640 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
641 if (sp_state ~ "new|join") {
642 reply("The game has not yet started")
644 else if (!(sp_from in sp_players)) {
645 reply("You are not playing")
648 reply(_str " is not logged in")
650 else if (_who in sp_players || _who in sp_auths) {
651 reply(_str " is a primary player")
653 else if (_who in sp_share) {
654 reply(_str " is already playing for " sp_share[_who])
657 sp_say(_str " can now play for " sp_from)
658 sp_share[_who] = sp_from
663 _who = $2 in USERS ? USERS[$2]["auth"] : $2
664 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
665 if (sp_state ~ "new|join") {
666 reply("The game has not yet started")
668 else if (!(sp_from in sp_players)) {
669 reply("You are not playing")
671 else if (_who in sp_players || _who in sp_auths) {
672 reply(_str " is a primary player")
674 else if (!(_who in sp_share) || sp_share[_who] != sp_from) {
675 reply(_str " is not playing for " sp_from)
678 sp_say(_str " can no longer play for " sp_from)
679 delete sp_share[_who]
684 if (!(sp_from in sp_players))
685 reply("You are not playing")
686 else if (sp_from == FROM)
687 say(FROM " has an existential crisis")
689 reply("You are playing for " sp_from);
693 if (sp_from in sp_notify)
694 reply("Your address is " sp_notify[sp_from])
696 reply("Your address is not set")
700 if (sp_from in sp_notify) {
701 reply("Removing address " sp_notify[sp_from])
702 delete sp_notify[sp_from]
704 reply("Your address is not set")
708 /^\.notify \S+@\S+.\S+$/ {
710 gsub(/[^a-zA-Z0-9_+@.-]/, "", _addr)
711 sp_notify[sp_from] = _addr
712 reply("Notifying you at " _addr)
715 sp_state ~ "(bid|pass|play)" &&
719 _lines[sp_share[_i]] = _lines[sp_share[_i]] " " _i
721 say(_i " allowed:" _lines[_i])
725 (sp_state == "bid" || sp_state == "play") &&
727 if (sp_from in sp_players)
728 reply("It is not your turn.")
730 reply("You are not playing.")
735 /^\.bid (0|[1-9][0-9]*)$/ {
736 if ($2 < 0 || $2 > 13) {
737 reply("You can only bid from 0 to 13")
741 if ($2 == 0 && !sp_looked[i]) {
742 sp_say(FROM " goes blind nil!")
744 } else if ($2 == 0) {
745 sp_say(FROM " goes nil!")
750 if (sp_turn != sp_dealer) {
751 sp_say(sp_player ": it is your bid! (" sp_bidders() ")")
753 sp_say(sp_extra() " (" sp_bidders() ")")
754 for (p in sp_players)
755 say(p, "You have: " sp_hand(p, p))
757 for (i=0; i<2; i++) {
759 sp_say(sp_team(i) ": select a card to pass " \
760 "(/msg " NICK " .pass <card>)")
764 if (sp_state == "play")
765 sp_say(sp_player ": you have the opening lead!")
770 sp_state == "pass" &&
773 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
775 # check validity and pass
776 if (!(sp_from in sp_players)) {
777 reply("You are not playing.")
779 else if (!sp_passer(_team)) {
780 reply("Your team did not go blind")
782 else if (sp_pass[sp_players[sp_from]]) {
783 reply("You have already passed a card")
785 else if (!(_card in sp_deck)) {
786 reply("Invalid card")
788 else if (!(_card in sp_hands[sp_from])) {
789 reply("You do not have that card")
792 sp_pass[sp_players[sp_from]] = $2
793 sp_say(FROM " passes a card")
796 # check for end of passing
797 if ((!sp_passer(0) || (sp_pass[0] && sp_pass[2])) &&
798 (!sp_passer(1) || (sp_pass[1] && sp_pass[3]))) {
802 delete sp_hands[sp_order[i]][_card]
803 sp_hands[sp_order[_partner]][_card] = 1
805 sp_say("Cards have been passed!")
806 sp_say(sp_player ": you have the opening lead!")
807 for (p in sp_players)
808 say(p, "You have: " sp_hand(p, p))
813 sp_state ~ "(bid|pass|play)" &&
815 if (!(sp_from in sp_players)) {
816 reply("You are not playing.")
818 sp_looked[sp_players[sp_from]] = 1
819 say(FROM, "You have: " sp_hand(FROM, sp_from))
824 sp_state == "play" &&
827 gsub(/[^A-Za-z0-9]/, "", _card);
828 if (!(_card in sp_deck)) {
829 reply("Invalid card")
831 else if (sp_suit && _card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
832 reply("You must follow suit (" sp_suit ")")
834 else if (_card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
835 reply("You cannot trump on the first hand")
837 else if (_card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
838 reply("Spades have not been broken")
840 else if (!(_card in sp_hands[sp_from])) {
841 reply("You do not have that card")
845 if (sp_state == "play") {
846 if (length(sp_hands[sp_from]))
847 say(FROM, "You have: " sp_hand(FROM, sp_from))
849 sp_say(sp_player ": it is your turn! " \
850 "(" sp_pretty(sp_piles, sp_player) ")")
852 sp_say(sp_player ": it is your turn!")
857 /^\.last/ && sp_state == "play" {
858 if (!isarray(sp_last))
859 say("No tricks have been taken!");
861 say(sp_last["player"] " took " \
862 sp_pretty(sp_last["pile"], FROM));
865 /^\.bids/ && sp_state == "bid" ||
866 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
868 _pile = sp_pretty(sp_piles, FROM)
873 _notify[0] = sp_player
874 for (_i in sp_share) {
875 if (sp_share[_i] != sp_player)
878 _extra = _extra " " _i "!"
880 _notify[length(_notify)] = _i
883 if (sp_state == "bid" && !_bids)
884 say("It is " sp_player "'s bid!" _extra)
885 if (sp_state == "bid" && _bids)
886 say("It is " sp_player "'s bid!" _extra " (" _bids ")")
887 if (sp_state == "play" && !_pile)
888 say("It is " sp_player "'s turn!" _extra)
889 if (sp_state == "play" && _pile)
890 say("It is " sp_player "'s turn!" _extra " (" _pile ")")
892 if (sp_state == "bid" || sp_state == "play") {
893 for (_i in _notify) {
894 if (_notify[_i] in sp_notify) {
895 _bids = _bids ? _bids : "none"
896 _pile = _pile ? sp_piles : "none"
897 mail_send(sp_notify[_notify[_i]], \
898 "It is your " sp_state "!", \
899 "Bids so far: " _bids "\n" \
900 "Cards played: " _pile)
901 say("Notified " _notify[_i] " at " sp_notify[_notify[_i]])
903 say("No email address for " _notify[_i])
908 for (_i=0; sp_state == "pass" && _i<4; _i++)
909 if (sp_passer(_i) && !sp_pass[_i])
910 say("Waiting for " sp_order[_i] " to pass a card!")
913 /^\.bids$/ && sp_state ~ "(pass|play)" {
914 say(sp_order[0] " bid " sp_bid(0) ", " \
915 sp_order[2] " bid " sp_bid(2) ", " \
916 "total: " sp_bids[0] + sp_bids[2])
917 say(sp_order[1] " bid " sp_bid(1) ", " \
918 sp_order[3] " bid " sp_bid(3) ", " \
919 "total: " sp_bids[1] + sp_bids[3])
922 /^\.tricks$/ && sp_state == "play" {
923 say(sp_order[0] " took " int(sp_tricks[0]) "/" sp_bid(0) ", " \
924 sp_order[2] " took " int(sp_tricks[2]) "/" sp_bid(2))
925 say(sp_order[1] " took " int(sp_tricks[1]) "/" sp_bid(1) ", " \
926 sp_order[3] " took " int(sp_tricks[3]) "/" sp_bid(3))
929 (TO == NICK || DST == sp_channel) &&
930 /^\.(score|status)$/ {
931 if (sp_state == "new") {
932 say("There is no game in progress")
934 if (sp_state ~ "join|bid|pass|play") {
936 sp_playto " points, " \
939 if (sp_state == "join") {
940 say("Waiting for players: " \
941 sp_order[0] " " sp_order[1] " " \
942 sp_order[2] " " sp_order[3])
944 if (sp_state ~ "bid|pass|play") {
945 say(sp_team(0) ": " \
946 int(sp_scores[0]) " points, " \
947 int(sp_bags(0)) " bags")
948 say(sp_team(1) ": " \
949 int(sp_scores[1]) " points, " \
950 int(sp_bags(1)) " bags")
954 (TO == NICK || DST == sp_channel) &&
956 say("http://pileus.org/andy/spades/" sp_log)
959 (TO == NICK || DST == sp_channel) &&
961 sp_stats("logs/" sp_log);
964 (TO == NICK || DST == sp_channel) &&
965 /^\.stats ([0-9]+_[0-9]+)(\.log)$/ {
966 gsub(/\.log$/, "", $2);
967 sp_stats("logs/" $2 ".log");
970 /^\.((new|end|load)game|join|look|bid|pass|play|notify)/ {
971 sp_save("var/sp_cur.json");