mirror of
https://github.com/oddluck/limnoria-plugins.git
synced 2025-04-26 21:11:16 -05:00
374 lines
16 KiB
Python
374 lines
16 KiB
Python
###
|
|
# Copyright (c) 2014, KgBot
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright notice,
|
|
# this list of conditions, and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions, and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
# * Neither the name of the author of this software nor the name of
|
|
# contributors to this software may be used to endorse or promote products
|
|
# derived from this software without specific prior written consent.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
###
|
|
import supybot.schedule as schedule
|
|
import json
|
|
import random
|
|
import time
|
|
import os
|
|
|
|
import supybot.utils as utils
|
|
from supybot.commands import *
|
|
import supybot.plugins as plugins
|
|
import supybot.ircutils as ircutils
|
|
import supybot.callbacks as callbacks
|
|
try:
|
|
from supybot.i18n import PluginInternationalization
|
|
_ = PluginInternationalization('BlackJack')
|
|
except:
|
|
# Placeholder that allows to run the plugin on a bot
|
|
# without the i18n module
|
|
_ = lambda x:x
|
|
|
|
class BlackJack(callbacks.Plugin):
|
|
"""Add the help for "@plugin help BlackJack" here
|
|
This should describe *how* to use this plugin."""
|
|
threaded = True
|
|
|
|
def __init__(self, irc):
|
|
self.__parent = super(BlackJack, self)
|
|
self.__parent.__init__(irc)
|
|
# Dictionary of players, holds important things about each player.
|
|
self.players = {}
|
|
# List of scheduled games
|
|
self.events = []
|
|
self.minStake = 10
|
|
self.maxStake = 50
|
|
|
|
def _isScheduled(self, name):
|
|
""" Checks to see if player is already playing game."""
|
|
if name in self.events:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def _waitingPlayerAction(self, player):
|
|
""" Checks to see if player has got his first 2 cards and now we're waiting for him to hit/stand or double."""
|
|
if player in self.players.keys() and self.players[player]["waitingAction"] == True:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def _deal(self, who, player):
|
|
_allowed_whos = ["player", "bank"]
|
|
if who in _allowed_whos:
|
|
cards = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K"]
|
|
card = random.choice(cards)
|
|
# Because we J/Q/K are not numbers we must convert them to 10's, but this is not nice, and we must implement
|
|
# 2 types of cards here, one that will be answered to player and one that will be added to score
|
|
if card == "J" or card == "Q" or card == "K":
|
|
card = 10
|
|
if who == "player":
|
|
if card == 1:
|
|
# If 11 + score is bigger then 21 1 will be 1
|
|
if self.players[player]["score"] + 11 > 21:
|
|
card = 1
|
|
# If 1 + score is less then 21 1 will be 11
|
|
else:
|
|
card = 11
|
|
self.players[player]["score"] = self.players[player]["score"] + card
|
|
# Returns card because we might want to tell the player which card he's got.
|
|
return card
|
|
else:
|
|
if card == 1:
|
|
if self.players[player]["bankScore"] + 11 > 21:
|
|
card = 1
|
|
else:
|
|
card = 11
|
|
self.players[player]["bankScore"] = self.players[player]["bankScore"] + card
|
|
return card
|
|
|
|
def _finishGame(self, irc, player):
|
|
self.players[player]["waitingAction"] = False
|
|
playerScore = self.players[player]["score"]
|
|
bankScore = self.players[player]["bankScore"]
|
|
if playerScore == 21 and bankScore != 21:
|
|
self._playerWins(irc, player)
|
|
elif playerScore == 21 and bankScore == 21:
|
|
irc.reply("This is push, nobody wins.")
|
|
self._push(player)
|
|
elif bankScore == 21 and playerScore != 21:
|
|
self._bankWins(irc, player)
|
|
elif playerScore < 21 and playerScore > bankScore:
|
|
self._playerWins(irc, player)
|
|
elif bankScore < 21 and bankScore > playerScore:
|
|
self._bankWins(irc, player)
|
|
elif playerScore == bankScore:
|
|
irc.reply("This is push, nobody wins.")
|
|
self._push(player)
|
|
elif playerScore > 21 and bankScore < 21:
|
|
self._bankWins(irc, player)
|
|
else:
|
|
self._playerWins(irc, player)
|
|
|
|
def _removeScheduledGame(self, name):
|
|
try:
|
|
schedule.removeEvent(name)
|
|
self.events.remove(name)
|
|
except:
|
|
try:
|
|
self.events.remove(name)
|
|
except:
|
|
pass
|
|
|
|
def _push(self, player):
|
|
stake = self.players[player]["stake"]
|
|
chips = Chips()
|
|
chips._addChips(player, stake)
|
|
game_name = "game_%s" % player
|
|
self._removeScheduledGame(game_name)
|
|
|
|
def _playerWins(self, irc, player, blackjack=False):
|
|
game_name = "game_%s" % player
|
|
if blackjack:
|
|
amount = self._blackjackPrize(self.players[player]["stake"])
|
|
else:
|
|
amount = self.players[player]["stake"] * 2
|
|
chips = Chips()
|
|
chips._addChips(player, amount)
|
|
irc.reply("Congrats, you have won and you got %s chips." % amount)
|
|
self._removeScheduledGame(game_name)
|
|
|
|
def _bankWins(self, irc, player):
|
|
game_name = "game_%s" % player
|
|
irc.reply("Sorry but you've lost this time.")
|
|
self._removeScheduledGame(game_name)
|
|
|
|
def _playerChips(self, player):
|
|
""" Return number of chips that player has."""
|
|
chipsClass = Chips()
|
|
chips = chipsClass._getChips(player)
|
|
return chips
|
|
|
|
def _finishBank(self, irc, player):
|
|
if player in self.players.keys():
|
|
while(self.players[player]["bankScore"] < 17):
|
|
card = self._deal("bank", player)
|
|
irc.reply("Dealer has got \x02%s\x02, and his score is \x02%s\x02." % (card, self.players[player]["bankScore"]))
|
|
self._finishGame(irc, player)
|
|
|
|
def _addNewPlayer(self, player, stake):
|
|
""" Adds new player and needed things to self.players dictionary."""
|
|
self.players[player] = {}
|
|
# This is set because this is the best way to check if player is playing when he wants to hit/double/stand
|
|
self.players[player]["waitingAction"] = False
|
|
# We must keep track of players score after each card is dealt
|
|
self.players[player]["score"] = 0
|
|
# Also we must keep track of bank score
|
|
self.players[player]["bankScore"] = 0
|
|
# And we need to know how much the player wants to stake
|
|
self.players[player]["stake"] = stake
|
|
# We must also remove initial stake from player, just like he put it on table
|
|
chips = Chips()
|
|
chips._removeChips(player, stake)
|
|
|
|
def _scheduleNewGame(self, command, when, name, player, irc):
|
|
# Here we're adding game name to the list of games, from where we check who's playing and who's not
|
|
self.events.append(name)
|
|
# Here we schedule the command to run after 10s and to finish game
|
|
schedule.addEvent(command, time.time() + when, name, args=(irc, player))
|
|
|
|
def _checkBlackjack(self, irc, player):
|
|
""" Checking to see if enyone has blackjack after first two cards are dealt."""
|
|
if player in self.players.keys():
|
|
if self.players[player]["score"] == 21 and self.players[player]["bankScore"] != 21:
|
|
self._playerWins(irc, player, True)
|
|
self.players[player]["waitingAction"] = False
|
|
elif self.players[player]["bankScore"] == 21 and self.players[player]["score"] != 21:
|
|
self._bankWins(irc, player)
|
|
else:
|
|
return
|
|
|
|
def _blackjackPrize(self, stake):
|
|
# BlackJack prize is not same as regular prize. It is 3:1 so we must calculate it
|
|
halfStake = stake / 2
|
|
newStake = (stake * 2) + halfStake
|
|
return newStake
|
|
|
|
|
|
def blackjack(self, irc, msg, args, stake):
|
|
"""<stake> - amount of stake, between 10 and 50
|
|
|
|
Starts a new game."""
|
|
# Because nicks are case-insensitive we must turn nick to lower version.
|
|
player = str(msg.nick).lower()
|
|
# Nicks are uniqe and we will use nick for scheduling game.
|
|
game_name = "game_%s" % player
|
|
# Checks if player has any chips.
|
|
chips = self._playerChips(player)
|
|
chipsClass = Chips()
|
|
# If this is True player is already playing blackjack and only one game is allowed per player.
|
|
if self._isScheduled(game_name):
|
|
irc.reply("You can play only one instance of the game in same time.")
|
|
# If player does not have chips he can't play, logical.
|
|
if chips == "NoChipsFile" or chips == False or chips == None:
|
|
chipsClass._addChips(player, stake)
|
|
chips = stake
|
|
elif stake > chips:
|
|
chipsClass._addChips(player, stake - chips)
|
|
chips = stake
|
|
if stake >= self.minStake and stake <= self.maxStake and stake <= chips:
|
|
# Now is good time to add new player and actually start a game.
|
|
self._addNewPlayer(player, stake)
|
|
self._startNewGame(irc, player)
|
|
else:
|
|
irc.reply("Something is wrong with your stake, maybe it's too high or too low, or maybe you don't have enough chips.")
|
|
blackjack = wrap(blackjack, ["int"])
|
|
|
|
def _startNewGame(self, irc, player):
|
|
# We deal first card to the player
|
|
playerFirstCard = self._deal('player', player)
|
|
# And we must tell the player which card he got
|
|
irc.reply("Your first card is %s" % playerFirstCard)
|
|
# We must also deal first card to the bank
|
|
bankFirstCard = self._deal('bank', player)
|
|
# And player shouldn't know which is the dealers first card
|
|
irc.reply("Dealer has got his first card, face down.")
|
|
# Now we deal second card to the player
|
|
playerSecondCard = self._deal('player', player)
|
|
# And we have to tell the player what's his second card, and also what's his score
|
|
irc.reply("Your second card is %s, and you're score is %s" % (playerSecondCard, self.players[player]["score"]))
|
|
# Bank just got it's second card
|
|
bankSecondCard = self._deal('bank', player)
|
|
# Player needs to know which is dealer's second card
|
|
irc.reply("Dealer has got his second card %s, his score is now \x02%s\02.What are you gonna do, stand, hit or double. You have 20 seconds to decide." % (bankSecondCard, self.players[player]["bankScore"]))
|
|
# Now we wait for user to hit/double/stand and our bot must know that he's waiting for player action
|
|
self.players[player]["waitingAction"] = True
|
|
# Each game will wait 10s for user input and then it'll end the game if nothing happens, and we must schedule it
|
|
self._scheduleNewGame(self._finishBank, 20, "game_%s" % player, player, irc)
|
|
# We must check if somebody has got blackjack after first 2 cards
|
|
self._checkBlackjack(irc, player)
|
|
|
|
def hit(self, irc, msg, args):
|
|
"""Takes no arguments
|
|
|
|
Hit!!!"""
|
|
player = str(msg.nick).lower()
|
|
if self._waitingPlayerAction(player) == True:
|
|
game_name = "game_%s" % player
|
|
self._removeScheduledGame(game_name)
|
|
card = self._deal('player', player)
|
|
irc.reply("You've got %s, and your score is %s." % (card, self.players[player]["score"]))
|
|
if self.players[player]["score"] > 21:
|
|
irc.reply("You're busted.")
|
|
self._bankWins(irc, player)
|
|
else:
|
|
self._scheduleNewGame(self._finishBank, 20, game_name, player, irc)
|
|
else:
|
|
irc.reply("You're not playing blackjack at this moment. Start a new game with +blackjack 50")
|
|
hit = wrap(hit)
|
|
|
|
def double(self, irc, msg, args):
|
|
"""Takes no arguments
|
|
|
|
Double!!!!"""
|
|
player = str(msg.nick).lower()
|
|
if self._waitingPlayerAction(player) == True:
|
|
stake = self.players[player]["stake"]
|
|
chips = self._playerChips(player)
|
|
if chips != False and chips != None and chips != "NoChipsFile" and chips >= stake:
|
|
game_name = "game_%s" % player
|
|
self._removeScheduledGame(game_name)
|
|
chipsClass = Chips()
|
|
chipsClass._removeChips(player, stake)
|
|
self.players[player]["stake"] = stake * 2
|
|
irc.reply("Your stake was %s, and now it is %s." % (stake, self.players[player]["stake"]))
|
|
card = self._deal('player', player)
|
|
irc.reply("You've got %s, and your score is %s" % (card, self.players[player]["score"]))
|
|
if self.players[player]["score"] > 21:
|
|
irc.reply("You're busted.")
|
|
self._bankWins(irc, player)
|
|
else:
|
|
self._finishBank(irc, player)
|
|
else:
|
|
irc.reply("You don't have enough chips for double stake.")
|
|
else:
|
|
irc.reply("You're not playing blackjack at this moment. Start a new game with +blackjack 50")
|
|
double = wrap(double)
|
|
|
|
def stand(self, irc, msg, args):
|
|
"""Takes no arguments.
|
|
|
|
Stand!!!"""
|
|
player = str(msg.nick).lower()
|
|
if self._waitingPlayerAction(player) == True:
|
|
self._finishBank(irc, player)
|
|
else:
|
|
irc.reply("You're not playing blackjack at this moment. Start a new game with +blackjack 50")
|
|
stand = wrap(stand)
|
|
|
|
class Chips():
|
|
def __init__(self):
|
|
try:
|
|
with open("{0}/local/chips.json".format(os.path.dirname(os.path.abspath(__file__))), "r") as chipsFile:
|
|
self.players = json.load(chipsFile)
|
|
except:
|
|
self.players = False
|
|
|
|
def _getChips(self, player):
|
|
if self.players:
|
|
if player in self.players.keys():
|
|
try:
|
|
return self.players[player]["chips"]
|
|
except:
|
|
return False
|
|
else:
|
|
return None
|
|
else:
|
|
return "NoChipsFile"
|
|
|
|
def _addChips(self, player, amount):
|
|
if self.players:
|
|
if player in self.players.keys():
|
|
self.players[player]["chips"] = self.players[player]["chips"] + amount
|
|
self._saveChips()
|
|
else:
|
|
self.players[player] = {}
|
|
self.players[player]["chips"] = amount
|
|
self._saveChips()
|
|
else:
|
|
return "NoChipsFile"
|
|
|
|
def _removeChips(self, player, amount):
|
|
if self.players:
|
|
if player in self.players.keys():
|
|
self.players[player]["chips"] = self.players[player]["chips"] - amount
|
|
self._saveChips()
|
|
|
|
def _saveChips(self):
|
|
with open("{0}/local/chips.json".format(os.path.dirname(os.path.abspath(__file__))), "w") as chips:
|
|
json.dump(self.players, chips, indent=4)
|
|
|
|
|
|
Class = BlackJack
|
|
|
|
|
|
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
|
|