diff --git a/packaging/debian/control b/packaging/debian/control
index 93660791..784c4b40 100644
--- a/packaging/debian/control
+++ b/packaging/debian/control
@@ -6,7 +6,7 @@ Build-Depends: debhelper, python-support
Standards-Version: 3.8.0
Package: python-fpdb
-Architecture: any
+Architecture: all
Section: games
Priority: extra
Depends: ${python:Depends}, python-gtk2, python-matplotlib,
diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py
index b8022a45..89f4fb29 100755
--- a/pyfpdb/Configuration.py
+++ b/pyfpdb/Configuration.py
@@ -278,6 +278,15 @@ class Import:
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \
% (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache)
+class HudUI:
+ def __init__(self, node):
+ self.node = node
+ self.label = node.getAttribute('label')
+
+ def __str__(self):
+ return " label = %s\n" % self.label
+
+
class Tv:
def __init__(self, node):
self.combinedStealFold = node.getAttribute("combinedStealFold")
@@ -311,13 +320,21 @@ class Config:
pass
if file == None: # that didn't work either, just die
- print "No HUD_config_xml found. Exiting"
- sys.stderr.write("No HUD_config_xml found. Exiting")
+ print "No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting"
+ sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting")
+ print "press enter to continue"
+ sys.stdin.readline()
sys.exit()
# Parse even if there was no real config file found and we are using the example
# If using the example, we'll edit it later
+# sc 2009/10/04 Example already copied to main filename, is this ok?
log.info("Reading configuration file %s" % file)
+ if os.sep in file:
+ print "\nReading configuration file %s\n" % file
+ else:
+ print "\nReading configuration file %s" % file
+ print "in %s\n" % os.getcwd()
try:
doc = xml.dom.minidom.parse(file)
except:
@@ -389,6 +406,10 @@ class Config:
imp = Import(node = imp_node)
self.imp = imp
+ for hui_node in doc.getElementsByTagName('hud_ui'):
+ hui = HudUI(node = hui_node)
+ self.ui = hui
+
for tv_node in doc.getElementsByTagName("tv"):
tv = Tv(node = tv_node)
self.tv = tv
@@ -405,6 +426,8 @@ class Config:
db_pass = df_parms['db-password'])
self.save(file=os.path.join(self.default_config_path, "HUD_config.xml"))
+ print ""
+
def set_hhArchiveBase(self, path):
self.imp.node.setAttribute("hhArchiveBase", path)
@@ -454,11 +477,15 @@ class Config:
def find_example_config(self):
if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd
- file = 'HUD_config.xml.example' # so we use it
+ file = 'HUD_config.xml' # so we use it
+ try:
+ shutil.copyfile(file+'.example', file)
+ except:
+ file = ''
print "No HUD_config.xml found, using HUD_config.xml.example.\n", \
- "A HUD_config.xml will be written. You will probably have to edit it."
+ "A HUD_config.xml has been created. You will probably have to edit it."
sys.stderr.write("No HUD_config.xml found, using HUD_config.xml.example.\n" + \
- "A HUD_config.xml will be written. You will probably have to edit it.")
+ "A HUD_config.xml has been created. You will probably have to edit it.")
else:
file = None
return file
@@ -598,6 +625,19 @@ class Config:
try: tv['combinedPostflop'] = self.tv.combinedPostflop
except: tv['combinedPostflop'] = True
return tv
+
+ # Allow to change the menu appearance
+ def get_hud_ui_parameters(self):
+ hui = {}
+ default_text = 'FPDB Menu - Right click\nLeft-Drag to Move'
+ try:
+ hui['label'] = self.ui.label
+ if self.ui.label == '': # Empty menu label is a big no-no
+ hui['label'] = default_text
+ except:
+ hui['label'] = default_text
+ return hui
+
def get_import_parameters(self):
imp = {}
diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py
index c923517e..38c475d9 100755
--- a/pyfpdb/Database.py
+++ b/pyfpdb/Database.py
@@ -537,6 +537,16 @@ class Database:
else:
return None
+ def get_player_names(self, config, site_id=None, like_player_name="%"):
+ """Fetch player names from players. Use site_id and like_player_name if provided"""
+
+ if site_id == None:
+ site_id = -1
+ c = self.get_cursor()
+ c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id))
+ rows = c.fetchall()
+ return rows
+
#returns the SQL ids of the names given in an array
# TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict
# { playername: id } instead of depending on it's relation to the positions list
@@ -1133,7 +1143,7 @@ class Database:
elif self.backend == self.MYSQL_INNODB:
c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout
,rebuyOrAddon, speed, headsUp, shootout, matrix)
- values (1, 1, 0, 0, 0, False, False, null, False, False, False);""")
+ values (1, 0, 0, 0, False, False, null, False, False, False);""")
#end def fillDefaultData
@@ -1372,11 +1382,17 @@ class Database:
importtime,
seats,
maxseats,
+ playersVpi,
boardcard1,
boardcard2,
boardcard3,
boardcard4,
boardcard5,
+ playersAtStreet1,
+ playersAtStreet2,
+ playersAtStreet3,
+ playersAtStreet4,
+ playersAtShowdown,
street1Pot,
street2Pot,
street3Pot,
@@ -1385,20 +1401,14 @@ class Database:
)
VALUES
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
- %s, %s, %s, %s, %s, %s, %s)"""
+ %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
+ %s, %s, %s)"""
#--- texture,
-#-- playersVpi,
-#-- playersAtStreet1,
-#-- playersAtStreet2,
-#-- playersAtStreet3,
-#-- playersAtStreet4,
-#-- playersAtShowdown,
#-- street0Raises,
#-- street1Raises,
#-- street2Raises,
#-- street3Raises,
#-- street4Raises,
-#-- seats,
q = q.replace('%s', self.sql.query['placeholder'])
print "DEBUG: p: %s" %p
@@ -1409,20 +1419,19 @@ class Database:
p['siteHandNo'],
p['handStart'],
datetime.today(), #importtime
-# len(p['names']), #seats
- p['maxSeats'],
p['seats'],
+ p['maxSeats'],
+ p['playersVpi'],
p['boardcard1'],
p['boardcard2'],
p['boardcard3'],
p['boardcard4'],
p['boardcard5'],
-# hudCache['playersVpi'],
-# hudCache['playersAtStreet1'],
-# hudCache['playersAtStreet2'],
-# hudCache['playersAtStreet3'],
-# hudCache['playersAtStreet4'],
-# hudCache['playersAtShowdown'],
+ p['playersAtStreet1'],
+ p['playersAtStreet2'],
+ p['playersAtStreet3'],
+ p['playersAtStreet4'],
+ p['playersAtShowdown'],
# hudCache['street0Raises'],
# hudCache['street1Raises'],
# hudCache['street2Raises'],
diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py
index 3de15ee5..a4fb630b 100644
--- a/pyfpdb/DerivedStats.py
+++ b/pyfpdb/DerivedStats.py
@@ -22,76 +22,6 @@ class DerivedStats():
def __init__(self, hand):
self.hand = hand
- self.activeSeats = 0
- self.position = 0
- self.tourneyTypeId = 0
-
- self.HDs = 0
- self.street0VPI = 0
- self.street0Aggr = 0
- self.street0_3BChance = 0
- self.street0_3BDone = 0
- self.street0_4BChance = 0
- self.street0_4BDone = 0
-
- self.street1Seen = 0
- self.street2Seen = 0
- self.street3Seen = 0
- self.street4Seen = 0
- self.sawShowdown = 0
-
- self.street1Aggr = 0
- self.street2Aggr = 0
- self.street3Aggr = 0
- self.street4Aggr = 0
-
- self.otherRaisedStreet1 = 0
- self.otherRaisedStreet2 = 0
- self.otherRaisedStreet3 = 0
- self.otherRaisedStreet4 = 0
- self.foldToOtherRaisedStreet1 = 0
- self.foldToOtherRaisedStreet2 = 0
- self.foldToOtherRaisedStreet3 = 0
- self.foldToOtherRaisedStreet4 = 0
- self.wonWhenSeenStreet1 = 0
- self.wonAtSD = 0
-
- self.stealAttemptChance = 0
- self.stealAttempted = 0
- self.foldBbToStealChance = 0
- self.foldedBbToSteal = 0
- self.foldSbToStealChance = 0
- self.foldedSbToSteal = 0
-
- self.street1CBChance = 0
- self.street1CBDone = 0
- self.street2CBChance = 0
- self.street2CBDone = 0
- self.street3CBChance = 0
- self.street3CBDone = 0
- self.street4CBChance = 0
- self.street4CBDone = 0
-
- self.foldToStreet1CBChance = 0
- self.foldToStreet1CBDone = 0
- self.foldToStreet2CBChance = 0
- self.foldToStreet2CBDone = 0
- self.foldToStreet3CBChance = 0
- self.foldToStreet3CBDone = 0
- self.foldToStreet4CBChance = 0
- self.foldToStreet4CBDone = 0
-
- self.totalProfit = 0
-
- self.street1CheckCallRaiseChance = 0
- self.street1CheckCallRaiseDone = 0
- self.street2CheckCallRaiseChance = 0
- self.street2CheckCallRaiseDone = 0
- self.street3CheckCallRaiseChance = 0
- self.street3CheckCallRaiseDone = 0
- self.street4CheckCallRaiseChance = 0
- self.street4CheckCallRaiseDone = 0
-
self.hands = {}
self.handsplayers = {}
@@ -106,6 +36,9 @@ class DerivedStats():
print "hands =", self.hands
print "handsplayers =", self.handsplayers
+ def getHands(self):
+ return self.hands
+
def assembleHands(self, hand):
self.hands['tableName'] = hand.tablename
self.hands['siteHandNo'] = hand.handid
@@ -114,17 +47,46 @@ class DerivedStats():
self.hands['importTime'] = None
self.hands['seats'] = self.countPlayers(hand)
self.hands['maxSeats'] = hand.maxseats
- self.hands['boardcard1'] = None
- self.hands['boardcard2'] = None
- self.hands['boardcard3'] = None
- self.hands['boardcard4'] = None
- self.hands['boardcard5'] = None
- boardCard = 1
- for street in hand.communityStreets:
- for card in hand.board[street]:
- self.hands['boardcard%s' % str(boardCard)] = Card.encodeCard(card)
- boardCard += 1
+ # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and
+ # those values remain default in stud.
+ boardcards = hand.board['FLOP'] + hand.board['TURN'] + hand.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
+ cards = [Card.encodeCard(c) for c in boardcards[0:5]]
+ self.hands['boardcard1'] = cards[0]
+ self.hands['boardcard2'] = cards[1]
+ self.hands['boardcard3'] = cards[2]
+ self.hands['boardcard4'] = cards[3]
+ self.hands['boardcard5'] = cards[4]
+
+ #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals()
+ #FIXME: Pot size still in decimal, needs to be converted to cents
+ (self.hands['street1Pot'],
+ self.hands['street2Pot'],
+ self.hands['street3Pot'],
+ self.hands['street4Pot'],
+ self.hands['showdownPot']) = hand.getStreetTotals()
+
+
+ self.vpip(hand) # Gives playersVpi (num of players vpip)
+ self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown
+
+ # texture smallint,
+
+ # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */
+ # Needs to be recorded
+ # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */
+ # Needs to be recorded
+ # street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */
+ # Needs to be recorded
+ # street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */
+ # Needs to be recorded
+ # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */
+ # Needs to be recorded
+
+ # comment TEXT,
+ # commentTs DATETIME
+
+
def assembleHandsPlayers(self, hand):
self.vpip(self.hand)
@@ -144,6 +106,47 @@ class DerivedStats():
self.handsplayers[player[1]]['vpip'] = False
self.hands['playersVpi'] = len(vpipers)
+ def playersAtStreetX(self, hand):
+ """playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */"""
+ # self.actions[street] is a list of all actions in a tuple, contining the player name first
+ # [ (player, action, ....), (player2, action, ...) ]
+ # The number of unique players in the list per street gives the value for playersAtStreetXXX
+
+ self.hands['playersAtStreet1'] = 0
+ self.hands['playersAtStreet2'] = 0
+ self.hands['playersAtStreet3'] = 0
+ self.hands['playersAtStreet4'] = 0
+ self.hands['playersAtShowdown'] = 0
+
+ for street in hand.actionStreets:
+ actors = {}
+ for act in a[street]:
+ actors[act[0]] = 1
+ #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys()))
+ if hand.gametype['base'] in ("hold"):
+ if street in "FLOP": self.hands['playersAtStreet1'] = len(actors.keys())
+ elif street in "TURN": self.hands['playersAtStreet2'] = len(actors.keys())
+ elif street in "RIVER": self.hands['playersAtStreet3'] = len(actors.keys())
+ elif hand.gametype['base'] in ("stud"):
+ if street in "FOURTH": self.hands['playersAtStreet1'] = len(actors.keys())
+ elif street in "FIFTH": self.hands['playersAtStreet2'] = len(actors.keys())
+ elif street in "SIXTH": self.hands['playersAtStreet3'] = len(actors.keys())
+ elif street in "SEVENTH": self.hands['playersAtStreet4'] = len(actors.keys())
+ elif hand.gametype['base'] in ("draw"):
+ if street in "DRAWONE": self.hands['playersAtStreet1'] = len(actors.keys())
+ elif street in "DRAWTWO": self.hands['playersAtStreet2'] = len(actors.keys())
+ elif street in "DRAWTHREE": self.hands['playersAtStreet3'] = len(actors.keys())
+
+ #Need playersAtShowdown
+
+
+ def streetXRaises(self, hand):
+ # self.actions[street] is a list of all actions in a tuple, contining the action as the second element
+ # [ (player, action, ....), (player2, action, ...) ]
+ # No idea what this value is actually supposed to be
+ # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl
+
+
def aggr(self, hand, i):
aggrers = set()
for act in hand.actions[hand.actionStreets[i]]:
@@ -157,4 +160,4 @@ class DerivedStats():
self.handsplayers[player[1]]['street%sAggr' % i] = False
def countPlayers(self, hand):
- pass
\ No newline at end of file
+ pass
diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py
index 9ded56b4..d4563059 100644
--- a/pyfpdb/Filters.py
+++ b/pyfpdb/Filters.py
@@ -23,6 +23,7 @@ import os
import sys
from optparse import OptionParser
from time import *
+import gobject
#import pokereval
import Configuration
@@ -228,7 +229,16 @@ class Filters(threading.Thread):
pname.set_width_chars(20)
hbox.pack_start(pname, False, True, 0)
pname.connect("changed", self.__set_hero_name, site)
- #TODO: Look at GtkCompletion - to fill out usernames
+
+ # Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices)
+ completion = gtk.EntryCompletion()
+ pname.set_completion(completion)
+ liststore = gtk.ListStore(gobject.TYPE_STRING)
+ completion.set_model(liststore)
+ completion.set_text_column(0)
+ names = self.db.get_player_names(self.conf) # (config=self.conf, site_id=None, like_player_name="%")
+ for n in names:
+ liststore.append(n)
self.__set_hero_name(pname, site)
diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example
index adc8141c..de2f1bba 100644
--- a/pyfpdb/HUD_config.xml.example
+++ b/pyfpdb/HUD_config.xml.example
@@ -4,6 +4,9 @@
+
+
9000:
+ getattr(self, 'h_aggBBmultItemAll').set_active(True)
+ #
if self.hud_params['agg_bb_mult'] == 1:
getattr(self, 'aggBBmultItem1').set_active(True)
elif self.hud_params['agg_bb_mult'] == 2:
@@ -209,12 +271,20 @@ class Hud:
getattr(self, 'aggBBmultItem10').set_active(True)
elif self.hud_params['agg_bb_mult'] > 9000:
getattr(self, 'aggBBmultItemAll').set_active(True)
+ #
if self.hud_params['h_hud_style'] == 'A':
- getattr(self, 'HAStyleOption').set_active(True)
+ getattr(self, 'h_hudStyleOptionA').set_active(True)
elif self.hud_params['h_hud_style'] == 'S':
- getattr(self, 'HSStyleOption').set_active(True)
+ getattr(self, 'h_hudStyleOptionS').set_active(True)
elif self.hud_params['h_hud_style'] == 'T':
- getattr(self, 'HTStyleOption').set_active(True)
+ getattr(self, 'h_hudStyleOptionT').set_active(True)
+ #
+ if self.hud_params['hud_style'] == 'A':
+ getattr(self, 'hudStyleOptionA').set_active(True)
+ elif self.hud_params['hud_style'] == 'S':
+ getattr(self, 'hudStyleOptionS').set_active(True)
+ elif self.hud_params['hud_style'] == 'T':
+ getattr(self, 'hudStyleOptionT').set_active(True)
eventbox.connect_object("button-press-event", self.on_button_press, menu)
@@ -254,41 +324,53 @@ class Hud:
pass
def set_aggregation(self, widget, val):
- # try setting these to true all the time, and set the multiplier to 1 to turn agg off:
- self.hud_params['aggregate_ring'] = True
- self.hud_params['aggregate_tour'] = True
- self.hud_params['h_aggregate_ring'] = True
- self.hud_params['h_aggregate_tour'] = True
+ (player_opp, num) = val
+ if player_opp == 'P':
+ # set these true all the time, set the multiplier to 1 to turn agg off:
+ self.hud_params['h_aggregate_ring'] = True
+ self.hud_params['h_aggregate_tour'] = True
- if self.hud_params['agg_bb_mult'] != val \
- and getattr(self, 'aggBBmultItem'+str(val)).get_active():
- print 'set_aggregation', val
- self.hud_params['agg_bb_mult'] = val
- self.hud_params['h_agg_bb_mult'] = val
- for mult in ('1', '2', '3', '10', '10000'):
- if mult != str(val):
- getattr(self, 'aggBBmultItem'+mult).set_active(False)
+ if self.hud_params['h_agg_bb_mult'] != num \
+ and getattr(self, 'h_aggBBmultItem'+str(num)).get_active():
+ print 'set_player_aggregation', num
+ self.hud_params['h_agg_bb_mult'] = num
+ for mult in ('1', '2', '3', '10', '10000'):
+ if mult != str(num):
+ getattr(self, 'h_aggBBmultItem'+mult).set_active(False)
+ else:
+ self.hud_params['aggregate_ring'] = True
+ self.hud_params['aggregate_tour'] = True
+
+ if self.hud_params['agg_bb_mult'] != num \
+ and getattr(self, 'aggBBmultItem'+str(num)).get_active():
+ print 'set_opponent_aggregation', num
+ self.hud_params['agg_bb_mult'] = num
+ for mult in ('1', '2', '3', '10', '10000'):
+ if mult != str(num):
+ getattr(self, 'aggBBmultItem'+mult).set_active(False)
def set_hud_style(self, widget, val):
- # try setting these to true all the time, and set the multiplier to 1 to turn agg off:
- if val[0] == 'H':
+ (player_opp, style) = val
+ if player_opp == 'P':
param = 'h_hud_style'
+ prefix = 'h_'
else:
param = 'hud_style'
+ prefix = ''
- if val[1] == 'A' and getattr(self, 'HAStyleOption').get_active():
+ if style == 'A' and getattr(self, prefix+'hudStyleOptionA').get_active():
self.hud_params[param] = 'A'
- getattr(self, 'HSStyleOption').set_active(False)
- getattr(self, 'HTStyleOption').set_active(False)
- elif val[1] == 'S' and getattr(self, 'HSStyleOption').get_active():
+ getattr(self, prefix+'hudStyleOptionS').set_active(False)
+ getattr(self, prefix+'hudStyleOptionT').set_active(False)
+ elif style == 'S' and getattr(self, prefix+'hudStyleOptionS').get_active():
self.hud_params[param] = 'S'
- getattr(self, 'HAStyleOption').set_active(False)
- getattr(self, 'HTStyleOption').set_active(False)
- elif val[1] == 'T' and self.HTStyleOption.get_active():
+ getattr(self, prefix+'hudStyleOptionA').set_active(False)
+ getattr(self, prefix+'hudStyleOptionT').set_active(False)
+ elif style == 'T' and getattr(self, prefix+'hudStyleOptionT').get_active():
self.hud_params[param] = 'T'
- getattr(self, 'HAStyleOption').set_active(False)
- getattr(self, 'HSStyleOption').set_active(False)
- print "setting self.hud_params[%s] = %s" % (param, val[1])
+ getattr(self, prefix+'hudStyleOptionA').set_active(False)
+ getattr(self, prefix+'hudStyleOptionS').set_active(False)
+ print "setting self.hud_params[%s] = %s" % (param, style)
def update_table_position(self):
if os.name == 'nt':
diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py
index 0c551634..1145afec 100644
--- a/pyfpdb/SQL.py
+++ b/pyfpdb/SQL.py
@@ -1235,6 +1235,13 @@ class Sql:
and Players.siteId = Sites.id
"""
+ self.query['get_player_names'] = """
+ select p.name
+ from Players p
+ where lower(p.name) like lower(%s)
+ and (p.siteId = %s or %s = -1)
+ """
+
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
self.query['get_stats_from_hand'] = """
diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py
old mode 100755
new mode 100644
index 5d8d7191..6d58f733
--- a/pyfpdb/fpdb.py
+++ b/pyfpdb/fpdb.py
@@ -458,7 +458,12 @@ class fpdb:
except Exceptions.FpdbMySQLFailedError:
self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR")
exit()
-
+ except FpdbError:
+ print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])
+ sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
+ except:
+ print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])
+ sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
if self.db.fdb.wrongDbVersion:
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))