class GameVoting(dict): def __init__(self): super().__init__() self._votes_received = 0 self._max_players = -1 self._timeout_delay = None self._popup = None self.result = None def select_callback(self, popup, index, option): self._votes_received += 1 if option.value != "WONT_PLAY": self[option.value] = self.get(option.value, 0) + 1 player = player_manager[index] broadcast(strings_module['player_voted'].tokenize( player=player.name, choice=option.value.caption)) if self._votes_received >= self._max_players: self.finish() def start(self, popup, targets, timeout): self._popup = popup self._max_players = len(targets) self._timeout_delay = Delay(timeout, self.finish) popup.send(*[player.index for player in targets]) def finish(self): if self._popup is None: return if self._timeout_delay is not None: if self._timeout_delay.running: self._timeout_delay.cancel() self._timeout_delay = None self._popup.close() self._popup = None if not self: broadcast(strings_module['result no_game']) InternalEvent.fire('jail_games_voting_result', result=None) return top_games = sorted( self.keys(), key=lambda key: self[key], reverse=True) top_score = self[top_games[0]] top_games = list(filter(lambda key: self[key] == top_score, top_games)) winner = choice(top_games) self.result = winner broadcast(strings_module['result chosen_game'], caption=winner.caption) InternalEvent.fire('jail_games_voting_result', result=winner) self.clear()
class FallProtectedPlayer: def __init__(self, player): self.player = player self.p_player = protected_player_manager[player.index] self._delay = None self._counter = None def protect(self, seconds): if self._counter is not None: raise ValueError("Player {} already protected".format( self.player.userid)) self._counter = self.p_player.new_counter( health=0, display=strings_module['health falldmg_protection']) def sub_hook(counter, info): self.p_player.delete_counter(counter) self.p_player.unset_protected() self._counter = None Shake(FALL_PROT_SHAKE_MAGNITUDE, FALL_PROT_SHAKE_TIME).send(self.player.index) self._delay.cancel() return False self._counter.hook_hurt = get_hook('W', next_hook=sub_hook) def delay_callback(): self.p_player.delete_counter(self._counter) self.p_player.unset_protected() self._counter = None self._delay = Delay(seconds, delay_callback) self.p_player.set_protected() def unprotect(self): if self._counter is None: raise ValueError("Player {} is not protected yet".format( self.player.userid)) self.cancel_delay() self.p_player.delete_counter(self._counter) self.p_player.unset_protected() self._counter = None @property def protected(self): return self._counter is not None def cancel_delay(self): if self._delay is not None and self._delay.running: self._delay.cancel()
class _PlayerEffect(object): """Class for player effects like freeze and burn.""" def __init__(self, descriptor_obj, player): """Initialize a new effect for a player. This doesn't enable the effect yet, it simply prepares it. The effect can be enabled via the _enable method, or via parenthesis which invokes the __call__. """ self._descriptor_obj = descriptor_obj self._player = player self._delay = None def _enable(self, duration=None, *args, **kwargs): """Enable the effect. Add the new effect to a player's effects and call the descriptor object's on function with the provided arguments and keyword arguments. If duration is a positive integer, adds a delay which automatically disables the effect after the duration. """ if isinstance(duration, int) and duration > 0: self._delay = Delay(duration, self._disable) self._player._effects[self._descriptor_obj].append(self) self._descriptor_obj._on_f(self._player, *args, **kwargs) def __call__(self, duration=None, *args, **kwargs): """Override () to call the _enable method.""" self._enable(duration, *args, **kwargs) return self def _disable(self, *args, **kwargs): """Disable the effect. Remove the effect from a player's effects and if there are no more effects of this type, calls the descriptor object's off function with the provided arguments. """ self._player._effects[self._descriptor_obj].remove(self) if not self._player._effects[self._descriptor_obj]: self._descriptor_obj._off_f(self._player, *args, **kwargs) def cancel(self, *args, **kwargs): """Cancel the tick_delay and disable the effect.""" if self._delay is not None: self._delay.cancel() self._delay = None self._disable(*args, **kwargs)
class _HostnameManager(object): """Class used to set the hostname.""" def __init__(self): """Store the base delay.""" self._convar = ConVar('hostname') self._original_hostname = self._convar.get_string() self.delay = Delay(0.1, self._set_hostname) def reset_hostname(self): """Sets the hostname back to the original value on unload.""" self._convar.set_string(self._original_hostname) def set_hostname(self): """Delay changing the hostname.""" # Is there currently a delay? if self.delay is not None: # Cancel the delay self.delay.cancel() # Delay before setting the hostname self.delay = Delay(0.2, self._set_hostname) def _set_hostname(self): """Set the hostname to show GunGame and Included/Custom Plugins.""" # Set the delay back to None self.delay = None # Set the hostname to the new value self._convar.set_string(self.get_hostname_value()) @staticmethod def get_hostname_value(): """Return the full value of the new hostname.""" # Get the basename value = database['Settings']['base_name'] # Create an empty dictionary plugin_values = dict() # Loop through all plugins in the database for plugin_name, values in database.items(): # Is the plugin loaded? if plugin_name in gg_plugin_manager: if (plugin_name == 'gg_bombing_objective' and not len(EntityIter('func_bomb_target'))): continue if (plugin_name == 'gg_hostage_objective' and not len(EntityIter('func_hostage_rescue'))): continue # Store the plugin's name and priority plugin_values[values['name']] = int(values['priority']) # Are there any plugins that are loaded? if plugin_values: # Add the base_break to the string value += database['Settings']['base_break'] # Sort the loaded plugins by their priority plugins = sorted( plugin_values, key=lambda plugin: plugin_values[plugin], ) # Add all loaded plugins to the string # Separate each with the feature_break value += database['Settings']['feature_break'].join(plugins) return value
class SavedPlayer: def __init__(self, player): self._ammo_refill_delay = None self._nade_refill_delay = None self.player = player self.health = 0 self.saved_weapons = [] self.infinite_weapons = [] def _nade_thrown(self, weapon_classname): if self._ammo_refill_delay is None: return if weapon_classname not in self.infinite_weapons: return self._nade_refill_delay = Delay(PROJECTILE_REFILL_DELAY, give_named_item, self.player, weapon_classname, 0) def save_health(self): self.health = self.player.health def save_weapons(self): self.saved_weapons = [] for weapon in self.player.weapons(): weapon_dict = { 'classname': weapon.classname, 'clip': weapon.clip, 'subtype': weapon.get_property_int('m_iSubType'), } try: weapon_dict['ammo'] = weapon.ammo except ValueError: weapon_dict['ammo'] = None self.saved_weapons.append(weapon_dict) self.strip() def save_all(self): self.save_health() self.save_weapons() def strip(self): for weapon in self.player.weapons(): self.player.drop_weapon(weapon.pointer, NULL_VECTOR, NULL_VECTOR) weapon.remove() def restore_health(self): self.player.health = self.health def restore_weapons(self): self.strip() for weapon_dict in self.saved_weapons: weapon = Weapon.create(weapon_dict['classname']) weapon.teleport(self.player.origin, None, None) weapon.spawn() weapon.clip = weapon_dict['clip'] if weapon_dict['ammo'] is not None: weapon.ammo = weapon_dict['ammo'] def restore_all(self): self.restore_health() self.restore_weapons() def max_ammo(self, weapon_classnames): for index in self.player.weapon_indexes(): weapon_classname = edict_from_index(index).classname if weapon_classname not in weapon_classnames: continue if weapon_classname in PROJECTILE_CLASSNAMES: continue weapon_class = weapon_manager[weapon_classname] if weapon_class.maxammo > 0: Weapon(index).ammo = weapon_class.maxammo def _refill_infinite_ammo(self): self.max_ammo(self.infinite_weapons) self._ammo_refill_delay = Delay(INFINITE_AMMO_REFILL_INTERVAL, self._refill_infinite_ammo) def infinite_on(self): if (self._ammo_refill_delay is not None or self._nade_refill_delay is not None): raise ValueError("Infinite equipment is already turned on") new_infinite_weapons = [] for weapon_classname in self.infinite_weapons: if weapon_manager[weapon_classname].maxammo > 0: new_infinite_weapons.append(weapon_classname) self.infinite_weapons = new_infinite_weapons self._refill_infinite_ammo() def infinite_off(self): if self._ammo_refill_delay is None: raise ValueError("Infinite equipment is already turned off") self._ammo_refill_delay.cancel() self._ammo_refill_delay = None if self._nade_refill_delay is not None: if self._nade_refill_delay.running: self._nade_refill_delay.cancel() self._nade_refill_delay = None
class VoteProgressBar: def __init__(self): self._refresh_delay = None self._message = None self._players_total = 0 self._players_voted = 0 def count_vote(self, map_): self._players_voted += 1 for exception in EXCLUDE_ENTRIES: if map_ is exception: return maps = list( filter( lambda map_: map_.votes, sorted(server_map_manager.values(), key=lambda map_: map_.votes, reverse=True))) map_tokens = { 'map1': popups_strings['vote_progress_map_without_votes'], 'map2': popups_strings['vote_progress_map_without_votes'], 'map3': popups_strings['vote_progress_map_without_votes'], } if len(maps) > 0: map_tokens['map1'] = popups_strings[ 'vote_progress_map_with_votes'].tokenized( map=maps[0].name, votes=maps[0].votes, ) if len(maps) > 1: map_tokens['map2'] = popups_strings[ 'vote_progress_map_with_votes'].tokenized( map=maps[1].name, votes=maps[1].votes, ) if len(maps) > 2: map_tokens['map3'] = popups_strings[ 'vote_progress_map_with_votes'].tokenized( map=maps[2].name, votes=maps[2].votes, ) self._message = popups_strings['vote_progress'].tokenized( players_voted=self._players_voted, players_total=self._players_total, **map_tokens, ) self.refresh() def refresh(self): if self._refresh_delay is not None and self._refresh_delay.running: self._refresh_delay.cancel() if not config_manager['votemap_show_progress']: return if self._message: time_left = int(status.vote_start_time + config_manager['vote_duration'] - time()) message_tokenized = self._message.tokenized( **self._message.tokens, time_left="{:02d}:{:02d}".format(*divmod(time_left, 60))) if config_manager['votemap_progress_use_hudmsg']: HudMsg( message_tokenized, color1=HUDMSG_MSG_COLOR, x=HUDMSG_MSG_X, y=HUDMSG_MSG_Y, effect=HUDMSG_MSG_EFFECT, fade_in=HUDMSG_MSG_FADEIN, fade_out=HUDMSG_MSG_FADEOUT, hold_time=HUDMSG_MSG_HOLDTIME, fx_time=HUDMSG_MSG_FXTIME, channel=HUDMSG_MSG_CHANNEL, ).send() else: HintText(message_tokenized).send() self._refresh_delay = Delay(REFRESH_INTERVAL, self.refresh) def start(self): self._players_total = len(mcplayers) self._players_voted = 0 self._message = popups_strings['vote_progress'].tokenized( players_voted=self._players_voted, players_total=self._players_total, map1=popups_strings['vote_progress_map_without_votes'], map2=popups_strings['vote_progress_map_without_votes'], map3=popups_strings['vote_progress_map_without_votes'], ) self.refresh() def stop(self): if self._refresh_delay is not None and self._refresh_delay.running: self._refresh_delay.cancel()
class PrepareTime(JailGame): stage_groups = { 'init': [ "set-initial-status", "prepare-prepare", ], 'destroy': [ "prepare-cancel-delays", "unsend-popups", "destroy", ], 'prepare-start': [ "prepare-freeze", "prepare-register-event-handlers", "prepare-entry", ], 'abort-prepare-interrupted': [ "abort-prepare-interrupted", ], 'prepare-continue': [ "prepare-cancel-countdown", "prepare-undo-prepare-start", "register-event-handlers", "set-start-status", "start-notify", "basegame-entry", ], } def __init__(self, players, **kwargs): super().__init__(players, **kwargs) self._prepare_delay = None self._prepare_countdown = None @stage('prepare-prepare') def stage_prepare_prepare(self): if self._settings.get('prepare', True): indexes = list(player.index for player in self._players) def callback(): self.undo_stages('prepare-start') self.set_stage_group('prepare-continue') self._prepare_delay = Delay(config_manager['prepare_timeout'], callback) def countdown(ticks_left): if (ticks_left > 3 or ticks_left < 1 or config_manager[ 'countdown_{}_material'.format(ticks_left)] == ""): TextMsg(str(ticks_left)).send(*indexes) else: for player in self._players: show_overlay( player, config_manager[ 'countdown_{}_material'.format(ticks_left)], 1) if config_manager['countdown_sound'] is not None: config_manager['countdown_sound'].play(*indexes) self._prepare_countdown = Delay(1.0, countdown, ticks_left - 1) countdown(int(config_manager['prepare_timeout'])) # TODO: Maybe better just tell prisoner and guard instead of # broadcasting? broadcast(strings_module['stage_prepare']) if config_manager['prepare_sound'] is not None: config_manager['prepare_sound'].play(*indexes) self.set_stage_group('prepare-start') else: self.set_stage_group('prepare-continue') def _prepare_event_handler_player_death(self, game_event): player = main_player_manager.get_by_userid( game_event.get_int('userid')) if player in self._players: self.set_stage_group('abort-prepare-interrupted') def _prepare_event_handler_main_player_deleted(self, event_var): player = event_var['player'] if player in self._players: self.set_stage_group('abort-prepare-interrupted') def _prepare_event_handler_player_hurt(self, game_event): player = main_player_manager.get_by_userid( game_event.get_int('userid')) if player in self._players: self.set_stage_group('abort-prepare-interrupted') @stage('prepare-register-event-handlers') def stage_prepare_register_event_handlers(self): event_manager.register_for_event( 'player_death', self._prepare_event_handler_player_death) event_manager.register_for_event( 'player_hurt', self._prepare_event_handler_player_hurt) internal_event_manager.register_event_handler( 'main_player_deleted', self._prepare_event_handler_main_player_deleted) @stage('undo-prepare-register-event-handlers') def stage_undo_prepare_register_event_handlers(self): event_manager.unregister_for_event( 'player_death', self._prepare_event_handler_player_death) event_manager.unregister_for_event( 'player_hurt', self._prepare_event_handler_player_hurt) internal_event_manager.unregister_event_handler( 'main_player_deleted', self._prepare_event_handler_main_player_deleted) @stage('prepare-cancel-delays') def stage_prepare_cancel_delays(self): for delay in (self._prepare_delay, self._prepare_countdown): if delay is not None and delay.running: delay.cancel() @stage('prepare-cancel-countdown') def stage_prepare_cancel_countdown(self): if self._prepare_countdown is not None: self._prepare_countdown.cancel() @stage('prepare-undo-prepare-start') def stage_prepare_undo_prepare_start(self): self.undo_stages('prepare-start') @stage('prepare-entry') def stage_prepare_entry(self): pass def _prepare_freeze_tick_handler(self): for player in self._players: weapon = player.active_weapon if weapon is None: continue weapon.next_attack += 1 weapon.next_secondary_fire_attack += 1 @stage('prepare-freeze') def stage_prepare_freeze(self): on_tick_listener_manager.register_listener( self._prepare_freeze_tick_handler) for player in self._players: player.stuck = True @stage('undo-prepare-freeze') def stage_undo_prepare_freeze(self): on_tick_listener_manager.unregister_listener( self._prepare_freeze_tick_handler) for player in self._players: player.stuck = False weapon = player.active_weapon if weapon is None: continue weapon.next_attack = 0 weapon.next_secondary_fire_attack = 0 @stage('abort-prepare-interrupted') def stage_abort_prepare_interrupted(self): broadcast(strings_module['abort prepare_interrupted']) if config_manager['prepare_sound'] is not None: config_manager['prepare_sound'].stop() self.set_stage_group('destroy')
class SavedPlayer: def __init__(self, player): self._ammo_refill_delay = None self._nade_refill_delay = None self.player = player self.health = 0 self.saved_weapons = [] self.infinite_weapons = [] def _nade_thrown(self, weapon_classname): if self._ammo_refill_delay is None: return if weapon_classname not in self.infinite_weapons: return self._nade_refill_delay = Delay(PROJECTILE_REFILL_DELAY, self.player.give_named_item, weapon_classname) def save_health(self): self.health = self.player.health def save_weapons(self): self.saved_weapons = [] for weapon in self.player.weapons(): weapon_dict = { 'classname': weapon.classname, 'subtype': weapon.get_property_int('m_iSubType'), 'ammo': weapon.ammo if weapon.has_ammo() else None, 'clip': weapon.ammo if weapon.has_clip() else None } self.saved_weapons.append(weapon_dict) self.strip() def save_all(self): self.save_health() self.save_weapons() def strip(self): for weapon in self.player.weapons(): self.player.drop_weapon(weapon.pointer, NULL_VECTOR, NULL_VECTOR) weapon.remove() def restore_health(self): self.player.health = self.health def restore_weapons(self): self.strip() for weapon_dict in self.saved_weapons: weapon = Weapon.create(weapon_dict['classname']) weapon.teleport(self.player.origin, None, None) weapon.spawn() if weapon_dict['clip'] is not None: weapon.clip = weapon_dict['clip'] if weapon_dict['ammo'] is not None: weapon.ammo = weapon_dict['ammo'] def restore_all(self): self.restore_health() self.restore_weapons() def max_ammo(self, weapon_classnames): maxed_weapons = [] for weapon in self.player.weapons(): if weapon.classname not in weapon_classnames: continue if weapon.classname in PROJECTILE_CLASSNAMES: continue weapon_class = weapon_manager[weapon.classname] if not weapon.has_ammo() or weapon_class.maxammo <= 0: continue weapon.ammo = weapon_class.maxammo maxed_weapons.append(weapon) return maxed_weapons def _refill_infinite_ammo(self): self.max_ammo(self.infinite_weapons) self._ammo_refill_delay = Delay(INFINITE_AMMO_REFILL_INTERVAL, self._refill_infinite_ammo) def infinite_on(self): if (self._ammo_refill_delay is not None or self._nade_refill_delay is not None): raise ValueError("Infinite equipment is already turned on") maxed_weapon_classnames = map(lambda weapon: weapon.classname, self.max_ammo(self.infinite_weapons)) self.infinite_weapons = list( filter( lambda classname: classname in maxed_weapon_classnames or classname in PROJECTILE_CLASSNAMES, self.infinite_weapons)) self._ammo_refill_delay = Delay(INFINITE_AMMO_REFILL_INTERVAL, self._refill_infinite_ammo) def infinite_off(self): if self._ammo_refill_delay is None: raise ValueError("Infinite equipment is already turned off") self._ammo_refill_delay.cancel() self._ammo_refill_delay = None if self._nade_refill_delay is not None: if self._nade_refill_delay.running: self._nade_refill_delay.cancel() self._nade_refill_delay = None