+# For saving
+@include "json.awk"
+
# Functions
function sp_init(cards, tmp0, tmp1)
{
- sp_valid = 0 # Message sent from sp_player
- sp_player = "" # Who's turn it is
- sp_turn = 0 # Index of who's turn it is
- delete sp_hands # [p] Each players cards
-
# Init deck
cards ="As Ks Qs Js 10s 9s 8s 7s 6s 5s 4s 3s 2s "\
"Ah Kh Qh Jh 10h 9h 8h 7h 6h 5h 4h 3h 2h "\
function sp_reset(type)
{
+ # Per message
+ if (type >= 0) {
+ sp_from = "" # The speakers player name
+ sp_valid = "" # It is the speaker turn
+ }
+
# Per hand
if (type >= 0) {
sp_suit = "" # The lead suit {s,h,d,c}
sp_owner = "" # Who started the game
sp_playto = 0 # Score the game will go to
sp_dealer =-1 # Who is dealing this round
+ sp_turn = 0 # Index of who's turn it is
+ sp_player = "" # Who's turn it is
+ sp_limit = 10 # Bag out limit
+ delete sp_hands # [p] Each players cards
delete sp_players # [p] Player names players["name"] -> i
+ delete sp_cloaks # [c] Player cloaks cloaks["cloak"] -> "name"
delete sp_order # [i] Player order order[i] -> "name"
delete sp_scores # [i] Teams score
}
}
+function sp_acopy(dst, src, key)
+{
+ if (isarray(src))
+ for (key in src)
+ json_copy(dst, key, src[key])
+}
+
+function sp_save(file, game)
+{
+ # Per hand
+ game["suit"] = sp_suit;
+ game["piles"] = sp_piles;
+ json_copy(game, "pile", sp_pile);
+
+ # Per round
+ game["state"] = sp_state;
+ game["broken"] = sp_broken;
+ json_copy(game, "looked", sp_looked);
+ json_copy(game, "bids", sp_bids);
+ json_copy(game, "nil", sp_nil);
+ json_copy(game, "pass", sp_pass);
+ json_copy(game, "tricks", sp_tricks);
+
+ # Per game
+ game["channel"] = sp_channel;
+ game["owner"] = sp_owner;
+ game["playto"] = sp_playto;
+ game["dealer"] = sp_dealer;
+ game["turn"] = sp_turn;
+ game["player"] = sp_player;
+ game["limit"] = sp_limit;
+ json_copy(game, "hands", sp_hands);
+ json_copy(game, "players", sp_players);
+ json_copy(game, "cloaks", sp_cloaks);
+ json_copy(game, "order", sp_order);
+ json_copy(game, "scores", sp_scores);
+
+ # Save
+ json_save(file, game);
+}
+
+function sp_load(file, game)
+{
+ # Load
+ json_load(file, game);
+
+ # Per hand
+ sp_suit = game["suit"];
+ sp_piles = game["piles"];
+ sp_acopy(sp_pile, game["pile"]);
+
+ # Per round
+ sp_state = game["state"];
+ sp_broken = game["broken"];
+ sp_acopy(sp_looked, game["looked"]);
+ sp_acopy(sp_bids, game["bids"]);
+ sp_acopy(sp_nil, game["nil"]);
+ sp_acopy(sp_pass, game["pass"]);
+ sp_acopy(sp_tricks, game["tricks"]);
+
+ # Per game
+ sp_channel = game["channel"];
+ sp_owner = game["owner"];
+ sp_playto = game["playto"];
+ sp_dealer = game["dealer"];
+ sp_turn = game["turn"];
+ sp_player = game["player"];
+ sp_limit = game["limit"];
+ sp_acopy(sp_hands, game["hands"]);
+ sp_acopy(sp_players, game["players"]);
+ sp_acopy(sp_cloaks, game["cloaks"]);
+ sp_acopy(sp_order, game["order"]);
+ sp_acopy(sp_scores, game["scores"]);
+}
+
function sp_pretty(cards, who)
{
if (!plain[who]) {
{
prev = sp_turn
sp_turn = who ? sp_players[who] : (sp_turn + 1) % 4
- sp_player = sp_order[sp_turn]
+ if (length(sp_order) == 4)
+ sp_player = sp_order[sp_turn]
return prev
}
function sp_bags(i, bags)
{
- bags = sp_scores[i] % 10
+ bags = sp_scores[i] % sp_limit
if (bags < 0)
- bags += 10
+ bags += sp_limit
return bags
}
+function sp_bidders( i, turn, bid, bids)
+{
+ for (i = 0; i < 4; i++) {
+ turn = (sp_dealer + i) % 4
+ if (sp_bids[turn] && !sp_nil[turn]) {
+ bid = sp_order[turn] ":" sp_bids[turn]
+ bids = bids " " bid
+ }
+ }
+ gsub(/^ +| +$/, "", bids)
+ return bids
+}
+
function sp_score( bids, tricks)
{
for (i=0; i<2; i++) {
bids = sp_bids[i] + sp_bids[i+2]
tricks = sp_tricks[i] + sp_tricks[i+2]
bags = tricks - bids
- if (sp_bags(i) + bags >= 10) {
+ if (sp_bags(i) + bags >= sp_limit) {
say(sp_team(i) " bag out")
- sp_scores[i] -= 100
+ sp_scores[i] -= sp_limit * 10
}
if (tricks >= bids) {
- say(sp_team(i) " make their bid")
+ say(sp_team(i) " make their bid: " tricks "/" bids)
sp_scores[i] += bids*10 + bags;
} else {
- say(sp_team(i) " go bust")
+ say(sp_team(i) " go bust: " tricks "/" bids)
sp_scores[i] -= bids*10;
}
}
function sp_play(card, winner, pi)
{
- delete sp_hands[FROM][card]
+ delete sp_hands[sp_from][card]
sp_pile[card] = sp_player
sp_piles = sp_piles (sp_piles?",":"") card
sp_next()
srand(seed)
sp_init()
sp_reset(2)
+ sp_load("var/sp_cur.json");
+ if (sp_channel)
+ say(sp_channel, "Game restored.")
}
// {
- sp_valid = (FROM && FROM == sp_player)
+ sp_from = AUTH in sp_cloaks ? sp_cloaks[AUTH] : FROM
+ sp_valid = sp_from && sp_from == sp_player
}
! /help/ &&
say("Spades! " sp_pretty("As,Ah,Ad,Ac", FROM))
}
+FROM == OWNER &&
+/^\.savegame/ {
+ sp_save("var/sp_save.json");
+ say("Game saved.")
+}
+
+FROM == OWNER &&
+/^\.loadgame/ {
+ sp_load("var/sp_save.json");
+ say("Game loaded.")
+}
+
# Help
/^\.help [Ss]pades$/ {
say("Spades -- play a game of spades")
say("Examples:")
say(".newgame [score] -- start a game to <score> points, default 500")
say(".endgame -- abort the current game")
+ say(".savegame -- save the current game to disk")
+ say(".loadgame -- load the previously saved game")
say(".join -- join the current game")
say(".look -- look at your cards")
say(".bid n -- bid for <n> tricks")
} else {
sp_owner = FROM
sp_playto = $2 ? $2 : 200
+ sp_limit = sp_playto > 200 ? 10 : 5;
sp_state = "join"
sp_channel = DST
- say(sp_owner " starts a game of Spades to " sp_playto "!")
+ say(sp_owner " starts a game of Spades to " sp_playto " with " sp_limit " bags!")
#say("#rhnoise", sp_owner " starts a game of Spades in " DST "!")
}
}
-(FROM == sp_owner || FROM == OWNER) &&
+(sp_from == sp_owner || FROM == OWNER) &&
/^\.endgame$/ {
if (sp_state == "new") {
reply("There is no game in progress.")
} else {
say(FROM " ends the game")
- sp_reset(5)
+ sp_reset(2)
}
}
else if (sp_state == "play") {
reply("The game has already started")
}
- else if (sp_state == "join" && FROM in sp_players) {
+ else if (sp_state == "join" && sp_from in sp_players) {
reply("You are already playing")
}
else if (sp_state == "join") {
i = sp_next()
- sp_order[i] = FROM
sp_players[FROM] = i
+ if (AUTH)
+ sp_cloaks[AUTH] = FROM
+ sp_order[i] = FROM
say(FROM " joins the game!")
}
if (sp_state == "join" && sp_turn == 0)
!sp_valid &&
(sp_state "bid" || sp_state == "play") &&
/^\.(bid|play)\>/ {
- if (FROM in sp_players)
+ if (sp_from in sp_players)
say(".slap " FROM ", it is not your turn.")
else
say(".slap " FROM ", you are not playing.")
} else if ($2 == 0) {
say(FROM " goes nil!")
sp_nil[i] = 1
+ } else {
+ sp_nil[i] = 0
}
if (sp_turn != sp_dealer) {
say("Bidding goes to " sp_player "!")
sp_state == "pass" &&
/^\.pass (\S+)$/ {
- card = $2
- team = sp_players[FROM] % 2
- if (!(FROM in sp_players)) {
+ _card = $2
+ _team = sp_from in sp_players ? sp_players[sp_from] % 2 : 0
+
+ # check validity and pass
+ if (!(sp_from in sp_players)) {
say(".slap " FROM ", you are not playing.")
}
- else if (sp_nil[team] != 2 && sp_nil[team+2] != 2) {
+ else if (sp_nil[_team] != 2 && sp_nil[_team+2] != 2) {
reply("Your team did not go blind")
}
- else if (sp_pass[sp_players[FROM]]) {
+ else if (sp_pass[sp_players[sp_from]]) {
reply("You have already passed a card")
}
- else if (!(card in sp_deck)) {
+ else if (!(_card in sp_deck)) {
reply("Invalid card")
}
- else if (!(card in sp_hands[FROM])) {
+ else if (!(_card in sp_hands[sp_from])) {
reply("You do not have that card")
}
else {
- sp_pass[sp_players[FROM]] = $2
+ sp_pass[sp_players[sp_from]] = $2
say(sp_channel, FROM " passes a card")
}
+
+ # check for end of passing
if (((sp_nil[0] != 2 && sp_nil[2] != 2) || (sp_pass[0] && sp_pass[2])) &&
((sp_nil[1] != 2 && sp_nil[3] != 2) || (sp_pass[1] && sp_pass[3]))) {
for (i in sp_pass) {
- partner = (i+2)%4
- card = sp_pass[i]
- delete sp_hands[sp_order[i]][card]
- sp_hands[sp_order[partner]][card] = 1
+ _partner = (i+2)%4
+ _card = sp_pass[i]
+ delete sp_hands[sp_order[i]][_card]
+ sp_hands[sp_order[_partner]][_card] = 1
}
say(sp_channel, "Cards have been passed, play starts with " sp_player "!")
for (p in sp_players)
sp_state ~ "(play|bid)" &&
/^\.look$/ {
- if (!(FROM in sp_players)) {
+ if (!(sp_from in sp_players)) {
say(".slap " FROM ", you are not playing.")
} else {
- sp_looked[sp_players[FROM]] = 1
- say(FROM, "You have: " sp_hand(FROM))
+ sp_looked[sp_players[sp_from]] = 1
+ say(FROM, "You have: " sp_hand(sp_from))
}
}
if (!(card in sp_deck)) {
reply("Invalid card")
}
- else if (!(card in sp_hands[FROM])) {
+ else if (!(card in sp_hands[sp_from])) {
reply("You do not have that card")
}
- else if (sp_suit && card !~ sp_suit && sp_hasa(FROM, sp_suit)) {
+ else if (sp_suit && card !~ sp_suit && sp_hasa(sp_from, sp_suit)) {
reply("You must follow suit (" sp_suit ")")
}
- else if (card ~ /s/ && length(sp_hands[FROM]) == 13 && sp_hasa(FROM, "[^s]$")) {
+ else if (card ~ /s/ && length(sp_hands[sp_from]) == 13 && sp_hasa(sp_from, "[^s]$")) {
reply("You cannot trump on the first hand")
}
- else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(FROM, "[^s]$") && !sp_broken) {
+ else if (card ~ /s/ && length(sp_pile) == 0 && sp_hasa(sp_from, "[^s]$") && !sp_broken) {
reply("Spades have not been broken")
}
else {
sp_play(card)
- say(FROM, "You have: " sp_hand(FROM))
if (sp_state == "play") {
+ if (length(sp_hands[sp_from]))
+ say(FROM, "You have: " sp_hand(sp_from))
if (sp_piles)
say(sp_player ": it is your turn! " \
"(" sp_pretty(sp_piles, sp_player) ")")
sp_order[3] " took " int(sp_tricks[3]) "/" int(sp_bids[3]))
}
+/^\.turn/ && sp_state ~ "(play|bid)" {
+ _bids = sp_bidders()
+ _pile = sp_pretty(sp_piles, FROM)
+ if (sp_state == "bid" && !_bids)
+ say("It is " sp_player "'s bid!")
+ if (sp_state == "bid" && _bids)
+ say("It is " sp_player "'s bid! (" _bids ")")
+ if (sp_state == "play" && !_pile)
+ say("It is " sp_player "'s turn!")
+ if (sp_state == "play" && _pile)
+ say("It is " sp_player "'s turn! (" _pile ")")
+}
+
(TO == NICK || DST == sp_channel) &&
/^\.(score|status)$/ {
if (sp_state == "new") {
}
}
+/^\.((new|end|load)game|join|look|bid|play)/ {
+ sp_save("var/sp_cur.json");
+}
+
# Standin
#/^\.playfor [^ ]*$/ {
#}