def handle(world_session, socket, reader): if len(reader.data) >= 6: # Avoid handling empty cast spell packet. spell_id, target_mask = unpack('<IH', reader.data[:6]) caster = world_session.player_mgr game_object = None if target_mask & SpellTargetMask.CAN_TARGET_TERRAIN != 0 and len(reader.data) >= 18: target_info = Vector.from_bytes(reader.data[-12:]) # Terrain, target is vector elif len(reader.data) == 14: target_info = unpack('<Q', reader.data[-8:])[0] # some object (read guid) game_object = MapManager.get_surrounding_gameobject_by_guid(caster, target_info) else: target_info = caster # Self # TODO: @Flug, gameobject is not resolving on 'elif target_mask & SpellTargetMask.CAN_TARGET_OBJECTS' # Not sure why, I had to force it. if game_object: spell_target = game_object elif target_mask & SpellTargetMask.CAN_TARGET_TERRAIN: spell_target = target_info elif target_mask & SpellTargetMask.UNIT_TARGET_MASK and target_info != caster: spell_target = MapManager.get_surrounding_unit_by_guid(caster, target_info, include_players=True) elif target_mask & SpellTargetMask.ITEM_TARGET_MASK: spell_target = caster.inventory.get_item_info_by_guid(target_info)[3] # (container_slot, container, slot, item) elif target_mask & SpellTargetMask.CAN_TARGET_OBJECTS: # Can also include items so we check for that first spell_target = MapManager.get_surrounding_gameobject_by_guid(caster, target_info) else: spell_target = caster # Assume self cast for now. Invalid target will be resolved later world_session.player_mgr.spell_manager.handle_cast_attempt(spell_id, world_session.player_mgr, spell_target, target_mask) return 0
def handle_channel_end(self, casting_spell): if not casting_spell.is_channeled(): return if self.unit_mgr.get_type() != ObjectTypes.TYPE_PLAYER: return if self.unit_mgr.channel_object: channel_object = MapManager.get_surrounding_gameobject_by_guid( self.unit_mgr, self.unit_mgr.channel_object) if channel_object and \ channel_object.gobject_template.type == GameObjectTypes.TYPE_RITUAL and \ channel_object.ritual_caster is self.unit_mgr: for player in channel_object.ritual_participants: ritual_channel_spell_id = channel_object.gobject_template.data2 player.spell_manager.remove_cast_by_id( ritual_channel_spell_id) MapManager.remove_object(channel_object) self.unit_mgr.set_channel_object(0) self.unit_mgr.set_channel_spell(0) self.unit_mgr.set_dirty() if self.unit_mgr.get_type() != ObjectTypes.TYPE_PLAYER: return data = pack('<I', 0) self.unit_mgr.enqueue_packet( PacketWriter.get_packet(OpCode.MSG_CHANNEL_UPDATE, data))
def handle(world_session, socket, reader): if len( reader.data ) >= 12: # Avoid handling empty quest giver request reward packet. guid, quest_id = unpack('<QI', reader.data[:12]) high_guid = ObjectManager.extract_high_guid(guid) is_item = False quest_giver = None if high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid( world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_ITEM: is_item = True quest_giver = world_session.player_mgr.inventory.get_item_by_guid( guid) if not quest_giver: Logger.error( f'Error in CMSG_QUESTGIVER_REQUEST_REWARD, could not find quest giver with guid: {guid}' ) return 0 if not is_item and world_session.player_mgr.is_enemy_to( quest_giver): return 0 world_session.player_mgr.quest_manager.handle_request_reward( guid, quest_id) return 0
def handle(world_session, socket, reader): if len(reader.data) >= 8: # Avoid handling empty quest giver status packet. quest_giver_guid = unpack('<Q', reader.data[:8])[0] quest_giver = None # NPC if quest_giver_guid & HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid(world_session.player_mgr, quest_giver_guid) # Gameobject elif quest_giver_guid & HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid(world_session.player_mgr, quest_giver_guid) if not quest_giver: return 0 quest_giver_status = QuestGiverStatus.QUEST_GIVER_NONE if world_session.player_mgr: if quest_giver.get_type() == ObjectTypes.TYPE_UNIT: quest_giver_status = world_session.player_mgr.quest_manager.get_dialog_status(quest_giver) elif quest_giver.get_type() == ObjectTypes.TYPE_GAMEOBJECT: # TODO: Proper handling for game object quest_giver_status = QuestGiverStatus.QUEST_GIVER_NONE else: Logger.error(f'Error in CMSG_QUESTGIVER_STATUS_QUERY, quest giver was an unexpected type of: {quest_giver.object_type}') world_session.player_mgr.quest_manager.send_quest_giver_status(quest_giver_guid, quest_giver_status) return 0
def is_quest_complete(self, quest_giver_guid): quest_giver = None high_guid = ObjectManager.extract_high_guid(quest_giver_guid) if high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid(self.owner, quest_giver_guid) elif high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid(self.owner, quest_giver_guid) if not quest_giver: return False if QuestHelpers.is_instant_complete_quest(self.quest): return True if self.db_state.state != QuestState.QUEST_REWARD: return False if quest_giver.get_type_id() == ObjectTypeIds.ID_UNIT and quest_giver.get_type_id() != ObjectTypeIds.ID_PLAYER: involved_relations_list = WorldDatabaseManager.QuestRelationHolder.creature_quest_finisher_get_by_entry(quest_giver.entry) elif quest_giver.get_type_id() == ObjectTypeIds.ID_GAMEOBJECT: involved_relations_list = WorldDatabaseManager.QuestRelationHolder.gameobject_quest_finisher_get_by_entry(quest_giver.entry) else: return False # Return if this quest is finished by this quest giver. return self.quest.entry in {quest_entry[1] for quest_entry in involved_relations_list}
def handle(world_session, socket, reader): if len(reader.data ) >= 8: # Avoid handling empty quest giver status packet. guid = unpack('<Q', reader.data[:8])[0] high_guid = ObjectManager.extract_high_guid(guid) quest_giver = None if high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid( world_session.player_mgr, guid) if not quest_giver: Logger.error( f'Error in CMSG_QUESTGIVER_STATUS_QUERY, could not find quest giver with guid of: {guid}' ) return 0 # Only units are able to provide quest status. if world_session.player_mgr and quest_giver.get_type_id( ) == ObjectTypeIds.ID_UNIT: quest_giver_status = world_session.player_mgr.quest_manager.get_dialog_status( quest_giver) world_session.player_mgr.quest_manager.send_quest_giver_status( guid, quest_giver_status) return 0
def get_target_info(world_session, target_mask, target_bytes): caster = world_session.player_mgr if target_mask & SpellTargetMask.CAN_TARGET_TERRAIN != 0 and len( target_bytes) == 12: target_info = Vector.from_bytes( target_bytes) # Terrain, target is vector. elif len(target_bytes) == 8: target_info = unpack('<Q', target_bytes)[0] # Some object (read guid). else: target_info = caster # Self if target_mask & SpellTargetMask.CAN_TARGET_TERRAIN: return target_info if target_mask & SpellTargetMask.UNIT and target_info != caster: return MapManager.get_surrounding_unit_by_guid( caster, target_info, include_players=True) if target_mask & SpellTargetMask.ITEM_TARGET_MASK and not target_mask & SpellTargetMask.TRADE_ITEM: return caster.inventory.get_item_info_by_guid(target_info)[ 3] # (container_slot, container, slot, item). if target_mask & SpellTargetMask.CAN_TARGET_OBJECTS: # Can also include items, so we check for that first. return MapManager.get_surrounding_gameobject_by_guid( caster, target_info) if target_mask & SpellTargetMask.ITEM_TARGET_MASK and target_mask & SpellTargetMask.TRADE_ITEM: if caster.trade_data and caster.trade_data.other_player and caster.trade_data.other_player.trade_data: return caster.trade_data.other_player.trade_data.get_item_by_slot( target_info) return caster # Assume self cast for now. Invalid target will be resolved later.
def handle(world_session, socket, reader): if len(reader.data ) >= 8: # Avoid handling empty quest giver hello packet. guid = unpack('<Q', reader.data[:8])[0] high_guid = ObjectManager.extract_high_guid(guid) quest_giver = None if high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid( world_session.player_mgr, guid) if not quest_giver: Logger.error( f'Error in CMSG_QUESTGIVER_HELLO, could not find quest giver with guid of: {guid}' ) return 0 if world_session.player_mgr.is_enemy_to(quest_giver): return 0 # TODO: Stop the npc if it's moving # TODO: Remove feign death from player (if it even exists in 0.5.3) # TODO: If the gossip menu is already open, do nothing if quest_giver.is_within_interactable_distance( world_session.player_mgr): world_session.player_mgr.quest_manager.handle_quest_giver_hello( quest_giver, guid) return 0
def handle(world_session, socket, reader): if len( reader.data ) >= 12: # Avoid handling empty quest giver accept quest packet. guid, quest_id = unpack('<QI', reader.data[:12]) high_guid = ObjectManager.extract_high_guid(guid) is_item = False quest_giver = None if high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid( world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_ITEM: is_item = True quest_giver = world_session.player_mgr.inventory.get_item_by_guid( guid) if not quest_giver: Logger.error( f'Error in CMSG_QUESTGIVER_ACCEPT_QUEST, could not find quest giver with guid of: {guid}' ) return 0 elif not is_item and world_session.player_mgr.is_enemy_to( quest_giver): return 0 elif world_session.player_mgr.quest_manager.is_quest_log_full(): world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_QUESTLOG_FULL)) else: world_session.player_mgr.quest_manager.handle_accept_quest( quest_id, guid, shared=False) return 0
def handle(world_session, socket, reader): if len(reader.data ) >= 8: # Avoid handling empty debug AI state packet. guid = unpack('<Q', reader.data[:8])[0] world_object = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid, include_players=True) # If no Unit or Player, try to get a Gameobject. if not world_object: world_object = MapManager.get_surrounding_gameobject_by_guid( world_session.player_mgr, guid) # Still no object with that Guid? Return. if not world_object: return 0 messages = world_object.get_debug_messages() data = pack('<QI', guid, len(messages)) for message in messages: message_bytes = PacketWriter.string_to_bytes( message[:127]) # Max length is 128 (127 + null byte). data += pack(f'<{len(message_bytes)}s', message_bytes) world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_DEBUG_AISTATE, data)) return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data ) >= 8: # Avoid handling empty debug AI state packet. guid = unpack('<Q', reader.data[:8])[0] high_guid: HighGuid = ObjectManager.extract_high_guid(guid) if high_guid == HighGuid.HIGHGUID_UNIT or high_guid == HighGuid.HIGHGUID_PLAYER: world_object = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid, include_players=True) else: world_object = MapManager.get_surrounding_gameobject_by_guid( world_session.player_mgr, guid) # No object with that Guid? Return. if not world_object: return 0 messages: list[str] = world_object.get_debug_messages() data = pack('<QI', guid, len(messages)) for message in messages: message_bytes = PacketWriter.string_to_bytes( message[:127]) # Max length is 128 (127 + null byte). data += pack(f'<{len(message_bytes)}s', message_bytes) world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_DEBUG_AISTATE, data)) return 0
def handle(world_session, socket, reader): if len( reader.data ) >= 12: # Avoid handling empty quest giver complete quest packet. guid, quest_id = unpack('<QI', reader.data[:12]) high_guid = ObjectManager.extract_high_guid(guid) quest_giver = None if high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid( world_session.player_mgr, guid) if not quest_giver: Logger.error( f'Error in CMSG_QUESTGIVER_COMPLETE_QUEST, could not find quest giver with guid of: {guid}' ) return 0 if world_session.player_mgr.is_enemy_to(quest_giver): return 0 world_session.player_mgr.quest_manager.handle_complete_quest( quest_id, guid) return 0
def handle(world_session, socket, reader): if len(reader.data) >= 8: # Avoid handling empty gameobj use packet. guid = unpack('<Q', reader.data[:8])[0] if guid > 0: gobject = MapManager.get_surrounding_gameobject_by_guid(world_session.player_mgr, guid) if gobject: if gobject.gobject_template.type != GameObjectTypes.TYPE_GENERIC: gobject.use(world_session.player_mgr) return 0
def handle_accept_quest(self, quest_id, quest_giver_guid, shared=False): if quest_id in self.active_quests: self.send_cant_take_quest_response(QuestFailedReasons.QUEST_ALREADY_ON) return if quest_id in self.completed_quests: self.send_cant_take_quest_response(QuestFailedReasons.QUEST_ONLY_ONE_TIMED) return quest_item_starter = None if quest_giver_guid: quest_giver = None high_guid = ObjectManager.extract_high_guid(quest_giver_guid) if high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid(self.player_mgr, quest_giver_guid) elif high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid(self.player_mgr, quest_giver_guid) elif high_guid == HighGuid.HIGHGUID_ITEM: quest_giver = self.player_mgr.inventory.get_item_by_guid(quest_giver_guid) quest_item_starter = quest_giver if not quest_giver: return quest = WorldDatabaseManager.QuestTemplateHolder.quest_get_by_entry(quest_id) if not quest: return req_src_item = quest.SrcItemId req_src_item_count = quest.SrcItemCount if req_src_item != 0: # Check if the required source item is the item quest starter, else check if we can add it to the inventory. if not quest_item_starter or quest_item_starter.entry != req_src_item: if not self.player_mgr.inventory.add_item(req_src_item, count=req_src_item_count): return active_quest = self._create_db_quest_status(quest) active_quest.save(is_new=True) self.add_to_quest_log(quest_id, active_quest) self.send_quest_query_response(quest) # If player is in a group and quest has QUEST_FLAGS_PARTY_ACCEPT flag, let other members accept it too. if self.player_mgr.group_manager and not shared: quest_template = WorldDatabaseManager.QuestTemplateHolder.quest_get_by_entry(quest_id) if quest_template and quest_template.QuestFlags & QuestFlags.QUEST_FLAGS_PARTY_ACCEPT: self.share_quest_event(active_quest) # Check if the player already has related items. active_quest.update_required_items_from_inventory() if active_quest.can_complete_quest(): self.complete_quest(active_quest, update_surrounding=False) self.update_surrounding_quest_status()
def handle(world_session, socket, reader): if len(reader.data ) >= 8: # Avoid handling empty quest giver query quest packet. guid, quest_entry = unpack('<QL', reader.data[:12]) high_guid = ObjectManager.extract_high_guid(guid) # NPC if high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, guid) if not quest_giver: return 0 quest_giver_is_related = world_session.player_mgr.quest_manager.check_quest_giver_npc_is_related( quest_giver.entry, quest_entry) if not quest_giver_is_related: return 0 # Gameobject elif high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid( world_session, guid) if not quest_giver: return 0 # Item elif high_guid == HighGuid.HIGHGUID_ITEM: item_info = world_session.player_mgr.inventory.get_item_info_by_guid( guid) if not item_info[3]: return 0 quest_giver = item_info[3].item_template quest_giver_is_related = quest_giver.start_quest == quest_entry if not quest_giver_is_related: return 0 else: Logger.error( f'Error in CMSG_QUESTGIVER_QUERY_QUEST, unknown quest giver type.' ) return 0 quest = WorldDatabaseManager.QuestTemplateHolder.quest_get_by_entry( quest_entry) if not quest: Logger.error( f'Error in CMSG_QUESTGIVER_QUERY_QUEST, could not find quest with an entry of: {quest_entry}' ) return 0 world_session.player_mgr.quest_manager.send_quest_giver_quest_details( quest, guid, True) return 0
def handle(world_session, socket, reader): if len(reader.data) >= 12: # Avoid handling empty gameobject query packet. entry, guid = unpack('<IQ', reader.data[:12]) if guid > 0: gobject_mgr = MapManager.get_surrounding_gameobject_by_guid(world_session.player_mgr, guid) if not gobject_mgr: gobject_spawn, session = WorldDatabaseManager.gameobject_spawn_get_by_guid(guid) if gobject_spawn and gobject_spawn.gameobject.entry == entry: gobject_mgr = GameObjectManager( gobject_template=gobject_spawn.gameobject ) session.close() if gobject_mgr: world_session.enqueue_packet(gobject_mgr.query_details()) return 0
def handle(world_session, socket, reader): # CGPlayer_C::GetQuestReward if len(reader.data) >= 16: # Avoid handling empty quest fiver choose reward packet. guid, quest_id, item_choice = unpack('<Q2I', reader.data[:16]) high_guid = ObjectManager.extract_high_guid(guid) quest_giver = None if high_guid == HighGuid.HIGHGUID_UNIT: quest_giver = MapManager.get_surrounding_unit_by_guid(world_session.player_mgr, guid) elif high_guid == HighGuid.HIGHGUID_GAMEOBJECT: quest_giver = MapManager.get_surrounding_gameobject_by_guid(world_session.player_mgr, guid) if not quest_giver: Logger.error(f'Error in CMSG_QUESTGIVER_COMPLETE_QUEST, could not find quest giver with guid of: {guid}') return 0 if world_session.player_mgr.is_enemy_to(quest_giver): return 0 world_session.player_mgr.quest_manager.handle_choose_reward(guid, quest_id, item_choice) return 0
def get_target_by_type(caster, target, target_type, param1, param2, spell_template): if target_type == ScriptTarget.TARGET_T_PROVIDED_TARGET: return target elif target_type == ScriptTarget.TARGET_T_HOSTILE: if ScriptManager._validate_is_unit(caster): if caster.combat_target: return caster.combat_target elif target_type == ScriptTarget.TARGET_T_HOSTILE_SECOND_AGGRO: if ScriptManager._validate_is_unit(caster): return caster.threat_manager.select_attacking_target(AttackingTarget.ATTACKING_TARGET_TOPAGGRO) elif target_type == ScriptTarget.TARGET_T_HOSTILE_LAST_AGGRO: if ScriptManager._validate_is_unit(caster): return caster.threat_manager.select_attacking_target(AttackingTarget.ATTACKING_TARGET_BOTTOMAGGRO) elif target_type == ScriptTarget.TARGET_T_HOSTILE_RANDOM: if ScriptManager._validate_is_unit(caster): return caster.threat_manager.select_attacking_target(AttackingTarget.ATTACKING_TARGET_RANDOM) elif target_type == ScriptTarget.TARGET_T_HOSTILE_RANDOM_NOT_TOP: if ScriptManager._validate_is_unit(caster): return caster.threat_manager.select_attacking_target(AttackingTarget.ATTACKING_TARGET_RANDOMNOTTOP) elif target_type == ScriptTarget.TARGET_T_OWNER_OR_SELF: # TODO # return source.get_charmer_or_self() pass elif target_type == ScriptTarget.TARGET_T_OWNER: # TODO # return source.get_owner(), what does owner means here? pass elif target_type == ScriptTarget.TARGET_T_NEAREST_CREATURE_WITH_ENTRY: # TODO, entry -> object type identification. # Based on objects high guids. pass elif target_type == ScriptTarget.TARGET_T_RANDOM_CREATURE_WITH_ENTRY: # TODO, entry -> object type identification. # Based on objects high guids. pass elif target_type == ScriptTarget.TARGET_T_CREATURE_WITH_GUID: # TODO, might need to do some guid conversion between low and high? unit_guid: Optional[int] = param1 unit = MapManager.get_surrounding_unit_by_guid(caster, unit_guid, True) return unit if unit and unit.is_alive else None elif target_type == ScriptTarget.TARGET_T_CREATURE_FROM_INSTANCE_DATA: # TODO, instancing. pass elif target_type == ScriptTarget.TARGET_T_NEAREST_GAMEOBJECT_WITH_ENTRY: # TODO, entry -> object type identification. # Based on objects high guids. pass elif target_type == ScriptTarget.TARGET_T_RANDOM_GAMEOBJECT_WITH_ENTRY: # TODO, entry -> object type identification. # Based on objects high guids. pass elif target_type == ScriptTarget.TARGET_T_GAMEOBJECT_WITH_GUID: # TODO, might need to do some guid conversion between low and high? gameobject_guid: Optional[int] = param1 gameobject = MapManager.get_surrounding_gameobject_by_guid(caster, gameobject_guid) return gameobject if gameobject and gameobject.is_spawned else None elif target_type == ScriptTarget.TARGET_T_GAMEOBJECT_FROM_INSTANCE_DATA: # TODO, instancing. pass elif target_type == ScriptTarget.TARGET_T_FRIENDLY: if not ScriptManager._validate_is_unit(caster): return None search_range: Optional[float] = param1 exclude_target: Optional[UnitManager] = param2 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) friendlies = ScriptManager._get_surrounding_units_and_players(caster, search_range=search_range, friends_only=True, exclude_unit=exclude_target) # Did not find any friendlies. if not friendlies: return None # Return 1 randomly picked friendly unit. return choice(friendlies) elif target_type == ScriptTarget.TARGET_T_FRIENDLY_INJURED: if not ScriptManager._validate_is_unit(caster): return None search_range: Optional[float] = param1 hp_percent: Optional[float] = param2 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) if not hp_percent: hp_percent = 50.0 injured_friendlies = ScriptManager._get_injured_friendly_units(caster, radius=search_range, hp_threshold=hp_percent) return injured_friendlies[0] if injured_friendlies else None elif target_type == ScriptTarget.TARGET_T_FRIENDLY_INJURED_EXCEPT: if not ScriptManager._validate_is_unit(caster): return None search_range: Optional[float] = param1 hp_percent: Optional[float] = param2 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) if not hp_percent: hp_percent = 50.0 injured_friendlies = ScriptManager._get_injured_friendly_units(caster, radius=search_range, hp_threshold=hp_percent, exclude_unit=target) return injured_friendlies[0] if injured_friendlies else None elif target_type == ScriptTarget.TARGET_T_FRIENDLY_MISSING_BUFF: search_range: Optional[float] = param1 spell_id: int = param2 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) # Surrounding friendly units. surrounding_units = ScriptManager._get_surrounding_units_and_players(caster, search_range, friends_only=True) # No surrounding units found. if not surrounding_units: return None for friendly_unit in surrounding_units: if not friendly_unit.aura_manager.has_aura_by_spell_id(spell_id): return friendly_unit # No suitable target found. return None elif target_type == ScriptTarget.TARGET_T_FRIENDLY_MISSING_BUFF_EXCEPT: search_range: Optional[float] = param1 spell_id: int = param2 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) # Surrounding friendly units. surrounding_units = ScriptManager._get_surrounding_units_and_players(caster, search_range, friends_only=True, exclude_unit=target) # No surrounding units found. if not surrounding_units: return None for friendly_unit in surrounding_units: if not friendly_unit.aura_manager.has_aura_by_spell_id(spell_id): return friendly_unit # No suitable target found. return None elif target_type == ScriptTarget.TARGET_T_FRIENDLY_CC: pass elif target_type == ScriptTarget.TARGET_T_MAP_EVENT_SOURCE: pass elif target_type == ScriptTarget.TARGET_T_MAP_EVENT_TARGET: pass elif target_type == ScriptTarget.TARGET_T_MAP_EVENT_EXTRA_TARGET: pass elif target_type == ScriptTarget.TARGET_T_NEAREST_PLAYER: search_range: Optional[float] = param1 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) # Surrounding units. surrounding_units = ScriptManager._get_surrounding_units_and_players(caster, search_range) # No surrounding units found. if not surrounding_units: return None # Filter players. players = [unit for unit in surrounding_units if unit.get_type_id() == ObjectTypeIds.ID_PLAYER] # No players found. if len(players) == 0: return None # Sort by distance. players.sort(key=lambda player: caster.location.distance(player.location)) return players[0] elif target_type == ScriptTarget.TARGET_T_NEAREST_HOSTILE_PLAYER: search_range: Optional[float] = param1 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) # Surrounding enemy units. surrounding_units = ScriptManager._get_surrounding_units_and_players(caster, search_range, enemies_only=True) # No surrounding units found. if not surrounding_units: return None # Filter enemy players. enemy_players = [unit for unit in surrounding_units if unit.get_type_id() == ObjectTypeIds.ID_PLAYER] # No enemy players found. if len(enemy_players) == 0: return None # Sort by distance. enemy_players.sort(key=lambda player: caster.location.distance(player.location)) return enemy_players[0] elif target_type == ScriptTarget.TARGET_T_NEAREST_FRIENDLY_PLAYER: search_range: Optional[float] = param1 # Set range if not provided. search_range = ScriptManager._get_search_range(search_range, spell_template) # Surrounding friendly units. surrounding_units = ScriptManager._get_surrounding_units_and_players(caster, search_range, friends_only=True) # No surrounding units found. if not surrounding_units: return None # Filter friendly players. friendly_players = [unit for unit in surrounding_units if unit.get_type_id() == ObjectTypeIds.ID_PLAYER] # No enemy players found. if len(friendly_players) == 0: return None # Sort by distance. friendly_players.sort(key=lambda player: caster.location.distance(player.location)) return friendly_players[0]