def parseWormDied(sig): global worms deaderID = int(sig[1]) killerID = int(sig[2]) worms[deaderID].Lives -= 1 worms[deaderID].Alive = False if not cfg.RANKING: return try: rank_file_path = io.getWriteFullFileName(cfg.RANKING_FILE) f = open(rank_file_path, "a") if not killerID in io.getComputerWormList(): try: portalocker.lock(f, portalocker.LOCK_EX) except: pass f.write( time.strftime("%Y-%m-%d %H:%M:%S") + "\t" + worms[deaderID].Name + "\t" + worms[killerID].Name + "\n") f.close() except IOError: io.messageLog( "parseWormDied: Unable to open ranking file: " + cfg.RANKING_FILE + " from path: " + rank_file_path, io.LOG_ERROR) if not killerID in io.getComputerWormList(): if deaderID == killerID: try: ranking.rank[worms[killerID].Name][2] += 1 except KeyError: ranking.rank[worms[killerID].Name] = [ 0, 0, 1, len(ranking.rank) + 1 ] else: try: ranking.rank[worms[killerID].Name][0] += 1 except KeyError: ranking.rank[worms[killerID].Name] = [ 1, 0, 0, len(ranking.rank) + 1 ] if not deaderID in io.getComputerWormList(): try: ranking.rank[worms[deaderID].Name][1] += 1 except KeyError: ranking.rank[worms[deaderID].Name] = [ 0, 1, 0, len(ranking.rank) + 1 ]
def parseWormDied(sig): global worms deaderID = int(sig[1]) killerID = int(sig[2]) worms[deaderID].Lives -= 1 worms[deaderID].Alive = False if not cfg.RANKING: return try: f = open(io.getWriteFullFileName("pwn0meter.txt"), "a") if not killerID in io.getComputerWormList(): try: portalocker.lock(f, portalocker.LOCK_EX) except: pass f.write( time.strftime("%Y-%m-%d %H:%M:%S") + "\t" + worms[deaderID].Name + "\t" + worms[killerID].Name + "\n") f.close() except IOError: io.msg("ERROR: Unable to open pwn0meter.txt") if not killerID in io.getComputerWormList(): if deaderID == killerID: try: ranking.rank[worms[killerID].Name][2] += 1 except KeyError: ranking.rank[worms[killerID].Name] = [ 0, 0, 1, len(ranking.rank) + 1 ] else: try: ranking.rank[worms[killerID].Name][0] += 1 except KeyError: ranking.rank[worms[killerID].Name] = [ 1, 0, 0, len(ranking.rank) + 1 ] if not deaderID in io.getComputerWormList(): try: ranking.rank[worms[deaderID].Name][1] += 1 except KeyError: ranking.rank[worms[deaderID].Name] = [ 0, 1, 0, len(ranking.rank) + 1 ]
def ParseAuthInfo(): try: f = open(io.getWriteFullFileName("pwn0meter_auth.txt"), "r") except IOError: return {} authInfo = {} l = f.readline() while l != "": l = l.strip() if not (l.count("\t") == 1): l = f.readline() continue (worm, auth) = l.split("\t") auth = auth.split(" ") authInfo[worm] = (int(auth[0]), " ".join(auth[1:]).lower()) l = f.readline() f.close() return authInfo
def parseWormDied(sig): global worms deaderID = int(sig[1]) killerID = int(sig[2]) worms[deaderID].Lives -= 1 worms[deaderID].Alive = False if not cfg.RANKING: return try: f = open(io.getWriteFullFileName("pwn0meter.txt"),"a") if not killerID in io.getComputerWormList(): try: portalocker.lock(f, portalocker.LOCK_EX) except: pass f.write( time.strftime("%Y-%m-%d %H:%M:%S") + "\t" + worms[deaderID].Name + "\t" + worms[killerID].Name + "\n" ) f.close() except IOError: io.msg("ERROR: Unable to open pwn0meter.txt") if not killerID in io.getComputerWormList(): if deaderID == killerID: try: ranking.rank[worms[killerID].Name][2] += 1 except KeyError: ranking.rank[worms[killerID].Name] = [0,0,1,len(ranking.rank)+1] else: try: ranking.rank[worms[killerID].Name][0] += 1 except KeyError: ranking.rank[worms[killerID].Name] = [1,0,0,len(ranking.rank)+1] if not deaderID in io.getComputerWormList(): try: ranking.rank[worms[deaderID].Name][1] += 1 except KeyError: ranking.rank[worms[deaderID].Name] = [0,1,0,len(ranking.rank)+1]
def ParseAuthInfo(): try: rank_auth_file_path = io.getWriteFullFileName(cfg.RANKING_AUTH_FILE) f = open(rank_auth_file_path,"r") except IOError: io.messageLog("ParseAuthInfo: Unable to open ranking authentication file: " + cfg.RANKING_AUTH_FILE + " from path: " + rank_auth_file_path, io.LOG_ERROR) return {} authInfo = {} l = f.readline() while l != "": l = l.strip() if not (l.count("\t") == 1): l = f.readline() continue ( worm, auth ) = l.split("\t") auth = auth.split(" ") authInfo[worm] = ( int(auth[0]), " ".join(auth[1:]).lower() ) l = f.readline() f.close() return authInfo
def parseNewWorm(wormID, name): global worms exists = False try: worm = worms[wormID] exists = True except KeyError: #Worm doesn't exist. worm = Worm() worm.real_name = name #NOTE: This is the name used by the server #Now prepare the name used by the script - used for ranking, for example name = name.replace("\t", " ").strip( ) # Do not allow tab in names, it will screw up our ranking tab-separated text-file database #Check if the player has quotation marks in his/her name quotemarks_in_nick = 0 if "\"" in name: name = name.replace( "\"", "\'\'" ) #Double quotes (") cause problems with chat/private messages - convert to single quotes (') quotemarks_in_nick = 1 worm.Name = name worm.iID = wormID worm.Ping = [] wormIP = io.getWormIP(wormID).split(":")[ 0] #Get worm IP address now - it will be needed later worm.Ip = wormIP worms[wormID] = worm #Set team for handler ##NOTE: OLX sets a team when the player joins - and it may not always be 0 (blue)!!! So get the team number now! #TEST: Log these initial teams if cfg.TEAMCHANGE_LOGGING: io.messageLog( "TEAMJOIN: Game reports team " + str(io.getWormTeam(wormID)) + " for joining worm " + str(name), io.LOG_INFO) worm.Team = io.getWormTeam(wormID) # io.messageLog("Curtime " + str(time.time()) + " IP " + str(wormIP) + " Kicked worms: " + str(kickedUsers), io.LOG_INFO) if wormIP in kickedUsers and kickedUsers[wormIP] > time.time(): io.kickWorm( wormID, "You can join in " + str(int(kickedUsers[wormIP] - time.time()) / 60 + 1) + " minutes") return #Original ranking authentication based on skin color... #NOTE: This is a weak way of authentication if cfg.RANKING_AUTHENTICATION: if not name in ranking.auth: ranking.auth[name] = getWormSkin(wormID) try: rank_auth_file_path = io.getWriteFullFileName( cfg.RANKING_AUTH_FILE) f = open(rank_auth_file_path, "a") try: portalocker.lock(f, portalocker.LOCK_EX) except: pass f.write(name + "\t" + str(ranking.auth[name][0]) + " " + ranking.auth[name][1] + "\n") f.close() except IOError: io.messageLog( "parseNewWorm: Unable to open ranking authentication file: " + cfg.RANKING_AUTH_FILE + " from path: " + rank_auth_file_path, io.LOG_ERROR) else: if ranking.auth[name] != getWormSkin(wormID): io.kickWorm(wormID, "Player with name %s already registered" % name) return #Notify or kick players that have forbidden nicks if name in cfg.FORBIDDEN_NAMES: if cfg.NAME_CHECK_ACTION == 1: worm.Name = "random" + str(random.randint( 0, cfg.NAME_CHECK_RANDOM)) #Assign random name io.privateMsg(wormID, cfg.NAME_CHECK_WARNMSG) elif cfg.NAME_CHECK_ACTION == 2: io.kickWorm(wormID, cfg.NAME_CHECK_KICKMSG) return #NEW: Kick players who have newline tags in their nicks - those can cause annoyance #NOTE: This may give false positives if there are nested tags, but it's an unlikely case if detectFormattingTags(name): io.kickWorm( wormID, "Please remove formatting tags ( <...> ) from your nickname - they cause problems" ) return #Kick players with excessively long nicks. #NOTE: In 0.59, oversized name are truncated automatically so this becomes obsolete if len(name) > cfg.MAX_NAME_LENGTH: io.kickWorm(wormID, "name too long") return #Kick players with quotation marks in their name (only if configured!) #NOTE: This should not be needed anymore if quotemarks_in_nick == 1 and cfg.KICK_QUOTEMARKS == 1: io.kickWorm( wormID, "please remove quotation marks from your nickname - they screw up ranking." ) return #If only one player per IP allowed, check if there is already a player from the IP #NOTE: This is a weak check and may cause more harm than good as it prevents people behind a shared IP from joining while not really preventing rank manipulation if cfg.ONE_PLAYER_PER_IP: for w in worms.keys(): if worms[w].Ip == wormIP and w != wormID: io.kickWorm(wormID, "only one player per IP address allowed") return #Nag players to download the latest version. 0.58 rc3 may still be in use, and this is less harsh than kicking. #TODO: Do this in a better way? if cfg.VERSION_CHECK: ver = io.getWormVersion(wormID) newest_ver = io.getVar("GameOptions.State.NewestVersion") #Newest version, everything OK if distutils.version.LooseVersion( ver.lower()) == distutils.version.LooseVersion( newest_ver.lower()): pass #Outdated 0.58 versions and older elif distutils.version.LooseVersion( ver.lower()) < distutils.version.LooseVersion( newest_ver.lower()): io.privateMsg( wormID, "You're using an outdated version! Please download " + newest_ver.replace("/", " ").replace("_", " ") + " from http://openlierox.net/") #0.59 b10 and later are buggy elif distutils.version.LooseVersion( ver.lower()) >= distutils.version.LooseVersion( "OpenLieroX/0.59_beta10".lower()): io.privateMsg( wormID, "You're using a buggy version of the game! You may want to download " + newest_ver.replace("/", " ").replace("_", " ") + " from http://openlierox.net/") #Other 0.59 versions are not as buggy but they lack the nice updates of 0.58 rc5 else: io.privateMsg( wormID, "You seem to be using an experimental version of the game! You may want to download " + newest_ver.replace("/", " ").replace("_", " ") + " from http://openlierox.net/") #Assign team if io.getGameType() == 1: worms[ wormID].votedTeams = 1 #Set vote status to 1 so that it will be TDM if it was TDM before this player joined io.privateMsg( wormID, "Game type is team deathmatch - say !noteams if you do not want teams for the next game" ) #NOTE: The player is already assigned to a team by the game! - so assigning him to the smallest team here would lead to unbalancement # if the team status were, for example, [4, 4]. So check whether 1) teams are balanced (difference <=1) or not, and 2) the player is not in the smallest team #NOTE: Calling balanceTeams might look more elegant, but it might move other players as well, and it should not be called when we are not in lobby #NOTE: Be careful with RandomTeamForNewWorm option! It may cause an exception! team_status = getNumberWormsInAllTeams() #Get team member counts team_status = team_status[ 0:cfg.MAX_TEAMS] #Remove teams that are not used wormteam = io.getWormTeam( wormID) #Could use worm.Team too, but this might be safer... if (max(team_status) - min(team_status) ) > 1 and wormteam != team_status.index(min(team_status)): setTeam(wormID, team_status.index(min(team_status))) #Update votes - this is needed if there are, let's say, 3 players who all vote for TDM but TDM requires 4 - now there are 4 and 3 of them vote so TDM should be selected! #No need to broadcast anything - TDM is broadcasted if the status changes. updateVotes()
def ParseRank(useRatios=True): #io.messageLog("ParseRank: Opening pwn0meter.txt", io.LOG_INFO) try: f = open(io.getWriteFullFileName("pwn0meter.txt"), "r") except IOError: return {} l = f.readline() killers = {} deaders = {} while l != "": l = l.strip() #io.messageLog("ParseRank: line: " + l, io.LOG_INFO) if not (l.count("\t") == 2): # Don't show empty names or empty lines ! l = f.readline() continue (date, deader, killer) = l.split("\t") killerOk = killer != "OpenLieroXor" if not killer in killers.keys() and killerOk: killers[killer] = [] if not deader in deaders.keys(): deaders[deader] = [] if killerOk: killers[killer].append(deader) deaders[deader].append(killer) l = f.readline() f.close() sorted = killers.keys() def sortFunc(s1, s2): suicides1 = killers[s1].count(s1) suicides2 = killers[s2].count(s2) kills1 = float(len(killers[s1]) - suicides1) # kills - suicides kills2 = float(len(killers[s2]) - suicides2) try: deaths1 = len(deaders[s1]) except KeyError: deaths1 = 0 try: deaths2 = len(deaders[s2]) except KeyError: deaths2 = 0 if useRatios: # You can change this to have the ratio you want... Here 2/3 is number of kill, and 1/3 is kills/deaths kills1 = kills1 / (deaths1 + 1 + suicides1) * kills1 * kills1 kills2 = kills2 / (deaths2 + 1 + suicides2) * kills2 * kills2 if kills1 < kills2: return 1 if kills1 > kills2: return -1 if deaths1 < deaths2: return -1 if deaths1 > deaths2: return 1 return 0 sorted.sort(cmp=sortFunc) rank = 0 total = {} for k in sorted: rank += 1 kills = len(killers[k]) try: deaths = len(deaders[k]) except KeyError: deaths = 0 suicides = killers[k].count(k) kills -= suicides deaths -= suicides total[k] = [kills, deaths, suicides, rank] #io.messageLog("ParseRank: rank " + str(total), io.LOG_INFO) return total
def ParseRank(useRatios = True): #io.messageLog("ParseRank: Opening pwn0meter.txt", io.LOG_INFO) try: f = open(io.getWriteFullFileName("pwn0meter.txt"),"r") except IOError: return {} l = f.readline() killers = {} deaders = {} while l != "": l = l.strip() #io.messageLog("ParseRank: line: " + l, io.LOG_INFO) if not (l.count("\t") == 2): # Don't show empty names or empty lines ! l = f.readline() continue ( date, deader, killer ) = l.split("\t") killerOk = killer != "OpenLieroXor" if not killer in killers.keys() and killerOk: killers[killer] = [] if not deader in deaders.keys(): deaders[deader] = [] if killerOk: killers[killer].append(deader) deaders[deader].append(killer) l = f.readline() f.close() sorted = killers.keys() def sortFunc(s1, s2): suicides1 = killers[s1].count(s1) suicides2 = killers[s2].count(s2) kills1 = float(len(killers[s1]) - suicides1) # kills - suicides kills2 = float(len(killers[s2]) - suicides2) try: deaths1 = len(deaders[s1]) except KeyError: deaths1 = 0 try: deaths2 = len(deaders[s2]) except KeyError: deaths2 = 0 if useRatios: # You can change this to have the ratio you want... Here 2/3 is number of kill, and 1/3 is kills/deaths kills1 = kills1 / (deaths1 + 1 + suicides1) * kills1 * kills1 kills2 = kills2 / (deaths2 + 1 + suicides2) * kills2 * kills2 if kills1 < kills2: return 1 if kills1 > kills2: return -1 if deaths1 < deaths2: return -1 if deaths1 > deaths2: return 1 return 0 sorted.sort(cmp=sortFunc) rank = 0 total = {} for k in sorted: rank += 1 kills = len(killers[k]) try: deaths = len(deaders[k]) except KeyError: deaths = 0 suicides = killers[k].count(k) kills -= suicides deaths -= suicides total[k]=[kills,deaths,suicides,rank] #io.messageLog("ParseRank: rank " + str(total), io.LOG_INFO) return total
def parseNewWorm(wormID, name): global worms name = name.replace("\t", " ").strip( ) # Do not allow tab in names, it will screw up our ranking tab-separated text-file database exists = False try: worm = worms[wormID] exists = True except KeyError: #Worm doesn't exist. worm = Worm() worm.Name = name worm.iID = wormID worm.Ping = [] worms[wormID] = worm if io.getGameType() == "Hide and Seek": minSeekers = 1 if len(worms.values()) >= 4: minSeekers = 2 if io.getNumberWormsInTeam(1) < minSeekers: io.setWormTeam(wormID, 1) # Seeker else: io.setWormTeam(wormID, 0) # Hider else: # Balance teams teams = [0, 0, 0, 0] for w in worms.keys(): teams[worms[w].Team] += 1 minTeam = 0 minTeamCount = teams[0] for f in range(cfg.MAX_TEAMS): if minTeamCount > teams[f]: minTeamCount = teams[f] minTeam = f io.setWormTeam(wormID, minTeam) if cfg.RANKING_AUTHENTICATION: if not name in ranking.auth: ranking.auth[name] = getWormSkin(wormID) try: f = open(io.getWriteFullFileName("pwn0meter_auth.txt"), "a") try: portalocker.lock(f, portalocker.LOCK_EX) except: pass f.write(name + "\t" + str(ranking.auth[name][0]) + " " + ranking.auth[name][1] + "\n") f.close() except IOError: msg("ERROR: Unable to open pwn0meter_auth.txt") else: if ranking.auth[name] != getWormSkin(wormID): io.kickWorm(wormID, "Player with name %s already registered" % name) wormIP = io.getWormIP(wormID).split(":")[0] # io.messageLog("Curtime " + str(time.time()) + " IP " + str(wormIP) + " Kicked worms: " + str(cmds.kickedUsers), io.LOG_INFO) if wormIP in cmds.kickedUsers and cmds.kickedUsers[wormIP] > time.time(): io.kickWorm( wormID, "You can join in " + str(int(cmds.kickedUsers[wormIP] - time.time()) / 60 + 1) + " minutes") return cmds.recheckVote()