def cancel(self): # Check if there's a current vote in the first place. cs = minqlbot.get_configstring(9, cached=False) if not cs: return res = re_vote.match(cs) vote = res.group("vote") args = res.group("args") votes = (int(minqlbot.get_configstring(10)), int(minqlbot.get_configstring(11))) # Return None if the vote's cancelled (like if the round starts before vote's over). super().trigger(votes, vote, args, None)
def trigger(self, passed): cs = minqlbot.get_configstring(9) if not cs: debug("vote_ended weird behavior.") return split_cs = cs.split() if len(split_cs) > 1: args = " ".join(split_cs[1:]) else: args = None votes = (int(minqlbot.get_configstring(10)), int(minqlbot.get_configstring(11))) super().trigger(split_cs[0], args, votes, passed)
def __init__(self, cached=True): self.cached = cached self.__valid = True cs = minqlbot.get_configstring(0, self.cached) if not cs: self.__valid = False raise NonexistentPlayerError("Tried to initialize a Game instance with no active game.")
def __player_configstrings(self): players = {} for i in range(24): cs = minqlbot.get_configstring(i + 529) if cs: players[i] = cs return players
def __player_configstrings(cls): players = {} for i in range(24): cs = minqlbot.get_configstring(i + 529) if cs: players[i] = cs return players
def __init__(self, cached=True): self.cached = cached self.__valid = True cs = minqlbot.get_configstring(0, self.cached) if not cs: self.__valid = False raise NonexistentPlayerError( "Tried to initialize a Game instance with no active game.")
def __getitem__(self, key): cs = minqlbot.get_configstring(0, self.cached) if not cs: self.__valid = False raise NonexistentGameError("Invalid game. Did the bot disconnect?") cvars = minqlbot.parse_variables(cs) return cvars[key]
def get_player(name): for i in range(24): cs = minqlbot.get_configstring(i + 529) if cs: cvars = parse_variables(cs) if name == cvars["n"]: return minqlbot.Player(i) return None
def map(self): return minqlbot.get_configstring(3, self.cached)
def parse(cmdstr): """Parses server commands or gamestates""" cmd = cmdstr.split(" ", 1) if cmd[0] == "chat": rm = re_chat.match(cmd[1]) if rm: # I tested the client ID passed through this command several times, and sooner # or later, it starts sending incorrect data. This applies for chat, tchat and tell. #cid = int(rm.group(1)) player = get_player(rm.group("name")) msg = rm.group("msg") channel = minqlbot.CHAT_CHANNEL # Use static channel event_handlers["chat"].trigger(player, msg, channel) return else: # Check if it's \tell rm = re_tell.match(cmd[1]) if rm: #cid = int(rm.group(1)) player = get_player(rm.group("name")) msg = rm.group("msg") channel = TellChannel(player) event_handlers["chat"].trigger(player, msg, channel) return elif cmd[0] == "tchat": # Team chat. rm = re_tchat.match(cmd[1]) if rm: #cid = int(rm.group(1)) player = get_player(rm.group("name")) msg = rm.group("msg") channel = minqlbot.TEAM_CHAT_CHANNEL # Use static channel event_handlers["chat"].trigger(player, msg, channel) return # big_configstring (bcs) res = re_bcs.match(cmdstr) if res: channel = int(res.group("mode")) index = int(res.group("index")) cvars = res.group("cvars") if channel == 0: bcs_buffer[index] = cvars elif channel == 1: bcs_buffer[index] += cvars elif channel == 2: full_cs = bcs_buffer[index] + cvars del bcs_buffer[index] handle_message('cs {} "{}"'.format(index, full_cs)) return # player_connect res = re_connect.match(cmdstr) if res: #event_handlers["player_connect"].trigger(res.group("name")) return # player_disconnect res = re_disconnect.match(cmdstr) if res: event_handlers["player_disconnect"].reason("disconnect") return # round_start res = re_round_start.match(cmdstr) if res: cvars = parse_variables(res.group("cvars")) if cvars: round_number = int(cvars["round"]) if round_number and "time" in cvars: if round_number == 1: # This is the case when the first countdown starts. event_handlers["round_countdown"].trigger(round_number) return event_handlers["round_countdown"].trigger(round_number) return elif round_number: event_handlers["round_start"].trigger(round_number) return # round_end res = re_round_end.match(cmdstr) if res and int(res.group("score")) != 0: winner = minqlbot.TEAMS[int(res.group("team")) - 5] # Offset by 5 score = (-1, -1) if winner == minqlbot.TEAMS[1]: score = (int(res.group("score")), int(minqlbot.get_configstring(7, cached=False))) elif winner == minqlbot.TEAMS[2]: score = (int(minqlbot.get_configstring(6, cached=False)), int(res.group("score"))) # If the game was forfeited, it'll act as if the round ended, but with -999 score # followed by the actual score. We simply skip the -999 one, since game_ended is # triggered later anyway. if score[0] == -999 or score[1] == -999: return # Otherwise, regular round end. event_handlers["round_end"].trigger(score, winner) return # game_change res = re_game_change.match(cmdstr) if res: cvars = res.group("cvars") cs = minqlbot.get_configstring(0, cached=False) if cvars and cs: old_cvars = parse_variables(cs) new_cvars = parse_variables(cvars) old_state = old_cvars["g_gameState"] new_state = new_cvars["g_gameState"] if old_state != new_state: if old_state == "PRE_GAME" and new_state == "IN_PROGRESS": event_handlers["vote_ended"].cancel( ) # Cancel current vote if any. event_handlers["game_start"].trigger(minqlbot.Game()) elif old_state == "PRE_GAME" and new_state == "COUNT_DOWN": event_handlers["game_countdown"].trigger() elif old_state == "COUNT_DOWN" and new_state == "IN_PROGRESS": event_handlers["vote_ended"].cancel( ) # Cancel current vote if any. event_handlers["game_start"].trigger(minqlbot.Game()) elif old_state == "IN_PROGRESS" and new_state == "PRE_GAME": pass else: debug("UNKNOWN GAME STATES: {} - {}".format( old_state, new_state)) return # game_end # TODO: Proper handling of non-team game modes. res = re_game_end.match(cmdstr) if res: value = int(res.group("value")) if value == 1: red_score = int(minqlbot.get_configstring(6, cached=False)) blue_score = int(minqlbot.get_configstring(7, cached=False)) if red_score > blue_score: event_handlers["vote_ended"].cancel( ) # Cancel current vote if any. event_handlers["game_end"].trigger(minqlbot.Game(), (red_score, blue_score), minqlbot.TEAMS[1]) elif red_score < blue_score: event_handlers["vote_ended"].cancel( ) # Cancel current vote if any. event_handlers["game_end"].trigger(minqlbot.Game(), (red_score, blue_score), minqlbot.TEAMS[2]) else: event_handlers["game_end"].trigger(minqlbot.Game(), (red_score, blue_score), None) return # abort res = re_abort.match(cmdstr) if res: #player = get_player(res.group("name")) event_handlers["abort"].trigger() return # kick res = re_kick.match(cmdstr) if res: event_handlers["player_disconnect"].reason("kick") return # ragequit res = re_ragequit.match(cmdstr) if res: event_handlers["player_disconnect"].reason("ragequit") return # timeout res = re_timeout.match(cmdstr) if res: event_handlers["player_disconnect"].reason("timeout") return # vote_called res = re_vote_called.match(cmdstr) if res: name = res.group("name") # Remove clan tag if any. n_split = name.split() if len(n_split) > 1: name = n_split[1] player = get_player(name) # We don't know yet what kind of vote it is, so no event trigger yet. event_handlers["vote_called"].caller(player) return # vote_called_ex res = re_vote_called_ex.match(cmdstr) if res: event_handlers["vote_called"].trigger(res.group("vote"), res.group("args")) return # vote_ended res = re_vote_ended.match(cmdstr) if res: if res.group("result") == "passed": event_handlers["vote_ended"].trigger(True) else: event_handlers["vote_ended"].trigger(False) return # player_change res = re_player_change.match(cmdstr) if res: cid = int(res.group("id")) - 29 # Offset by 29 cvars = res.group("cvars") csn = cid + 529 # Configstring number cs = minqlbot.get_configstring(csn, cached=False) if cvars and cs: old_cvars = parse_variables(cs) new_cvars = parse_variables(cvars) old_team = minqlbot.TEAMS[int(old_cvars["t"])] new_team = minqlbot.TEAMS[int(new_cvars["t"])] if old_team != new_team: event_handlers["team_switch"].trigger(minqlbot.Player(cid), old_team, new_team) elif cvars: event_handlers["player_connect"].trigger(minqlbot.Player(cid)) elif cs: # Make a Player instance without cached configstrings. This'll allow the plugin # to grab whatever info the player had before the instance is invalidated. event_handlers["player_disconnect"].trigger( minqlbot.Player(cid, cached=False)) return # scores_ca res = re_scores_ca.match(cmdstr) if res: global castats_order total_players = int(res.group("total_players")) raw_scores = [int(i) for i in res.group("scores").split()] scores = [] castats_order.clear() for i in range(total_players): castats_order.append(raw_scores[i * 17]) scores.append(minqlbot.CaScores(raw_scores[i * 17:i * 17 + 17])) event_handlers["scores"].trigger(scores) return # castats res = re_castats.match(cmdstr) if res: global castats_buffer, castats_order raw_stats = [int(i) for i in res.group("stats").split()] cid = castats_order[0] del castats_order[0] castats_buffer.append(minqlbot.CaEndStats(cid, raw_stats)) if not len(castats_order): # Are we ready to trigger? tmp = castats_buffer castats_buffer = [] event_handlers["stats"].trigger(tmp) return # scores_race res = re_scores_race.match(cmdstr) if res: # Race scores actually send the number of players currently playing. # In other words, total_players decrease if someone spectates, but still sends the stats. total_players = len( res.group("scores").split()) // 5 # Should never have a remainder. raw_scores = [int(i) for i in res.group("scores").split()] scores = [] for i in range(total_players): scores.append(minqlbot.RaceScores(raw_scores[i * 5:i * 5 + 5])) event_handlers["scores"].trigger(scores) return
def parse(cmdstr): """Parses server commands or gamestates""" cmd = cmdstr.split(" ", 1) if cmd[0] == "chat": rm = re_chat.match(cmd[1]) if rm: # I tested the client ID passed through this command several times, and sooner # or later, it starts sending incorrect data. This applies for chat, tchat and tell. #cid = int(rm.group(1)) player = get_player(rm.group("name")) msg = rm.group("msg") channel = minqlbot.CHAT_CHANNEL # Use static channel event_handlers["chat"].trigger(player, msg, channel) return else: # Check if it's \tell rm = re_tell.match(cmd[1]) if rm: #cid = int(rm.group(1)) player = get_player(rm.group("name")) msg = rm.group("msg") channel = TellChannel(player) event_handlers["chat"].trigger(player, msg, channel) return elif cmd[0] == "tchat": # Team chat. rm = re_tchat.match(cmd[1]) if rm: #cid = int(rm.group(1)) player = get_player(rm.group("name")) msg = rm.group("msg") channel = minqlbot.TEAM_CHAT_CHANNEL # Use static channel event_handlers["chat"].trigger(player, msg, channel) return # big_configstring (bcs) res = re_bcs.match(cmdstr) if res: channel = int(res.group("mode")) index = int(res.group("index")) cvars = res.group("cvars") if channel == 0: bcs_buffer[index] = cvars elif channel == 1: bcs_buffer[index] += cvars elif channel == 2: full_cs = bcs_buffer[index] + cvars del bcs_buffer[index] handle_message('cs {} "{}"'.format(index, full_cs)) return # player_connect res = re_connect.match(cmdstr) if res: #event_handlers["player_connect"].trigger(res.group("name")) return # player_disconnect res = re_disconnect.match(cmdstr) if res: event_handlers["player_disconnect"].reason("disconnect") return # round_start res = re_round_start.match(cmdstr) if res: cvars = parse_variables(res.group("cvars")) if cvars: round_number = int(cvars["round"]) if round_number and "time" in cvars: if round_number == 1: # This is the case when the first countdown starts. event_handlers["round_countdown"].trigger(round_number) return event_handlers["round_countdown"].trigger(round_number) return elif round_number: event_handlers["round_start"].trigger(round_number) return # round_end res = re_round_end.match(cmdstr) if res and int(res.group("score")) != 0: winner = minqlbot.TEAMS[int(res.group("team")) - 5] # Offset by 5 score = (-1, -1) if winner == minqlbot.TEAMS[1]: score = (int(res.group("score")), int(minqlbot.get_configstring(7, cached=False))) elif winner == minqlbot.TEAMS[2]: score = (int(minqlbot.get_configstring(6, cached=False)), int(res.group("score"))) # If the game was forfeited, it'll act as if the round ended, but with -999 score # followed by the actual score. We simply skip the -999 one, since game_ended is # triggered later anyway. if score[0] == -999 or score[1] == -999: return # Otherwise, regular round end. event_handlers["round_end"].trigger(score, winner) return # game_change res = re_game_change.match(cmdstr) if res: cvars = res.group("cvars") cs = minqlbot.get_configstring(0, cached=False) if cvars and cs: old_cvars = parse_variables(cs) new_cvars = parse_variables(cvars) old_state = old_cvars["g_gameState"] new_state = new_cvars["g_gameState"] if old_state != new_state: if old_state == "PRE_GAME" and new_state == "IN_PROGRESS": event_handlers["vote_ended"].cancel() # Cancel current vote if any. event_handlers["game_start"].trigger(minqlbot.Game()) elif old_state == "PRE_GAME" and new_state == "COUNT_DOWN": event_handlers["game_countdown"].trigger() elif old_state == "COUNT_DOWN" and new_state == "IN_PROGRESS": event_handlers["vote_ended"].cancel() # Cancel current vote if any. event_handlers["game_start"].trigger(minqlbot.Game()) elif old_state == "IN_PROGRESS" and new_state == "PRE_GAME": pass else: debug("UNKNOWN GAME STATES: {} - {}".format(old_state, new_state)) return # game_end res = re_game_end.match(cmdstr) if res: value = int(res.group("value")) if value == 1: red_score = int(minqlbot.get_configstring(6, cached=False)) blue_score = int(minqlbot.get_configstring(7, cached=False)) if red_score > blue_score: event_handlers["vote_ended"].cancel() # Cancel current vote if any. event_handlers["game_end"].trigger(minqlbot.Game(), (red_score, blue_score), minqlbot.TEAMS[1]) elif red_score < blue_score: event_handlers["vote_ended"].cancel() # Cancel current vote if any. event_handlers["game_end"].trigger(minqlbot.Game(), (red_score, blue_score), minqlbot.TEAMS[2]) else: debug("game_end: Weird behaviour!") return # kick res = re_kick.match(cmdstr) if res: event_handlers["player_disconnect"].reason("kick") return # ragequit res = re_ragequit.match(cmdstr) if res: event_handlers["player_disconnect"].reason("ragequit") return # timeout res = re_timeout.match(cmdstr) if res: event_handlers["player_disconnect"].reason("timeout") return # vote_called res = re_vote_called.match(cmdstr) if res: name = res.group("name") # Remove clan tag if any. n_split = name.split() if len(n_split) > 1: name = n_split[1] player = get_player(name) # We don't know yet what kind of vote it is, so no event trigger yet. event_handlers["vote_called"].caller(player) return # vote_called_ex res = re_vote_called_ex.match(cmdstr) if res: event_handlers["vote_called"].trigger(res.group("vote"), res.group("args")) return # vote_ended res = re_vote_ended.match(cmdstr) if res: if res.group("result") == "passed": event_handlers["vote_ended"].trigger(True) else: event_handlers["vote_ended"].trigger(False) return # player_change res = re_player_change.match(cmdstr) if res: cid = int(res.group("id")) - 29 # Offset by 29 cvars = res.group("cvars") csn = cid + 529 # Configstring number cs = minqlbot.get_configstring(csn, cached=False) if cvars and cs: old_cvars = parse_variables(cs) new_cvars = parse_variables(cvars) old_team = minqlbot.TEAMS[int(old_cvars["t"])] new_team = minqlbot.TEAMS[int(new_cvars["t"])] if old_team != new_team: event_handlers["team_switch"].trigger(minqlbot.Player(cid), old_team, new_team) elif cvars: event_handlers["player_connect"].trigger(minqlbot.Player(cid)) elif cs: # Make a Player instance without cached configstrings. This'll allow the plugin # to grab whatever info the player had before the instance is invalidated. event_handlers["player_disconnect"].trigger(minqlbot.Player(cid, cached=False)) return # scores_ca res = re_scores_ca.match(cmdstr) if res: global castats_order total_players = int(res.group("total_players")) raw_scores = [int(i) for i in res.group("scores").split()] scores = [] castats_order.clear() for i in range(total_players): castats_order.append(raw_scores[i*17]) scores.append(minqlbot.CaScores(raw_scores[i*17:i*17+17])) event_handlers["scores"].trigger(scores) return # castats res = re_castats.match(cmdstr) if res: global castats_buffer, castats_order raw_scores = [int(i) for i in res.group("scores").split()] cid = castats_order[0] del castats_order[0] castats_buffer.append(minqlbot.CaEndScores(cid, raw_scores)) if not len(castats_order): # Are we ready to trigger? tmp = castats_buffer castats_buffer = [] event_handlers["stats"].trigger(tmp) return # scores_race res = re_scores_race.match(cmdstr) if res: # Race scores actually send the number of players currently playing. # In other words, total_players decrease if someone spectates, but still sends the stats. total_players = len(res.group("scores").split()) // 5 # Should never have a remainder. raw_scores = [int(i) for i in res.group("scores").split()] scores = [] for i in range(total_players): scores.append(minqlbot.RaceScores(raw_scores[i*5:i*5+5])) event_handlers["scores"].trigger(scores) return
def is_vote_active(cls): if minqlbot.get_configstring(9): return True else: return False
def red_score(self): return int(minqlbot.get_configstring(6, self.cached))
def blue_score(self): return int(minqlbot.get_configstring(7, self.cached))
def is_vote_active(self): if minqlbot.get_configstring(9): return True else: return False