Advertisement
KirillMysnik

team_balancer.py

Jul 11th, 2016
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.20 KB | None | 0 0
  1. # This file is part of ArcJail.
  2. #
  3. # ArcJail is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # ArcJail is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with ArcJail.  If not, see <http://www.gnu.org/licenses/>.
  15.  
  16. from commands.client import ClientCommand
  17. from engines.server import engine_server
  18. from events import Event
  19. from messages import TextMsg, VGUIMenu
  20. from players.teams import teams_by_name
  21.  
  22. from controlled_cvars import InvalidValue
  23. from controlled_cvars.handlers import bool_handler, sound_nullable_handler
  24.  
  25. from ..arcjail import InternalEvent
  26.  
  27. from ..resource.strings import build_module_strings
  28.  
  29. from .game_status import GameStatus, set_status
  30.  
  31. from .guards_license import guards_licenses_manager
  32.  
  33. from .teams import PRISONERS_TEAM, GUARDS_TEAM
  34.  
  35. from .players import broadcast, main_player_manager, tell
  36.  
  37. from . import build_module_config
  38.  
  39.  
  40. strings_module = build_module_strings('team_balancer')
  41. config_manager = build_module_config('team_balancer')
  42.  
  43. config_manager.controlled_cvar(
  44.     bool_handler,
  45.     "enabled",
  46.     default=1,
  47.     description="Enable/Disable team balancing",
  48. )
  49.  
  50. text_msg = {
  51.     'denied your_team': TextMsg(strings_module['denied your_team']),
  52.     'denied locked':  TextMsg(strings_module['denied locked']),
  53.     'denied balance': TextMsg(strings_module['denied balance']),
  54.     'denied no_license': TextMsg(strings_module['denied no_license']),
  55. }
  56.  
  57.  
  58. def ratio_handler(cvar):
  59.     try:
  60.         val = float(cvar.get_string())
  61.     except ValueError:
  62.         raise InvalidValue
  63.  
  64.     if val < 0:
  65.         raise InvalidValue
  66.  
  67.     return val
  68.  
  69. config_manager.controlled_cvar(
  70.     ratio_handler,
  71.     "min_ratio",
  72.     default=2.5,
  73.     description="No less than <value> prisoners per 1 guard",
  74. )
  75. config_manager.controlled_cvar(
  76.     ratio_handler,
  77.     "max_ratio",
  78.     default=5,
  79.     description="No more than <value> prisoners per 1 guard",
  80. )
  81. config_manager.controlled_cvar(
  82.     sound_nullable_handler,
  83.     "deny_sound",
  84.     default="buttons\weapon_cant_buy.wav",
  85.     description="Sound to play when player tries to join unavailable team",
  86. )
  87.  
  88.  
  89. INF = float('inf')
  90. SPECTATORS_TEAM = teams_by_name['spec']
  91.  
  92.  
  93. def count_teams():
  94.     num_prisoners = num_guards = 0
  95.     for player in main_player_manager.values():
  96.         if player.team == PRISONERS_TEAM:
  97.             num_prisoners += 1
  98.         elif player.team == GUARDS_TEAM:
  99.             num_guards += 1
  100.     return num_prisoners, num_guards
  101.  
  102.  
  103. class ImbalanceCase:
  104.     BALANCED = 1
  105.     NEED_MORE_PRISONERS = 2
  106.     NEED_MORE_GUARDS = 3
  107.  
  108.  
  109. def check_teams(num_prisoners, num_guards):
  110.     rmin = max(0, config_manager['min_ratio'])
  111.     rmax = config_manager['max_ratio']
  112.  
  113.     if (num_guards == 0) or (num_prisoners / num_guards > rmax):
  114.         return ImbalanceCase.NEED_MORE_GUARDS
  115.  
  116.     if num_prisoners / num_guards < rmin:
  117.         return ImbalanceCase.NEED_MORE_PRISONERS
  118.  
  119.     return ImbalanceCase.BALANCED
  120.  
  121.  
  122. class SwapDirection:
  123.     MORE_PRISONERS = 1
  124.     MORE_GUARDS = 2
  125.  
  126.  
  127. def check_swap(num_prisoners, num_guards, swap_direction):
  128.     state = check_teams(num_prisoners, num_guards)
  129.     if state == ImbalanceCase.BALANCED:
  130.         return True
  131.  
  132.     if (state == ImbalanceCase.NEED_MORE_PRISONERS and
  133.                 swap_direction == SwapDirection.MORE_PRISONERS):
  134.  
  135.         return True
  136.  
  137.     if (state == ImbalanceCase.NEED_MORE_GUARDS and
  138.                 swap_direction == SwapDirection.MORE_GUARDS):
  139.         return True
  140.  
  141.     return False
  142.  
  143.  
  144. def deny(player):
  145.     if config_manager['deny_sound'] is not None:
  146.         config_manager['deny_sound'].play(player.index)
  147.  
  148.  
  149. def reset_cvars():
  150.     engine_server.server_command("mp_limitteams 0;")
  151.     engine_server.server_command("mp_autoteambalance 0;")
  152.  
  153.  
  154. def show_team_selection(player):
  155.     VGUIMenu('team', show=True).send(player.index)
  156.  
  157.  
  158. _locked = 0
  159.  
  160.  
  161. def lock_teams():
  162.     global _locked
  163.     _locked += 1
  164.  
  165.  
  166. def unlock_teams():
  167.     global _locked
  168.     _locked = max(0, _locked - 1)
  169.  
  170.  
  171. @InternalEvent('load')
  172. def on_load(arc_event):
  173.     reset_cvars()
  174.  
  175.  
  176. @Event('player_team')
  177. def on_player_team(game_event):
  178.     if _locked:
  179.         return
  180.  
  181.     if check_teams(*count_teams()):
  182.         return
  183.  
  184.     broadcast(strings_module['imbalance'])
  185.  
  186.  
  187. @Event('round_start')
  188. def on_round_start(game_event):
  189.     reset_cvars()
  190.  
  191.  
  192. @Event('player_spawn')
  193. def on_player_spawn(game_event):
  194.     player = main_player_manager.get_by_userid(game_event['userid'])
  195.     if player.team != GUARDS_TEAM:
  196.         return
  197.  
  198.     if guards_licenses_manager.has_license(player):
  199.         return
  200.  
  201.     # Bots will help us testing such things as LR on them
  202.     if player.steamid == "BOT":
  203.         return
  204.  
  205.     player.team = PRISONERS_TEAM
  206.     tell(player, strings_module['swapped no_license'])
  207.  
  208.  
  209. @InternalEvent('jail_game_status_reset')
  210. def on_jail_game_status_reset(event_var):
  211.     if check_teams(*count_teams()) == ImbalanceCase.BALANCED:
  212.         set_status(GameStatus.FREE)
  213.     else:
  214.         broadcast(strings_module['imbalance'])
  215.  
  216.  
  217. @ClientCommand('jointeam')
  218. def cl_jointeam(command, index):
  219.     # TODO: premium_base.is_premium support
  220.  
  221.     # Deny empty args
  222.     if len(command) < 2:
  223.         return False
  224.  
  225.     player = main_player_manager[index]
  226.  
  227.     # Deny invalid args
  228.     try:
  229.         new_team = int(command[1])
  230.     except ValueError:
  231.         return False
  232.  
  233.     # Deny joining the same team, with the exception made
  234.     # for unassigned (team 0) players trying to use auto-assign (team 0)
  235.     if player.team == new_team != 0:
  236.         deny(player)
  237.         text_msg['denied your_team'].send(index)
  238.         show_team_selection(player)
  239.         return False
  240.  
  241.     # Always allow switching to spectators
  242.     if new_team == SPECTATORS_TEAM:
  243.         return True
  244.  
  245.     # Deny switching teams while teams are locked
  246.     # (e.g. Last Request in progress)
  247.     if _locked:
  248.         deny(player)
  249.         text_msg['denied locked'].send(index)
  250.         return False
  251.  
  252.     # We count team members as if player has already left their team
  253.     num_prisoners, num_guards = count_teams()
  254.     if player.team == PRISONERS_TEAM:
  255.         num_prisoners -= 1
  256.     elif player.team == GUARDS_TEAM:
  257.         num_guards -= 1
  258.  
  259.     # Emulate auto-assign: try to send them to guards,
  260.     # and if that's impossible - send them to prisoners
  261.     if new_team == 0:
  262.         can_go_guards = check_swap(
  263.             num_prisoners, num_guards + 1, SwapDirection.MORE_GUARDS)
  264.  
  265.         if can_go_guards and guards_licenses_manager.has_license(player):
  266.             if player.team != GUARDS_TEAM:
  267.                 player.team = GUARDS_TEAM
  268.         else:
  269.             if player.team != PRISONERS_TEAM:
  270.                 player.team = PRISONERS_TEAM
  271.  
  272.         # Suppress default auto-assigning behavior
  273.         return False
  274.  
  275.     if new_team == PRISONERS_TEAM:
  276.         can_go_guards = check_swap(
  277.             num_prisoners, num_guards + 1, SwapDirection.MORE_GUARDS)
  278.  
  279.         can_go_prisoners = check_swap(
  280.             num_prisoners + 1, num_guards, SwapDirection.MORE_PRISONERS)
  281.  
  282.         if can_go_guards and not can_go_prisoners:
  283.             deny(player)
  284.             text_msg['denied balance'].send(index)
  285.             show_team_selection(player)
  286.             return False
  287.  
  288.         return True
  289.  
  290.     if new_team == GUARDS_TEAM:
  291.         can_go_guards = check_swap(
  292.             num_prisoners, num_guards + 1, SwapDirection.MORE_GUARDS)
  293.  
  294.         if can_go_guards and guards_licenses_manager.has_license(player):
  295.             return True
  296.  
  297.         deny(player)
  298.  
  299.         if guards_licenses_manager.has_license(player):
  300.             text_msg['denied balance'].send(index)
  301.         else:
  302.             text_msg['denied no_license'].send(index)
  303.  
  304.         show_team_selection(player)
  305.         return False
  306.  
  307.     # Deny non-existing team numbers
  308.     return False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement