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))