-- require "cards"
-- the above is taken care of with loadscript in init
------------------------------------------------------------------------------------------------
-- General functions with no class or objects, includes global variables --
------------------------------------------------------------------------------------------------
in_session = false
player_lookup={}
local white_deck
local black_deck
local function load_cards()
local blk=loadtbl("black_deck")
local wht=loadtbl("white_deck")
loadscript("aethyn", "cards")
black_deck = blk and blk or black_cards_deck
white_deck = wht and wht or white_cards_deck
end
local function save_cards()
if white_deck then
savetbl("white_deck", white_deck)
end
if black_deck then
savetbl("black_deck", black_deck)
end
end
function init(char_name)
-- checks that no game is in session then initializes a new Player object with the player's name in the variable
if in_session then
tell(char_name, "Game is already in session.")
else
gecho("{MA game of Cards Against Humanity has been started.{x")
gecho("{MTo join : \ttell gamemaster join\t (or click the link){x")
gecho("{MSee \thelp cards\t for more information.{x")
load_cards()
players = {}
-- Set the number of points required to win a game. 5 is default.
winning_points = 5
local plr=Player.new(char_name)
player_lookup[char_name]=plr
table.insert(players,plr)
in_session = true
active_players = 1
explain_rules(char_name)
-- How long the gamemaster waits to start the game, in seconds.
delay(45, start_game)
end
end
function add_player(char_name)
-- Adds a player to the game
if not players then
tell(char_name, "There is no game in session! Maybe you should start one?")
return
end
for _,v in ipairs(players) do
if v.name == char_name then
tell(char_name, "You've already joined the game!")
else
local plr=Player.new(char_name)
player_lookup[char_name] = plr
table.insert(players,plr)
active_players = active_players + 1
explain_rules(char_name)
return
end
end
end
function start_game()
-- Require at least 3 players to start a game.
if #players > 2 then
-- Deals a hand to every player
say("dealt a hand")
start_hand()
else
for _,v in ipairs(players) do
tell(v.name, "Not enough players.")
end
-- Clear values so the next game starts OK
in_session = false
players = nil
end
end
function explain_rules(char_name)
tell(char_name, "Welcome to Cards Against Humanity.")
tell(char_name, "For licensing and website information about the original game please check \thelp cards\t.")
tell(char_name, "These are the available commands. They can be repeated by telling the Gamemaster \t'help'\t:")
tell(char_name, "To show the white cards in your hand : tell Gamemaster \t'show'\t in it.")
tell(char_name, "To play a card : tell Gamemaster 'play <#>' , where # is the number of the card in your hand.")
tell(char_name, "To vote on a card : tell Gamemaster 'vote <#>' , where # is the number of the card that has been played.")
tell(char_name, "You can also click the link of the card you want to choose if your MUD client supports MXP.")
tell(char_name, "Enjoy the game!")
end
function check_player_num()
for _,v in ipairs(players) do
if not(getpc(v.name)) then
missing_players = {}
table.insert(missing_players, v.name)
active_players = #players - #missing_players
end
end
if active_players > 2 then
start_hand()
else
for _,j in ipairs(players) do
tell(j.name, "We're missing "..util.format_list("and", missing_players).."! We require three players to play, and we currently have "..active_players.."!")
tell(j.name, "There will be a 30 second break for another player to join, or for "..util.format_list("and", missing_players).." to return.")
delay(30, final_check)
end
end
end
function final_check()
for k,v in ipairs(missing_players) do
if getpc(v) then
active_players = active_players + 1
table.remove(missing_players, k)
end
end
if active_players < 3 then
for _,v in ipairs(players) do
tell(v.name, "Not enough players to continue. Ending game.")
in_session = false
players = {}
end
else
tell(v.name, "We have enough players to continue.")
start_hand()
end
end
function start_hand()
for _,v in ipairs(players) do
v:deal_hand()
v:display_hand()
end
-- Starts a hand by playing a black card
local card_id = randnum(1,#black_deck)
black_card_in_play = black_deck[card_id]
-- tell everyone what the black card is
for _,v in ipairs(players) do
tell(v.name, "{x ")
tell(v.name, "A hand has started. The black card in play is:")
tell(v.name, "{D"..black_card_in_play.."{x")
tell(v.name, "Send \"play <#>\" with the card number you wish to play or click the link.")
end
-- create table for player's white cards
cards_in_play = {}
-- remove the black card from the deck
table.remove(black_deck, card_id)
if #black_deck<1 then
loadscript("aethyn", "cards")
black_deck=black_cards_deck
end
delay(30,display_played) -- 30 seconds to play a card
end
-- play_card() function is of class Player, see there for function
function display_played()
-- Displays all the cards currently played, allows for a vote
for _,v in ipairs(players) do
tell(v.name, "The black card currently in play is:{D "..black_card_in_play.."{x")
tell(v.name, "The white cards currently played are:")
for i,j in ipairs(cards_in_play) do
if string.find(black_card_in_play, "__________") then
tell(v.name, "\t"..i.." \t"..string.gsub(black_card_in_play, "__________", "_{w"..j.text.."{T_"))
else
tell(v.name, "\t"..i.." \t"..black_card_in_play.." {w"..j.text.."{x")
end
end
tell(v.name, "Send \"vote <#>\" with the card number you wish to vote on or click the link.")
end
votes = 0
delay(20,declare_winner) -- 20 seconds to vote on a card
end
-- vote_card() is a function of class Player
function declare_winner()
-- Declares a winner, then starts a new hand with start_hand, unless point total is met
-- sort to get the winner of the hand, that card will move to front of table
-- check to see if a card has actually been played
if #cards_in_play > 0 then
table.sort(cards_in_play, function(a,b) return a.votes>b.votes end)
-- this goes here, not sure if it's the right way to do it ... the tie code seems to work, but might need more testing
winners = {}
for i=1,#cards_in_play do
if cards_in_play[1].votes == cards_in_play[i].votes then
player_lookup[cards_in_play[i].owner]:add_points()
table.insert(winners, cards_in_play[i].owner)
end
end
for _,v in ipairs(players) do
if #winners > 1 then
tell(v.name, "We have a tie at "..cards_in_play[1].votes.." votes! The winners are ")
for _,win in pairs(winners) do
for _,crd in pairs(cards_in_play) do
if crd.owner==win then
tell(v.name, win.." with "..crd.text)
end
end
end
else
tell(v.name, cards_in_play[1].owner.." is the winner with "..util.pluralize(cards_in_play[1].votes, "vote").."!")
tell(v.name, "Winning card: "..cards_in_play[1].text)
end
v.voted = false
v.played = false
player_lookup[v.name]:deal_hand()
end
-- check to see if game is ended, delay the output
delay(2, display_points)
delay(4, end_game)
else
-- End game if no one plays a card
say("no cards played")
for _,v in ipairs(players) do
tell(v.name, "No cards were played. Ending game.")
end
players = nil
in_session = false
end
-- Make sure we always have enough cards to play, "reshuffles" the deck
--if #white_cards_deck < 50 or #black_cards_deck < 5 then
--loadscript("aethyn","cards")
--end
end
function display_points()
-- Displays everyone's current points
for _,v in ipairs(players) do
tell(v.name, "The current scores are:")
for _,j in ipairs(players) do
tell(v.name, j.name.." with "..util.pluralize(j.points, "point")..".")
--tell(v.name, j.name.." with "..j.points..".")
-- if j.point == 1 then
-- mdo("tell "..v.name.." "..j.name.." with "..j.points.." point.")
-- else
-- mdo("tell "..v.name.." "..j.name.." with "..j.points.." points.")
-- end
end
end
end
-- Need a better way to end the game. in_session goes to false, but we should reset the tables too (at least players)
-- Also, need a way to end a game without a winner, either as a request or something else (too many players leave?)
function end_game()
winner = false
-- Checks if someone has enough points, then ends the game
for _,v in ipairs(players) do
if v.points == winning_points then
-- Use says for now, will use tells later
--say("Game is over. "..v.name.." is the winner!")
winning_char = v.name
winner = true
in_session = false
end
end
if not(winner) then
check_player_num()
else
for _,v in ipairs(players) do
tell(v.name, "The game is over. "..winning_char.." is the winner!")
end
mob:reward(getpc(winning_char), "qp", 5)
players = nil
end
save_cards()
end
------------------------------------------------------------------------------------------------
-- The player class, which allows us to use lua hacks to make object-like tables. --
-- Allows each player to be it's own object with attributes. --
------------------------------------------------------------------------------------------------
Player = {}
Player.__index = Player
function Player.new(char_name)
-- Initializes a player
local self = setmetatable({}, Player)
self.name = char_name
self.cards = {}
self.points = 0
self.voted = false
self.played = false
return self
end
function Player.show_instructions(self)
tell(self.name, "These are the available commands. They can be repeated at anytime by send the command 'help':")
tell(self.name, "To show what cards are in your hand, send a tell to the Gamemaster with 'show' in it.")
tell(self.name, "To show what black and white cards are currently in play, send a tell to the Gamemaster with 'display' in it.")
tell(self.name, "To play a card, send a tell to Gamemaster with 'play <#>' where # is the number of the corresponding card in your hand.")
tell(self.name, "To vote on a card, send a tell to Gamemaster with 'vote <#>', where # is the number of the corresponding card that has been played.")
tell(self.name, "You can also click the link of the card you want to choose if your MUD client supports MXP.")
end
function Player.deal_hand(self)
-- deal cards
for i=#self.cards+1,10 do
local card_id = randnum(1, #white_deck)
local card=Card.new(self.name, white_deck[card_id])
table.insert(self.cards, card)
-- remove the white card from the deck
table.remove(white_deck, card_id)
if #white_deck<1 then
loadscript("aethyn", "cards")
white_deck=white_cards_deck
end
end
end
function Player.add_points(self)
self.points = self.points + 1
end
function Player.display_hand(self)
tell(self.name, "Your cards:")
for k,v in ipairs(self.cards) do
tell(self.name, "\t"..k.." \t"..v.text)
end
end
function Player.play_card(self, card_num)
-- Plays a white card by the player. For now can only play one card, may need second card if we move on to
-- dual card black cards
if card_num < 1 or card_num > #self.cards then
tell(self.name, "That isn't a valid card number.")
else
if self.played then
tell(self.name, "You already played a card.")
else
tell(self.name, "You've successfully played card "..card_num)
table.insert(cards_in_play, self.cards[card_num])
table.remove(self.cards, card_num)
self.played = true
end
if #cards_in_play == #players then
say("all players have played a card")
cancel() -- cancel the timer that's running
display_played()
end
end
end
function Player.vote_card(self, hand_num)
-- Votes on a card
if hand_num < 1 or hand_num > #cards_in_play then
tell(self.name, "That isn't a valid card number.")
else
if self.voted then
tell(self.name, "You already voted.")
elseif self.name == cards_in_play[hand_num].owner then
tell(self.name, "You can't vote on your own card!")
else
cards_in_play[hand_num]:add_vote()
self.voted = true
votes = votes + 1
tell(self.name, "Vote recorded.")
if votes == #players then
cancel() -- cancel the timer that's running
declare_winner()
end
end
end
end
------------------------------------------------------------------------------------------------
-- The card class, which allows us to use lua hacks to make object-like tables. --
-- Each card will have name, id, owner, votes --
------------------------------------------------------------------------------------------------
Card = {}
Card.__index = Card
function Card.new(char_name, card_text)
-- Initializes a new card
local self = setmetatable({}, Card)
self.owner = char_name
self.text = card_text
self.votes = 0
return self
end
function Card.add_vote(self)
self.votes = self.votes + 1
end