def check_version(self, player=None, channel=None): url = "https://raw.githubusercontent.com/barelymissed/minqlx-plugins/master/{}.py"\ .format(self.__class__.__name__) res = requests.get(url) if res.status_code != requests.codes.ok: return for line in res.iter_lines(): if line.startswith(b'VERSION'): line = line.replace(b'VERSION = ', b'') line = line.replace(b'"', b'') # If called manually and outdated if channel and VERSION.encode() != line: channel.reply("^4Server: ^7Currently using ^4BarelyMiSSeD^7's ^6{}^7 plugin ^1outdated^7 version" " ^6{}^7. The latest version is ^6{}" .format(self.__class__.__name__, VERSION, line.decode())) channel.reply("^4Server: ^7See ^3https://github.com/BarelyMiSSeD/minqlx-plugins") # If called manually and alright elif channel and VERSION.encode() == line: channel.reply("^4Server: ^7Currently using ^4BarelyMiSSeD^7's latest ^6{}^7 plugin version ^6{}^7." .format(self.__class__.__name__, VERSION)) channel.reply("^4Server: ^7See ^3https://github.com/BarelyMiSSeD/minqlx-plugins") # If routine check and it's not alright. elif player and VERSION.encode() != line: try: player.tell("^4Server: ^3Plugin update alert^7:^6 {}^7's latest version is ^6{}^7 and you're" " using ^6{}^7!".format(self.__class__.__name__, line.decode(), VERSION)) player.tell("^4Server: ^7See ^3https://github.com/BarelyMiSSeD/minqlx-plugins") except Exception as e: minqlx.console_command("echo {}".format(e)) return
def update_realscores(teams): minqlx.console_command("echo Updating realscores (red: {} - blue: {})".format(self.game.red_score, self.game.blue_score)) # Calculate if we are in a special case (in case of plugin reload) first_round = self.game.red_score + self.game.blue_score == 1 special_case = not (self.scores_snapshot or first_round) for _p in teams['red'] + teams['blue']: # Gather the data sid = _p.steam_id score = _p.stats.score frags = _p.stats.kills curr_dmg = _p.stats.damage_dealt hc = int(_p.cvars.get('handicap', 100)) prev_dmg = self.scores_snapshot.get(sid, [None, curr_dmg if special_case else 0])[1] diff = curr_dmg - prev_dmg actual_diff = diff / hc # Calculate / update the 'real' scores self.realdamage[sid] = self.realdamage.get(sid, 0) + actual_diff self.realscores[sid] = int(self.realdamage[sid] + frags) # while we're here, update snapshots for next round self.scores_snapshot[sid] = [_p.team, curr_dmg] dbg = "echo DBG: {}({}%) pdmg: {} cdmg: {} diff: {} tot.kills: {} scr: {} rscr: {}" minqlx.console_command(dbg.format(_p.name, hc, prev_dmg, curr_dmg, diff, frags, score, self.realscores[sid]))
def cmd_addbot(self, player, msg, channel): if player.team == "spectator": player.tell("You can't use this command as a spectator.") return minqlx.RET_STOP_ALL elif self.current_bot: player.tell("The bot is already active.") return minqlx.RET_STOP_ALL elif len(msg) < 2: return minqlx.RET_USAGE try: thinktime = int(msg[1]) if (thinktime < 0 or thinktime > 200): raise ValueError except ValueError: player.tell( "Please select a skill between 0 and 200. 0 is very difficult, 60 is hard, 200 is easier but still not noob-friendly" ) return minqlx.RET_STOP_ALL self.set_cvar("bot_thinktime", thinktime) teams = self.teams() team = "b" if len(teams["red"]) > len(teams["blue"]) else "r" self.expecting_bot = True minqlx.console_command("addbot {} {} 0 {} \"{}\"".format( self.get_cvar("qlx_bot"), self.get_cvar("qlx_botSkill"), team, self.get_cvar("qlx_botName"))) self.expecting_bot = False
def check_server(self): def unload(): minqlx.console_print("^1The specqueue script, version 2.08.4 or higher, is required for the bots script." " Include specqueue in the server configuration to use the bots script.") self.msg("^1The specqueue script, version 2.08.4 or higher, is required for the bots script." " Include specqueue in the server configuration to use the bots script.") minqlx.console_command("qlx {}unload {}" .format(self.get_cvar("qlx_commandPrefix"), self.__class__.__name__)) try: queue_version = self.specqueue_version() except AttributeError: unload() return version_list = queue_version.split(".") old_version = False if int(version_list[0]) < 2: old_version = True elif int(version_list[0]) == 2 and int(version_list[1]) < 8: old_version = True elif int(version_list[0]) == 2 and int(version_list[1]) == 8 and int(version_list[2]) < 4: old_version = True if old_version: unload() return self.reset_avail_bots() if not self.get_cvar("bot_enable", bool): minqlx.console_command("set bot_enable 1") minqlx.console_command("map {}".format(self.get_cvar("qlx_botsMap"))) else: self.add_bots() Timer(60, self.start_all_bots_game).start()
def unload(): minqlx.console_print("^1The specqueue script, version 2.08.4 or higher, is required for the bots script." " Include specqueue in the server configuration to use the bots script.") self.msg("^1The specqueue script, version 2.08.4 or higher, is required for the bots script." " Include specqueue in the server configuration to use the bots script.") minqlx.console_command("qlx {}unload {}" .format(self.get_cvar("qlx_commandPrefix"), self.__class__.__name__))
def handle_player_spawn(self, player): """Spawns player instantly and gives quad/haste on some maps. Moves player to position if they used !goto or !loadpos. Removes player from frame dict.""" map_name = self.game.map.lower() if self.map_restart: self.map_restart = False minqlx.console_command("map_restart") if player.team == "free": player.is_alive = True if map_name == "wsm": player.powerups(quad=999999) elif map_name in HASTE: player.powerups(haste=999999) elif map_name == "bokluk": player.flight(fuel=3500, max_fuel=3500) if player.steam_id in self.move_player and player.is_alive: if player.steam_id not in self.goto: player.tell("^6Your time will not count, unless you kill yourself.") self.goto[player.steam_id] = player.score minqlx.set_position(player.id, self.move_player.pop(player.steam_id)) if map_name == "kraglejump": player.powerups(haste=60) # some stages need haste and some don't, so 60 is a compromise... self.frame.pop(player.steam_id, None)
def cmd_ruleset(self, player, msg, channel): if len(msg) < 2: return minqlx.RET_USAGE if msg[1].lower() == "pql": minqlx.set_cvar("pmove_airControl", "1") minqlx.set_cvar("pmove_rampJump", "1") minqlx.set_cvar("weapon_reload_rg", "1200") minqlx.set_cvar("pmove_weaponRaiseTime", "10") minqlx.set_cvar("pmove_weaponDropTime", "10") minqlx.set_cvar("g_damage_lg", "7") minqlx.set_cvar("dmflags", "60") if self.game.type_short == "ca": minqlx.set_cvar("g_startingHealth", "200") minqlx.set_cvar("g_startingArmor", "200") minqlx.console_command("map_restart") self.msg("PQL ruleset is now set.") if msg[1].lower() == "vql": minqlx.set_cvar("pmove_airControl", "0") minqlx.set_cvar("pmove_rampJump", "0") minqlx.set_cvar("weapon_reload_rg", "1500") minqlx.set_cvar("pmove_weaponRaiseTime", "200") minqlx.set_cvar("pmove_weaponDropTime", "200") minqlx.set_cvar("g_damage_lg", "6") if self.game.type_short == "ca": minqlx.set_cvar("dmflags", "28") else: minqlx.console_command("reset dmflags") minqlx.console_command("reset g_startingHealth") minqlx.console_command("reset g_startingArmor") minqlx.console_command("map_restart") self.msg("VQL ruleset is now set.")
def cmd_rcon(self, player, msg, channel): """Sends an rcon command to the server.""" if len(msg) < 2: return minqlx.RET_USAGE with minqlx.redirect_print(channel): minqlx.console_command(" ".join(msg[1:]))
def cmd_addbot(self, player, msg, channel): if player.team == "spectator": player.tell("You can't use this command as a spectator.") return minqlx.RET_STOP_ALL elif self.current_bot: player.tell("The bot is already active.") return minqlx.RET_STOP_ALL elif len(msg) < 2: return minqlx.RET_USAGE try: thinktime = int(msg[1]) if (thinktime < 0 or thinktime > 200): raise ValueError except ValueError: player.tell("Please select a skill between 0 and 200. 0 is very difficult, 60 is hard, 200 is easier but still not noob-friendly") return minqlx.RET_STOP_ALL self.set_cvar("bot_thinktime", thinktime) teams = self.teams() team = "b" if len(teams["red"]) > len(teams["blue"]) else "r" self.expecting_bot = True minqlx.console_command("addbot {} {} 0 {} \"{}\"" .format(self.get_cvar("qlx_bot"), self.get_cvar("qlx_botSkill"), team, self.get_cvar("qlx_botName"))) self.expecting_bot = False
def handle_client_command(self, player, command): command = command.lower() command = command.split() if command[0] == "stopserver": if player == self.Owner: minqlx.console_command("quit") if command[0] == "addmod": if player == self.Owner: try: target = self.player(int(command[1])) except: player.tell("Invalid ID.") return minqlx.RET_STOP_ALL self.addmod(target) return minqlx.RET_STOP_ALL if command[0] == "demote": if player == self.Owner: try: target = self.player(int(command[1])) except: player.tell("Invalid ID.") return minqlx.RET_STOP_ALL if target == self.Owner: player.tell("You cannot demote the server owner.") return minqlx.RET_STOP_ALL self.demote(target) return minqlx.RET_STOP_ALL
def check_version(self, player=None, channel=None): url = "https://raw.githubusercontent.com/dsverdlo/minqlx-plugins/master/{}.py".format( self.__class__.__name__) res = requests.get(url) last_status = res.status_code if res.status_code != requests.codes.ok: return for line in res.iter_lines(): if line.startswith(b'VERSION'): line = line.replace(b'VERSION = ', b'') line = line.replace(b'"', b'') # If called manually and outdated if channel and VERSION.encode() != line: channel.reply( "^7Currently using ^3iou^7one^4girl^7's ^6{}^7 plugin ^1outdated^7 version ^6{}^7." .format(self.__class__.__name__, VERSION)) # If called manually and alright elif channel and VERSION.encode() == line: channel.reply( "^7Currently using ^3iou^7one^4girl^7's latest ^6{}^7 plugin version ^6{}^7." .format(self.__class__.__name__, VERSION)) # If routine check and it's not alright. elif player and VERSION.encode() != line: time.sleep(15) try: player.tell( "^3Plugin update alert^7:^6 {}^7's latest version is ^6{}^7 and you're using ^6{}^7!" .format(self.__class__.__name__, line.decode(), VERSION)) except Exception as e: minqlx.console_command("echo {}".format(e)) return
def reactivate_normal_game(self): if self.music_started: self.stop_sound() self.music_started = False self.showdown_activated = False for p in self.players(): p.weapons(g=False, mg=False, sg=False, gl=False, rl=False, lg=False, rg=False, pg=False, bfg=False, gh=False, ng=False, pl=False, cg=False, hmg=False, hands=False) p.weapon(15) minqlx.console_command("g_guidedRocket 0") r = "^3Restoring weapons in " self.blink([r + "5", r + "4", r + "3", r + "2", r + "1", "^2FIGHT!"], interval=1, sound="sound/items/regen", callback=self.restore_original_weapons)
def fetch(self, player, gt, callback): try: sid = player.steam_id except: sid = player attempts = 0 last_status = 0 while attempts < MAX_ATTEMPTS: attempts += 1 url = "http://qlstats.net:8080/{elo}/{}".format(sid, elo=self.get_cvar('qlx_balanceApi')) res = requests.get(url) last_status = res.status_code if res.status_code != requests.codes.ok: continue js = res.json() if "players" not in js: last_status = -1 continue for p in js["players"]: _sid = int(p["steamid"]) if _sid == sid: # got our player if gt not in p: return minqlx.console_command("echo No {} rating for {}".format(gt, _sid)) _gt = p[gt] return callback(player, _gt["elo"], _gt["games"]) minqlx.console_command("echo Problem fetching glicko: " + str(last_status)) return
def unlock(cls, team=None): if team is None: return minqlx.console_command("unlock") elif team.lower() not in minqlx.TEAMS.values(): raise ValueError("Invalid team.") return minqlx.console_command("unlock {}".format(team.lower()))
def handle_player_connect(self, player): # If admin, check version number if self.db.has_permission(player, 5): self.check_version(player=player) # If you are not an exception, you must be checked for elo limit if not (player.steam_id in self.exceptions): if int(self.get_cvar("qlx_elo_block_connecters")): try: url = "http://qlstats.net:8080/{elo}/{}".format(player.steam_id, elo=self.get_cvar('qlx_balanceApi')) res = requests.get(url) if res.status_code != requests.codes.ok: raise js = res.json() gt = self.game.type_short if "players" not in js: raise for p in js["players"]: if int(p["steamid"]) == player.steam_id and gt in p: eval_elo = self.evaluate_elo_games(player, p[gt]['elo'], p[gt]['games']) if eval_elo: return "^1Sorry, but your skill rating {} is too {}! Accepted ratings: {} - {}".format(eval_elo[1], eval_elo[0], self.ELO_MIN, self.ELO_MAX) except Exception as e: minqlx.console_command("echo Error: {}".format(e)) pass else: self.fetch(player, self.game.type_short, self.callback) # Record their join times regardless self.jointimes[player.steam_id] = time.time()
def set_fun_warm_up(self): self.fw_active = True self.fw_weapons = [] for setting in self.PLAYER_CVARS: minqlx.console_command("set {}".format(setting)) fw_id = self.fw_id = random.randint(0, 10000000) self.cycle_fun_weapons(fw_id)
def cmd_setpass(self, player, msg, channel): if len(msg) < 2: player.tell("^3usage^7=^2<password>") return minqlx.RET_STOP_EVENT minqlx.console_command("set g_password \"{}\"".format(msg[1])) player.tell("^3Server join password is set to ^1{}.".format(msg[1])) return minqlx.RET_STOP_EVENT
def handle_round_end(self, _data): self.between_rounds = True self.showdown_skipped_this_round = False self.showdown_weapon = None self.showdown_votes = None minqlx.console_command("g_guidedRocket 0") minqlx.console_command("g_friendlyfire 0") minqlx.remove_dropped_items() if self.last_standing_time is not None: timestamp = datetime.now().timestamp() base_key = LAST_STANDING_LOG.format(self.last_standing_steam_id) last_standing_time = int(time.time() - self.last_standing_time) # noinspection PyUnresolvedReferences if redis.VERSION[0] == 2: self.db.zadd(base_key, last_standing_time, timestamp) else: self.db.zadd(base_key, {timestamp: last_standing_time}) self.last_standing_steam_id = None self.last_standing_time = None if not self.showdown_activated: return self.showdown_activated = False if self.music_started and self.game.roundlimit not in [ self.game.red_score, self.game.blue_score ]: self.stop_sound() self.music_started = False
def cmd_inviteOnlyAdd(self, player, msg, channel): if len(msg) < 2: player.tell("^3usage^7=^7<^2player id^7|^2steam id^7> <^2name^7>") return minqlx.RET_STOP_EVENT target_player = False file = os.path.join(self.get_cvar("fs_homepath"), INVITEONLY_FILE) try: with open(file) as test: pass except Exception as e: player.tell("^1Error ^3reading the Invite Only list file: {}".format(e)) return minqlx.RET_STOP_EVENT # Checks to see if client_id or steam_id was used try: id = int(msg[1]) if 0 <= id <= 63: try: target_player = self.player(id) except minqlx.NonexistentPlayerError: player.tell("^3There is no one on the server using that Client ID.") return minqlx.RET_STOP_EVENT if not target_player: player.tell("^3There is no one on the server using that Client ID.") return minqlx.RET_STOP_EVENT id = int(target_player.steam_id) elif len(msg) < 3 or id < 0: player.tell("^3usage^7=^7<^2player id^7|^2steam id^7> <^2name^7>") return minqlx.RET_STOP_EVENT elif len(str(id)) != 17: player.tell("^3The STEAM ID given needs to be 17 digits in length.") return minqlx.RET_STOP_EVENT except ValueError: player.tell("^3Invalid ID. Use either a client ID or a SteamID64.") return minqlx.RET_STOP_EVENT if not target_player: target_player = " ".join(msg[2:]) # Checks to see if the player is already on the Invite Only list and adds if not. if id in self.inviteonly: player.tell("^2{}^3 is already in the Invite Only list.".format(target_player)) return minqlx.RET_STOP_EVENT h = open(file, "a") h.write(str(id) + " " + str(target_player) + "\n") h.close() self.inviteonly.append(id) player.tell("^2{}^3 has been added to the Invite Only list.".format(target_player)) if id in self.notOnIOList: self.notOnIOList.remove(id) player_list = self.players() for p in player_list: if id == p.steam_id: minqlx.console_command("tell {} ^3You have been added to the Invited Player list for this server. Enjoy your game!".format(p.id)) return minqlx.RET_STOP_EVENT return minqlx.RET_STOP_EVENT
def get_maps(self, player=None, msg=None, channel=None): with self.gather_maps(): minqlx.console_command("dir maps") if player: player.tell("^4Server^7: The server maps have been stored in the file ^3{}^7.".format(FILE_NAME)) return True
def grabmaps(self): if self.supported_maps: return def callback(maps=[]): self.supported_maps = maps with minqlx.redirect_print(GetMaps(callback)): minqlx.console_command("dir maps bsp")
def unlock(cls, team: Optional[str] = None) -> None: if team is None: minqlx.console_command("unlock") return if team.lower() not in minqlx.TEAMS.values(): raise ValueError("Invalid team.") minqlx.console_command(f"unlock {team.lower()}")
def slap(cls, player: Union[str, int, minqlx.Player], damage: int = 0) -> None: cid = cls.client_id(player) if cid is None: raise ValueError("Invalid player.") minqlx.console_command(f"slap {cid} {damage}")
def put(cls, player: Player, team: str) -> None: cid = minqlx.Plugin.client_id(player) if cid is None: raise ValueError("Invalid player.") if team.lower() not in minqlx.TEAMS.values(): raise ValueError("Invalid team.") minqlx.console_command(f"put {cid} {team.lower()}")
def def_change_map(self): current_map = "{} {}".format(self.get_cvar("mapname"), self.get_cvar("g_factory")) default_map = self.get_cvar("qlx_mmDefaultMap").strip() if current_map != default_map: minqlx.console_print("^1Changing map to {}".format(default_map)) self.map_changed = True minqlx.console_command("map {}".format( self.get_cvar("qlx_mmDefaultMap")))
def handle_player_connect(self, player): if not self.plugin_enabled: return minqlx.RET_NONE if not self.game: return minqlx.RET_NONE if not self.check_for_correct_balance_plugin(): self.disable_policy_check(minqlx.CHAT_CHANNEL) return minqlx.RET_NONE b = minqlx.Plugin._loaded_plugins['balance'] # pylint: disable=protected-access # noinspection PyUnresolvedReferences b.add_request({player.steam_id: self.game.type_short}, self.callback_connect, minqlx.CHAT_CHANNEL) if not self.get_cvar("qlx_qlstatsPrivacyBlock", bool): return minqlx.RET_NONE if player.steam_id not in self.connectthreads: ct = ConnectThread(player.steam_id, self.get_cvar("qlx_balanceApi")) self.connectthreads[player.steam_id] = ct ct.start() self.remove_thread(player.steam_id) # remove it after a while # Check if thread is ready or not ct = self.connectthreads[player.steam_id] if ct.is_alive(): return "Fetching your qlstats settings..." # Check if thread is ready or not try: # noinspection PyProtectedMember res = ct._result # pylint: disable=protected-access if not res: return "Fetching your qlstats settings..." if res.status_code != requests.codes.ok: raise IOError("Invalid response code from qlstats.net.") self.logger.debug(res.text) js = res.json() if "playerinfo" not in js: raise IOError("Invalid response content from qlstats.net.") if str(player.steam_id) not in js["playerinfo"]: raise IOError("Response from qlstats.net did not include data for the requested player.") if "privacy" not in js["playerinfo"][str(player.steam_id)]: raise IOError("Response from qlstats.net did not include privacy information.") if js["playerinfo"][str(player.steam_id)]["privacy"] not in self.allowed_privacy: return minqlx.Plugin.clean_text(self.colored_qlstats_instructions()) except Exception as e: # pylint: disable=broad-except minqlx.console_command(f"echo QLStatsPrivacyError: {e}") return minqlx.RET_NONE
def restore_original_weapons(self): @minqlx.next_frame def set_weapons(_p): minqlx.set_weapons(_p.id, self.weapons_taken or _p.weapons()) for p in self.players(): set_weapons(p) minqlx.console_command("g_friendlyfire 0") self.play_sound("sound/vo_evil/fight")
def iouonegirlplugin_check_version(self, player=None, channel=None): @minqlx.next_frame def reply(m): channel.reply(m) @minqlx.next_frame def tell(m): player.tell(m) url = "{}{}.py".format(self._loc, self._name) res = requests.get(url) last_status = res.status_code if res.status_code != requests.codes.ok: m = "^7Currently using ^3iou^7one^4girl^7's ^6{}^7 plugin version ^6{}^7." if channel: reply(m.format(self._name, self._vers)) elif player: tell(m.format(self._name, self._vers)) return for line in res.iter_lines(): if line.startswith(b'VERSION'): line = line.replace(b'VERSION = ', b'') line = line.replace(b'"', b'') serv_version = line.decode() comp = self.v_compare(self._vers, serv_version) # If called manually and outdated if channel and comp in [self.cr_outdated, self.cr_custom]: if self.get_cvar("qlx_autoupdate_iouplugins", int): reply( "^1{} ^3iou^7one^4girl^7's ^6{}^7 plugin detected. Autoupdating..." .format(comp, self._name)) self.iouonegirlplugin_update(player, None, channel) else: reply( "^7Currently using ^3iou^7one^4girl^7's ^6{}^7 plugin ^1{}^7 version ^6{}^7." .format(self._name, comp, self._vers)) # If called manually and alright elif channel and comp in [self.cr_advanced, self.cr_latest]: reply( "^7Currently using ^3iou^7one^4girl^7's {} ^6{}^7 plugin version ^6{}^7." .format(comp, self._name, self._vers)) # If routine check and it's not alright. elif player and comp in [self.cr_outdated, self.cr_custom]: if self.get_cvar("qlx_autoupdate_iouplugins", int): minqlx.console_command( "echo Autoupdating iouonegirl's {} plugin.".format( self._name)) self.iouonegirlplugin_update(player, None, player.channel) else: time.sleep(15) try: tell( "^3Plugin update alert^7:^6 {}^7's latest version is ^6{}^7 and you're using ^6{}^7!" .format(self._name, line.decode(), self._vers)) except Exception as e: minqlx.console_command("echo Error: {}".format(e)) return
def start_all_bots_game(self): if self.game.state not in ["in_progress", "countdown"]: teams = self.teams() bot_players = [] for player in teams["red"] + teams["blue"] + teams["free"]: if str(player.steam_id)[0] == "9": bot_players.append(player) if len(bot_players) > 1 and len(bot_players) == len(teams["red"] + teams["blue"] + teams["free"]): minqlx.console_command("qlx {}allready".format(self.get_cvar("qlx_commandPrefix"))) self.bot_game_timer = None
def get_maps(self, player=None, msg=None, channel=None): with self.gather_maps(): minqlx.console_command("dir maps") if player: player.tell( "^4Server^7: The server maps have been stored in the file ^3{}^7." .format(FILE_NAME)) return True
def initialize_settings(self): for setting in SETTINGS: minqlx.console_command("set {}".format(setting)) minqlx.console_command("map {} ffa".format( self.get_cvar("qlx_brLoadMap"))) self.logging_enabled = self.get_cvar("qlx_brLogErrors", bool) if self.logging_enabled: self.logger.info( "Initializing Battle Royale Version {}: Changing map to {}" " and setting server to settings: {}".format( VERSION, self.get_cvar("qlx_brLoadMap"), SETTINGS))
def handle_map(self, mapname, factory): if self.get_cvar("bot_enable", bool): self.botError = False minqlx.console_command("addbot trainer 5 a 0 TestingBotSupport") minqlx.console_command("kick TestingBotSupport") self.atGameEnd = False @minqlx.delay(11) def f(): if self.botError: self.msg("^3Warning:^7 Bots are not supported on this map.") self.talk_beep() f()
def check_restart_time(self): try: if self.checking_restart: return self.checking_restart = True try: if self.check_timer.is_alive(): self.check_timer.cancel() except AttributeError: pass except Exception as e: minqlx.console_print( "^1restartserver check_restart_time Timer Exception: {}". format(e)) restart_time = [ time.strftime("%Y"), "0", (self.restart_time if self.restart_time else self.get_cvar("qlx_restartTime")) ] if time.strptime(" ".join(self.start_time), "%Y %j %H:%M:%S") < \ time.strptime("{} {} {}".format(time.strftime("%Y"), time.strftime("%j"), restart_time[2]), "%Y %j %H:%M"): restart_time[1] = self.start_time[1] elif time.strptime(time.strftime("%H:%M"), "%H:%M") < time.strptime( restart_time[2], "%H:%M"): restart_time[1] = time.strftime("%j") else: restart_time[1] = str(int(time.strftime("%j")) + 1) restart_time[0] = int(restart_time[0]) restart_time[1] = int(restart_time[1]) year = int(self.start_time[0]) while self.checking_restart: if (restart_time[1] <= int(time.strftime("%j")) or restart_time[0] < year) and\ time.strptime(time.strftime("%H:%M"), "%H:%M") >= time.strptime(restart_time[2], "%H:%M"): minqlx.console_print( "^1RestartServer^7: Restarting the empty server after the scheduled time of {}" .format(restart_time[2])) minqlx.console_command("quit") time.sleep(60) if len(self.players()) > 0: self.checking_restart = False except Exception as e: minqlx.console_print( "^1restartserver check_time Exceptions: {}".format(e)) finally: self.checking_restart = False self.check_timer = Timer(3600, self.check_restart_time) self.check_timer.start()
def cmd_delayed_restart(self, player, msg, channel): """Quits server if server is empty. If server is not empty but no one is playing a quit is scheduled in 30 seconds. Otherwise server will quit when people leave/spectate.""" if len(self.players()) == 0: channel.reply("Restarting server now.") minqlx.console_command("quit") elif self.amount_playing() == 0: channel.reply("Server will restart in 30 seconds if nobody joins.") self.check_quit() else: player.tell("Server will restart when no one is playing.") self.restart = True
def set_normal_mode(self): msg = False if self.fw_active: msg = True self.fw_active = False minqlx.console_print("Fun Warm Up: Setting normal mode.") if msg: for player in self.players(): player.center_print("^6Fun Warmup mode is ^3OFF") player.tell("^6Fun Warmup mode is ^3OFF") self.fw_weapons = [] for setting in self.DFLT_CVARS: minqlx.console_command("set {}".format(setting))
def iouonegirlplugin_check_myversion(self, player=None, channel=None): @minqlx.next_frame def reply(m): channel.reply(m) @minqlx.next_frame def tell(m): player.tell(m) url = "https://raw.githubusercontent.com/dsverdlo/minqlx-plugins/master/iouonegirl.py" res = requests.get(url) last_status = res.status_code if res.status_code != requests.codes.ok: m = "^7Currently using ^3iou^7one^4girl^7's ^6iouonegirl^7 superplugin version ^6{}^7." if channel: reply(m.format(VERSION)) elif player: tell(m.format(VERSION)) return for line in res.iter_lines(): if line.startswith(b'VERSION'): line = line.replace(b'VERSION = ', b'') line = line.replace(b'"', b'') comp = self.v_compare(VERSION, line.decode()) if channel and self._flag: reply( "^7Latest ^3iou^7one^4girl^7's superplugin update has been downloaded and is waiting for a restart." ) # If called manually and outdated elif channel and comp in [self.cr_outdated, self.cr_custom]: reply( "^7Currently using ^3iou^7one^4girl^7's superplugin ^1{}^7 version ^6{}^7!" .format(comp.upper(), VERSION)) # If called manually and alright elif channel and comp in [self.cr_latest, self.cr_advanced]: reply( "^7Currently using ^3iou^7one^4girl^7's {} ^6iouonegirl^7 superplugin version ^6{}^7." .format(comp, VERSION)) # If routine check and it's not alright. elif player and comp in [self.cr_outdated, self.cr_custom]: if self.get_cvar('qlx_autoupdate_iouplugins', int): self.iouonegirlplugin_updateAbstractDelayed( player, None, player.channel) else: time.sleep(15) try: tell( "^3Plugin update alert^7:^6 iouonegirl^7's latest version is ^6{}^7 and you're using ^6{}^7! ---> ^2!update iouonegirl" .format(line.decode(), VERSION)) except Exception as e: minqlx.console_command( "echo IouoneError: {}".format(e)) return
def cmd_get_hc(self, player, msg, channel): """Check a person's handicap percentage. If no one was specified, display the handicap of the command calling player Ex: !hc - Returns callers' own HC Ex: !hc 2 - Returns the HC of player with ingame id 2 Ex: !hc 2 silent - Returns a pm of the HC of player with ingame id 2 Ex: !hc iou - Returns the HC of person with iou in their name. Ex: !hc iou silent - Returns a PM of the HC of person with iou in their name. """ if len(msg) == 1: target_player = player silent = False elif len(msg) == 2: target_player = self.find_by_name_or_id(player, msg[1]) silent = False elif len(msg) == 3 and msg[2] == "silent": target_player = self.find_by_name_or_id(player, msg[1]) silent = True else: return minqlx.RET_USAGE if target_player: name = target_player.name try: target_player.update() hc = target_player.cvars["handicap"] if int(hc) < 100: m = "^7Player ^6{} ^7is currently playing with handicap ^3{}^7%".format(target_player.name, hc) if silent: player.tell("^6Psst: "+m) return minqlx.RET_STOP_ALL else: channel.reply(m) else: m = "^7Player ^6{} ^7has no active handicap.".format(target_player.name) if silent: player.tell("^6Psst: "+m) return minqlx.RET_STOP_ALL else: channel.reply(m) except Exception as e: minqlx.console_command("echo Error: {}".format(e)) m = "^7Something unexpected happened while getting ^6{}^7's handicap.".format(name) if silent: player.tell("^6Psst: "+m) else: channel.reply(m)
def check_quit(self): """Quits server in 30 seconds if no one is playing. If someone joins the game within 20 seconds then the server won't be restarted until people leave/spectate.""" self.msg("Server will restart in 30 seconds if nobody joins.") self.checking = True time.sleep(20) if self.amount_playing() > 0: self.checking = False self.restart = True else: self.msg("Restarting server in 10 seconds.") time.sleep(10) minqlx.console_command("quit")
def check_players(self): bots_count = 0 players = self.players() for player in players: if str(player.steam_id)[0] == "9": bots_count += 1 if bots_count > 0 and bots_count == len(players): if self.get_cvar("qlx_rboRestartServer", bool): minqlx.console_print("^1Restarting server because no human players are connected.") minqlx.console_command("quit") else: minqlx.console_print("^1Kicking the bots because no human players are connected.") for player in players: player.kick()
def put(cls, player, team): cid = minqlx.Plugin.client_id(player) if cid == None: raise ValueError("Invalid player.") elif team.lower() not in minqlx.TEAMS.values(): raise ValueError("Invalid team.") return minqlx.console_command("put {} {}".format(cid, team.lower()))
def set_cvar(cls, name, value, flags=0): """Sets a cvar. If the cvar exists, it will be set as if set from the console, otherwise create it. :param name: The name of the cvar. :type name: str :param value: The value of the cvar. :type value: Anything with an __str__ method. :param flags: The flags to set if, and only if, the cvar does not exist and has to be created. :type flags: int :returns: True if a new cvar was created, False if an existing cvar was set. :rtype: bool """ if cls.get_cvar(name) is None: minqlx.set_cvar(name, value, flags) return True else: minqlx.console_command("{} \"{}\"".format(name, value)) return False
def iouonegirlplugin_check_version(self, player=None, channel=None): @minqlx.next_frame def reply(m): channel.reply(m) @minqlx.next_frame def tell(m): player.tell(m) url = "{}{}.py".format(self._loc, self._name) res = requests.get(url) last_status = res.status_code if res.status_code != requests.codes.ok: m = "^7Currently using ^3iou^7one^4girl^7's ^6{}^7 plugin version ^6{}^7." if channel: reply(m.format(self._name, self._vers)) elif player: tell(m.format(self._name, self._vers)) return for line in res.iter_lines(): if line.startswith(b'VERSION'): line = line.replace(b'VERSION = ', b'') line = line.replace(b'"', b'') serv_version = line.decode() comp = self.v_compare(self._vers, serv_version) # If called manually and outdated if channel and comp in [self.cr_outdated, self.cr_custom]: if self.get_cvar("qlx_autoupdate_iouplugins", int): reply("^1{} ^3iou^7one^4girl^7's ^6{}^7 plugin detected. Autoupdating...".format(comp,self._name)) self.iouonegirlplugin_update(player, None, channel) else: reply("^7Currently using ^3iou^7one^4girl^7's ^6{}^7 plugin ^1{}^7 version ^6{}^7.".format(self._name, comp, self._vers)) # If called manually and alright elif channel and comp in [self.cr_advanced, self.cr_latest]: reply("^7Currently using ^3iou^7one^4girl^7's {} ^6{}^7 plugin version ^6{}^7.".format(comp, self._name, self._vers)) # If routine check and it's not alright. elif player and comp in [self.cr_outdated, self.cr_custom]: if self.get_cvar("qlx_autoupdate_iouplugins", int): minqlx.console_command("echo Autoupdating iouonegirl's {} plugin.".format(self._name)) self.iouonegirlplugin_update(player, None, player.channel) else: time.sleep(15) try: tell("^3Plugin update alert^7:^6 {}^7's latest version is ^6{}^7 and you're using ^6{}^7!".format(self._name, line.decode(), self._vers)) except Exception as e: minqlx.console_command("echo Error: {}".format(e)) return
def help_get_last(self): teams = self.teams() # See which team is bigger than the other if len(teams["red"]) < len(teams["blue"]): bigger_team = teams["blue"].copy() else: bigger_team = teams["red"].copy() if (self.game.red_score + self.game.blue_score) >= 1: minqlx.console_command("echo Autospec: Picking someone to spec based on score") # Get the last person in that team lowest_players = [bigger_team[0]] for p in bigger_team: if p.stats.score < lowest_players[0].stats.score: lowest_players = [p] elif p.stats.score == lowest_players[0].stats.score: lowest_players.append(p) # Sort on joining times highest(newest) to lowest(oldest) lowest_players.sort(key= lambda el: self.find_time(el), reverse=True ) lowest_player = lowest_players[0] else: minqlx.console_command("echo Autospec: Picking someone to spec based on join times.") bigger_team.sort(key = lambda el: self.find_time(el), reverse=True) lowest_player = bigger_team[0] minqlx.console_command("echo Autospec: Picked {} from the {} team.".format(lowest_player.name, lowest_player.team)) return lowest_player
def check_version(self, player=None, channel=None): url = "https://raw.githubusercontent.com/dsverdlo/minqlx-plugins/master/{}.py".format(self.__class__.__name__) res = requests.get(url) last_status = res.status_code if res.status_code != requests.codes.ok: return for line in res.iter_lines(): if line.startswith(b'VERSION'): line = line.replace(b'VERSION = ', b'') line = line.replace(b'"', b'') # If called manually and outdated if channel and VERSION.encode() != line: channel.reply("^7Currently using ^3iou^7one^4girl^7's ^6{}^7 plugin ^1outdated^7 version ^6{}^7.".format(self.__class__.__name__, VERSION)) # If called manually and alright elif channel and VERSION.encode() == line: channel.reply("^7Currently using ^3iou^7one^4girl^7's latest ^6{}^7 plugin version ^6{}^7.".format(self.__class__.__name__, VERSION)) # If routine check and it's not alright. elif player and VERSION.encode() != line: time.sleep(15) try: player.tell("^3Plugin update alert^7:^6 {}^7's latest version is ^6{}^7 and you're using ^6{}^7!".format(self.__class__.__name__, line.decode(), VERSION)) except Exception as e: minqlx.console_command("echo {}".format(e)) return
def iouonegirlplugin_check_myversion(self, player=None, channel=None): @minqlx.next_frame def reply(m): channel.reply(m) @minqlx.next_frame def tell(m): player.tell(m) url = "https://raw.githubusercontent.com/dsverdlo/minqlx-plugins/master/iouonegirl.py" res = requests.get(url) last_status = res.status_code if res.status_code != requests.codes.ok: m = "^7Currently using ^3iou^7one^4girl^7's ^6iouonegirl^7 superplugin version ^6{}^7." if channel: reply(m.format(VERSION)) elif player: tell(m.format(VERSION)) return for line in res.iter_lines(): if line.startswith(b'VERSION'): line = line.replace(b'VERSION = ', b'') line = line.replace(b'"', b'') comp = self.v_compare(VERSION, line.decode()) if channel and self._flag: reply("^7Latest ^3iou^7one^4girl^7's superplugin update has been downloaded and is waiting for a restart.") # If called manually and outdated elif channel and comp in [self.cr_outdated, self.cr_custom]: reply("^7Currently using ^3iou^7one^4girl^7's superplugin ^1{}^7 version ^6{}^7!".format(comp.upper(), VERSION)) # If called manually and alright elif channel and comp in [self.cr_latest, self.cr_advanced]: reply("^7Currently using ^3iou^7one^4girl^7's {} ^6iouonegirl^7 superplugin version ^6{}^7.".format(comp, VERSION)) # If routine check and it's not alright. elif player and comp in [self.cr_outdated, self.cr_custom]: if self.get_cvar('qlx_autoupdate_iouplugins', int): self.iouonegirlplugin_updateAbstractDelayed(player,None,player.channel) else: time.sleep(15) try: tell("^3Plugin update alert^7:^6 iouonegirl^7's latest version is ^6{}^7 and you're using ^6{}^7! ---> ^2!update iouonegirl".format(line.decode(), VERSION)) except Exception as e: minqlx.console_command("echo IouoneError: {}".format(e)) return
def set_cvar_limit(cls, name, value, minimum, maximum, flags=0): """Sets a cvar with upper and lower limits. If the cvar exists, it will be set as if set from the console, otherwise create it. :param name: The name of the cvar. :type name: str :param value: The value of the cvar. :type value: int, float :param minimum: The minimum value of the cvar. :type value: int, float :param maximum: The maximum value of the cvar. :type value: int, float :param flags: The flags to set if, and only if, the cvar does not exist and has to be created. :type flags: int :returns: True if a new cvar was created, False if an existing cvar was set. :rtype: bool """ if cls.get_cvar(name) is None: minqlx.set_cvar(name, value, flags) return True else: minqlx.console_command("{} \"{}\"".format(name, value)) return False
def algo_get_last(self, excluded_teams = False): # Find the player to be acted upon. If there are more than 1 rounds # played, we will take the lowest score. Otherwise the last to join # If teams are even, just return teams = excluded_teams or self.teams() # See which team is bigger than the other if len(teams["red"]) < len(teams["blue"]): bigger_team = teams["blue"].copy() else: bigger_team = teams["red"].copy() if (self.game.red_score + self.game.blue_score) >= 1: minqlx.console_command("echo Picking someone to {} based on score".format(self.last_action)) # Get the last person in that team lowest_players = [bigger_team[0]] for p in bigger_team: if p.stats.score < lowest_players[0].stats.score: lowest_players = [p] elif p.stats.score == lowest_players[0].stats.score: lowest_players.append(p) # Sort on joining times highest(newest) to lowest(oldest) lowest_players.sort(key= lambda el: self.find_time(el), reverse=True ) lowest_player = lowest_players[0] else: minqlx.console_command("echo Picking someone to {} based on join times.".format(self.last_action)) bigger_team.sort(key = lambda el: self.find_time(el), reverse=True) lowest_player = bigger_team[0] minqlx.console_command("echo Picked {} from the {} team.".format(lowest_player.name, lowest_player.team)) return lowest_player
def cmd_excessive_weaps(self, player, msg, channel): if len(msg) < 2: return minqlx.RET_USAGE if msg[1] == "on": minqlx.set_cvar("weapon_reload_sg", "200") minqlx.set_cvar("weapon_reload_rl", "200") minqlx.set_cvar("weapon_reload_rg", "50") minqlx.set_cvar("weapon_reload_prox", "200") minqlx.set_cvar("weapon_reload_pg", "40") minqlx.set_cvar("weapon_reload_ng", "800") minqlx.set_cvar("weapon_reload_mg", "40") minqlx.set_cvar("weapon_reload_hmg", "40") minqlx.set_cvar("weapon_reload_gl", "200") minqlx.set_cvar("weapon_reload_gauntlet", "100") minqlx.set_cvar("weapon_reload_cg", "30") minqlx.set_cvar("weapon_reload_bfg", "75") minqlx.set_cvar("qlx_excessive", "1") self.msg("Excessive weapons are enabled.") if msg[1] == "off": minqlx.console_command("reset weapon_reload_sg") minqlx.console_command("reset weapon_reload_rl") if (minqlx.get_cvar("pmove_airControl")) == "1": minqlx.set_cvar("weapon_reload_rg", "1200") else: minqlx.console_command("reset weapon_reload_rg") minqlx.console_command("reset weapon_reload_prox") minqlx.console_command("reset weapon_reload_pg") minqlx.console_command("reset weapon_reload_ng") minqlx.console_command("reset weapon_reload_mg") minqlx.console_command("reset weapon_reload_hmg") minqlx.console_command("reset weapon_reload_gl") minqlx.console_command("reset weapon_reload_gauntlet") minqlx.console_command("reset weapon_reload_cg") minqlx.console_command("reset weapon_reload_bfg") minqlx.set_cvar("qlx_excessive", "0") self.msg("Excessive weapons are disabled.")
def cmd_globalVoice(self, player, msg, channel): minqlx.console_command("set g_alltalk 1") channel.reply("^3Voice chatting has been set to ^4GLOBAL^3.")
def cmd_teamVoice(self, player, msg, channel): minqlx.console_command("set g_alltalk 0") channel.reply("^3Voice chatting has been set to ^4TEAM^3.")
def slay(cls, player): cid = cls.client_id(player) if cid is None: raise ValueError("Invalid player.") minqlx.console_command("slay {}".format(cid))
def slap(cls, player, damage=0): cid = cls.client_id(player) if cid is None: raise ValueError("Invalid player.") minqlx.console_command("slap {} {}".format(cid, damage))
def change_map(cls, new_map, factory=None): if not factory: minqlx.Game().map = new_map else: minqlx.console_command("map {} {}".format(new_map, factory))
def cmd_rcon(self, player, msg, channel): """Sends an rcon command to the server.""" if len(msg) < 2: return minqlx.RET_USAGE # TODO: Maybe hack up something to redirect the output of !rcon? minqlx.console_command(" ".join(msg[1:]))