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
59 delete sp_teams # [i] Teams names
64 sp_channel = "" # channel to play in
65 sp_log = "" # Log file name
66 sp_sock = "" # UDP log socket
67 delete sp_notify # [p] E-mail notification address
71 function sp_acopy(dst, src, key)
76 json_copy(dst, key, src[key])
80 function sp_save(file, game)
83 game["suit"] = sp_suit;
84 game["piles"] = sp_piles;
85 json_copy(game, "pile", sp_pile);
88 game["state"] = sp_state;
89 game["broken"] = sp_broken;
90 json_copy(game, "last", sp_last);
91 json_copy(game, "looked", sp_looked);
92 json_copy(game, "bids", sp_bids);
93 json_copy(game, "nil", sp_nil);
94 json_copy(game, "pass", sp_pass);
95 json_copy(game, "tricks", sp_tricks);
98 game["owner"] = sp_owner;
99 game["playto"] = sp_playto;
100 game["dealer"] = sp_dealer;
101 game["turn"] = sp_turn;
102 game["player"] = sp_player;
103 game["limit"] = sp_limit;
104 json_copy(game, "hands", sp_hands);
105 json_copy(game, "players", sp_players);
106 json_copy(game, "auths", sp_auths);
107 json_copy(game, "share", sp_share);
108 json_copy(game, "order", sp_order);
109 json_copy(game, "scores", sp_scores);
110 json_copy(game, "teams", sp_teams);
113 game["channel"] = sp_channel;
114 game["log"] = sp_log;
115 json_copy(game, "notify", sp_notify);
118 json_save(file, game);
121 function sp_load(file, game)
124 if (!json_load(file, game))
128 sp_suit = game["suit"];
129 sp_piles = game["piles"];
130 sp_acopy(sp_pile, game["pile"]);
133 sp_state = game["state"];
134 sp_broken = game["broken"];
135 sp_acopy(sp_last, game["last"]);
136 sp_acopy(sp_looked, game["looked"]);
137 sp_acopy(sp_bids, game["bids"]);
138 sp_acopy(sp_nil, game["nil"]);
139 sp_acopy(sp_pass, game["pass"]);
140 sp_acopy(sp_tricks, game["tricks"]);
143 sp_owner = game["owner"];
144 sp_playto = game["playto"];
145 sp_dealer = game["dealer"];
146 sp_turn = game["turn"];
147 sp_player = game["player"];
148 sp_limit = game["limit"];
149 sp_acopy(sp_hands, game["hands"]);
150 sp_acopy(sp_players, game["players"]);
151 sp_acopy(sp_auths, game["auths"]);
152 sp_acopy(sp_share, game["share"]);
153 sp_acopy(sp_order, game["order"]);
154 sp_acopy(sp_scores, game["scores"]);
155 sp_acopy(sp_teams, game["teams"]);
158 sp_channel = game["channel"];
159 sp_log = game["log"];
160 sp_acopy(sp_notify, game["notify"]);
167 print strftime("%Y-%m-%d %H:%M:%S | ") msg >> "logs/" sp_log
168 fflush("logs/" sp_log)
171 function sp_pretty(cards, who)
174 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
175 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
177 if (!nounicode[who]) {
178 gsub(/s/, "\002♠", cards)
179 gsub(/h/, "\002♥", cards)
180 gsub(/d/, "\002♦", cards)
181 gsub(/c/, "\002♣", cards)
186 function sp_next(who, prev)
189 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
190 if (length(sp_order) == 4)
191 sp_player = sp_order[sp_turn]
195 function sp_shuf(i, mixed)
197 sp_usort(sp_players, mixed)
199 sp_order[i-1] = mixed[i]
200 sp_players[mixed[i]] = i-1
204 function sp_deal( shuf)
206 sp_say("/me deals the cards")
207 sp_usort(sp_deck, shuf)
208 for (i=1; i<=52; i++)
209 sp_hands[sp_order[i%4]][shuf[i]] = 1
211 sp_dealer = (sp_dealer+1)%4
213 sp_player = sp_order[sp_turn]
214 sp_say(sp_player ": you bid first!")
217 function sp_hand(to, who, sort, str)
219 asorti(sp_hands[who], sort, "sp_csort")
220 for (i=0; i<length(sort); i++)
221 str = str "" sprintf("%4s", sort[i])
222 gsub(/^ +| +$/, "", str)
223 return sp_pretty(str, to)
226 function sp_hasa(who, expr)
228 for (c in sp_hands[who]) {
235 function sp_type(card)
237 return substr(card, length(card))
240 function sp_usort(list, out) {
243 asorti(out, out, "@val_num_asc")
246 function sp_csort(i1,v1,i2,v2) {
247 return sp_deck[i1] > sp_deck[i2] ? +1 :
248 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
251 function sp_winner( card, tmp)
253 for (card in sp_pile)
254 if (card !~ sp_suit && card !~ /s/)
256 asorti(sp_pile, tmp, "sp_csort")
257 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
261 function sp_team(i, players)
263 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
264 if ((i in sp_teams) && !players)
267 return sp_order[i+0] "/" sp_order[i+2]
270 function sp_bags(i, bags)
272 bags = sp_scores[i] % sp_limit
280 return sp_nil[who] == 0 ? sp_bids[who] :
281 sp_nil[who] == 1 ? "nil" :
282 sp_nil[who] == 2 ? "blind" : "n/a"
285 function sp_passer(who)
287 return sp_nil[(who+0)%4] == 2 || sp_nil[(who+1)%4] != 0 ||
288 sp_nil[(who+2)%4] == 2 || sp_nil[(who+3)%4] != 0
291 function sp_bidders( i, turn, bid, bids)
293 for (i = 0; i < 4; i++) {
294 turn = (sp_dealer + i) % 4
295 if (bid = sp_bid(turn))
296 bids = bids " " sp_order[turn] ":" bid
298 gsub(/^ +| +$/, "", bids)
302 function sp_extra( n, s)
304 n = sp_bids[0] + sp_bids[1] + sp_bids[2] + sp_bids[3];
305 s = n == 12 || n == 14 ? "" : "s";
307 return n<13 ? "Playing with " 13-n " bag" s "!" :
308 n>13 ? "Fighting for " n-13 " trick" s "!" : "No bags!";
311 function sp_score( bids, times, tricks)
313 for (i=0; i<2; i++) {
314 bids = sp_bids[i] + sp_bids[i+2]
315 tricks = sp_tricks[i] + sp_tricks[i+2]
317 times = int((sp_bags(i) + bags) / sp_limit)
319 sp_say(sp_team(i) " bag" (times>1?" way ":" ") "out")
320 sp_scores[i] -= sp_limit * 10 * times;
322 if (tricks >= bids) {
323 sp_say(sp_team(i) " make their bid: " tricks "/" bids)
324 sp_scores[i] += bids*10 + bags;
326 sp_say(sp_team(i) " go bust: " tricks "/" bids)
327 sp_scores[i] -= bids*10;
330 for (i=0; i<4; i++) {
333 sp_say(sp_order[i] " " \
334 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
335 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
336 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
337 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
339 sp_scores[i%2] += sp_limit * 10 * sp_nil[i] * \
340 (sp_tricks[i] == 0 ? 1 : -1)
342 if (sp_scores[0] > sp_scores[1])
343 sp_say(sp_team(0) " lead " sp_scores[0] " to " sp_scores[1] " of " sp_playto)
344 else if (sp_scores[1] > sp_scores[0])
345 sp_say(sp_team(1) " lead " sp_scores[1] " to " sp_scores[0] " of " sp_playto)
347 sp_say("tied at " sp_scores[0] " of " sp_playto)
350 function sp_play(card, winner, pi)
352 delete sp_hands[sp_from][card]
353 sp_pile[card] = sp_player
354 sp_piles = sp_piles (sp_piles?",":"") card
361 if (length(sp_pile) == 1)
362 sp_suit = sp_type(card)
365 if (length(sp_pile) == 4) {
367 pi = sp_players[sp_pile[winner]]
369 sp_say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
370 " (" sp_pretty(sp_piles, FROM) ")")
371 sp_last["player"] = sp_pile[winner];
372 sp_last["pile"] = sp_piles;
373 sp_next(sp_pile[winner])
378 if (sp_tricks[0] + sp_tricks[1] + \
379 sp_tricks[2] + sp_tricks[3] == 13) {
380 sp_say("Round over!")
382 if ((sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto) &&
383 (sp_scores[0] != sp_scores[1])) {
385 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
387 say(CHANNEL, sp_team(winner) " wins the game " \
388 sp_scores[winner] " to " sp_scores[looser])
389 say(CHANNEL, sp_order[winner+0] "++")
390 say(CHANNEL, sp_order[winner+2] "++")
394 if (sp_scores[0] == sp_scores[1] &&
395 sp_scores[0] >= sp_playto)
396 sp_say("It's a tie! Playing an extra round!");
404 function sp_delay(sec)
406 return (sec > 60*60*24 ? int(sec/60/60/24) "d " : "") \
407 (sec > 60*60 ? int(sec/60/60)%24 "h " : "") \
411 function sp_max(list, i, max)
413 for (i=0; i<length(list); i++)
414 if (max == "" || list[i] > max)
419 function sp_avg(list, i, sum)
421 for (i=0; i<length(list); i++)
423 return sum / length(list)
426 function sp_cur(list)
428 return list[length(list)-1]
431 function sp_stats(file, line, arr, time, user, turn, start, delay, short, extra)
434 while ((stat = getline line < file) > 0) {
436 if (!match(line, /^([0-9\- \:]*) \| (.*)$/, arr))
438 gsub(/[:-]/, " ", arr[1])
439 time = mktime(arr[1])
442 if (!match(arr[2], /^([^:]*): (.*)$/, arr))
446 # Record user latency
448 delay[turn][length(delay[turn])] = time - start
451 if (match(arr[2], /^(it is your|you .*(first|lead)!$)/, arr)) {
458 # Add current latency
460 delay[turn][length(delay[turn])] = systime() - start
461 debug("time: " (systime() - start))
466 reply("File does not exist: " file);
469 for (user in delay) {
470 short = length(user) <= 4 ? user : substr(user, 0, 4)
471 extra = (user != turn) ? "" : \
472 ", " sp_delay(sp_cur(delay[user])) " (cur)";
473 say("latency for " short \
474 ": " sp_delay(sp_avg(delay[user])) " (avg)" \
475 ", " sp_delay(sp_max(delay[user])) " (max)" extra)
481 cmd = "od -An -N4 -td4 /dev/random"
487 sp_load("var/sp_cur.json")
488 sp_sock = "/inet/udp/0/localhost/6173"
489 print "starting rhawk" |& sp_sock
491 # sp_say("Game restored.")
495 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : \
496 AUTH in sp_share ? sp_share[AUTH] : FROM
497 sp_valid = sp_from && sp_from == sp_player
503 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
508 sp_save("var/sp_save.json");
514 sp_load("var/sp_save.json");
520 say(".help spades -- play a game of spades")
523 /^\.help [Ss]pades$/ {
524 say("Spades -- play a game of spades")
525 say(".help game -- setup and administer the game")
526 say(".help play -- commands for playing spades")
527 say(".help auth -- control player authorization")
532 say(".newgame [score] -- start a game to <score> points, default 300")
533 say(".endgame -- abort the current game")
534 say(".savegame -- save the current game to disk")
535 say(".loadgame -- load the previously saved game")
540 say(".join -- join the current game")
541 say(".look -- look at your cards")
542 say(".bid [n] -- bid for <n> tricks")
543 say(".pass [card] -- pass a card to your partner")
544 say(".play [card] -- play a card")
545 say(".team [name] -- set your team name")
546 say(".last -- show who took the previous trick")
547 say(".turn -- check whose turn it is")
548 say(".bids -- check what everyone bid")
549 say(".tricks -- check how many trick have been taken")
550 say(".score -- check the score")
555 say(".auth [who] -- display authentication info for a user")
556 say(".allow [who] -- allow another person to play on your behalf")
557 say(".deny [who] -- prevent a previously allowed user from playing")
558 say(".show -- display which users can play for which players")
559 say(".notify [addr] -- email user when it is their turn")
565 /^\.deal (\w+) (.*)/ {
566 sp_say(FROM " is cheating for " $2)
568 for (i=3; i<=NF; i++)
574 /^\.order (\w+) ([0-4])/ {
575 sp_say(FROM " is cheating for " $2)
578 sp_player = sp_order[sp_turn]
582 sp_state == "play" &&
583 /^\.force (\w+) (\S+)$/ {
584 sp_say(FROM " is cheating for " $2)
592 match($0, /^\.newgame ?([1-9][0-9]*) *- *([1-9][0-9]*)$/, _arr) {
593 if (_arr[2] > _arr[1])
594 $0 = $1 " " int(rand() * (_arr[2]-_arr[1])+_arr[1])
597 /^\.newgame ?([1-9][0-9]*)?$/ {
598 if (sp_state != "new") {
599 reply("There is already a game in progress.")
603 sp_playto = $2 ? $2 : 300
604 sp_limit = sp_playto > 200 ? 10 : 5;
607 sp_log = strftime("%Y%m%d_%H%M%S.log")
608 sp_say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
612 (sp_from == sp_owner || AUTH == OWNER) &&
614 if (sp_state == "new") {
615 reply("There is no game in progress.")
617 sp_say(FROM " ends the game")
623 if (sp_state == "new") {
624 reply("There is no game in progress")
626 else if (sp_state == "play") {
627 reply("The game has already started")
629 else if (sp_state == "join" && sp_from in sp_players) {
630 reply("You are already playing")
632 else if (sp_state == "join") {
636 sp_auths[AUTH] = FROM
638 sp_say(FROM " joins the game!")
640 if (sp_state == "join" && sp_turn == 0) {
647 _who = $2 in USERS ? USERS[$2]["auth"] : ""
648 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
649 if (sp_state ~ "new|join") {
650 reply("The game has not yet started")
652 else if (!(sp_from in sp_players)) {
653 reply("You are not playing")
656 reply(_str " is not logged in")
658 else if (_who in sp_players || _who in sp_auths) {
659 reply(_str " is a primary player")
661 else if (_who in sp_share) {
662 reply(_str " is already playing for " sp_share[_who])
665 sp_say(_str " can now play for " sp_from)
666 sp_share[_who] = sp_from
671 _who = $2 in USERS ? USERS[$2]["auth"] : $2
672 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
673 if (sp_state ~ "new|join") {
674 reply("The game has not yet started")
676 else if (!(sp_from in sp_players)) {
677 reply("You are not playing")
679 else if (_who in sp_players || _who in sp_auths) {
680 reply(_str " is a primary player")
682 else if (!(_who in sp_share) || sp_share[_who] != sp_from) {
683 reply(_str " is not playing for " sp_from)
686 sp_say(_str " can no longer play for " sp_from)
687 delete sp_share[_who]
692 gsub(/^\.team */, "")
693 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
694 if (sp_state ~ "new|join") {
695 reply("The game has not yet started")
697 else if (!(sp_from in sp_players)) {
698 reply("You are not playing")
700 else if ($0 ~ /^[^a-zA-Z0-9]/) {
701 reply("Invalid team name")
703 else if ($0 ~ /^./) {
704 sp_teams[_team] = substr($0, 0, 32)
705 sp_say(sp_team(_team,1) " are now known as " sp_team(_team))
708 delete sp_teams[_team]
709 sp_say(sp_team(_team,1) " are boring")
714 if (!(sp_from in sp_players))
715 reply("You are not playing")
716 else if (sp_from == FROM)
717 say(FROM " has an existential crisis")
719 reply("You are playing for " sp_from);
723 if (sp_from in sp_notify)
724 reply("Your address is " sp_notify[sp_from])
726 reply("Your address is not set")
730 if (sp_from in sp_notify) {
731 reply("Removing address " sp_notify[sp_from])
732 delete sp_notify[sp_from]
734 reply("Your address is not set")
738 /^\.notify \S+@\S+.\S+$/ {
740 gsub(/[^a-zA-Z0-9_+@.-]/, "", _addr)
741 sp_notify[sp_from] = _addr
742 reply("Notifying you at " _addr)
745 sp_state ~ "(bid|pass|play)" &&
749 _lines[sp_share[_i]] = _lines[sp_share[_i]] " " _i
751 say(_i " allowed:" _lines[_i])
755 (sp_state == "bid" || sp_state == "play") &&
757 if (sp_from in sp_players)
758 reply("It is not your turn.")
760 reply("You are not playing.")
765 /^\.bid (0|[1-9][0-9]*)$/ {
766 if ($2 < 0 || $2 > 13) {
767 reply("You can only bid from 0 to 13")
771 if ($2 == 0 && !sp_looked[i]) {
772 sp_say(FROM " goes blind nil!")
774 } else if ($2 == 0) {
775 sp_say(FROM " goes nil!")
780 if (sp_turn != sp_dealer) {
781 sp_say(sp_player ": it is your bid! (" sp_bidders() ")")
783 sp_say(sp_extra() " (" sp_bidders() ")")
784 for (p in sp_players)
785 say(p, "You have: " sp_hand(p, p))
787 for (i=0; i<2; i++) {
789 sp_say(sp_team(i,1) ": select a card to pass " \
790 "(/msg " NICK " .pass <card>)")
794 if (sp_state == "play")
795 sp_say(sp_player ": you have the opening lead!")
800 sp_state == "pass" &&
803 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
805 # check validity and pass
806 if (!(sp_from in sp_players)) {
807 reply("You are not playing.")
809 else if (!sp_passer(_team)) {
810 reply("Your team did not go blind")
812 else if (sp_pass[sp_players[sp_from]]) {
813 reply("You have already passed a card")
815 else if (!(_card in sp_deck)) {
816 reply("Invalid card")
818 else if (!(_card in sp_hands[sp_from])) {
819 reply("You do not have that card")
822 sp_pass[sp_players[sp_from]] = $2
823 sp_say(FROM " passes a card")
826 # check for end of passing
827 if ((!sp_passer(0) || (sp_pass[0] && sp_pass[2])) &&
828 (!sp_passer(1) || (sp_pass[1] && sp_pass[3]))) {
832 delete sp_hands[sp_order[i]][_card]
833 sp_hands[sp_order[_partner]][_card] = 1
835 sp_say("Cards have been passed!")
836 sp_say(sp_player ": you have the opening lead!")
837 for (p in sp_players)
838 say(p, "You have: " sp_hand(p, p))
843 sp_state ~ "(bid|pass|play)" &&
845 if (!(sp_from in sp_players)) {
846 reply("You are not playing.")
848 sp_looked[sp_players[sp_from]] = 1
849 say(FROM, "You have: " sp_hand(FROM, sp_from))
854 sp_state == "play" &&
857 gsub(/[^A-Za-z0-9]/, "", _card);
858 if (!(_card in sp_deck)) {
859 reply("Invalid card")
861 else if (sp_suit && _card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
862 reply("You must follow suit (" sp_suit ")")
864 else if (_card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
865 reply("You cannot trump on the first hand")
867 else if (_card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
868 reply("Spades have not been broken")
870 else if (!(_card in sp_hands[sp_from])) {
871 reply("You do not have that card")
875 if (sp_state == "play") {
876 if (length(sp_hands[sp_from]))
877 say(FROM, "You have: " sp_hand(FROM, sp_from))
879 sp_say(sp_player ": it is your turn! " \
880 "(" sp_pretty(sp_piles, sp_player) ")")
882 sp_say(sp_player ": it is your turn!")
887 /^\.last/ && sp_state == "play" {
888 if (!isarray(sp_last))
889 say("No tricks have been taken!");
891 say(sp_last["player"] " took " \
892 sp_pretty(sp_last["pile"], FROM));
895 /^\.bids/ && sp_state == "bid" ||
896 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
898 _pile = sp_pretty(sp_piles, FROM)
903 _notify[0] = sp_player
904 for (_i in sp_share) {
905 if (sp_share[_i] != sp_player)
908 _extra = _extra " " _i "!"
910 _notify[length(_notify)] = _i
913 if (sp_state == "bid" && !_bids)
914 say("It is " sp_player "'s bid!" _extra)
915 if (sp_state == "bid" && _bids)
916 say("It is " sp_player "'s bid!" _extra " (" _bids ")")
917 if (sp_state == "play" && !_pile)
918 say("It is " sp_player "'s turn!" _extra)
919 if (sp_state == "play" && _pile)
920 say("It is " sp_player "'s turn!" _extra " (" _pile ")")
922 if (sp_state == "bid" || sp_state == "play") {
923 for (_i in _notify) {
924 if (_notify[_i] in sp_notify) {
925 _bids = _bids ? _bids : "none"
926 _pile = _pile ? sp_piles : "none"
927 mail_send(sp_notify[_notify[_i]], \
928 "It is your " sp_state "!", \
929 "Bids so far: " _bids "\n" \
930 "Cards played: " _pile)
931 say("Notified " _notify[_i] " at " sp_notify[_notify[_i]])
933 say("No email address for " _notify[_i])
938 for (_i=0; sp_state == "pass" && _i<4; _i++)
939 if (sp_passer(_i) && !sp_pass[_i])
940 say("Waiting for " sp_order[_i] " to pass a card!")
943 /^\.bids$/ && sp_state ~ "(pass|play)" {
944 say(sp_order[0] " bid " sp_bid(0) ", " \
945 sp_order[2] " bid " sp_bid(2) ", " \
946 "total: " sp_bids[0] + sp_bids[2])
947 say(sp_order[1] " bid " sp_bid(1) ", " \
948 sp_order[3] " bid " sp_bid(3) ", " \
949 "total: " sp_bids[1] + sp_bids[3])
952 /^\.tricks$/ && sp_state == "play" {
953 say(sp_order[0] " took " int(sp_tricks[0]) "/" sp_bid(0) ", " \
954 sp_order[2] " took " int(sp_tricks[2]) "/" sp_bid(2))
955 say(sp_order[1] " took " int(sp_tricks[1]) "/" sp_bid(1) ", " \
956 sp_order[3] " took " int(sp_tricks[3]) "/" sp_bid(3))
959 (TO == NICK || DST == sp_channel) &&
960 /^\.(score|status)$/ {
961 if (sp_state == "new") {
962 say("There is no game in progress")
964 if (sp_state ~ "join|bid|pass|play") {
966 sp_playto " points, " \
969 if (sp_state == "join") {
970 say("Waiting for players: " \
971 sp_order[0] " " sp_order[1] " " \
972 sp_order[2] " " sp_order[3])
974 if (sp_state ~ "bid|pass|play") {
975 say(sp_team(0) ": " \
976 int(sp_scores[0]) " points, " \
977 int(sp_bags(0)) " bags")
978 say(sp_team(1) ": " \
979 int(sp_scores[1]) " points, " \
980 int(sp_bags(1)) " bags")
984 (TO == NICK || DST == sp_channel) &&
986 say("http://pileus.org/andy/spades/" sp_log)
989 (TO == NICK || DST == sp_channel) &&
991 sp_stats("logs/" sp_log);
994 (TO == NICK || DST == sp_channel) &&
995 /^\.stats ([0-9]+_[0-9]+)(\.log)$/ {
996 gsub(/\.log$/, "", $2);
997 sp_stats("logs/" $2 ".log");
1000 /^\.((new|end|load)game|join|look|bid|pass|play|allow|deny|team|notify)/ {
1001 sp_save("var/sp_cur.json");