def parseWormLeft(sig): global worms, scriptPaused wormID = int(sig[1]) name = sig[2:] try: if worms[wormID].isAdmin: io.messageLog( ("Worm %i (%s) removed from admins" % (wormID, name)), io.LOG_ADMIN) except KeyError: io.messageLog( "AdminRemove: Our local copy of wormses doesn't match the real list.", io.LOG_ERROR) # Call last, that way we still have the data active. worms.pop(wormID) cmds.recheckVote() # If all admins left unpause ded server (or it will be unusable) isAdmins = False for w in worms.keys(): if worms[w].isAdmin: isAdmins = True if not isAdmins: scriptPaused = False
def setTeam(wormid, team): if wormid in worms.keys() and worms[wormid].iID != -1: worms[wormid].Team = team io.setWormTeam(wormid, team) if cfg.TEAMCHANGE_LOGGING: io.messageLog( "TEAMCHANGE: Set worm " + str(wormid) + " " + worms[wormid].Name + " to team " + str(team), io.LOG_INFO) else: io.messageLog("Worm id %i invalid" % wormid, LOG_ADMIN)
def checkConfigLists(): availableMapList = io.listMaps() for l in cfg.LEVELS: if l not in availableMapList: io.messageLog("Autocycle map not found: %s" % l, io.LOG_ERROR) for k in presetcfg.MAP_SHORTCUTS.values(): if k not in availableMapList: io.messageLog("Shortcut map not found: %s" % k, io.LOG_ERROR)
def setupTeams(): global worms if cfg.TEAMCHANGE_LOGGING: io.messageLog("TEAMSETUP: setupTeams called", io.LOG_INFO) counter = 0 for w in worms.values(): if w.iID != -1: setTeam(w.iID, counter % cfg.MAX_TEAMS) counter += 1
def recheckVote(verbose=True): global voteCommand, voteTime, votePoster, voteDescription global kickedUsers if not voteCommand: return voteCount = 0 notVoted = 0 if cfg.VOTING_COUNT_NEGATIVE: for w in hnd.worms.keys(): voteCount += hnd.worms[w].Voted if hnd.worms[w].Voted == 0: notVoted += 1 else: for w in hnd.worms.keys(): if hnd.worms[w].Voted == 1: voteCount += 1 else: notVoted += 1 humanWormCount = len(hnd.worms) - len(io.getComputerWormList()) needVoices = int(math.ceil(humanWormCount * cfg.VOTING_PERCENT / 100.0)) if voteCount >= needVoices or (time.time() - voteTime >= cfg.VOTING_TIME and cfg.VOTING_AUTO_ACCEPT): try: exec(voteCommand) except: io.messageLog(formatExceptionInfo(), io.LOG_ERROR) #Helps to fix errors voteCommand = None voteTime = 0 return if time.time( ) - voteTime >= cfg.VOTING_TIME or needVoices - voteCount > notVoted: voteCommand = None voteTime = 0 io.chatMsg("Vote failed: " + voteDescription) if (votePoster in hnd.worms.keys()) and ( hnd.worms[votePoster].Voted == 1 ): # Check if worm left and another worm joined with same ID hnd.worms[votePoster].FailedVoteTime = time.time() return if verbose: io.chatMsg("Vote: " + voteDescription + ", " + str(needVoices - voteCount) + " voices to go, " + str(int(cfg.VOTING_TIME + voteTime - time.time())) + (" seconds, say %sy or %sn" % (cfg.ADMIN_PREFIX, cfg.ADMIN_PREFIX)))
def parseWormAuthorized(sig): global worms wormID = int(sig[1]) try: if not worms[wormID].isAdmin: worms[wormID].isAdmin = True io.messageLog(("Worm %i (%s) added to admins" % (wormID,worms[wormID].Name)),io.LOG_ADMIN) # TODO: Send the last part in a PM to the admin. (Needs new backend for private messaging. Add teamchat too!) io.authorizeWorm(wormID) io.privateMsg(wormID, "%s authenticated for admin! Type %shelp for command info" % (worms[wormID].Name,cfg.ADMIN_PREFIX)) except KeyError: io.messageLog("AdminAdd: Our local copy of wormses doesn't match the real list.",io.LOG_ERROR)
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 initPresets(): global availablePresets # Reset - incase we get called a second time availablePresets = [] for f in os.listdir(presetDir): if f.lower() != "defaults" and f.lower() != ".svn": availablePresets.append(f) for p in cfg.PRESETS: if availablePresets.count(p) == 0: availablePresets.append(p) if (len(availablePresets) == 0): io.messageLog("There are no presets available - nothing to do. Exiting.",io.LOG_CRITICAL) exit()
def parseWormLeft(sig): global worms, gameState, scriptPaused wormID = int(sig[1]) name = sig[2:] try: if worms[wormID].isAdmin: io.messageLog( ("Worm %i (%s) removed from admins" % (wormID, name)), io.LOG_ADMIN) except KeyError: io.messageLog( "AdminRemove: Our local copy of wormses doesn't match the real list.", io.LOG_ERROR) #NOTE: There may be a better way to do this... #Check which vote options to broadcast when this player leaves temp_votedstatus = [] if wormID in worms.keys( ): #Note: this should be always true but checked anyway... if worms[wormID].votedMap: temp_votedstatus.append("map") if worms[wormID].votedPreset: temp_votedstatus.append("mod") #NOTE: No need to check team votes here because team status will be checked separately. # Call last, that way we still have the data active. worms.pop(wormID) #Update voting status after removing this player from the worms table updateVotes(send_msg=tuple(temp_votedstatus)) #Balance teams if io.getGameType() == 1: if gameState == GAME_LOBBY or cfg.BALANCE_TEAMS_INGAME: balanceTeams(bmsg="player left") # If all admins left unpause ded server (or it will be unusable) isAdmins = False for w in worms.keys(): if worms[w].isAdmin: isAdmins = True if not isAdmins: scriptPaused = False
def init(): initPresets() io.startLobby(cfg.SERVER_PORT) # if we load this script with already some worms on board, we have to update our worm list now for w in io.getWormList(): parseNewWorm( w, io.getWormName(w) ) global GLOBAL_SETTINGS; for f in GLOBAL_SETTINGS.keys(): io.setvar( f, GLOBAL_SETTINGS[f] ) for f in cfg.GLOBAL_SETTINGS.keys(): io.setvar( f, cfg.GLOBAL_SETTINGS[f] ) if io.getVar("GameOptions.GameInfo.AllowEmptyGames") == "false" and cfg.MIN_PLAYERS < 2: io.messageLog("GameOptions.GameInfo.AllowEmptyGames is false - setting cfg.MIN_PLAYERS to 2", io.LOG_WARN) cfg.MIN_PLAYERS = 2
def recheckVote(verbose = True): global voteCommand, voteTime, votePoster, voteDescription global kickedUsers if not voteCommand: return voteCount = 0 notVoted = 0 if cfg.VOTING_COUNT_NEGATIVE: for w in hnd.worms.keys(): voteCount += hnd.worms[w].Voted if hnd.worms[w].Voted == 0: notVoted += 1 else: for w in hnd.worms.keys(): if hnd.worms[w].Voted == 1: voteCount += 1 else: notVoted += 1 humanWormCount = len(hnd.worms) - len(io.getComputerWormList()) needVoices = int( math.ceil( humanWormCount * cfg.VOTING_PERCENT / 100.0 ) ) if voteCount >= needVoices or (time.time() - voteTime >= cfg.VOTING_TIME and cfg.VOTING_AUTO_ACCEPT): try: exec(voteCommand) except: io.messageLog(formatExceptionInfo(),io.LOG_ERROR) #Helps to fix errors voteCommand = None voteTime = 0 return if time.time() - voteTime >= cfg.VOTING_TIME or needVoices - voteCount > notVoted: voteCommand = None voteTime = 0 io.chatMsg("Vote failed: " + voteDescription ) if ( votePoster in hnd.worms.keys() ) and ( hnd.worms[votePoster].Voted == 1 ): # Check if worm left and another worm joined with same ID hnd.worms[votePoster].FailedVoteTime = time.time() return if verbose: io.chatMsg("Vote: " + voteDescription + ", " + str( needVoices - voteCount ) + " voices to go, " + str(int( cfg.VOTING_TIME + voteTime - time.time() )) + ( " seconds, say %sy or %sn" % ( cfg.ADMIN_PREFIX, cfg.ADMIN_PREFIX ) ) )
def initPresets(): global availablePresets # Reset - incase we get called a second time availablePresets = [] for f in os.listdir(presetDir): if f.lower() != "defaults" and f.lower() != ".svn": availablePresets.append(f) for p in cfg.PRESETS: if availablePresets.count(p) == 0: availablePresets.append(p) if (len(availablePresets) == 0): io.messageLog( "There are no presets available - nothing to do. Exiting.", io.LOG_CRITICAL) exit()
def parseWormAuthorized(sig): global worms wormID = int(sig[1]) try: if not worms[wormID].isAdmin: worms[wormID].isAdmin = True io.messageLog(("Worm %i (%s) added to admins" % (wormID, worms[wormID].Name)), io.LOG_ADMIN) # TODO: Send the last part in a PM to the admin. (Needs new backend for private messaging. Add teamchat too!) io.authorizeWorm(wormID) io.privateMsg( wormID, "%s authenticated for admin! Type %shelp for command info" % (worms[wormID].Name, cfg.ADMIN_PREFIX)) except KeyError: io.messageLog( "AdminAdd: Our local copy of wormses doesn't match the real list.", io.LOG_ERROR)
def init(): checkConfigLists() initPresets() io.startLobby(cfg.SERVER_PORT) # if we load this script with already some worms on board, we have to update our worm list now for w in io.getWormList(): parseNewWorm(w, io.getWormName(w)) for f in cfg.GLOBAL_SETTINGS.keys(): io.setvar(f, cfg.GLOBAL_SETTINGS[f]) if io.getVar("GameOptions.GameInfo.AllowEmptyGames" ) == "false" and cfg.MIN_PLAYERS < 2: io.messageLog( "GameOptions.GameInfo.AllowEmptyGames is false - setting cfg.MIN_PLAYERS to 2", io.LOG_WARN) cfg.MIN_PLAYERS = 2
def getNumberWormsInAllTeams(): ret = [0, 0, 0, 0] for t in range(0, 4): ret[t] = getNumberWormsInTeam(t) #Check whether the handler and the game are reporting the same number of players per team if cfg.TEAMCHANGE_LOGGING: testret = [0, 0, 0, 0] for w in worms.values(): testret[w.Team] += 1 #Only 4 teams so we can do ugly hard-coded check if (ret[0] == testret[0] and ret[1] == testret[1] and ret[2] == testret[2] and ret[3] == testret[3]): testmsg = "everything is OK." else: testmsg = "THERE IS AN ERROR!" io.messageLog( "TEAMSTATUS: Game reports " + str(ret) + ", handler counts " + str(testret) + " -- " + testmsg, io.LOG_INFO) return ret
def shuffleTeams(): global worms, shuffle_counter if cfg.TEAMCHANGE_LOGGING: io.messageLog("TEAMSHUFFLE: shuffleTeams called", io.LOG_INFO) # Create team mask tmask = [] for k in range(0, len(worms)): tmask.append(k % cfg.MAX_TEAMS) # Shuffle it random.shuffle(tmask) # Assign teams k = 0 for w in worms.values(): setTeam(w.iID, tmask[k]) k += 1 #Advance counter shuffle_counter += 1
def apply(self): if not self.curSelection: return StandardCiclerBase.apply(self) global availablePresets, presetDir sDefaults = os.path.join(presetDir,"Defaults") try: execfile(sDefaults) except: io.messageLog("Error in preset: " + str(formatExceptionInfo()),io.LOG_ERROR) sFile = os.path.join(presetDir,self.curSelection) try: fPreset = file(sFile,"r") line = fPreset.readline() if line.find("python") != -1: fPreset.close() execfile(sFile) else: print line.strip().replace('"','') for line in fPreset.readlines(): print line.strip().replace('"','') fPreset.close() except IOError: # File does not exist, perhaps it was removed. io.messageLog(("Unable to load %s, forcing rehash of all presets" % sFile),io.LOG_WARN) initPresets() except: io.messageLog("Error in preset: " + str(formatExceptionInfo()),io.LOG_ERROR)
def apply(self): if not self.curSelection: return StandardCiclerBase.apply(self) global availablePresets, presetDir sDefaults = os.path.join(presetDir, "Defaults") try: execfile(sDefaults) except: io.messageLog("Error in preset: " + str(formatExceptionInfo()), io.LOG_ERROR) sFile = os.path.join(presetDir, self.curSelection) try: fPreset = file(sFile, "r") line = fPreset.readline() if line.find("python") != -1: fPreset.close() execfile(sFile) else: print line.strip().replace('"', '') for line in fPreset.readlines(): print line.strip().replace('"', '') fPreset.close() except IOError: # File does not exist, perhaps it was removed. io.messageLog( ("Unable to load %s, forcing rehash of all presets" % sFile), io.LOG_WARN) initPresets() except: io.messageLog("Error in preset: " + str(formatExceptionInfo()), io.LOG_ERROR)
def balanceTeams(bmsg=""): global worms if cfg.TEAMCHANGE_LOGGING: if bmsg: io.messageLog("TEAMBALANCE: balanceTeams called: " + bmsg, io.LOG_INFO) else: io.messageLog( "TEAMBALANCE: balanceTeams called without reason given", io.LOG_INFO) while True: team_status = getNumberWormsInAllTeams() team_status = team_status[0:cfg.MAX_TEAMS] #truncate list if (max(team_status) - min(team_status)) > 1: maxteam = team_status.index( max(team_status)) #team with most members minteam = team_status.index( min(team_status)) #team with least members for w in worms.values(): if io.getWormTeam(w.iID) == maxteam: setTeam( w.iID, minteam) #move player from biggest team to smallest break else: #If the difference is 1 or less, no need to do changes break #Log the team status after balancing if cfg.TEAMCHANGE_LOGGING: io.messageLog("TEAMBALANCE: balance ended, calling for teamstatus...", io.LOG_INFO) getNumberWormsInAllTeams()
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 parseWormLeft(sig): global worms, scriptPaused wormID = int(sig[1]) name = sig[2:] try: if worms[wormID].isAdmin: io.messageLog(("Worm %i (%s) removed from admins" % (wormID,name)),io.LOG_ADMIN) except KeyError: io.messageLog("AdminRemove: Our local copy of wormses doesn't match the real list.",io.LOG_ERROR) # Call last, that way we still have the data active. worms.pop(wormID) cmds.recheckVote() # If all admins left unpause ded server (or it will be unusable) isAdmins = False for w in worms.keys(): if worms[w].isAdmin: isAdmins = True if not isAdmins: scriptPaused = False
def initPresets(): global availablePresets # Reset - incase we get called a second time availablePresets = [] if len(cfg.PRESETS) == 0: for f in presetcfg.MOD_PRESETS.keys(): availablePresets.append(f) else: for p in cfg.PRESETS: if p not in presetcfg.MOD_PRESETS.keys(): io.messageLog( "Preset error - %s not found in preset table." % p, io.LOG_WARN) else: if not p in availablePresets: availablePresets.append(p) if (len(availablePresets) == 0): io.messageLog( "There are no presets available - nothing to do. Exiting.", io.LOG_CRITICAL) exit()
def signalHandler(sig): global gameState, oldGameState, scriptPaused, sentStartGame, worms oldGameState = gameState if len(sig) == 0: return False #Didn't get anything header = sig[0] try: if header == "newworm": parseNewWorm(int(sig[1]), sig[2]) elif header == "wormleft": parseWormLeft(sig) elif header == "privatemessage": parsePrivateMessage(sig) elif header == "chatmessage": parseChatMessage(sig) elif header == "wormdied": parseWormDied(sig) elif header == "wormspawned": parseWormSpawned(sig) elif header == "wormauthorized": parseWormAuthorized(sig) elif header == "wormgotadmin": worms[int(sig[1])].isDedAdmin = True # no other difference to wormauthorized yet - and we also get wormauthorized, so nothing to do anymore pass ## Check GameState ## elif header == "quit": gameState = GAME_QUIT exit() elif header == "backtolobby" or header == "lobbystarted": if cfg.RANKING: ranking.refreshRank() gameState = GAME_LOBBY sentStartGame = False controlHandler() elif header == "weaponselections": gameState = GAME_WEAPONS controlHandler() elif header == "gamestarted": gameState = GAME_PLAYING sentStartGame = False controlHandler() #TODO: gamestarted && gameloopstart are pretty much duplicates # Or are they? Check. # Same thing for gameloopend and backtolobby elif header == "gameloopstart": #Sent when game starts pass elif header == "gameloopend": #Sent at game end pass elif header == "gameloopend": #Sent when OLX starts pass elif header == "timer": # Sent once per second controlHandler() elif header == "custom": parseCustom(sig) else: io.messageLog(("I don't understand %s." % (sig)),io.LOG_ERROR) except Exception: traceback.print_exc(None, sys.stderr) return True
def parseChatMessage(sig): global worms wormID = int(sig[1]) message = sig[2] #Length-based anti-spam - see dedicated_config for details if cfg.ANTISPAM != 0: if len(message) > cfg.ANTISPAM_KICKLIMIT: if cfg.ANTISPAM > 1 and len(message) > cfg.ANTISPAM_BANLIMIT: if cfg.ANTISPAM == 2: kickWithTime(wormID, "excessive spamming") return elif cfg.ANTISPAM == 3: io.banWorm(wormID, "excessive spamming") io.messageLog( "Player " + worms[wormID].Name + " from IP " + worms[wormID].Ip + " was banned for spamming", io.LOG_INFO) return else: io.kickWorm(wormID, "spamming") return #NEW: Impersonation protection - check if the player tries to impersonate another player using the newline tags. #NOTE: The "GOGO" spamfest taunt is whitelisted here! if cfg.ANTI_IMPERSONATION: if message not in cfg.ANTI_IMPERSONATION_WHITELIST and detectFormattingTags( message): #Warn the player and count the attempt io.privateMsg(wormID, cfg.ANTI_IMPERSONATION_CLIENT_WARNING) worms[wormID].tags_detected += 1 #TODO HACK EXPERIMENTAL TEST: Check whether the message contains other players' nicknames - if yes, warn the other players for w in worms.keys(): if w != wormID and (worms[w].real_name.strip() in message or worms[w].getCleanName().strip() in message): if cfg.ANTI_IMPERSONATION_SERVER_WARNING: #Do not broadcast warning if it doesn't exist io.chatMsg( cfg.ANTI_IMPERSONATION_SERVER_WARNING.replace( "<player>", worms[wormID].getCleanName()).replace( "<another>", worms[w].getCleanName())) #Apply sanctions if worms[wormID].tags_detected > cfg.ANTI_IMPERSONATION_LIMIT: if cfg.ANTI_IMPERSONATION_ACTION == 1: io.kickWorm(wormID, "used non-allowed formatting tags in chat") return elif cfg.ANTI_IMPERSONATION_ACTION == 2: kickWithTime(wormID, "used non-allowed formatting tags in chat") return #Taunt antispam - see dedicated_config for details if cfg.TAUNT_ANTISPAM: for kw in cfg.TAUNT_KEYWORDS: if kw in message.lower(): worms[wormID].spammed += 1 io.privateMsg(wormID, cfg.TAUNT_ANTISPAM_WARNING) if worms[wormID].spammed > cfg.TAUNT_ANTISPAM_LIMIT: if cfg.TAUNT_ANTISPAM == 1: io.kickWorm(wormID, "spamming") elif cfg.TAUNT_ANTISPAM == 2: kickWithTime(wormID, "spamming") return #Commands ret = None aret = None if worms[wormID].isAdmin and message.startswith(cfg.ADMIN_PREFIX): aret = cmds.parseAdminCommand(wormID, message) if message.startswith(cfg.USER_PREFIX): ret = cmds.parseUserCommand(wormID, message) if ret == "map": updateVotes(send_msg=("map", )) elif ret == "mod": updateVotes(send_msg=("mod", )) elif ret == "teams": updateVotes(send_msg=("teams", )) elif ret == "kick": #Don't broadcast voting status if voted for kick updateVotes(send_msg=())
def controlHandlerDefault(): global worms, gameState, lobbyChangePresetTimeout, lobbyWaitBeforeGame, lobbyWaitAfterGame global lobbyWaitGeneral, lobbyEnoughPlayers, oldGameState, scriptPaused, sentStartGame global presetCicler, modCicler, mapCicler, LT_Cicler global videoRecorder, videoRecorderSignalTime if scriptPaused: return curTime = time.time() cmds.recheckVote(False) if gameState == GAME_LOBBY: # Do not check ping in lobby - it's wrong if oldGameState != GAME_LOBBY: mapCicler.check() modCicler.check() LT_Cicler.check() presetCicler.check() lobbyEnoughPlayers = False # reset the state lobbyWaitGeneral = curTime + cfg.WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE lobbyWaitAfterGame = curTime if oldGameState == GAME_PLAYING: lobbyWaitAfterGame = curTime + cfg.WAIT_AFTER_GAME if videoRecorder: os.kill(videoRecorder.pid, signal.SIGINT) # videoRecorder.send_signal(signal.SIGINT) # This is available only on Python 2.6 videoRecorderSignalTime = time.time() io.chatMsg("Waiting for video recorder to finish") canStart = True if videoRecorder and videoRecorder.returncode == None: canStart = False videoRecorder.poll() if time.time() - videoRecorderSignalTime > cfg.TIME_TO_KILL_VIDEORECORDER: io.chatMsg("Video recorder stalled, killing") os.kill(videoRecorder.pid, signal.SIGKILL) videoRecorder.poll() if videoRecorder.returncode != None: io.chatMsg("Video recorder encoding took " + str(int(time.time() - videoRecorderSignalTime)) + " secs") canStart = True videoRecorder = None if lobbyWaitAfterGame <= curTime: if not lobbyEnoughPlayers and lobbyWaitGeneral <= curTime: lobbyWaitGeneral = curTime + cfg.WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE io.chatMsg(cfg.TOO_FEW_PLAYERS_MESSAGE) if not lobbyEnoughPlayers and len(worms) >= cfg.MIN_PLAYERS: # Enough players already - start game lobbyEnoughPlayers = True io.chatMsg(cfg.WAIT_BEFORE_GAME_MESSAGE) lobbyWaitBeforeGame = curTime + cfg.WAIT_BEFORE_GAME if lobbyEnoughPlayers and len(worms) < cfg.MIN_PLAYERS: # Some players left when game not yet started lobbyEnoughPlayers = False io.chatMsg(cfg.TOO_FEW_PLAYERS_MESSAGE) if lobbyEnoughPlayers and not sentStartGame: if lobbyWaitBeforeGame <= curTime and canStart: # Start the game if io.getGameType() in ["Death Match","Team Death Match"]: if len(worms) >= cfg.MIN_PLAYERS_TEAMS: # Split in teams setvar("GameOptions.GameInfo.GameType", "Team Death Match") if not cfg.ALLOW_TEAM_CHANGE: counter = 0 for w in worms.values(): if w.iID != -1: io.setWormTeam( w.iID, counter % cfg.MAX_TEAMS ) counter += 1 else: io.setvar("GameOptions.GameInfo.GameType", "Death Match") if io.startGame(): if cfg.ALLOW_TEAM_CHANGE and len(worms) >= cfg.MIN_PLAYERS_TEAMS: io.chatMsg(cfg.TEAM_CHANGE_MESSAGE) sentStartGame = True if cfg.RECORD_VIDEO: try: #io.messageLog("Running dedicated-video-record.sh, curdir " + os.path.abspath(os.path.curdir) ,io.LOG_INFO) videoRecorder = subprocess.Popen( ["./dedicated-video-record.sh", "./dedicated-video-record.sh"], stdin=open("/dev/null","r"), stdout=open("../../../dedicatedVideo.log","w"), stderr=subprocess.STDOUT, cwd=".." ) except: io.messageLog(formatExceptionInfo(),io.LOG_ERROR) else: io.chatMsg("Game could not be started") oldGameState == GAME_PLAYING # hack that it resets at next control handler call if gameState == GAME_WEAPONS: #checkMaxPing() # if we allow empty games, ignore this check if len(worms) < cfg.MIN_PLAYERS and not io.getVar("GameOptions.GameInfo.AllowEmptyGames"): # Some players left when game not yet started io.chatMsg("Too less players -> back to lobby") io.gotoLobby() sentStartGame = False if gameState == GAME_PLAYING: checkMaxPing()
rank[k] = [oldrank[k][0],oldrank[k][1],oldrank[k][2],count] 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 io.messageLog("Ranking: Parsing rank data") rank = ParseRank() auth = ParseAuthInfo() io.messageLog("Ranking: Rank data parsing completed")
def parseUserCommand(wormid, message): global kickedUsers try: # Do not check on msg size or anything, exception handling is further down if message in [ "y", "n", "start", "stop", "rank", "toprank", "ranktotal" ]: # Single-word usercommands for faster typing cmd = message else: if (not message.startswith(cfg.USER_PREFIX)): return False # normal chat cmd = message.split(" ")[0] cmd = cmd.replace(cfg.USER_PREFIX, "", 1).lower() #Remove the prefix if wormid >= 0: io.messageLog( "%i:%s issued %s" % (wormid, hnd.worms[wormid].Name, cmd.replace(cfg.USER_PREFIX, "", 1)), io.LOG_USRCMD) else: io.messageLog("ded admin issued %s" % cmd, io.LOG_USRCMD) # Unnecesary to split multiple times, this saves CPU. params = message.split(" ")[1:] if cmd == "help": userCommandHelp(wormid) if cfg.ALLOW_TEAM_CHANGE and cmd == "team": if not params: io.privateMsg(wormid, "You need to specify a team") raise Exception, "You need to specify a team" else: if params[0].lower() == "blue" or params[0].lower() == "b": io.setWormTeam(wormid, 0) elif params[0].lower() == "red" or params[0].lower() == "r": io.setWormTeam(wormid, 1) elif (params[0].lower() == "green" or params[0].lower() == "g") and cfg.MAX_TEAMS >= 3: io.setWormTeam(wormid, 2) elif (params[0].lower() == "yellow" or params[0].lower() == "y") and cfg.MAX_TEAMS >= 4: io.setWormTeam(wormid, 3) if cfg.RANKING: if cmd == "toprank": ranking.firstRank(wormid) if cmd == "rank": if wormid in hnd.worms: wormName = hnd.worms[wormid].Name if params: wormName = " ".join(params) ranking.myRank(wormName, wormid) if cmd == "ranktotal": io.privateMsg( wormid, "There are " + str(len(ranking.rank)) + " players in the ranking.") if cfg.VOTING: if cmd == "kick": kicked = int(params[0]) if not kicked in hnd.worms.keys(): raise Exception, "Invalid worm ID" addVote( "io.kickWorm(" + str(kicked) + ", 'You are kicked for " + str(cfg.VOTING_KICK_TIME) + " minutes')", wormid, "Kick %i: %s" % (kicked, hnd.worms[kicked].Name)) hnd.worms[kicked].Voted = -1 if cmd == "mute": if not kicked in hnd.worms.keys(): raise Exception, "Invalid worm ID" kicked = int(params[0]) addVote("io.muteWorm(" + str(kicked) + ")", wormid, "Mute %i: %s" % (kicked, hnd.worms[kicked].Name)) hnd.worms[kicked].Voted = -1 if cmd == "mod": # Users are proven to be stupid and can't tell the difference between mod and preset # so here we're first looking for a preset, and then looking for a mod with the same name if preset not found # (well, let's call that UI simplification) preset = -1 for p in range(len(hnd.availablePresets)): if hnd.availablePresets[p].lower().find( params[0].lower()) != -1: preset = p break if preset != -1: addVote( 'hnd.selectPreset( Preset = "%s" )' % hnd.availablePresets[preset], wormid, "Preset %s" % hnd.availablePresets[preset]) else: mod = "" for m in io.listMods(): if m.lower().find(" ".join(params[0:]).lower()) != -1: mod = m break if mod == "": io.privateMsg( wormid, "Invalid mod, available mods: " + ", ".join(hnd.availablePresets) + ", ".join(io.listMods())) else: addVote('hnd.selectPreset( Mod = "%s" )' % mod, wormid, "Mod %s" % mod) if cmd == "map": level = "" for l in io.listMaps(): if l.lower().find(" ".join(params[0:]).lower()) != -1: level = l break if level == "": io.privateMsg( wormid, "Invalid map, available maps: " + ", ".join(io.listMaps())) else: addVote('hnd.selectPreset( Level = "%s" )' % level, wormid, "Map %s" % level) if cmd == "lt": addVote('hnd.selectPreset( LT = %i )' % int(params[0]), wormid, "Loading time %i" % int(params[0])) if cmd == "start": addVote( 'hnd.lobbyWaitAfterGame = time.time(); hnd.lobbyWaitBeforeGame = time.time()', wormid, "Start game now") if cmd == "stop": addVote('io.gotoLobby()', wormid, "Go to lobby") if (cmd == "y" or cmd == "yes"): if hnd.worms[wormid].Voted != 1: hnd.worms[wormid].Voted = 1 recheckVote() if (cmd == "n" or cmd == "no"): if hnd.worms[wormid].Voted != -1: hnd.worms[wormid].Voted = -1 recheckVote() elif parseUserCommand_Preset and parseUserCommand_Preset( wormid, cmd, params): pass else: raise Exception, "Invalid user command" except: # All python classes derive from main "Exception", but confused me, this has the same effect. if wormid >= 0: io.privateMsg( wormid, "Invalid user command - type !help for list of commands") io.messageLog(formatExceptionInfo(), io.LOG_ERROR) #Helps to fix errors return False return True
def ParseRank(useRatios = True): #io.messageLog("ParseRank: Opening ranking file: " + cfg.RANKING_FILE, io.LOG_INFO) try: rank_file_path = io.getWriteFullFileName(cfg.RANKING_FILE) f = open(rank_file_path,"r") except IOError: io.messageLog("ParseRank: Unable to open ranking file: " + cfg.RANKING_FILE + " from path: " + rank_file_path, io.LOG_ERROR) 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") if not killer in killers.keys(): killers[killer] = [] if not deader in deaders.keys(): deaders[deader] = [] 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 parseUserCommand(wormid,message): global kickedUsers try: # Do not check on msg size or anything, exception handling is further down if message in [ "y", "n", "start", "stop", "rank", "toprank", "ranktotal" ]: # Single-word usercommands for faster typing cmd = message else: if (not message.startswith(cfg.USER_PREFIX)): return False # normal chat cmd = message.split(" ")[0] cmd = cmd.replace(cfg.USER_PREFIX,"",1).lower() #Remove the prefix if wormid >= 0: io.messageLog("%i:%s issued %s" % (wormid,hnd.worms[wormid].Name,cmd.replace(cfg.USER_PREFIX,"",1)),io.LOG_USRCMD) else: io.messageLog("ded admin issued %s" % cmd, io.LOG_USRCMD) # Unnecesary to split multiple times, this saves CPU. params = message.split(" ")[1:] if cmd == "help": userCommandHelp(wormid) if cfg.ALLOW_TEAM_CHANGE and cmd == "team": if not params: io.privateMsg(wormid, "You need to specify a team" ) raise Exception, "You need to specify a team" else: if params[0].lower() == "blue" or params[0].lower() == "b": io.setWormTeam(wormid, 0) elif params[0].lower() == "red" or params[0].lower() == "r": io.setWormTeam(wormid, 1) elif ( params[0].lower() == "green" or params[0].lower() == "g" ) and cfg.MAX_TEAMS >= 3: io.setWormTeam(wormid, 2) elif ( params[0].lower() == "yellow" or params[0].lower() == "y" ) and cfg.MAX_TEAMS >= 4: io.setWormTeam(wormid, 3) if cfg.RANKING: if cmd == "toprank": ranking.firstRank(wormid) if cmd == "rank": if wormid in hnd.worms: wormName = hnd.worms[wormid].Name if params: wormName = " ".join(params) ranking.myRank(wormName, wormid) if cmd == "ranktotal": io.privateMsg(wormid, "There are " + str(len(ranking.rank)) + " players in the ranking.") if cfg.VOTING: if cmd == "kick": kicked = int( params[0] ) if not kicked in hnd.worms.keys(): raise Exception, "Invalid worm ID" addVote( "io.kickWorm(" + str(kicked) + ", 'You are kicked for " + str(cfg.VOTING_KICK_TIME) + " minutes')", wormid, "Kick %i: %s" % ( kicked, hnd.worms[kicked].Name ) ) hnd.worms[kicked].Voted = -1 if cmd == "mute": if not kicked in hnd.worms.keys(): raise Exception, "Invalid worm ID" kicked = int( params[0] ) addVote( "io.muteWorm(" + str(kicked) +")", wormid, "Mute %i: %s" % ( kicked, hnd.worms[kicked].Name ) ) hnd.worms[kicked].Voted = -1 if cmd == "mod": # Users are proven to be stupid and can't tell the difference between mod and preset # so here we're first looking for a preset, and then looking for a mod with the same name if preset not found # (well, let's call that UI simplification) preset = -1 for p in range(len(hnd.availablePresets)): if hnd.availablePresets[p].lower().find(params[0].lower()) != -1: preset = p break if preset != -1: addVote( 'hnd.selectPreset( Preset = "%s" )' % hnd.availablePresets[preset], wormid, "Preset %s" % hnd.availablePresets[preset] ) else: mod = "" for m in io.listMods(): if m.lower().find(" ".join(params[0:]).lower()) != -1: mod = m break if mod == "": io.privateMsg(wormid,"Invalid mod, available mods: " + ", ".join(hnd.availablePresets) + ", ".join(io.listMods())) else: addVote( 'hnd.selectPreset( Mod = "%s" )' % mod, wormid, "Mod %s" % mod ) if cmd == "map": level = "" for l in io.listMaps(): if l.lower().find(" ".join(params[0:]).lower()) != -1: level = l break if level == "": io.privateMsg(wormid,"Invalid map, available maps: " + ", ".join(io.listMaps())) else: addVote( 'hnd.selectPreset( Level = "%s" )' % level, wormid, "Map %s" % level ) if cmd == "lt": addVote( 'hnd.selectPreset( LT = %i )' % int(params[0]), wormid, "Loading time %i" % int(params[0]) ) if cmd == "start": addVote( 'hnd.lobbyWaitAfterGame = time.time(); hnd.lobbyWaitBeforeGame = time.time()', wormid, "Start game now" ) if cmd == "stop": addVote( 'io.gotoLobby()', wormid, "Go to lobby" ) if ( cmd == "y" or cmd == "yes" ): if hnd.worms[wormid].Voted != 1: hnd.worms[wormid].Voted = 1 recheckVote() if ( cmd == "n" or cmd == "no" ): if hnd.worms[wormid].Voted != -1: hnd.worms[wormid].Voted = -1 recheckVote() elif parseUserCommand_Preset and parseUserCommand_Preset(wormid, cmd, params): pass else: raise Exception, "Invalid user command" except: # All python classes derive from main "Exception", but confused me, this has the same effect. if wormid >= 0: io.privateMsg(wormid, "Invalid user command - type !help for list of commands") io.messageLog(formatExceptionInfo(),io.LOG_ERROR) #Helps to fix errors return False return True
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 signalHandler(sig): global gameState, oldGameState, scriptPaused, sentStartGame, worms global vote_locked oldGameState = gameState if len(sig) == 0: return False #Didn't get anything header = sig[0] try: if header == "newworm": parseNewWorm(int(sig[1]), sig[2]) elif header == "wormleft": parseWormLeft(sig) elif header == "privatemessage": parsePrivateMessage(sig) elif header == "chatmessage": parseChatMessage(sig) elif header == "wormdied": parseWormDied(sig) elif header == "wormspawned": parseWormSpawned(sig) elif header == "wormauthorized": parseWormAuthorized(sig) elif header == "wormgotadmin": worms[int(sig[1])].isDedAdmin = True # no other difference to wormauthorized yet - and we also get wormauthorized, so nothing to do anymore pass ## Check GameState ## elif header == "quit": gameState = GAME_QUIT exit() elif header == "backtolobby" or header == "lobbystarted": if cfg.RANKING: ranking.refreshRank() gameState = GAME_LOBBY sentStartGame = False vote_locked = False #Always unlock voting when back to lobby controlHandler() elif header == "weaponselections": gameState = GAME_WEAPONS controlHandler() elif header == "gamestarted": gameState = GAME_PLAYING sentStartGame = False controlHandler() #TODO: gamestarted && gameloopstart are pretty much duplicates # Or are they? Check. # Same thing for gameloopend and backtolobby elif header == "gameloopstart": #Sent when game starts pass #io.messageLog("TEST -- SIGNAL: gameloopstart", io.LOG_INFO) #TEST elif header == "gameloopend": #Sent at game end pass #io.messageLog("TEST -- SIGNAL: gameloopend", io.LOG_INFO) #TEST #elif header == "gameloopend": #Sent when OLX starts # pass elif header == "timer": # Sent once per second controlHandler() elif header == "custom": io.messageLog(("CUSTOMSIGNAL: %s" % (sig)), io.LOG_INFO) #TEST parseCustom(sig) else: io.messageLog(("I don't understand %s." % (sig)), io.LOG_ERROR) except Exception: traceback.print_exc(None, sys.stderr) return True
def parseAdminCommand(wormid,message): global kickedUsers try: # Do not check on msg size or anything, exception handling is further down if (not message.startswith(cfg.ADMIN_PREFIX)): return False # normal chat cmd = message.split(" ")[0] cmd = cmd.replace(cfg.ADMIN_PREFIX,"",1).lower() #Remove the prefix if wormid >= 0: io.messageLog("%i:%s issued %s" % (wormid,hnd.worms[wormid].Name,cmd.replace(cfg.ADMIN_PREFIX,"",1)),io.LOG_ADMIN) else: io.messageLog("ded admin issued %s" % cmd, io.LOG_USRCMD) # Unnecesary to split multiple times, this saves CPU. params = message.split(" ")[1:] if cmd == "help": adminCommandHelp(wormid) elif cmd == "kick": kickTime = cfg.VOTING_KICK_TIME if len(params) > 1: # Time for kick kickTime = float(params[1]) wormIP = io.getWormIP(int( params[0] )).split(":")[0] if wormIP != "127.0.0.1": kickedUsers[ wormIP ] = time.time() + kickTime*60 if len(params) > 2: # Given some reason io.kickWorm( int( params[0] ), " ".join(params[2:]) ) else: io.kickWorm( int( params[0] ) ) elif cmd == "ban": if len(params) > 1: # Given some reason io.banWorm( int( params[0] ), " ".join(params[1:]) ) else: io.banWorm( int( params[0] ) ) elif cmd == "mute": io.muteWorm( int( params[0] ) ) elif cmd == "preset": preset = -1 for p in range(len(hnd.availablePresets)): if hnd.availablePresets[p].lower().find(params[0].lower()) != -1: preset = p break if preset == -1: io.privateMsg(wormid,"Invalid preset, available presets: " + ", ".join(hnd.availablePresets)) else: hnd.selectPreset( Preset = hnd.availablePresets[preset] ) elif cmd == "mod": mod = "" for m in io.listMods(): if m.lower().find(" ".join(params[0:]).lower()) != -1: mod = m break if mod == "": io.privateMsg(wormid,"Invalid mod, available mods: " + ", ".join(io.listMods())) else: hnd.selectPreset( Mod = mod ) elif cmd == "map": level = "" for l in io.listMaps(): if l.lower().find(" ".join(params[0:]).lower()) != -1: level = l break if level == "": io.privateMsg(wormid,"Invalid map, available maps: " + ", ".join(io.listMaps())) else: hnd.selectPreset( Level = level ) elif cmd == "lt": hnd.selectPreset( LT = int(params[0]) ) elif cmd == "start": io.startGame() elif cmd == "stop": io.gotoLobby() elif cmd == "pause": io.privateMsg(wormid,"Ded script paused") hnd.scriptPaused = True elif cmd == "unpause": io.privateMsg(wormid,"Ded script continues") hnd.scriptPaused = False elif cmd == "setvar": io.setvar(params[0], " ".join(params[1:])) # In case value contains spaces elif cmd == "authorize": try: wormID = int(params[0]) if not hnd.worms[wormID].isAdmin: hnd.worms[wormID].isAdmin = True io.authorizeWorm(wormID) io.messageLog( "Worm %i (%s) added to admins by %i (%s)" % (wormID,hnd.worms[wormID].Name,wormid,hnd.worms[wormid].Name),io.LOG_INFO) io.privateMsg(wormID, "%s made you admin! Type %shelp for commands" % (hnd.worms[wormid].Name,cfg.ADMIN_PREFIX)) io.privateMsg(wormid, "%s added to admins." % hnd.worms[wormID].Name) except KeyError: io.messageLog("parseAdminCommand: Our local copy of wormses doesn't match the real list.",io.LOG_ERROR) elif parseAdminCommand_Preset and parseAdminCommand_Preset(wormid, cmd, params): pass else: raise Exception, "Invalid admin command" except: # All python classes derive from main "Exception", but confused me, this has the same effect. if wormid >= 0: io.privateMsg(wormid, "Invalid admin command") io.messageLog(formatExceptionInfo(),io.LOG_ERROR) #Helps to fix errors return False return True
def __init__(self): StandardCiclerGameVar.__init__(self) self.gameVar = "GameOptions.GameInfo.ModName" def apply(self): if not self.curSelection: return StandardCiclerGameVar.apply(self) SetWeaponBans() modCicler = ModCicler() modCicler.list = cfg.MODS if len(modCicler.list) == 0: modCicler.list = io.listMods() if len(modCicler.list) == 0: io.messageLog("Waiting for mod list ...") while len(modCicler.list) == 0: modCicler.list = io.listMods() class PresetCicler(StandardCiclerBase): def __init__(self): StandardCiclerBase.__init__(self) def apply(self): if not self.curSelection: return StandardCiclerBase.apply(self) global availablePresets, presetDir sDefaults = os.path.join(presetDir, "Defaults")
def controlHandlerDefault(): global worms, gameState, lobbyChangePresetTimeout, lobbyWaitBeforeGame, lobbyWaitAfterGame global lobbyWaitGeneral, lobbyEnoughPlayers, oldGameState, scriptPaused, sentStartGame global presetCicler, modCicler, mapCicler, LT_Cicler global videoRecorder, videoRecorderSignalTime if scriptPaused: return curTime = time.time() cmds.recheckVote(False) if gameState == GAME_LOBBY: # Do not check ping in lobby - it's wrong if oldGameState != GAME_LOBBY: mapCicler.check() modCicler.check() LT_Cicler.check() presetCicler.check() lobbyEnoughPlayers = False # reset the state lobbyWaitGeneral = curTime + cfg.WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE lobbyWaitAfterGame = curTime if oldGameState == GAME_PLAYING: lobbyWaitAfterGame = curTime + cfg.WAIT_AFTER_GAME if videoRecorder: os.kill( videoRecorder.pid, signal.SIGINT ) # videoRecorder.send_signal(signal.SIGINT) # This is available only on Python 2.6 videoRecorderSignalTime = time.time() io.chatMsg("Waiting for video recorder to finish") canStart = True if videoRecorder and videoRecorder.returncode == None: canStart = False videoRecorder.poll() if time.time( ) - videoRecorderSignalTime > cfg.TIME_TO_KILL_VIDEORECORDER: io.chatMsg("Video recorder stalled, killing") os.kill(videoRecorder.pid, signal.SIGKILL) videoRecorder.poll() if videoRecorder.returncode != None: io.chatMsg("Video recorder encoding took " + str(int(time.time() - videoRecorderSignalTime)) + " secs") canStart = True videoRecorder = None if lobbyWaitAfterGame <= curTime: if not lobbyEnoughPlayers and lobbyWaitGeneral <= curTime: lobbyWaitGeneral = curTime + cfg.WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE io.chatMsg(cfg.TOO_FEW_PLAYERS_MESSAGE) if not lobbyEnoughPlayers and len( worms ) >= cfg.MIN_PLAYERS: # Enough players already - start game lobbyEnoughPlayers = True io.chatMsg(cfg.WAIT_BEFORE_GAME_MESSAGE) lobbyWaitBeforeGame = curTime + cfg.WAIT_BEFORE_GAME if lobbyEnoughPlayers and len( worms ) < cfg.MIN_PLAYERS: # Some players left when game not yet started lobbyEnoughPlayers = False io.chatMsg(cfg.TOO_FEW_PLAYERS_MESSAGE) if lobbyEnoughPlayers and not sentStartGame: if lobbyWaitBeforeGame <= curTime and canStart: # Start the game if io.getGameType() in ["Death Match", "Team Death Match"]: if len(worms ) >= cfg.MIN_PLAYERS_TEAMS: # Split in teams setvar("GameOptions.GameInfo.GameType", "Team Death Match") if not cfg.ALLOW_TEAM_CHANGE: counter = 0 for w in worms.values(): if w.iID != -1: io.setWormTeam(w.iID, counter % cfg.MAX_TEAMS) counter += 1 else: io.setvar("GameOptions.GameInfo.GameType", "Death Match") if io.startGame(): if cfg.ALLOW_TEAM_CHANGE and len( worms) >= cfg.MIN_PLAYERS_TEAMS: io.chatMsg(cfg.TEAM_CHANGE_MESSAGE) sentStartGame = True if cfg.RECORD_VIDEO: try: #io.messageLog("Running dedicated-video-record.sh, curdir " + os.path.abspath(os.path.curdir) ,io.LOG_INFO) videoRecorder = subprocess.Popen( [ "./dedicated-video-record.sh", "./dedicated-video-record.sh" ], stdin=open("/dev/null", "r"), stdout=open("../../../dedicatedVideo.log", "w"), stderr=subprocess.STDOUT, cwd="..") except: io.messageLog(formatExceptionInfo(), io.LOG_ERROR) else: io.chatMsg("Game could not be started") oldGameState == GAME_PLAYING # hack that it resets at next control handler call if gameState == GAME_WEAPONS: #checkMaxPing() # if we allow empty games, ignore this check if len(worms) < cfg.MIN_PLAYERS and not io.getVar( "GameOptions.GameInfo.AllowEmptyGames" ): # Some players left when game not yet started io.chatMsg("Too less players -> back to lobby") io.gotoLobby() sentStartGame = False if gameState == GAME_PLAYING: checkMaxPing()
def parseAdminCommand(wormid, message): try: # Do not check on msg size or anything, exception handling is further down cmd = message.split(" ")[0] cmd = cmd.replace(cfg.ADMIN_PREFIX, "", 1).lower() #Remove the prefix if wormid >= 0: io.messageLog( "%i:%s issued %s" % (wormid, hnd.worms[wormid].Name, cmd.replace(cfg.ADMIN_PREFIX, "", 1)), io.LOG_ADMIN) else: io.messageLog("ded admin issued %s" % cmd, io.LOG_USRCMD) # Unnecesary to split multiple times, this saves CPU. params = message.split(" ")[1:] if cmd == "help": adminCommandHelp(wormid) elif cmd == "kick": wormid = int(params[0]) wormIP = io.getWormIP(wormid).split(":")[0] if wormIP != "127.0.0.1": if len(params) > 1: # Given some reason hnd.kickWithTime(wormid, " ".join(params[2:])) else: hnd.kickWithTime(wormid) elif cmd == "ban": if len(params) > 1: # Given some reason io.banWorm(int(params[0]), " ".join(params[1:])) else: io.banWorm(int(params[0])) elif cmd == "mute": io.muteWorm(int(params[0])) elif cmd == "mod": preset = -1 for p in range(len(hnd.availablePresets)): if hnd.availablePresets[p].lower().find( params[0].lower()) != -1: preset = p break if preset == -1: io.privateMsg( wormid, "Invalid preset, available presets: " + ", ".join(hnd.availablePresets)) else: hnd.loadPreset(availablePresets[p]) elif cmd == "map": level = "" for l in io.listMaps(): if l.lower().find(" ".join(params[0:]).lower()) != -1: level = l break if level == "": io.privateMsg( wormid, "Invalid map, available maps: " + ", ".join(io.listMaps())) else: hnd.loadMap(l) elif cmd == "pause": io.privateMsg(wormid, "Ded script paused") hnd.scriptPaused = True elif cmd == "unpause": io.privateMsg(wormid, "Ded script continues") hnd.scriptPaused = False else: raise Exception, "Invalid admin command" except: # All python classes derive from main "Exception", but confused me, this has the same effect. if wormid >= 0: io.privateMsg(wormid, "Invalid admin command") io.messageLog(io.formatExceptionInfo(), io.LOG_ERROR) #Helps to fix errors return False return True
def parseAdminCommand(wormid, message): global kickedUsers try: # Do not check on msg size or anything, exception handling is further down if (not message.startswith(cfg.ADMIN_PREFIX)): return False # normal chat cmd = message.split(" ")[0] cmd = cmd.replace(cfg.ADMIN_PREFIX, "", 1).lower() #Remove the prefix if wormid >= 0: io.messageLog( "%i:%s issued %s" % (wormid, hnd.worms[wormid].Name, cmd.replace(cfg.ADMIN_PREFIX, "", 1)), io.LOG_ADMIN) else: io.messageLog("ded admin issued %s" % cmd, io.LOG_USRCMD) # Unnecesary to split multiple times, this saves CPU. params = message.split(" ")[1:] if cmd == "help": adminCommandHelp(wormid) elif cmd == "kick": kickTime = cfg.VOTING_KICK_TIME if len(params) > 1: # Time for kick kickTime = float(params[1]) wormIP = io.getWormIP(int(params[0])).split(":")[0] if wormIP != "127.0.0.1": kickedUsers[wormIP] = time.time() + kickTime * 60 if len(params) > 2: # Given some reason io.kickWorm(int(params[0]), " ".join(params[2:])) else: io.kickWorm(int(params[0])) elif cmd == "ban": if len(params) > 1: # Given some reason io.banWorm(int(params[0]), " ".join(params[1:])) else: io.banWorm(int(params[0])) elif cmd == "mute": io.muteWorm(int(params[0])) elif cmd == "preset": preset = -1 for p in range(len(hnd.availablePresets)): if hnd.availablePresets[p].lower().find( params[0].lower()) != -1: preset = p break if preset == -1: io.privateMsg( wormid, "Invalid preset, available presets: " + ", ".join(hnd.availablePresets)) else: hnd.selectPreset(Preset=hnd.availablePresets[preset]) elif cmd == "mod": mod = "" for m in io.listMods(): if m.lower().find(" ".join(params[0:]).lower()) != -1: mod = m break if mod == "": io.privateMsg( wormid, "Invalid mod, available mods: " + ", ".join(io.listMods())) else: hnd.selectPreset(Mod=mod) elif cmd == "map": level = "" for l in io.listMaps(): if l.lower().find(" ".join(params[0:]).lower()) != -1: level = l break if level == "": io.privateMsg( wormid, "Invalid map, available maps: " + ", ".join(io.listMaps())) else: hnd.selectPreset(Level=level) elif cmd == "lt": hnd.selectPreset(LT=int(params[0])) elif cmd == "start": io.startGame() elif cmd == "stop": io.gotoLobby() elif cmd == "pause": io.privateMsg(wormid, "Ded script paused") hnd.scriptPaused = True elif cmd == "unpause": io.privateMsg(wormid, "Ded script continues") hnd.scriptPaused = False elif cmd == "setvar": io.setvar(params[0], " ".join(params[1:])) # In case value contains spaces elif cmd == "authorize": try: wormID = int(params[0]) if not hnd.worms[wormID].isAdmin: hnd.worms[wormID].isAdmin = True io.authorizeWorm(wormID) io.messageLog( "Worm %i (%s) added to admins by %i (%s)" % (wormID, hnd.worms[wormID].Name, wormid, hnd.worms[wormid].Name), io.LOG_INFO) io.privateMsg( wormID, "%s made you admin! Type %shelp for commands" % (hnd.worms[wormid].Name, cfg.ADMIN_PREFIX)) io.privateMsg( wormid, "%s added to admins." % hnd.worms[wormID].Name) except KeyError: io.messageLog( "parseAdminCommand: Our local copy of wormses doesn't match the real list.", io.LOG_ERROR) elif parseAdminCommand_Preset and parseAdminCommand_Preset( wormid, cmd, params): pass else: raise Exception, "Invalid admin command" except: # All python classes derive from main "Exception", but confused me, this has the same effect. if wormid >= 0: io.privateMsg(wormid, "Invalid admin command") io.messageLog(formatExceptionInfo(), io.LOG_ERROR) #Helps to fix errors return False return True
def controlHandlerDefault(): global worms, gameState, lobbyChangePresetTimeout, lobbyWaitBeforeGame, lobbyWaitAfterGame global lobbyWaitGeneral, lobbyEnoughPlayers, oldGameState, scriptPaused, sentStartGame global currentAutocyclePreset, currentAutocycleMap global vote_locked, shuffle_counter if scriptPaused: return curTime = time.time() if gameState == GAME_LOBBY: # Do not check ping in lobby - it's wrong if oldGameState != GAME_LOBBY: lobbyEnoughPlayers = False # reset the state lobbyWaitGeneral = curTime + cfg.WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE lobbyWaitAfterGame = curTime if oldGameState == GAME_PLAYING: lobbyWaitAfterGame = curTime + cfg.WAIT_AFTER_GAME #Reset shuffle counter shuffle_counter = 0 #Update votes when game ends updateResult = updateVotes(send_msg=("map", "mod", "teams")) #Autocycle if not voted #Advance autocycle counters first if not updateResult[0]: currentAutocycleMap += 1 if currentAutocycleMap >= len(cfg.LEVELS): currentAutocycleMap = 0 if not updateResult[1]: currentAutocyclePreset += 1 if currentAutocyclePreset >= len(cfg.PRESETS): currentAutocyclePreset = 0 ##Map if not updateResult[0]: io.setvar("GameOptions.GameInfo.LevelName", cfg.LEVELS[currentAutocycleMap]) ##Mod (preset) if not updateResult[1]: loadPreset(cfg.PRESETS[currentAutocyclePreset]) #Check if teams are balanced ##This should be done because teams may become uneven if people leave during game and BALANCE_TEAMS_INGAME is not set if io.getGameType() == 1: io.chatMsg("Checking if teams are even...") balanceTeams(bmsg="game ended") if lobbyWaitAfterGame <= curTime: if not lobbyEnoughPlayers and lobbyWaitGeneral <= curTime: lobbyWaitGeneral = curTime + cfg.WAIT_BEFORE_SPAMMING_TOO_FEW_PLAYERS_MESSAGE io.chatMsg(cfg.TOO_FEW_PLAYERS_MESSAGE) if not lobbyEnoughPlayers and len( worms ) >= cfg.MIN_PLAYERS: # Enough players already - start game lobbyEnoughPlayers = True io.chatMsg(cfg.WAIT_BEFORE_GAME_MESSAGE) lobbyWaitBeforeGame = curTime + cfg.WAIT_BEFORE_GAME if lobbyEnoughPlayers and len( worms ) < cfg.MIN_PLAYERS: # Some players left when game not yet started lobbyEnoughPlayers = False io.chatMsg(cfg.TOO_FEW_PLAYERS_MESSAGE) if lobbyEnoughPlayers and not sentStartGame: if lobbyWaitBeforeGame <= curTime: # Start the game #Starting game... ##NOTE Removed team check from here - teams should be assigned before the round starts if io.startGame(): if cfg.ALLOW_TEAM_CHANGE and len( worms) >= cfg.MIN_PLAYERS_TEAMS: io.chatMsg(cfg.TEAM_CHANGE_MESSAGE) sentStartGame = True vote_locked = True #Lock vote-able settings when starting clearVotes() #Clear votes when starting else: io.messageLog("Game could not be started", io.LOG_ERROR) #Log these errors! io.chatMsg("Game could not be started") oldGameState == GAME_PLAYING # hack that it resets at next control handler call if gameState == GAME_WEAPONS: # if we allow empty games, ignore this check if len(worms) < cfg.MIN_PLAYERS and not io.getVar( "GameOptions.GameInfo.AllowEmptyGames" ): # Some players left when game not yet started io.chatMsg("Too few players -> back to lobby") io.gotoLobby() sentStartGame = False if gameState == GAME_PLAYING: if cfg.PING_CHECK: checkMaxPing() #Unlock voting when the game is safely running if (gameState == GAME_WEAPONS or gameState == GAME_PLAYING) and oldGameState != GAME_LOBBY and vote_locked: vote_locked = False
def parseUserCommand(wormid, message): try: # Do not check on msg size or anything, exception handling is further down cmd = message.split(" ")[0] cmd = cmd.replace(cfg.USER_PREFIX, "", 1).lower() #Remove the prefix if cfg.USERCOMMAND_LOGGING: if wormid >= 0: io.messageLog( "%i:%s issued %s" % (wormid, hnd.worms[wormid].Name, cmd.replace(cfg.USER_PREFIX, "", 1)), io.LOG_USRCMD) else: io.messageLog("ded admin issued %s" % cmd, io.LOG_USRCMD) # Unnecesary to split multiple times, this saves CPU. params = message.split(" ")[1:] if cmd == "help": userCommandHelp(wormid) return "none" elif cmd == "maphelp": mapHelp(wormid) return "none" #News feed (previously called updates, hence the command name...) elif cmd == "news": controlUpdatesList(wormid) return "none" #Teamchanges... elif cfg.ALLOW_TEAM_CHANGE and cmd == "team": #Not team deathmatch if io.getGameType() != 1: io.privateMsg(wormid, "Game type is not team deathmatch") #Not in lobby elif hnd.gameState != hnd.GAME_LOBBY: io.privateMsg(wormid, "You can only change team in lobby") #No team specified elif not params: io.privateMsg(wormid, "You need to specify a team") #Everything OK else: if params[0].lower() == "blue" or params[0].lower() == "b": hnd.setTeam(wormid, 0) elif params[0].lower() == "red" or params[0].lower() == "r": hnd.setTeam(wormid, 1) elif (params[0].lower() == "green" or params[0].lower() == "g") and cfg.MAX_TEAMS >= 3: hnd.setTeam(wormid, 2) elif (params[0].lower() == "yellow" or params[0].lower() == "y") and cfg.MAX_TEAMS >= 4: hnd.setTeam(wormid, 3) else: io.privateMsg(wormid, "Invalid team") elif cfg.RANKING and cmd in ("rank", "toprank", "ranktotal"): if cmd == "toprank": ranking.firstRank(wormid) if cmd == "rank": if wormid in hnd.worms: wormName = hnd.worms[wormid].Name if params: wormName = " ".join(params).replace( "\"", "\'\'" ) #Convert double quotes to prevent annoyance ranking.myRank(wormName, wormid) if cmd == "ranktotal": if cfg.NAME_CHECK_ACTION == 1 and cfg.HANDLE_RANDOMS_IN_RANKTOTAL: tmp_rankplayers = sortRankPlayers( randoms=0, random_max=cfg.NAME_CHECK_RANDOM) tmp_rankrandoms = sortRankPlayers( randoms=1, random_max=cfg.NAME_CHECK_RANDOM) io.privateMsg( wormid, "There are " + str(len(tmp_rankplayers)) + " players and " + str(len(tmp_rankrandoms)) + " unnamed players in the ranking.") else: io.privateMsg( wormid, "There are " + str(len(ranking.rank)) + " players in the ranking.") return "none" elif cfg.KICK_VOTING and cmd == "kick": try: kicked = int(params[0]) except ValueError: io.privateMsg(wormid, "Invalid player ID") if not kicked in hnd.worms.keys(): io.privateMsg(wormid, "Invalid player ID") else: hnd.worms[wormid].votedKick = kicked io.chatMsg( hnd.worms[wormid].getCleanName() + " votes to kick " + hnd.worms[kicked].getCleanName() ) #NOTE: We are using the real name here - so it should be cleaned return "kick" elif cfg.VOTING and cmd in ("mod", "map", "m"): if cmd == "mod": #NEW: only presets preset = -1 for p in range(len(hnd.availablePresets)): if hnd.availablePresets[p].lower().find( params[0].lower()) != -1: preset = p break if preset != -1: hnd.worms[wormid].votedPreset = hnd.availablePresets[ preset] io.privateMsg(wormid, "You voted for %s" % hnd.worms[wormid].votedPreset ) #Send these as private msgs to reduce spam return "mod" else: io.privateMsg( wormid, "Invalid preset, available presets: " + ", ".join(hnd.availablePresets)) if cmd == "map": level = "" for l in io.listMaps(): if l.lower().find(" ".join(params[0:]).lower()) != -1: level = l break if level != "": hnd.worms[wormid].votedMap = level io.privateMsg( wormid, "You voted for %s" % hnd.worms[wormid].votedMap) return "map" else: io.privateMsg( wormid, "Invalid map, available maps: " + ", ".join(io.listMaps()) ) #NOTE: This generates a very spammy message... #Quick map voting if cmd == "m": if not params: io.privateMsg( wormid, "No map specified, try %smaphelp for a list of options" % cfg.USER_PREFIX) elif params[0].lower() in presetcfg.MAP_SHORTCUTS.keys(): hnd.worms[wormid].votedMap = presetcfg.MAP_SHORTCUTS[ params[0].lower()] io.privateMsg( wormid, "You voted for %s" % hnd.worms[wormid].votedMap) return "map" else: io.privateMsg( wormid, "Invalid map option, try %smaphelp for a list of available options" % cfg.USER_PREFIX) elif cfg.TEAMGAMES_VOTING and (cmd == "teams" or cmd == "noteams"): if cmd == "teams": hnd.worms[wormid].votedTeams = 1 io.privateMsg(wormid, "You voted for team game!") elif cmd == "noteams": hnd.worms[wormid].votedTeams = 0 io.privateMsg(wormid, "You voted for deathmatch!") return "teams" #Team shuffling elif cmd == "shuffle" and cfg.TEAM_SHUFFLE: #Not TDM if io.getGameType() != 1: io.privateMsg(wormid, "Not TDM - cannot shuffle") #Not in lobby elif hnd.gameState != hnd.GAME_LOBBY: io.privateMsg(wormid, "Cannot shuffle when not in lobby") #Too many shuffles elif hnd.shuffle_counter >= cfg.TEAM_SHUFFLE: io.privateMsg(wormid, "Shuffle limit already reached") else: hnd.shuffleTeams() #Not in lobby #TEST: Use this to check team status... #elif cfg.TEAMCHANGE_LOGGING and cmd == "teamtest": # io.messageLog("TEAMTEST: teamtest called by player " + str(wormid), io.LOG_INFO) # teamtestresult = str(hnd.getNumberWormsInAllTeams()).replace("[","").replace("]","").replace(","," ") # io.privateMsg(wormid, "Team status is "+teamtestresult+" - is this reasonable?") # return "none" else: raise Exception, "Invalid user command" except: # All python classes derive from main "Exception", but confused me, this has the same effect. if wormid >= 0: io.privateMsg( wormid, "Invalid user command - type !help for list of commands") if cfg.USERCOMMAND_ERROR_LOGGING: io.messageLog(io.formatExceptionInfo(), io.LOG_ERROR) #Helps to fix errors return None return "none"
def __init__(self): StandardCiclerGameVar.__init__(self) self.gameVar = "GameOptions.GameInfo.ModName" def apply(self): if not self.curSelection: return StandardCiclerGameVar.apply(self) SetWeaponBans() modCicler = ModCicler() modCicler.list = cfg.MODS if len(modCicler.list) == 0: modCicler.list = io.listMods() if len(modCicler.list) == 0: io.messageLog("Waiting for mod list ...") while len(modCicler.list) == 0: modCicler.list = io.listMods() class PresetCicler(StandardCiclerBase): def __init__(self): StandardCiclerBase.__init__(self) def apply(self): if not self.curSelection: return StandardCiclerBase.apply(self) global availablePresets, presetDir sDefaults = os.path.join(presetDir,"Defaults") try: