]> Pileus Git - ~andy/rhawk/blob - spades.awk
Save game after passing cards
[~andy/rhawk] / spades.awk
1 # For saving
2 @include "json.awk"
3
4 # Functions
5 function sp_init(cards, tmp0, tmp1)
6 {
7         # Init deck
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"
12         split(cards, tmp0)
13         for (i=1; i<=length(tmp0); i++)
14                 sp_deck[tmp0[i]] = i
15 }
16
17 function sp_reset(type)
18 {
19         # Per message
20         if (type <  0) {
21                 sp_from     = ""    #    The speakers player name
22                 sp_valid    = ""    #    It is the speaker turn
23         }
24
25         # Per hand
26         if (type >= 0) {
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
30         }
31
32         # Per round
33         if (type >= 1) {
34                 sp_state    = "bid" #     {new,join,bid,pass,play}
35                 sp_broken   = 0     #     Whether spades are broken
36                 delete sp_looked    # [i] Whether a player has looked a their cards
37                 delete sp_bids      # [i] Each players bid
38                 delete sp_nil       # [i] Nil multiplier 0=regular, 1=nil, 2=blind
39                 delete sp_pass      # [i] Cards to pass
40                 delete sp_tricks    # [i] Tricks this round
41         }
42
43         # Per game
44         if (type >= 2) {
45                 sp_channel  = ""    #     channel to play in
46                 sp_state    = "new" #     {new,join,bid,pass,play}
47                 sp_owner    = ""    #     Who started the game
48                 sp_playto   = 0     #     Score the game will go to
49                 sp_dealer   =-1     #     Who is dealing this round
50                 sp_turn     = 0     #     Index of who's turn it is
51                 sp_player   = ""    #     Who's turn it is
52                 sp_limit    = 10    #     Bag out limit / nil bonus
53                 delete sp_hands     # [p] Each players cards
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         }
60 }
61
62 function sp_acopy(dst, src,     key)
63 {
64         if (isarray(src))
65                 for (key in src)
66                         json_copy(dst, key, src[key])
67 }
68
69 function sp_save(file,  game)
70 {
71         # Per hand
72         game["suit"]    = sp_suit;
73         game["piles"]   = sp_piles;
74         json_copy(game, "pile",    sp_pile);
75
76         # Per round
77         game["state"]   = sp_state;
78         game["broken"]  = sp_broken;
79         json_copy(game, "looked",  sp_looked);
80         json_copy(game, "bids",    sp_bids);
81         json_copy(game, "nil",     sp_nil);
82         json_copy(game, "pass",    sp_pass);
83         json_copy(game, "tricks",  sp_tricks);
84
85         # Per game
86         game["channel"] = sp_channel;
87         game["owner"]   = sp_owner;
88         game["playto"]  = sp_playto;
89         game["dealer"]  = sp_dealer;
90         game["turn"]    = sp_turn;
91         game["player"]  = sp_player;
92         game["limit"]   = sp_limit;
93         json_copy(game, "hands",   sp_hands);
94         json_copy(game, "players", sp_players);
95         json_copy(game, "auths",   sp_auths);
96         json_copy(game, "share",   sp_share);
97         json_copy(game, "order",   sp_order);
98         json_copy(game, "scores",  sp_scores);
99
100         # Save
101         json_save(file, game);
102 }
103
104 function sp_load(file,  game)
105 {
106         # Load
107         if (!json_load(file, game))
108                 return
109
110         # Per hand
111         sp_suit    = game["suit"];
112         sp_piles   = game["piles"];
113         sp_acopy(sp_pile,    game["pile"]);
114
115         # Per round
116         sp_state   = game["state"];
117         sp_broken  = game["broken"];
118         sp_acopy(sp_looked,  game["looked"]);
119         sp_acopy(sp_bids,    game["bids"]);
120         sp_acopy(sp_nil,     game["nil"]);
121         sp_acopy(sp_pass,    game["pass"]);
122         sp_acopy(sp_tricks,  game["tricks"]);
123
124         # Per game
125         sp_channel = game["channel"];
126         sp_owner   = game["owner"];
127         sp_playto  = game["playto"];
128         sp_dealer  = game["dealer"];
129         sp_turn    = game["turn"];
130         sp_player  = game["player"];
131         sp_limit   = game["limit"];
132         sp_acopy(sp_hands,   game["hands"]);
133         sp_acopy(sp_players, game["players"]);
134         sp_acopy(sp_auths,   game["auths"]);
135         sp_acopy(sp_share,   game["share"]);
136         sp_acopy(sp_order,   game["order"]);
137         sp_acopy(sp_scores,  game["scores"]);
138 }
139
140 function sp_pretty(cards, who)
141 {
142         if (!nocolor[who]) {
143                 gsub(/[0-9JQKA]*[sc]/, "\0031,00\002&\017", cards) # black
144                 gsub(/[0-9JQKA]*[hd]/, "\0034,00\002&\017", cards) # red
145         }
146         if (!nounicode[who]) {
147                 gsub(/s/, "\002♠", cards)
148                 gsub(/h/, "\002♥", cards)
149                 gsub(/d/, "\002♦", cards)
150                 gsub(/c/, "\002♣", cards)
151         }
152         return cards
153 }
154
155 function sp_next(who, prev)
156 {
157         prev      = sp_turn
158         sp_turn   = who ? sp_players[who] : (sp_turn + 1) % 4
159         if (length(sp_order) == 4)
160                 sp_player = sp_order[sp_turn]
161         return prev
162 }
163
164 function sp_deal(       shuf)
165 {
166         say("/me deals the cards")
167         asorti(sp_deck, shuf, "sp_usort")
168         for (i=1; i<=52; i++)
169                 sp_hands[sp_order[i%4]][shuf[i]] = 1
170         sp_state  = "bid"
171         sp_dealer = (sp_dealer+1)%4
172         sp_turn   =  sp_dealer
173         sp_player =  sp_order[sp_turn]
174         say("Bidding starts with " sp_player "!")
175 }
176
177 function sp_hand(to, who,       sort, str)
178 {
179         asorti(sp_hands[who], sort, "sp_csort")
180         for (i=0; i<length(sort); i++)
181                 str = str "" sprintf("%4s", sort[i])
182         gsub(/^ +| +$/, "", str)
183         return sp_pretty(str, to)
184 }
185
186 function sp_hasa(who, expr)
187 {
188         for (c in sp_hands[who]) {
189                 if (c ~ expr)
190                         return 1
191         }
192         return 0
193 }
194
195 function sp_type(card)
196 {
197         return substr(card, length(card))
198 }
199
200 function sp_usort(a,b,c,d) {
201         return rand() - 0.5
202 }
203
204 function sp_csort(i1,v1,i2,v2) {
205         return sp_deck[i1] > sp_deck[i2] ? +1 :
206                sp_deck[i1] < sp_deck[i2] ? -1 : 0;
207 }
208
209 function sp_winner(     card, tmp)
210 {
211         for (card in sp_pile)
212                 if (card !~ sp_suit && card !~ /s/)
213                         delete sp_pile[card]
214         asorti(sp_pile, tmp, "sp_csort")
215         #print "pile: " tmp[1] ">" tmp[2] ">" tmp[3] ">" tmp[4]
216         return tmp[1]
217 }
218
219 function sp_team(i)
220 {
221         #return "{" sp_order[i+0] "," sp_order[i+2] "}"
222         return sp_order[i+0] "/" sp_order[i+2]
223 }
224
225 function sp_bags(i,     bags)
226 {
227         bags = sp_scores[i] % sp_limit
228         if (bags < 0)
229                 bags += sp_limit
230         return bags
231 }
232
233 function sp_bidders(    i, turn, bid, bids)
234 {
235         for (i = 0; i < 4; i++) {
236                 turn = (sp_dealer + i) % 4
237                 if (sp_bids[turn] && !sp_nil[turn])
238                         bid  = sp_order[turn] ":" sp_bids[turn]
239                 else if (sp_nil[turn] == 1)
240                         bid  = sp_order[turn] ":" "nil"
241                 else if (sp_nil[turn] == 2)
242                         bid  = sp_order[turn] ":" "blind"
243                 else
244                         continue
245                 bids = bids " " bid
246         }
247         gsub(/^ +| +$/, "", bids)
248         return bids
249 }
250
251 function sp_score(      bids, times, tricks)
252 {
253         for (i=0; i<2; i++) {
254                 bids   = sp_bids[i]   + sp_bids[i+2]
255                 tricks = sp_tricks[i] + sp_tricks[i+2]
256                 bags   = tricks - bids
257                 times  = int((sp_bags(i) + bags) / sp_limit)
258                 if (times > 0) {
259                         say(sp_team(i) " bag" (times>1?" way ":" ") "out")
260                         sp_scores[i] -= sp_limit * 10 * times;
261                 }
262                 if (tricks >= bids) {
263                         say(sp_team(i) " make their bid: " tricks "/" bids)
264                         sp_scores[i] += bids*10 + bags;
265                 } else {
266                         say(sp_team(i) " go bust: " tricks "/" bids)
267                         sp_scores[i] -= bids*10;
268                 }
269         }
270         for (i=0; i<4; i++) {
271                 if (!sp_nil[i])
272                         continue
273                 say(sp_order[i] " " \
274                     (sp_nil[i] == 1 && !sp_tricks[i] ? "makes nil!"       :
275                      sp_nil[i] == 1 &&  sp_tricks[i] ? "fails at nil!"    :
276                      sp_nil[i] == 2 && !sp_tricks[i] ? "makes blind nil!" :
277                      sp_nil[i] == 2 &&  sp_tricks[i] ? "fails miserably at blind nil!" :
278                                                        "unknown"))
279                 sp_scores[i%2] += sp_limit * 10 * sp_nil[i] * \
280                         (sp_tricks[i] == 0 ? 1 : -1)
281         }
282 }
283
284 function sp_play(card,  winner, pi)
285 {
286         delete sp_hands[sp_from][card]
287         sp_pile[card] = sp_player
288         sp_piles      = sp_piles (sp_piles?",":"") card
289         sp_next()
290
291         if (card ~ /s/)
292                 sp_broken = 1
293
294         # Start hand
295         if (length(sp_pile) == 1)
296                 sp_suit = sp_type(card)
297
298         # Finish hand
299         if (length(sp_pile) == 4) {
300                 winner = sp_winner()
301                 pi     = sp_players[sp_pile[winner]]
302                 sp_tricks[pi]++
303                 say(sp_pile[winner] " wins with " sp_pretty(winner, FROM) \
304                     " (" sp_pretty(sp_piles, FROM) ")")
305                 sp_next(sp_pile[winner])
306                 sp_reset(0)
307         }
308
309         # Finish round
310         if (sp_tricks[0] + sp_tricks[1] + \
311             sp_tricks[2] + sp_tricks[3] == 13) {
312                 say("Round over!")
313                 sp_score()
314                 if (sp_scores[0] >= sp_playto || sp_scores[1] >= sp_playto &&
315                     sp_scores[0]              != sp_scores[1]) {
316                         say("Game over!")
317                         winner = sp_scores[0] > sp_scores[1] ? 0 : 1
318                         looser = !winner
319                         say(CHANNEL, sp_team(winner) " wins the game " \
320                             sp_scores[winner] " to " sp_scores[looser])
321                         say(CHANNEL, sp_order[winner+0] "++")
322                         say(CHANNEL, sp_order[winner+2] "++")
323                         sp_reset(2)
324
325                 } else {
326                         if (sp_scores[0] == sp_scores[1] && 
327                             sp_scores[0] >= sp_playto)
328                                 say("It's tie! Playing an extra round!");
329                         sp_reset(1)
330                         sp_deal()
331                 }
332         }
333 }
334
335 # Misc
336 BEGIN {
337         cmd = "od -An -N4 -td4 /dev/random"
338         cmd | getline seed
339         close(cmd)
340         srand(seed)
341         sp_init()
342         sp_reset(2)
343         sp_load("var/sp_cur.json");
344         #if (sp_channel)
345         #       say(sp_channel, "Game restored.")
346 }
347
348 // {
349         sp_from  = AUTH in sp_auths ? sp_auths[AUTH] : \
350                    AUTH in sp_share ? sp_share[AUTH] : FROM
351         sp_valid = sp_from && sp_from == sp_player
352 }
353
354 CMD == "PRIVMSG" &&
355 ! /help/ &&
356 /[Ss]pades/ {
357         say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
358 }
359
360 AUTH == OWNER &&
361 /^\.savegame/ {
362         sp_save("var/sp_save.json");
363         say("Game saved.")
364 }
365
366 AUTH == OWNER &&
367 /^\.loadgame/ {
368         sp_load("var/sp_save.json");
369         say("Game loaded.")
370 }
371
372 # Help
373 /^\.help [Ss]pades$/ {
374         say("Spades -- play a game of spades")
375         say("Examples:")
376         say(".newgame [score] -- start a game to <score> points, default 500")
377         say(".endgame -- abort the current game")
378         say(".savegame -- save the current game to disk")
379         say(".loadgame -- load the previously saved game")
380         say(".join -- join the current game")
381         say(".look -- look at your cards")
382         say(".bid n -- bid for <n> tricks")
383         say(".play [card] -- play a card")
384         say(".score -- check the score")
385         say(".tricks -- check how many trick have been taken")
386         say(".bids -- check what everyone bid")
387         next
388 }
389
390 # Debugging
391 AUTH == OWNER &&
392 /^\.deal (\w+) (.*)/ {
393         say(sp_channel, FROM " is cheating for " $2)
394         delete sp_hands[$2]
395         for (i=3; i<=NF; i++)
396                 sp_hands[$2][$i] = 1
397         next
398 }
399
400 AUTH == OWNER &&
401 sp_state == "play" &&
402 /^\.force (\w+) (\S+)$/ {
403         say(sp_channel, FROM " is cheating for " $2)
404         sp_from = $2
405         sp_play($3)
406         next
407 }
408
409
410 # Setup
411 /^\.newgame ?([0-9]+)?$/ {
412         if (sp_state != "new") {
413                 reply("There is already a game in progress.")
414         } else {
415                 $1         = ".join"
416                 sp_owner   = FROM
417                 sp_playto  = $2 ? $2 : 200
418                 sp_limit   = sp_playto > 200 ? 10 : 5;
419                 sp_state   = "join"
420                 sp_channel = DST
421                 say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
422         }
423 }
424
425 (sp_from == sp_owner || AUTH == OWNER) &&
426 /^\.endgame$/ {
427         if (sp_state == "new") {
428                 reply("There is no game in progress.")
429         } else {
430                 say(FROM " ends the game")
431                 sp_reset(2)
432         }
433 }
434
435 /^\.join$/ {
436         if (sp_state == "new") {
437                 reply("There is no game in progress")
438         }
439         else if (sp_state == "play") {
440                 reply("The game has already started")
441         }
442         else if (sp_state == "join" && sp_from in sp_players) {
443                 reply("You are already playing")
444         }
445         else if (sp_state == "join") {
446                 i = sp_next()
447                 sp_players[FROM] = i
448                 if (AUTH)
449                         sp_auths[AUTH] = FROM
450                 sp_order[i] = FROM
451                 say(FROM " joins the game!")
452         }
453         if (sp_state == "join" && sp_turn == 0)
454                 sp_deal()
455 }
456
457 /^\.allow \S+$/ {
458         _who = $2 in USERS ? USERS[$2]["auth"] : ""
459         _str = _who && _who != $2 ? $2 " (" _who ")" : $2
460         if (sp_state ~ "new|join") {
461                 reply("The game has not yet started")
462         }
463         else if (!(sp_from in sp_players)) {
464                 reply("You are not playing")
465         }
466         else if (!_who) {
467                 reply(_str " is not logged in")
468         }
469         else if (_who in sp_players || _who in sp_auths) {
470                 reply(_str " is a primary player")
471         }
472         else if (_who in sp_share) {
473                 reply(_str " is already playing for " sp_share[_who])
474         }
475         else {
476                 reply(_str " can now play for " sp_from)
477                 sp_share[_who] = sp_from
478         }
479 }
480
481 /^\.deny \S+$/ {
482         _who = $2 in USERS ? USERS[$2]["auth"] : $2
483         _str = _who && _who != $2 ? $2 " (" _who ")" : $2
484         if (sp_state ~ "new|join") {
485                 reply("The game has not yet started")
486         }
487         else if (!(sp_from in sp_players)) {
488                 reply("You are not playing")
489         }
490         else if (_who in sp_players || _who in sp_auths) {
491                 reply(_str " is a primary player")
492         }
493         else if (!(_who in sp_share) || sp_share[_who] != sp_from) {
494                 reply(_str " is not playing for " sp_from)
495         }
496         else {
497                 reply(_str " can no longer play for " sp_from)
498                 delete sp_share[_who]
499         }
500 }
501
502 sp_state ~ "(bid|pass|play)" &&
503 /^\.show/ {
504         for (_i in sp_share)
505                 say(_i " can play for " sp_share[_i]);
506 }
507
508 !sp_valid &&
509 (sp_state == "bid" || sp_state == "play") &&
510 /^\.(bid|play)\>/ {
511         if (sp_from in sp_players)
512                 say(".slap " FROM ", it is not your turn.")
513         else
514                 say(".slap " FROM ", you are not playing.")
515 }
516
517 sp_valid &&
518 sp_state == "bid" &&
519 /^\.bid [0-9]+$/ {
520         if ($2 < 0 || $2 > 13) {
521                 say("You can only bid from 0 to 13")
522         } else {
523                 i = sp_next()
524                 sp_bids[i] = $2
525                 if ($2 == 0 && !sp_looked[i]) {
526                         say(FROM " goes blind nil!")
527                         sp_nil[i] = 2
528                 } else if ($2 == 0) {
529                         say(FROM " goes nil!")
530                         sp_nil[i] = 1
531                 } else {
532                         sp_nil[i] = 0
533                 }
534                 if (sp_turn != sp_dealer) {
535                         say("Bidding goes to " sp_player "!")
536                 } else {
537                         for (p in sp_players)
538                                 say(p, "You have: " sp_hand(p, p))
539                         sp_state = "play"
540                         for (i=0; i<2; i++) {
541                                 if (sp_nil[i] == 2 || sp_nil[i+2] == 2) {
542                                         say(sp_team(i) ": select a card to pass " \
543                                             "(/msg " NICK " .pass <card>)")
544                                         sp_state = "pass"
545                                 }
546                         }
547                         if (sp_state == "play")
548                                 say("Play starts with " sp_player "!")
549                 }
550         }
551 }
552
553 sp_state == "pass" &&
554 /^\.pass (\S+)$/ {
555         _card = $2
556         _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
557
558         # check validity and pass
559         if (!(sp_from in sp_players)) {
560                 say(".slap " FROM ", you are not playing.")
561         }
562         else if (sp_nil[_team] != 2 && sp_nil[_team+2] != 2) {
563                 reply("Your team did not go blind")
564         }
565         else if (sp_pass[sp_players[sp_from]]) {
566                 reply("You have already passed a card")
567         }
568         else if (!(_card in sp_deck)) {
569                 reply("Invalid card")
570         }
571         else if (!(_card in sp_hands[sp_from])) {
572                 reply("You do not have that card")
573         }
574         else {
575                 sp_pass[sp_players[sp_from]] = $2
576                 say(sp_channel, FROM " passes a card")
577         }
578
579         # check for end of passing
580         if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
581             ((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
582                 for (i in sp_pass) {
583                         _partner = (i+2)%4
584                         _card    = sp_pass[i]
585                         delete sp_hands[sp_order[i]][_card]
586                         sp_hands[sp_order[_partner]][_card] = 1
587                 }
588                 say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
589                 for (p in sp_players)
590                         say(p, "You have: " sp_hand(p, p))
591                 sp_state = "play"
592         }
593 }
594
595 sp_state ~ "(bid|pass|play)" &&
596 /^\.look$/ {
597         if (!(sp_from in sp_players)) {
598                 say(".slap " FROM ", you are not playing.")
599         } else {
600                 sp_looked[sp_players[sp_from]] = 1
601                 say(FROM, "You have: " sp_hand(FROM, sp_from))
602         }
603 }
604
605 sp_valid &&
606 sp_state == "play" &&
607 /^\.play (\S+)/ {
608         _card = $2
609         gsub(/[^A-Za-z0-9]/, "", _card);
610         if (!(_card in sp_deck)) {
611                 reply("Invalid card")
612         }
613         else if (!(_card in sp_hands[sp_from])) {
614                 reply("You do not have that card")
615         }
616         else if (sp_suit && _card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
617                 reply("You must follow suit (" sp_suit ")")
618         }
619         else if (_card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
620                 reply("You cannot trump on the first hand")
621         }
622         else if (_card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
623                 reply("Spades have not been broken")
624         }
625         else {
626                 sp_play(_card)
627                 if (sp_state == "play") {
628                         if (length(sp_hands[sp_from]))
629                                 say(FROM, "You have: " sp_hand(FROM, sp_from))
630                         if (sp_piles)
631                                 say(sp_player ": it is your turn! " \
632                                     "(" sp_pretty(sp_piles, sp_player) ")")
633                         else
634                                 say(sp_player ": it is your turn!")
635                 }
636         }
637 }
638
639 /^\.turn/ && sp_state ~ "(bid|pass|play)" {
640         _bids = sp_bidders()
641         _pile = sp_pretty(sp_piles, FROM)
642         if (sp_state == "bid" && !_bids)
643                 say("It is " sp_player "'s bid!")
644         if (sp_state == "bid" && _bids)
645                 say("It is " sp_player "'s bid! (" _bids ")")
646         if (sp_state == "play" && !_pile)
647                 say("It is " sp_player "'s turn!")
648         if (sp_state == "play" && _pile)
649                 say("It is " sp_player "'s turn! (" _pile ")")
650         for (_i=0; sp_state == "pass" && _i<4; _i++)
651                 if ((sp_nil[_i%2+0]==2 || sp_nil[_i%2+2]==2) && !sp_pass[_i])
652                         say("Waiting for " sp_order[_i] " to pass a card!")
653 }
654
655 /^\.bids$/ && sp_state ~ "(pass|play)" {
656         say(sp_order[0] " bid " sp_bids[0] ", " \
657             sp_order[2] " bid " sp_bids[2] ", " \
658             "total: " sp_bids[0] + sp_bids[2])
659         say(sp_order[1] " bid " sp_bids[1] ", " \
660             sp_order[3] " bid " sp_bids[3] ", " \
661             "total: " sp_bids[1] + sp_bids[3])
662 }
663
664 /^\.tricks$/ && sp_state == "play" {
665         say(sp_order[0] " took " int(sp_tricks[0]) "/" int(sp_bids[0]) ", " \
666             sp_order[2] " took " int(sp_tricks[2]) "/" int(sp_bids[2]))
667         say(sp_order[1] " took " int(sp_tricks[1]) "/" int(sp_bids[1]) ", " \
668             sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
669 }
670
671 (TO == NICK || DST == sp_channel) &&
672 /^\.(score|status)$/ {
673         if (sp_state == "new") {
674                 say("There is no game in progress")
675         }
676         if (sp_state ~ "join|bid|pass|play") {
677                 say("Playing to: " \
678                     sp_playto " points, " \
679                     sp_limit  " bags")
680         }
681         if (sp_state == "join") {
682                 say("Waiting for players: " \
683                     sp_order[0] " " sp_order[1] " " \
684                     sp_order[2] " " sp_order[3])
685         }
686         if (sp_state ~ "bid|pass|play") {
687                 say(sp_team(0) ": " \
688                     int(sp_scores[0]) " points, " \
689                     int(sp_bags(0))   " bags")
690                 say(sp_team(1) ": " \
691                     int(sp_scores[1]) " points, " \
692                     int(sp_bags(1))   " bags")
693         }
694 }
695
696 /^\.((new|end|load)game|join|look|bid|pass|play)/ {
697         sp_save("var/sp_cur.json");
698 }
699
700 # Standin
701 #/^\.playfor [^ ]*$/ {
702 #}
703 #
704 #/^\.standin [^ ]*$/ {
705 #       if (p in sp_players) {
706 #       }
707 #       for (p in sp_standin) {
708 #               if ($2 in sp_standin) 
709 #               say(here " is already playing for " sp_standin[p]);
710 #       }
711 #       sp_standin[away] = here
712 #}
713 #