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 | ") sp_ugly(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_ugly(cards, who)
188 gsub(/[\2\17]|\3[14],00|/, "", cards)
189 gsub(/♠/, "s", cards)
190 gsub(/♥/, "h", cards)
191 gsub(/♦/, "d", cards)
192 gsub(/♣/, "c", cards)
196 function sp_next(who, prev)
199 sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
200 if (length(sp_order) == 4)
201 sp_player = sp_order[sp_turn]
205 function sp_shuf(i, mixed)
207 sp_usort(sp_players, mixed)
209 sp_order[i-1] = mixed[i]
210 sp_players[mixed[i]] = i-1
214 function sp_deal( shuf)
216 sp_say("/me deals the cards")
217 sp_usort(sp_deck, shuf)
218 for (i=1; i<=52; i++)
219 sp_hands[sp_order[i%4]][shuf[i]] = 1
221 sp_dealer = (sp_dealer+1)%4
223 sp_player = sp_order[sp_turn]
224 sp_say(sp_player ": you bid first!")
227 function sp_hand(to, who, sort, str)
229 asorti(sp_hands[who], sort, "sp_csort")
230 for (i=0; i<length(sort); i++)
231 str = str "" sprintf("%4s", sort[i])
232 gsub(/^ +| +$/, "", str)
233 return sp_pretty(str, to)
236 function sp_hasa(who, expr)
238 for (c in sp_hands[who]) {
245 function sp_type(card)
247 return substr(card, length(card))
250 function sp_usort(list, out) {
253 asorti(out, out, "@val_num_asc")
256 function sp_csort(i1,v1,i2,v2) {
257 return sp_deck[i1] > sp_deck[i2] ? +1 :
258 sp_deck[i1] < sp_deck[i2] ? -1 : 0;
261 function sp_winner( card, tmp)
263 for (card in sp_pile)
264 if (card !~ sp_suit && card !~ /s/)
266 asorti(sp_pile, tmp, "sp_csort")
267 #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
271 function sp_team(i, players)
273 #return "{" sp_order[i+0] "," sp_order[i+2] "}"
274 if ((i in sp_teams) && !players)
277 return sp_order[i+0] "/" sp_order[i+2]
280 function sp_bags(i, bags)
282 bags = sp_scores[i] % sp_limit
290 return sp_nil[who] == 0 ? sp_bids[who] :
291 sp_nil[who] == 1 ? "nil" :
292 sp_nil[who] == 2 ? "blind" : "n/a"
295 function sp_passer(who)
297 return sp_nil[(who+0)%4] == 2 || sp_nil[(who+1)%4] != 0 ||
298 sp_nil[(who+2)%4] == 2 || sp_nil[(who+3)%4] != 0
301 function sp_bidders( i, turn, bid, bids)
303 for (i = 0; i < 4; i++) {
304 turn = (sp_dealer + i) % 4
305 if (bid = sp_bid(turn))
306 bids = bids " " sp_order[turn] ":" bid
308 gsub(/^ +| +$/, "", bids)
312 function sp_extra( n, s)
314 n = sp_bids[0] + sp_bids[1] + sp_bids[2] + sp_bids[3];
315 s = n == 12 || n == 14 ? "" : "s";
317 return n<13 ? "Playing with " 13-n " bag" s "!" :
318 n>13 ? "Fighting for " n-13 " trick" s "!" : "No bags!";
321 function sp_score( bids, times, tricks)
323 for (i=0; i<2; i++) {
324 bids = sp_bids[i] + sp_bids[i+2]
325 tricks = sp_tricks[i] + sp_tricks[i+2]
327 times = int((sp_bags(i) + bags) / sp_limit)
329 sp_say(sp_team(i) " bag" (times>1?" way ":" ") "out")
330 sp_scores[i] -= sp_limit * 10 * times;
332 if (tricks >= bids) {
333 sp_say(sp_team(i) " make their bid: " tricks "/" bids)
334 sp_scores[i] += bids*10 + bags;
336 sp_say(sp_team(i) " go bust: " tricks "/" bids)
337 sp_scores[i] -= bids*10;
340 for (i=0; i<4; i++) {
343 sp_say(sp_order[i] " " \
344 (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!" :
345 sp_nil[i] == 1 && sp_tricks[i] ? "fails at nil!" :
346 sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
347 sp_nil[i] == 2 && sp_tricks[i] ? "fails miserably at blind nil!" :
349 sp_scores[i%2] += sp_limit * 10 * sp_nil[i] * \
350 (sp_tricks[i] == 0 ? 1 : -1)
352 if (sp_scores[0] > sp_scores[1])
353 sp_say(sp_team(0) " lead " sp_scores[0] " to " sp_scores[1] " of " sp_playto)
354 else if (sp_scores[1] > sp_scores[0])
355 sp_say(sp_team(1) " lead " sp_scores[1] " to " sp_scores[0] " of " sp_playto)
357 sp_say("tied at " sp_scores[0] " of " sp_playto)
360 function sp_play(card, winner, pi)
362 delete sp_hands[sp_from][card]
363 sp_pile[card] = sp_player
364 sp_piles = sp_piles (sp_piles?",":"") card
371 if (length(sp_pile) == 1)
372 sp_suit = sp_type(card)
375 if (length(sp_pile) == 4) {
377 pi = sp_players[sp_pile[winner]]
379 sp_say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
380 " (" sp_pretty(sp_piles, FROM) ")")
381 sp_last["player"] = sp_pile[winner];
382 sp_last["pile"] = sp_piles;
383 sp_next(sp_pile[winner])
388 if (sp_tricks[0] + sp_tricks[1] + \
389 sp_tricks[2] + sp_tricks[3] == 13) {
390 sp_say("Round over!")
392 if ((sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto) &&
393 (sp_scores[0] != sp_scores[1])) {
395 winner = sp_scores[0] > sp_scores[1] ? 0 : 1
397 say(CHANNEL, sp_team(winner) " wins the game " \
398 sp_scores[winner] " to " sp_scores[looser])
399 say(CHANNEL, sp_order[winner+0] "++")
400 say(CHANNEL, sp_order[winner+2] "++")
404 if (sp_scores[0] == sp_scores[1] &&
405 sp_scores[0] >= sp_playto)
406 sp_say("It's a tie! Playing an extra round!");
414 function sp_delay(sec)
416 return (sec > 60*60*24 ? int(sec/60/60/24) "d " : "") \
417 (sec > 60*60 ? int(sec/60/60)%24 "h " : "") \
421 function sp_max(list, i, max)
423 for (i=0; i<length(list); i++)
424 if (max == "" || list[i] > max)
429 function sp_avg(list, i, sum)
431 for (i=0; i<length(list); i++)
433 return sum / length(list)
436 function sp_cur(list)
438 return list[length(list)-1]
441 function sp_stats(file, line, arr, time, user, turn, start, delay, short, extra)
444 while ((stat = getline line < file) > 0) {
446 if (!match(line, /^([0-9\- \:]*) \| (.*)$/, arr))
448 gsub(/[:-]/, " ", arr[1])
449 time = mktime(arr[1])
452 if (!match(arr[2], /^([^:]*): (.*)$/, arr))
456 # Record user latency
458 delay[turn][length(delay[turn])] = time - start
461 if (match(arr[2], /^(it is your|you .*(first|lead)!$)/, arr)) {
468 # Add current latency
470 delay[turn][length(delay[turn])] = systime() - start
471 debug("time: " (systime() - start))
476 reply("File does not exist: " file);
479 for (user in delay) {
480 short = length(user) <= 4 ? user : substr(user, 0, 4)
481 extra = (user != turn) ? "" : \
482 ", " sp_delay(sp_cur(delay[user])) " (cur)";
483 say("latency for " short \
484 ": " sp_delay(sp_avg(delay[user])) " (avg)" \
485 ", " sp_delay(sp_max(delay[user])) " (max)" extra)
491 cmd = "od -An -N4 -td4 /dev/random"
497 sp_load("var/sp_cur.json")
498 sp_sock = "/inet/udp/0/localhost/6173"
499 print "starting rhawk" |& sp_sock
501 # sp_say("Game restored.")
505 sp_from = AUTH in sp_auths ? sp_auths[AUTH] : \
506 AUTH in sp_share ? sp_share[AUTH] : FROM
507 sp_valid = sp_from && sp_from == sp_player
513 say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
518 sp_save("var/sp_save.json");
524 sp_load("var/sp_save.json");
530 say(".help spades -- play a game of spades")
533 /^\.help [Ss]pades$/ {
534 say("Spades -- play a game of spades")
535 say(".help game -- setup and administer the game")
536 say(".help play -- commands for playing spades")
537 say(".help auth -- control player authorization")
542 say(".newgame [score] -- start a game to <score> points, default 300")
543 say(".endgame -- abort the current game")
544 say(".savegame -- save the current game to disk")
545 say(".loadgame -- load the previously saved game")
550 say(".join -- join the current game")
551 say(".look -- look at your cards")
552 say(".bid [n] -- bid for <n> tricks")
553 say(".pass [card] -- pass a card to your partner")
554 say(".play [card] -- play a card")
555 say(".team [name] -- set your team name")
556 say(".last -- show who took the previous trick")
557 say(".turn -- check whose turn it is")
558 say(".bids -- check what everyone bid")
559 say(".tricks -- check how many trick have been taken")
560 say(".score -- check the score")
565 say(".auth [who] -- display authentication info for a user")
566 say(".allow [who] -- allow another person to play on your behalf")
567 say(".deny [who] -- prevent a previously allowed user from playing")
568 say(".show -- display which users can play for which players")
569 say(".notify [addr] -- email user when it is their turn")
575 /^\.deal (\w+) (.*)/ {
576 sp_say(FROM " is cheating for " $2)
578 for (i=3; i<=NF; i++)
584 /^\.order (\w+) ([0-4])/ {
585 sp_say(FROM " is cheating for " $2)
588 sp_player = sp_order[sp_turn]
592 sp_state == "play" &&
593 /^\.force (\w+) (\S+)$/ {
594 sp_say(FROM " is cheating for " $2)
602 match($0, /^\.newgame ?([1-9][0-9]*) *- *([1-9][0-9]*)$/, _arr) {
603 if (_arr[2] > _arr[1])
604 $0 = $1 " " int(rand() * (_arr[2]-_arr[1])+_arr[1])
607 /^\.newgame ?([1-9][0-9]*)?$/ {
608 if (sp_state != "new") {
609 reply("There is already a game in progress.")
613 sp_playto = $2 ? $2 : 300
614 sp_limit = sp_playto > 200 ? 10 : 5;
617 sp_log = strftime("%Y%m%d_%H%M%S.log")
618 sp_say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
622 /^\.(endgame|fliptable)$/ {
623 if (sp_state == "new") {
624 reply("There is no game in progress.")
626 else if (!(sp_from in sp_players)) {
627 reply("You are not playing")
629 else if (sp_state == "join") {
630 sp_say(FROM " ends the game")
634 _looser = (sp_players[sp_from]+0) % 2;
635 _winner = (sp_players[sp_from]+1) % 2;
636 sp_say(FROM " goes on a rampage")
637 say(CHANNEL, sp_team(_winner) " wins the game " \
638 sp_scores[_winner] " to " sp_scores[_looser])
639 say(CHANNEL, sp_order[_winner+0] "++")
640 say(CHANNEL, sp_order[_winner+2] "++")
646 if (sp_state == "new") {
647 reply("There is no game in progress")
649 else if (sp_state == "play") {
650 reply("The game has already started")
652 else if (sp_state == "join" && sp_from in sp_players) {
653 reply("You are already playing")
655 else if (sp_state == "join") {
659 sp_auths[AUTH] = FROM
661 sp_say(FROM " joins the game!")
663 if (sp_state == "join" && sp_turn == 0) {
672 _who = $2 in USERS ? USERS[$2]["auth"] : ""
673 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
674 if (sp_state ~ "new|join") {
675 reply("The game has not yet started")
677 else if (!(sp_from in sp_players)) {
678 reply("You are not playing")
681 reply(_str " is not logged in")
683 else if (_who in sp_players || _who in sp_auths) {
684 reply(_str " is a primary player")
686 else if (_who in sp_share) {
687 reply(_str " is already playing for " sp_share[_who])
690 sp_say(_str " can now play for " sp_from)
691 sp_share[_who] = sp_from
696 _who = $2 in USERS ? USERS[$2]["auth"] : $2
697 _str = _who && _who != $2 ? $2 " (" _who ")" : $2
698 if (sp_state ~ "new|join") {
699 reply("The game has not yet started")
701 else if (!(sp_from in sp_players)) {
702 reply("You are not playing")
704 else if (_who in sp_players || _who in sp_auths) {
705 reply(_str " is a primary player")
707 else if (!(_who in sp_share) || sp_share[_who] != sp_from) {
708 reply(_str " is not playing for " sp_from)
711 sp_say(_str " can no longer play for " sp_from)
712 delete sp_share[_who]
717 gsub(/^\.team */, "")
718 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
719 if (sp_state ~ "new|join") {
720 reply("The game has not yet started")
722 else if (!(sp_from in sp_players)) {
723 reply("You are not playing")
725 else if ($0 ~ /^[^a-zA-Z0-9]/) {
726 reply("Invalid team name")
728 else if ($0 ~ /^./) {
729 sp_teams[_team] = substr($0, 0, 32)
730 sp_say(sp_team(_team,1) " are now known as " sp_team(_team))
733 delete sp_teams[_team]
734 sp_say(sp_team(_team,1) " are boring")
739 if (!(sp_from in sp_players))
740 reply("You are not playing")
741 else if (sp_from == FROM)
742 say(FROM " has an existential crisis")
744 reply("You are playing for " sp_from);
748 if (sp_from in sp_notify)
749 reply("Your address is " sp_notify[sp_from])
751 reply("Your address is not set")
755 if (sp_from in sp_notify) {
756 reply("Removing address " sp_notify[sp_from])
757 delete sp_notify[sp_from]
759 reply("Your address is not set")
763 /^\.notify \S+@\S+.\S+$/ {
765 gsub(/[^a-zA-Z0-9_+@.-]/, "", _addr)
766 sp_notify[sp_from] = _addr
767 reply("Notifying you at " _addr)
770 sp_state ~ "(bid|pass|play)" &&
774 _lines[sp_share[_i]] = _lines[sp_share[_i]] " " _i
776 say(_i " allowed:" _lines[_i])
780 (sp_state == "bid" || sp_state == "play") &&
782 if (sp_from in sp_players)
783 reply("It is not your turn.")
785 reply("You are not playing.")
790 /^\.bid (0|[1-9][0-9]*)$/ {
791 if ($2 < 0 || $2 > 13) {
792 reply("You can only bid from 0 to 13")
796 if ($2 == 0 && !sp_looked[i]) {
797 sp_say(FROM " goes blind nil!")
799 } else if ($2 == 0) {
800 sp_say(FROM " goes nil!")
805 if (sp_turn != sp_dealer) {
806 sp_say(sp_player ": it is your bid! (" sp_bidders() ")")
808 sp_say(sp_extra() " (" sp_bidders() ")")
809 for (p in sp_players)
810 say(p, "You have: " sp_hand(p, p))
812 for (i=0; i<2; i++) {
814 sp_say(sp_team(i,1) ": select a card to pass " \
815 "(/msg " NICK " .pass <card>)")
819 if (sp_state == "play")
820 sp_say(sp_player ": you have the opening lead!")
825 sp_state == "pass" &&
828 _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
830 # check validity and pass
831 if (!(sp_from in sp_players)) {
832 reply("You are not playing.")
834 else if (!sp_passer(_team)) {
835 reply("Your team did not go blind")
837 else if (sp_pass[sp_players[sp_from]]) {
838 reply("You have already passed a card")
840 else if (!(_card in sp_deck)) {
841 reply("Invalid card")
843 else if (!(_card in sp_hands[sp_from])) {
844 reply("You do not have that card")
847 sp_pass[sp_players[sp_from]] = $2
848 sp_say(FROM " passes a card")
851 # check for end of passing
852 if ((!sp_passer(0) || (sp_pass[0] && sp_pass[2])) &&
853 (!sp_passer(1) || (sp_pass[1] && sp_pass[3]))) {
857 delete sp_hands[sp_order[i]][_card]
858 sp_hands[sp_order[_partner]][_card] = 1
860 sp_say("Cards have been passed!")
861 sp_say(sp_player ": you have the opening lead!")
862 for (p in sp_players)
863 say(p, "You have: " sp_hand(p, p))
868 sp_state ~ "(bid|pass|play)" &&
870 if (!(sp_from in sp_players)) {
871 reply("You are not playing.")
873 sp_looked[sp_players[sp_from]] = 1
874 say(FROM, "You have: " sp_hand(FROM, sp_from))
879 sp_state == "play" &&
882 gsub(/[^A-Za-z0-9]/, "", _card);
883 if (!(_card in sp_deck)) {
884 reply("Invalid card")
886 else if (sp_suit && _card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
887 reply("You must follow suit (" sp_suit ")")
889 else if (_card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
890 reply("You cannot trump on the first hand")
892 else if (_card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
893 reply("Spades have not been broken")
895 else if (!(_card in sp_hands[sp_from])) {
896 reply("You do not have that card")
900 if (sp_state == "play") {
901 if (length(sp_hands[sp_from]))
902 say(FROM, "You have: " sp_hand(FROM, sp_from))
904 sp_say(sp_player ": it is your turn! " \
905 "(" sp_pretty(sp_piles, sp_player) ")")
907 sp_say(sp_player ": it is your turn!")
912 /^\.last/ && sp_state == "play" {
913 if (!isarray(sp_last))
914 say("No tricks have been taken!");
916 say(sp_last["player"] " took " \
917 sp_pretty(sp_last["pile"], FROM));
920 /^\.bids/ && sp_state == "bid" ||
921 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
923 _pile = sp_pretty(sp_piles, FROM)
928 _notify[0] = sp_player
929 for (_i in sp_share) {
930 if (sp_share[_i] != sp_player)
933 _extra = _extra " " _i "!"
935 _notify[length(_notify)] = _i
938 if (sp_state == "bid" && !_bids)
939 say("It is " sp_player "'s bid!" _extra)
940 if (sp_state == "bid" && _bids)
941 say("It is " sp_player "'s bid!" _extra " (" _bids ")")
942 if (sp_state == "play" && !_pile)
943 say("It is " sp_player "'s turn!" _extra)
944 if (sp_state == "play" && _pile)
945 say("It is " sp_player "'s turn!" _extra " (" _pile ")")
947 if (sp_state == "bid" || sp_state == "play") {
948 for (_i in _notify) {
949 if (_notify[_i] in sp_notify) {
950 _bids = _bids ? _bids : "none"
951 _pile = _pile ? sp_piles : "none"
952 mail_send(sp_notify[_notify[_i]], \
953 "It is your " sp_state "!", \
954 "Bids so far: " _bids "\n" \
955 "Cards played: " _pile)
956 say("Notified " _notify[_i] " at " sp_notify[_notify[_i]])
958 say("No email address for " _notify[_i])
963 for (_i=0; sp_state == "pass" && _i<4; _i++)
964 if (sp_passer(_i) && !sp_pass[_i])
965 say("Waiting for " sp_order[_i] " to pass a card!")
968 /^\.bids$/ && sp_state ~ "(pass|play)" {
969 say(sp_order[0] " bid " sp_bid(0) ", " \
970 sp_order[2] " bid " sp_bid(2) ", " \
971 "total: " sp_bids[0] + sp_bids[2])
972 say(sp_order[1] " bid " sp_bid(1) ", " \
973 sp_order[3] " bid " sp_bid(3) ", " \
974 "total: " sp_bids[1] + sp_bids[3])
977 /^\.tricks$/ && sp_state == "play" {
978 say(sp_order[0] " took " int(sp_tricks[0]) "/" sp_bid(0) ", " \
979 sp_order[2] " took " int(sp_tricks[2]) "/" sp_bid(2))
980 say(sp_order[1] " took " int(sp_tricks[1]) "/" sp_bid(1) ", " \
981 sp_order[3] " took " int(sp_tricks[3]) "/" sp_bid(3))
984 (TO == NICK || DST == sp_channel) &&
985 /^\.(score|status)$/ {
986 if (sp_state == "new") {
987 say("There is no game in progress")
989 if (sp_state ~ "join|bid|pass|play") {
991 sp_playto " points, " \
994 if (sp_state == "join") {
995 say("Waiting for players: " \
996 sp_order[0] " " sp_order[1] " " \
997 sp_order[2] " " sp_order[3])
999 if (sp_state ~ "bid|pass|play") {
1000 say(sp_team(0) ": " \
1001 int(sp_scores[0]) " points, " \
1002 int(sp_bags(0)) " bags")
1003 say(sp_team(1) ": " \
1004 int(sp_scores[1]) " points, " \
1005 int(sp_bags(1)) " bags")
1009 (TO == NICK || DST == sp_channel) &&
1011 say("http://pileus.org/andy/spades/" sp_log)
1014 (TO == NICK || DST == sp_channel) &&
1016 sp_stats("logs/" sp_log);
1019 (TO == NICK || DST == sp_channel) &&
1020 /^\.stats ([0-9]+_[0-9]+)(\.log)$/ {
1021 gsub(/\.log$/, "", $2);
1022 sp_stats("logs/" $2 ".log");
1025 /^\.((new|end|load)game|join|look|bid|pass|play|allow|deny|team|notify)/ {
1026 sp_save("var/sp_cur.json");