class PlayerManager(UnitManager): def __init__( self, player=None, session=None, num_inv_slots=0x89, # Paperdoll + Bag slots + Bag space player_bytes=0, # skin, face, hair style, hair color xp=0, next_level_xp=0, player_bytes_2=0, # player flags, facial hair, bank slots, 0 talent_points=0, skill_points=0, block_percentage=0, dodge_percentage=0, parry_percentage=0, base_mana=0, sheath_state=0, combo_points=0, chat_flags=0, is_online=False, **kwargs): super().__init__(**kwargs) self.update_packet_factory = UpdatePacketFactory([ ObjectTypes.TYPE_OBJECT, ObjectTypes.TYPE_UNIT, ObjectTypes.TYPE_PLAYER ]) self.session = session self.flagged_for_update = False self.player = player self.is_online = is_online self.num_inv_slots = num_inv_slots self.xp = xp self.next_level_xp = next_level_xp self.talent_points = talent_points self.skill_points = skill_points self.block_percentage = block_percentage self.dodge_percentage = dodge_percentage self.parry_percentage = parry_percentage self.base_mana = base_mana self.sheath_state = sheath_state self.combo_points = combo_points self.chat_flags = chat_flags self.group_status = WhoPartyStatuses.WHO_PARTY_STATUS_NOT_IN_PARTY self.race_mask = 0 self.class_mask = 0 self.spells = [] self.skills = [] if self.player: self.set_player_variables() self.guid = self.player.guid self.inventory = InventoryManager(self) self.level = self.player.level self.object_type.append(ObjectTypes.TYPE_PLAYER) self.bytes_0 = unpack( '<I', pack('<4B', self.player.race, self.player.class_, self.player.gender, self.power_type))[0] self.bytes_1 = unpack( '<I', pack('<4B', self.stand_state, 0, self.shapeshift_form, self.sheath_state))[0] self.bytes_2 = unpack('<I', pack('<4B', self.combo_points, 0, 0, 0))[0] self.player_bytes = unpack( '<I', pack('<4B', self.player.skin, self.player.face, self.player.hairstyle, self.player.haircolour))[0] self.player_bytes_2 = unpack( '>I', pack('>4B', self.player.extra_flags, self.player.bankslots, self.player.facialhair, 0))[0] self.map_ = self.player.map self.zone = self.player.zone self.location.x = self.player.position_x self.location.y = self.player.position_y self.location.z = self.player.position_z self.location.o = self.player.orientation self.is_gm = self.session.account_mgr.account.gmlevel > 0 if self.is_gm: self.set_gm() # test self.xp = 0 self.next_level_xp = 200 self.health = 1 self.max_health = 1 self.max_power_1 = 100 self.power_1 = 100 self.max_power_2 = 1000 self.power_2 = 0 self.max_power_3 = 100 self.power_4 = 100 self.max_power_4 = 100 self.power_4 = 100 self.guild_manager = GuildManager() def get_native_display_id(self, is_male, race_data=None): if not race_data: race_data = DbcDatabaseManager.chr_races_get_by_race( self.player.race) return race_data.MaleDisplayId if is_male else race_data.FemaleDisplayId def set_player_variables(self): race = DbcDatabaseManager.chr_races_get_by_race(self.player.race) self.faction = race.FactionID is_male = self.player.gender == Genders.GENDER_MALE self.display_id = self.get_native_display_id(is_male, race) if self.player.class_ == Classes.CLASS_WARRIOR: self.power_type = PowerTypes.TYPE_RAGE elif self.player.class_ == Classes.CLASS_HUNTER: self.power_type = PowerTypes.TYPE_FOCUS elif self.player.class_ == Classes.CLASS_ROGUE: self.power_type = PowerTypes.TYPE_ENERGY else: self.power_type = PowerTypes.TYPE_MANA if self.player.race == Races.RACE_HUMAN: self.bounding_radius = 0.306 if is_male else 0.208 elif self.player.race == Races.RACE_ORC: self.bounding_radius = 0.372 if is_male else 0.236 elif self.player.race == Races.RACE_DWARF: self.bounding_radius = 0.347 elif self.player.race == Races.RACE_NIGHT_ELF: self.bounding_radius = 0.389 if is_male else 0.306 elif self.player.race == Races.RACE_UNDEAD: self.bounding_radius = 0.383 elif self.player.race == Races.RACE_TAUREN: self.bounding_radius = 0.9747 if is_male else 0.8725 self.scale = 1.3 if is_male else 1.25 elif self.player.race == Races.RACE_GNOME: self.bounding_radius = 0.3519 elif self.player.race == Races.RACE_TROLL: self.bounding_radius = 0.306 self.race_mask = 1 << self.player.race self.class_mask = 1 << self.player.class_ def set_gm(self, on=True): self.player.extra_flags |= PlayerFlags.PLAYER_FLAGS_GM self.faction = 35 # Friendly to all self.chat_flags = ChatFlags.CHAT_TAG_GM def complete_login(self): self.is_online = True GridManager.update_object(self) self.update_surrounding() def logout(self): self.session.save_character() GridManager.remove_object(self) self.session.player_mgr = None self.session = None self.is_online = False def get_tutorial_packet(self): # Not handling any tutorial (are them even implemented?) return PacketWriter.get_packet(OpCode.SMSG_TUTORIAL_FLAGS, pack('<5I', 0, 0, 0, 0, 0)) def get_initial_spells(self): data = pack('<BH', 0, len(self.spells)) for spell in self.spells: data += pack('<2H', spell.ID, 0) data += pack('<H', 0) return PacketWriter.get_packet(OpCode.SMSG_INITIAL_SPELLS, data) def get_action_buttons(self): data = b'' for x in range(0, MAX_ACTION_BUTTONS): data += pack('<I', 0) # TODO: Handle action buttons later return PacketWriter.get_packet(OpCode.SMSG_ACTION_BUTTONS, data) def update_surrounding(self, destroy=False): if destroy: grid = GRIDS[self.current_grid] for guid, player in list(grid.players.items()): if player.guid != self.guid: self.session.request.sendall(player.get_destroy_packet()) update_packet = UpdatePacketFactory.compress_if_needed( PacketWriter.get_packet( OpCode.SMSG_UPDATE_OBJECT, self.get_update_packet(update_type=UpdateTypes.UPDATE_FULL, is_self=False))) GridManager.send_surrounding(update_packet, self, include_self=False) GridManager.send_surrounding(NameQueryHandler.get_query_details( self.player), self, include_self=True) for guid, player in list( GridManager.get_surrounding_players(self).items()): if self.guid != guid: self.session.request.sendall( PacketWriter.get_packet( OpCode.SMSG_UPDATE_OBJECT, player.get_update_packet( update_type=UpdateTypes.UPDATE_FULL, is_self=False))) self.session.request.sendall( NameQueryHandler.get_query_details(player.player)) def sync_player(self): if self.player and self.player.guid == self.guid: self.player.level = self.level self.player.xp = self.xp self.player.talent_points = self.talent_points self.player.skillpoints = self.skill_points self.player.position_x = self.location.x self.player.position_y = self.location.y self.player.position_z = self.location.z self.player.map = self.map_ self.player.orientation = self.location.o self.player.zone = self.zone self.player.health = self.health self.player.power1 = self.power_1 self.player.power2 = self.power_2 self.player.power3 = self.power_3 self.player.power4 = self.power_4 def teleport(self, map_, location): GridManager.send_surrounding(self.get_destroy_packet(), self, include_self=False) # Same map and not inside instance if self.map_ == map_ and self.map_ <= 1: data = pack( '<Q9fI', self.transport_id, self.transport.x, self.transport.y, self.transport.z, self.transport.o, location.x, location.y, location.z, location.o, 0, # ? 0 # MovementFlags ) self.session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_MOVE_WORLDPORT_ACK, data)) # Loading screen else: data = pack('<I', map_) self.session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_TRANSFER_PENDING, data)) data = pack('<B4f', map_, location.x, location.y, location.z, location.o) self.session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_NEW_WORLD, data)) self.map_ = map_ self.location.x = location.x self.location.y = location.y self.location.z = location.z self.location.o = location.o def mount(self, mount_display_id): if mount_display_id > 0 and self.mount_display_id == 0 and \ DbcDatabaseManager.creature_display_info_get_by_model_id(mount_display_id): self.mount_display_id = mount_display_id self.unit_flags |= UnitFlags.UNIT_FLAG_MOUNTED self.flagged_for_update = True def unmount(self): if self.mount_display_id > 0: self.mount_display_id = 0 self.unit_flags &= ~UnitFlags.UNIT_FLAG_MOUNTED self.flagged_for_update = True def set_weapon_mode(self, weapon_mode): # TODO: Not working if weapon_mode == 0: self.unit_flags |= UnitFlags.UNIT_FLAG_SHEATHE elif weapon_mode == 1: self.unit_flags &= ~UnitFlags.UNIT_FLAG_SHEATHE elif weapon_mode == 2: self.unit_flags &= ~UnitFlags.UNIT_FLAG_SHEATHE self.flagged_for_update = True def morph(self, display_id): if display_id > 0 and \ DbcDatabaseManager.creature_display_info_get_by_model_id(display_id): self.display_id = display_id self.flagged_for_update = True def demorph(self): self.morph(self.get_native_display_id(self.player.gender == 0)) # TODO Maybe merge all speed changes in one method def change_speed(self, speed=0): if speed <= 0: speed = 7.0 # Default run speed elif speed >= 56: speed = 56 # Max speed without glitches self.running_speed = speed data = pack('<f', speed) self.session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_FORCE_SPEED_CHANGE, data)) def change_swim_speed(self, swim_speed=0): if swim_speed <= 0: swim_speed = 4.7222223 # Default swim speed elif swim_speed >= 56: swim_speed = 56 # Max possible swim speed self.swim_speed = swim_speed data = pack('<f', swim_speed) self.session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_FORCE_SWIM_SPEED_CHANGE, data)) def change_walk_speed(self, walk_speed=0): if walk_speed <= 0: walk_speed = 2.5 # Default walk speed elif walk_speed >= 56: walk_speed = 56 # Max speed without glitches self.swim_speed = walk_speed data = pack('<f', walk_speed) self.session.request.sendall( PacketWriter.get_packet(OpCode.MSG_MOVE_SET_WALK_SPEED, data)) def change_turn_speed(self, turn_speed=0): if turn_speed <= 0: turn_speed = pi # Default turn rate speed self.turn_rate = turn_speed data = pack('<f', turn_speed) # TODO NOT WORKING self.session.request.sendall( PacketWriter.get_packet(OpCode.MSG_MOVE_SET_TURN_RATE_CHEAT, data)) def load_skills(self): for skill in WorldDatabaseManager.player_create_skill_get( self.player.race, self.player.class_): skill_to_add = DbcDatabaseManager.skill_get_by_id(skill.Skill) self.skills.append(skill_to_add) def load_spells(self): for spell in WorldDatabaseManager.player_create_spell_get( self.player.race, self.player.class_): spell_to_load = DbcDatabaseManager.spell_get_by_id(spell.Spell) if spell_to_load: self.spells.append(spell_to_load) def send_equip_error(self, error, item_1=None, item_2=None): data = pack('<B', error) if error != InventoryError.EQUIP_ERR_OK: if error == InventoryError.EQUIP_ERR_CANT_EQUIP_LEVEL_I: data += pack( '<I', item_1.item_template.required_level if item_1 else 0) data += pack('<2QB', item_1.guid if item_1 else self.guid, item_2.guid if item_2 else self.guid, 0) self.session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_INVENTORY_CHANGE_FAILURE, data)) # TODO: UPDATE_PARTIAL is not being used anywhere (it's implemented but not sure if it works correctly). # override def get_update_packet(self, update_type=UpdateTypes.UPDATE_FULL, is_self=True): self.inventory.send_inventory_update(self.session, is_self) self.bytes_1 = unpack( '<I', pack('<4B', self.stand_state, 0, self.shapeshift_form, self.sheath_state))[0] self.bytes_2 = unpack('<I', pack('<4B', self.combo_points, 0, 0, 0))[0] self.player_bytes_2 = unpack( '<I', pack('<4B', self.player.extra_flags, self.player.facialhair, self.player.bankslots, 0))[0] # Object fields self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_GUID, self.player.guid, 'Q') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_TYPE, self.get_object_type_value(), 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_ENTRY, self.entry, 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_SCALE_X, self.scale, 'f') # Unit fields self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_CHANNEL_SPELL, self.channel_spell, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_CHANNEL_OBJECT, self.channel_object, 'Q') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_HEALTH, self.health, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_POWER1, self.power_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_POWER2, self.power_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_POWER3, self.power_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_POWER4, self.power_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_MAXHEALTH, self.max_health, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_MAXPOWER1, self.max_power_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_MAXPOWER2, self.max_power_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_MAXPOWER3, self.max_power_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_MAXPOWER4, self.max_power_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_LEVEL, self.level, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_FACTIONTEMPLATE, self.faction, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BYTES_0, self.bytes_0, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_STAT0, self.stat_0, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_STAT1, self.stat_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_STAT2, self.stat_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_STAT3, self.stat_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_STAT4, self.stat_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASESTAT0, self.base_stat_0, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASESTAT1, self.base_stat_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASESTAT2, self.base_stat_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASESTAT3, self.base_stat_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASESTAT4, self.base_stat_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_FLAGS, self.unit_flags, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_COINAGE, self.coinage, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASEATTACKTIME, self.base_attack_time, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASEATTACKTIME + 1, self.offhand_attack_time, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES, self.resistance_0, 'q') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 1, self.resistance_1, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 2, self.resistance_2, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 3, self.resistance_3, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 4, self.resistance_4, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 5, self.resistance_5, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BOUNDINGRADIUS, self.bounding_radius, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_COMBATREACH, self.combat_reach, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_DISPLAYID, self.display_id, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_MOUNTDISPLAYID, self.mount_display_id, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE, self.resistance_buff_mods_positive_0, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 1, self.resistance_buff_mods_positive_1, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 2, self.resistance_buff_mods_positive_2, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 3, self.resistance_buff_mods_positive_3, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 4, self.resistance_buff_mods_positive_4, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 5, self.resistance_buff_mods_positive_5, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE, self.resistance_buff_mods_negative_0, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 1, self.resistance_buff_mods_negative_1, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 2, self.resistance_buff_mods_negative_2, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 3, self.resistance_buff_mods_negative_3, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 4, self.resistance_buff_mods_negative_4, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 5, self.resistance_buff_mods_negative_5, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BYTES_1, self.bytes_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_MOD_CAST_SPEED, self.mod_cast_speed, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_DYNAMIC_FLAGS, self.dynamic_flags, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_DAMAGE, self.damage, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BYTES_2, self.bytes_2, 'I') # Player fields self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_FIELD_NUM_INV_SLOTS, self.num_inv_slots, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_BYTES, self.player_bytes, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_XP, self.xp, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_NEXT_LEVEL_XP, self.next_level_xp, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_BYTES_2, self.player_bytes_2, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_CHARACTER_POINTS1, self.talent_points, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_CHARACTER_POINTS2, self.skill_points, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_BLOCK_PERCENTAGE, self.block_percentage, 'f') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_DODGE_PERCENTAGE, self.dodge_percentage, 'f') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_PARRY_PERCENTAGE, self.parry_percentage, 'f') self.update_packet_factory.update( self.update_packet_factory.player_values, self.update_packet_factory.updated_player_fields, PlayerFields.PLAYER_BASE_MANA, self.base_mana, 'I') self.inventory.build_update(self.update_packet_factory) packet = b'' if update_type == UpdateTypes.UPDATE_FULL: packet += self.create_update_packet(is_self) else: packet += self.create_partial_update_packet( self.update_packet_factory) update_packet = packet + self.update_packet_factory.build_packet() return update_packet # override def update(self): now = time.time() if now > self.last_tick > 0: elapsed = now - self.last_tick self.player.totaltime += elapsed self.player.leveltime += elapsed self.last_tick = now if self.flagged_for_update: self.session.request.sendall( PacketWriter.get_packet( OpCode.SMSG_UPDATE_OBJECT, self.get_update_packet(update_type=UpdateTypes.UPDATE_FULL, is_self=True))) GridManager.send_surrounding(PacketWriter.get_packet( OpCode.SMSG_UPDATE_OBJECT, self.get_update_packet(update_type=UpdateTypes.UPDATE_FULL, is_self=False)), self, include_self=False) GridManager.update_object(self) self.flagged_for_update = False # override def get_type(self): return ObjectTypes.TYPE_PLAYER # override def get_type_id(self): return ObjectTypeIds.TYPEID_PLAYER
class PlayerManager(UnitManager): def __init__( self, player=None, num_inv_slots=0x89, # Paperdoll + Bag slots + Bag space player_bytes=0, # skin, face, hair style, hair color xp=0, next_level_xp=0, player_bytes_2=0, # player flags, facial hair, bank slots, 0 talent_points=0, skill_points=0, block_percentage=0, dodge_percentage=0, parry_percentage=0, base_mana=0, sheath_state=0, combo_points=0, is_online=False, **kwargs): super().__init__(**kwargs) self.update_packet_factory = UpdatePacketFactory([ ObjectTypes.TYPE_OBJECT.value, ObjectTypes.TYPE_UNIT.value, ObjectTypes.TYPE_PLAYER.value ]) self.player = player self.is_online = is_online self.num_inv_slots = num_inv_slots self.xp = xp self.next_level_xp = next_level_xp self.talent_points = talent_points self.skill_points = skill_points self.block_percentage = block_percentage self.dodge_percentage = dodge_percentage self.parry_percentage = parry_percentage self.base_mana = base_mana self.sheath_state = sheath_state self.combo_points = combo_points if player: self.guid = player.guid self.level = player.level self.object_type.append(ObjectTypes.TYPE_PLAYER) self.bytes_0 = unpack( '<I', pack('<4B', player.race, player.class_, player.gender, 1))[0] # power type, handle later self.bytes_1 = unpack( '<I', pack('<4B', self.stand_state, 0, self.shapeshift_form, self.sheath_state))[0] self.bytes_2 = unpack('<I', pack('<4B', self.combo_points, 0, 0, 0))[0] self.player_bytes = unpack( '<I', pack('<4B', player.skin, player.face, player.hairstyle, player.haircolour))[0] self.player_bytes_2 = unpack( '<I', pack('<4B', player.extra_flags, player.bankslots, player.facialhair, 0))[0] self.map_ = player.map self.zone = player.zone self.location.x = player.position_x self.location.y = player.position_y self.location.z = player.position_z self.orientation = player.orientation # test self.health = 1 self.max_health = 1 self.display_id = 278 self.movement_flags = 0x08000000 def complete_login(self): self.is_online = True def logout(self): self.is_online = False self._sync_player() def get_tutorial_packet(self): # Not handling any tutorial (are them even implemented?) return PacketWriter.get_packet(OpCode.SMSG_TUTORIAL_FLAGS, pack('<8I', 0, 0, 0, 0, 0, 0, 0, 0)) def get_initial_spells(self): return PacketWriter.get_packet(OpCode.SMSG_INITIAL_SPELLS, pack('<BHHHH', 0, 1, 133, 1, 0)) # TODO Test with spell 133 def get_query_details(self): name_bytes = PacketWriter.string_to_bytes(self.player.name) player_data = pack('<Q%usIII' % len(name_bytes), self.player.guid, name_bytes, self.player.race, self.player.gender, self.player.class_) return PacketWriter.get_packet(OpCode.SMSG_NAME_QUERY_RESPONSE, player_data) def get_update_packet(self): self._sync_player() # Object fields self.update_packet_factory.update( self.update_packet_factory.object_values, ObjectFields.OBJECT_FIELD_GUID.value, self.player.guid, 'Q') self.update_packet_factory.update( self.update_packet_factory.object_values, ObjectFields.OBJECT_FIELD_TYPE.value, self.get_object_type_value(), 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, ObjectFields.OBJECT_FIELD_ENTRY.value, self.entry, 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, ObjectFields.OBJECT_FIELD_SCALE_X.value, self.scale, 'f') # Unit fields self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_CHANNEL_SPELL.value, self.channel_spell, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_CHANNEL_OBJECT.value, self.channel_object, 'Q') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_HEALTH.value, self.health, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_POWER1.value, self.power_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_POWER2.value, self.power_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_POWER3.value, self.power_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_POWER4.value, self.power_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_MAXHEALTH.value, self.max_health, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_MAXPOWER1.value, self.max_power_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_MAXPOWER2.value, self.max_power_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_MAXPOWER3.value, self.max_power_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_MAXPOWER4.value, self.max_power_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_LEVEL.value, self.level, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_FACTIONTEMPLATE.value, self.faction, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BYTES_0.value, self.bytes_0, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_STAT0.value, self.stat_0, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_STAT1.value, self.stat_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_STAT2.value, self.stat_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_STAT3.value, self.stat_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_STAT4.value, self.stat_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BASESTAT0.value, self.base_stat_0, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BASESTAT1.value, self.base_stat_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BASESTAT2.value, self.base_stat_2, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BASESTAT3.value, self.base_stat_3, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BASESTAT4.value, self.base_stat_4, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_FLAGS.value, self.flags, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_COINAGE.value, self.coinage, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BASEATTACKTIME.value, self.base_attack_time, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BASEATTACKTIME.value + 1, self.offhand_attack_time, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCES.value, self.resistance_0, 'q') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCES.value + 1, self.resistance_1, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCES.value + 2, self.resistance_2, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCES.value + 3, self.resistance_3, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCES.value + 4, self.resistance_4, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCES.value + 5, self.resistance_5, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BOUNDINGRADIUS.value, self.bounding_radius, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_COMBATREACH.value, self.combat_reach, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_DISPLAYID.value, self.display_id, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_MOUNTDISPLAYID.value, self.mount_display_id, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE.value, self.resistance_buff_mods_positive_0, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE.value + 1, self.resistance_buff_mods_positive_1, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE.value + 2, self.resistance_buff_mods_positive_2, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE.value + 3, self.resistance_buff_mods_positive_3, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE.value + 4, self.resistance_buff_mods_positive_4, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE.value + 5, self.resistance_buff_mods_positive_5, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE.value, self.resistance_buff_mods_negative_0, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE.value + 1, self.resistance_buff_mods_negative_1, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE.value + 2, self.resistance_buff_mods_negative_2, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE.value + 3, self.resistance_buff_mods_negative_3, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE.value + 4, self.resistance_buff_mods_negative_4, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE.value + 5, self.resistance_buff_mods_negative_5, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BYTES_1.value, self.bytes_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_MOD_CAST_SPEED.value, self.mod_cast_speed, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_DYNAMIC_FLAGS.value, self.dynamic_flags, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_DAMAGE.value, self.damage, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, UnitFields.UNIT_FIELD_BYTES_2.value, self.bytes_2, 'I') # Player fields self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_FIELD_NUM_INV_SLOTS.value, self.num_inv_slots, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_BYTES.value, self.player_bytes, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_XP.value, self.xp, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_NEXT_LEVEL_XP.value, self.next_level_xp, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_BYTES_2.value, self.player_bytes_2, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_CHARACTER_POINTS1.value, self.talent_points, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_CHARACTER_POINTS2.value, self.skill_points, 'I') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_BLOCK_PERCENTAGE.value, self.block_percentage, 'f') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_DODGE_PERCENTAGE.value, self.dodge_percentage, 'f') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_PARRY_PERCENTAGE.value, self.parry_percentage, 'f') self.update_packet_factory.update( self.update_packet_factory.player_values, PlayerFields.PLAYER_BASE_MANA.value, self.base_mana, 'I') return self.update_packet_factory.build_packet() def _sync_player(self): if self.player and self.player.guid == self.guid: self.player.level = self.level self.player.xp = self.xp self.player.talent_points = self.talent_points self.player.skillpoints = self.skill_points self.player.position_x = self.location.x self.player.position_y = self.location.y self.player.position_z = self.location.z self.player.map = self.map_ self.player.orientation = self.orientation self.player.zone = self.zone self.player.health = self.health self.player.power1 = self.power_1 self.player.power2 = self.power_2 self.player.power3 = self.power_3 self.player.power4 = self.power_4
class CreatureManager(UnitManager): def __init__(self, creature_template, creature_instance=None, **kwargs): super().__init__(**kwargs) self.update_packet_factory = UpdatePacketFactory( [ObjectTypes.TYPE_OBJECT, ObjectTypes.TYPE_UNIT]) self.creature_template = creature_template self.creature_instance = creature_instance self.guid = (creature_instance.spawn_id if creature_instance else 0) | HighGuid.HIGHGUID_UNIT if self.creature_template: self.entry = self.creature_template.entry self.scale = self.creature_template.scale if self.creature_template.scale > 0 else 1 self.max_health = self.creature_template.health_max self.level = randrange(self.creature_template.level_min, self.creature_template.level_max + 1) self.resistance_0 = self.creature_template.armor self.resistance_1 = self.creature_template.holy_res self.resistance_2 = self.creature_template.fire_res self.resistance_3 = self.creature_template.nature_res self.resistance_4 = self.creature_template.frost_res self.resistance_5 = self.creature_template.shadow_res display_id_list = list( filter((0).__ne__, [ self.creature_template.display_id1, self.creature_template.display_id2, self.creature_template.display_id3, self.creature_template.display_id4 ])) self.display_id = choice( display_id_list) if len(display_id_list) > 0 else 4 # 4 = cube self.npc_flags = self.creature_template.npc_flags self.mod_cast_speed = 1.0 self.base_attack_time = self.creature_template.base_attack_time self.unit_flags = self.creature_template.unit_flags self.faction = self.creature_template.faction if 0 < self.creature_template.rank < 4: self.unit_flags = self.unit_flags | UnitFlags.UNIT_FLAG_PLUS_MOB self.model_info_loaded = False if self.creature_instance: self.health = int((self.creature_instance.health_percent / 100) * self.max_health) self.map_ = self.creature_instance.map self.location.x = self.creature_instance.position_x self.location.y = self.creature_instance.position_y self.location.z = self.creature_instance.position_z self.location.o = self.creature_instance.orientation self.object_type.append(ObjectTypes.TYPE_UNIT) def load(self): GridManager.add_or_get(self, True) def send_inventory_list(self, world_session): vendor_data, session = WorldDatabaseManager.creature_get_vendor_data( self.entry) item_count = len(vendor_data) if vendor_data else 0 data = pack('<QB', self.guid, item_count) if item_count == 0: data += pack('<B', 0) else: for vendor_data_entry in vendor_data: data += pack( '<7I', 1, # mui vendor_data_entry.item, vendor_data_entry.item_template.display_id, 0xFFFFFFFF if vendor_data_entry.maxcount <= 0 else vendor_data_entry.maxcount, vendor_data_entry.item_template.buy_price, 0, # durability 0, # stack count ) world_session.request.sendall( ItemManager(item_template=vendor_data_entry.item_template). query_details()) session.close() world_session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_LIST_INVENTORY, data)) # override def get_update_packet(self, update_type=UpdateTypes.UPDATE_FULL, is_self=True): if self.creature_template and self.creature_instance: if not self.model_info_loaded: creature_model_info = WorldDatabaseManager.creature_get_model_info( self.display_id) if creature_model_info: self.bounding_radius = creature_model_info.bounding_radius self.combat_reach = creature_model_info.combat_reach self.model_info_loaded = True self.bytes_1 = unpack( '<I', pack('<4B', self.stand_state, self.npc_flags, 0, 0))[0] self.damage = int(self.creature_template.dmg_max) # temp # Object fields self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_GUID, self.guid, 'Q') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_TYPE, self.get_object_type_value(), 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_ENTRY, self.entry, 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_SCALE_X, self.scale, 'f') # Unit fields self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_CHANNEL_SPELL, self.channel_spell, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_CHANNEL_OBJECT, self.channel_object, 'Q') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_HEALTH, self.health, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_MAXHEALTH, self.max_health, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_LEVEL, self.level, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_FACTIONTEMPLATE, self.faction, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_FLAGS, self.unit_flags, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_COINAGE, self.coinage, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASEATTACKTIME, self.base_attack_time, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BASEATTACKTIME + 1, 0, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES, self.resistance_0, 'q') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 1, self.resistance_1, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 2, self.resistance_2, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 3, self.resistance_3, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 4, self.resistance_4, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_RESISTANCES + 5, self.resistance_5, 'i') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BOUNDINGRADIUS, self.bounding_radius, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_COMBATREACH, self.combat_reach, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_DISPLAYID, self.display_id, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_BYTES_1, self.bytes_1, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_MOD_CAST_SPEED, self.mod_cast_speed, 'f') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_DYNAMIC_FLAGS, self.dynamic_flags, 'I') self.update_packet_factory.update( self.update_packet_factory.unit_values, self.update_packet_factory.updated_unit_fields, UnitFields.UNIT_FIELD_DAMAGE, self.damage, 'I') packet = b'' if update_type == UpdateTypes.UPDATE_FULL: packet += self.create_update_packet(is_self) else: packet += self.create_partial_update_packet( self.update_packet_factory) update_packet = packet + self.update_packet_factory.build_packet() return update_packet def query_details(self): name_bytes = PacketWriter.string_to_bytes(self.creature_template.name) subname_bytes = PacketWriter.string_to_bytes( self.creature_template.subname) data = pack('<I%ussss%us3I' % (len(name_bytes), len(subname_bytes)), self.entry, name_bytes, b'\x00', b'\x00', b'\x00', subname_bytes, self.creature_template.type_flags, self.creature_template.type, self.creature_template.beast_family) return PacketWriter.get_packet(OpCode.SMSG_CREATURE_QUERY_RESPONSE, data) # override def get_type(self): return ObjectTypes.TYPE_UNIT # override def get_type_id(self): return ObjectTypeIds.ID_UNIT
class GameObjectManager(ObjectManager): def __init__(self, gobject_template, gobject_instance=None, **kwargs): super().__init__(**kwargs) self.update_packet_factory = UpdatePacketFactory( [ObjectTypes.TYPE_OBJECT, ObjectTypes.TYPE_GAMEOBJECT]) self.gobject_template = gobject_template self.gobject_instance = gobject_instance self.guid = (gobject_instance.spawn_id if gobject_instance else 0) | HighGuid.HIGHGUID_GAMEOBJECT if self.gobject_template: self.display_id = self.gobject_template.display_id if gobject_instance: self.state = self.gobject_instance.spawn_state self.location.x = self.gobject_instance.spawn_positionX self.location.y = self.gobject_instance.spawn_positionY self.location.z = self.gobject_instance.spawn_positionZ self.location.o = self.gobject_instance.spawn_orientation self.map_ = self.gobject_instance.spawn_map self.scale = self.gobject_template.scale self.object_type.append(ObjectTypes.TYPE_GAMEOBJECT) def load(self): GridManager.add_or_get(self, True) def use(self, player): if self.gobject_template.type == GameObjectTypes.TYPE_DOOR or \ self.gobject_template.type == GameObjectTypes.TYPE_BUTTON: # TODO: Check locks for doors if self.state == GameObjectStates.GO_STATE_READY: self.state = GameObjectStates.GO_STATE_ACTIVE # TODO: Trigger sripts / events on cooldown restart self.send_update_surrounding() elif self.gobject_template.type == GameObjectTypes.TYPE_CAMERA: cinematic_id = self.gobject_template.data2 if DbcDatabaseManager.cinematic_sequences_get_by_id(cinematic_id): data = pack('<I', cinematic_id) player.session.request.sendall( PacketWriter.get_packet(OpCode.SMSG_TRIGGER_CINEMATIC, data)) elif self.gobject_template.type == GameObjectTypes.TYPE_CHAIR: slots = self.gobject_template.data1 height = self.gobject_template.data2 lowest_distance = 90.0 x_lowest = self.location.x y_lowest = self.location.y if slots > 0: orthogonal_orientation = self.location.o + pi * 0.5 for x in range(0, slots): relative_distance = (self.scale * x) - (self.scale * (slots - 1) / 2.0) x_i = self.location.x + relative_distance * cos( orthogonal_orientation) y_i = self.location.y + relative_distance * sin( orthogonal_orientation) player_slot_distance = player.location.distance( Vector(x_i, y_i, player.location.z)) if player_slot_distance <= lowest_distance: lowest_distance = player_slot_distance x_lowest = x_i y_lowest = y_i player.teleport( player.map_, Vector(x_lowest, y_lowest, self.location.z, self.location.o)) player.stand_state = StandState.UNIT_SITTINGCHAIRLOW.value + height # override def get_update_packet(self, update_type=UpdateTypes.UPDATE_FULL, is_self=True): if self.gobject_template and self.gobject_instance: # Object fields self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_GUID, self.guid, 'Q') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_TYPE, self.get_object_type_value(), 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_ENTRY, self.gobject_template.entry, 'I') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_SCALE_X, self.scale, 'f') self.update_packet_factory.update( self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_PADDING, 0, 'I') # Gameobject fields self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_DISPLAYID, self.display_id, 'I') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_FLAGS, self.gobject_template.flags, 'I') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_FACTION, self.gobject_template.faction, 'I') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_STATE, self.state, 'I') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_ROTATION, self.gobject_instance.spawn_rotation0, 'f') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_ROTATION + 1, self.gobject_instance.spawn_rotation1, 'f') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_ROTATION + 2, self.gobject_instance.spawn_rotation2, 'f') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_ROTATION + 3, self.gobject_instance.spawn_rotation3, 'f') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_POS_X, self.location.x, 'f') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_POS_Y, self.location.y, 'f') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_POS_Z, self.location.z, 'f') self.update_packet_factory.update( self.update_packet_factory.gameobject_values, self.update_packet_factory.updated_gameobject_fields, GameObjectFields.GAMEOBJECT_FACING, self.location.o, 'f') packet = b'' if update_type == UpdateTypes.UPDATE_FULL: packet += self.create_update_packet(is_self) else: packet += self.create_partial_update_packet( self.update_packet_factory) update_packet = packet + self.update_packet_factory.build_packet() return update_packet def query_details(self): name_bytes = PacketWriter.string_to_bytes(self.gobject_template.name) data = pack( '<3I%ussss10I' % len(name_bytes), self.gobject_template.entry, self.gobject_template.type, self.display_id, name_bytes, b'\x00', b'\x00', b'\x00', self.gobject_template.data1, self.gobject_template.data2, self.gobject_template.data3, self.gobject_template.data4, self.gobject_template.data5, self.gobject_template.data6, self.gobject_template.data7, self.gobject_template.data8, self.gobject_template.data9, self.gobject_template.data10, ) return PacketWriter.get_packet(OpCode.SMSG_GAMEOBJECT_QUERY_RESPONSE, data) def send_update_surrounding(self, update_type=UpdateTypes.UPDATE_FULL): update_packet = UpdatePacketFactory.compress_if_needed( PacketWriter.get_packet( OpCode.SMSG_UPDATE_OBJECT, self.get_update_packet(update_type=update_type, is_self=False))) GridManager.send_surrounding(update_packet, self, include_self=False) # override def get_type(self): return ObjectTypes.TYPE_GAMEOBJECT # override def get_type_id(self): return ObjectTypeIds.ID_GAMEOBJECT
class ItemManager(ObjectManager): def __init__(self, item_template, item_instance=None, current_slot=0, **kwargs): super().__init__(**kwargs) self.update_packet_factory = UpdatePacketFactory([ObjectTypes.TYPE_OBJECT, ObjectTypes.TYPE_ITEM]) self.item_template = item_template self.item_instance = item_instance self.guid = (item_instance.guid if item_instance else 0) | HighGuid.HIGHGUID_ITEM self.current_slot = item_instance.slot if item_instance else 0 self.is_contained = item_instance.owner if item_instance else 0 self.is_backpack = False self.stats = [] self.damage_stats = [] self.spell_stats = [] if item_template: self.display_id = item_template.display_id self.equip_slot = self.get_inv_slot_by_type(self.item_template.inventory_type) self.stats.append(ItemManager.Stat(self.item_template.stat_type1, self.item_template.stat_value1)) self.stats.append(ItemManager.Stat(self.item_template.stat_type2, self.item_template.stat_value2)) self.stats.append(ItemManager.Stat(self.item_template.stat_type3, self.item_template.stat_value3)) self.stats.append(ItemManager.Stat(self.item_template.stat_type4, self.item_template.stat_value4)) self.stats.append(ItemManager.Stat(self.item_template.stat_type5, self.item_template.stat_value5)) self.stats.append(ItemManager.Stat(self.item_template.stat_type6, self.item_template.stat_value6)) self.stats.append(ItemManager.Stat(self.item_template.stat_type7, self.item_template.stat_value7)) self.stats.append(ItemManager.Stat(self.item_template.stat_type8, self.item_template.stat_value8)) self.stats.append(ItemManager.Stat(self.item_template.stat_type9, self.item_template.stat_value9)) self.stats.append(ItemManager.Stat(self.item_template.stat_type10, self.item_template.stat_value10)) self.damage_stats.append(ItemManager.DamageStat(self.item_template.dmg_min1, self.item_template.dmg_max1, self.item_template.dmg_type1)) self.damage_stats.append(ItemManager.DamageStat(self.item_template.dmg_min2, self.item_template.dmg_max2, self.item_template.dmg_type2)) self.damage_stats.append(ItemManager.DamageStat(self.item_template.dmg_min3, self.item_template.dmg_max3, self.item_template.dmg_type3)) self.damage_stats.append(ItemManager.DamageStat(self.item_template.dmg_min4, self.item_template.dmg_max4, self.item_template.dmg_type4)) self.damage_stats.append(ItemManager.DamageStat(self.item_template.dmg_min5, self.item_template.dmg_max5, self.item_template.dmg_type5)) self.spell_stats.append( ItemManager.SpellStat(self.item_template.spellid_1, self.item_template.spelltrigger_1, self.item_template.spellcharges_1, self.item_template.spellcooldown_1, self.item_template.spellcategory_1, self.item_template.spellcategorycooldown_1)) self.spell_stats.append( ItemManager.SpellStat(self.item_template.spellid_2, self.item_template.spelltrigger_2, self.item_template.spellcharges_2, self.item_template.spellcooldown_2, self.item_template.spellcategory_2, self.item_template.spellcategorycooldown_2)) self.spell_stats.append( ItemManager.SpellStat(self.item_template.spellid_3, self.item_template.spelltrigger_3, self.item_template.spellcharges_3, self.item_template.spellcooldown_3, self.item_template.spellcategory_3, self.item_template.spellcategorycooldown_3)) self.spell_stats.append( ItemManager.SpellStat(self.item_template.spellid_4, self.item_template.spelltrigger_4, self.item_template.spellcharges_4, self.item_template.spellcooldown_4, self.item_template.spellcategory_4, self.item_template.spellcategorycooldown_4)) self.spell_stats.append( ItemManager.SpellStat(self.item_template.spellid_5, self.item_template.spelltrigger_5, self.item_template.spellcharges_5, self.item_template.spellcooldown_5, self.item_template.spellcategory_5, self.item_template.spellcategorycooldown_5)) self.object_type.append(ObjectTypes.TYPE_ITEM) class Stat(object): def __init__(self, stat_type, value): self.stat_type = stat_type self.value = value class DamageStat(object): def __init__(self, minimum, maximum, stat_type): self.minimum = minimum self.maximum = maximum self.stat_type = stat_type class SpellStat(object): def __init__(self, spell_id, trigger, charges, cooldown, category, category_cooldown): self.spell_id = spell_id self.trigger = trigger self.charges = charges self.cooldown = cooldown self.category = category self.category_cooldown = category_cooldown def is_container(self): if self.item_template: return self.item_template.inventory_type == InventoryTypes.BAG return False def is_equipped(self): return self.current_slot < InventorySlots.SLOT_BAG1 @staticmethod def get_inv_slot_by_type(inventory_type): return AVAILABLE_EQUIP_SLOTS[inventory_type if inventory_type <= 26 else 0].value @staticmethod def generate_starting_item(owner, entry, last_bag_slot): item_template = WorldDatabaseManager.item_template_get_by_entry(entry) if item_template: slot = ItemManager.get_inv_slot_by_type(item_template.inventory_type) if slot >= InventorySlots.SLOT_INBACKPACK: slot = last_bag_slot bag = InventorySlots.SLOT_INBACKPACK.value count = 1 if item_template.inventory_type == 0 and item_template.class_ == 0: count = 2 if item_template.spellid_1 == 430 else 4 elif item_template.inventory_type == 24: count = 200 return ItemManager.generate_item(item_template, owner, bag, slot, count=count) return None @staticmethod def generate_item(item_template, owner, bag, slot, creator=0, count=1): if item_template and item_template.entry > 0: item = CharacterInventory( owner=owner, creator=creator, item_template=item_template.entry, stackcount=count, slot=slot, bag=bag ) RealmDatabaseManager.character_inventory_add_item(item) if item_template.inventory_type == InventoryTypes.BAG: from game.world.managers.objects.item.ContainerManager import ContainerManager item_mgr = ContainerManager( owner=owner, item_template=item_template, item_instance=item ) else: item_mgr = ItemManager( item_template=item_template, item_instance=item ) return item_mgr return None def query_details(self): item_name_bytes = PacketWriter.string_to_bytes(self.item_template.name) data = pack( '<3I%ussss6I2i7I' % len(item_name_bytes), self.item_template.entry, self.item_template.class_, self.item_template.subclass, item_name_bytes, b'\x00', b'\x00', b'\x00', self.item_template.display_id, self.item_template.quality, self.item_template.flags, self.item_template.buy_price, self.item_template.sell_price, self.item_template.inventory_type, self.item_template.allowable_class, self.item_template.allowable_race, self.item_template.item_level, self.item_template.required_level, self.item_template.required_skill, self.item_template.required_skill_rank, self.item_template.max_count, self.item_template.stackable, self.item_template.container_slots ) for stat in self.stats: data += pack('<Ii', stat.stat_type, stat.value) for damage_stat in self.damage_stats: data += pack('<3i', int(damage_stat.minimum), int(damage_stat.maximum), damage_stat.stat_type) data += pack( '<6i3I', self.item_template.armor, self.item_template.holy_res, self.item_template.fire_res, self.item_template.nature_res, self.item_template.frost_res, self.item_template.shadow_res, self.item_template.delay, self.item_template.ammo_type, 0 # TODO: Durability, not implemented ) for spell_stat in self.spell_stats: data += pack( '<Q4i', spell_stat.spell_id, spell_stat.trigger, spell_stat.charges, spell_stat.cooldown, spell_stat.category_cooldown ) description_bytes = PacketWriter.string_to_bytes(self.item_template.description) data += pack( '<I%us5IiI' % len(description_bytes), self.item_template.bonding, description_bytes, self.item_template.page_text, self.item_template.page_language, self.item_template.page_material, self.item_template.start_quest, self.item_template.lock_id, self.item_template.material, self.item_template.sheath ) return PacketWriter.get_packet(OpCode.SMSG_ITEM_QUERY_SINGLE_RESPONSE, data) # override def get_update_packet(self, update_type=UpdateTypes.UPDATE_FULL, is_self=True): if self.item_template and self.item_instance: from game.world.managers.objects.item.ContainerManager import MAX_BAG_SLOTS, ContainerManager # Object fields self.update_packet_factory.update(self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_GUID, self.guid, 'Q') self.update_packet_factory.update(self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_TYPE, self.get_object_type_value(), 'I') self.update_packet_factory.update(self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_ENTRY, self.item_template.entry, 'I') self.update_packet_factory.update(self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_SCALE_X, 1, 'f') self.update_packet_factory.update(self.update_packet_factory.object_values, self.update_packet_factory.updated_object_fields, ObjectFields.OBJECT_FIELD_PADDING, 0, 'I') # Item fields self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_OWNER, self.item_instance.owner, 'Q') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_CREATOR, self.item_instance.creator, 'Q') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_CONTAINED, self.is_contained, 'Q') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_STACK_COUNT, self.item_instance.stackcount, 'I') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_FLAGS, self.item_template.flags, 'I') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_SPELL_CHARGES, self.item_instance.SpellCharges1, 'i') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_SPELL_CHARGES + 1, self.item_instance.SpellCharges2, 'i') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_SPELL_CHARGES + 2, self.item_instance.SpellCharges3, 'i') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_SPELL_CHARGES + 3, self.item_instance.SpellCharges4, 'i') self.update_packet_factory.update(self.update_packet_factory.item_values, self.update_packet_factory.updated_item_fields, ItemFields.ITEM_FIELD_SPELL_CHARGES + 4, self.item_instance.SpellCharges5, 'i') # Container fields if self.is_container() and isinstance(self, ContainerManager): self.update_packet_factory.update(self.update_packet_factory.container_values, self.update_packet_factory.updated_container_fields, ContainerFields.CONTAINER_FIELD_NUM_SLOTS, self.item_template.container_slots, 'I') for x in range(0, MAX_BAG_SLOTS): guid = self.sorted_slots[x].guid if x in self.sorted_slots else 0 self.update_packet_factory.update(self.update_packet_factory.container_values, self.update_packet_factory.updated_container_fields, ContainerFields.CONTAINER_FIELD_SLOT_1 + x * 2, guid, 'Q') packet = b'' if update_type == UpdateTypes.UPDATE_FULL: packet += self.create_update_packet(is_self) else: packet += self.create_partial_update_packet(self.update_packet_factory) update_packet = packet + self.update_packet_factory.build_packet() return update_packet # override def get_type(self): return ObjectTypes.TYPE_ITEM # override def get_type_id(self): return ObjectTypeIds.ID_ITEM