Ejemplo n.º 1
0
    def load(self):
        filename = f'{self.cell_map:03}{self.cell_x:02}{self.cell_y:02}.map'
        maps_path = PathManager.get_map_file_path(filename)
        Logger.debug(f'[Maps] Loading map file: {filename}')

        if not path.exists(maps_path):
            Logger.warning(f'Unable to locate map file: {filename}')
        else:
            with open(maps_path, "rb") as map_tiles:
                version = PacketReader.read_string(map_tiles.read(10), 0)
                if version != MapTile.EXPECTED_VERSION:
                    Logger.error(f'Unexpected map version. Expected "{MapTile.EXPECTED_VERSION}", received "{version}".')
                    return

                # TODO: AreaFlags
                # for x in range(0, RESOLUTION_FLAGS + 1):
                #     for y in range(0, RESOLUTION_FLAGS + 1):
                #         self.explore_flag[x][y] = unpack('<H', map_tiles.read(2))[0]
                #
                # TODO: AreaTerrain
                # for x in range(0, RESOLUTION_TERRAIN + 1):
                #     for y in range(0, RESOLUTION_TERRAIN + 1):
                #         self.area_terrain[x][y] = map_tiles.read(1)[0]
                #
                # TODO: Liquids
                # for x in range(0, RESOLUTION_WATER + 1):
                #     for y in range(0, RESOLUTION_WATER + 1):
                #         self.water_level[x][y] = unpack('<f', map_tiles.read(4))[0]

                # Height Map
                for x in range(0, RESOLUTION_ZMAP + 1):
                    for y in range(0, RESOLUTION_ZMAP + 1):
                        self.z_coords[x][y] = unpack('<f', map_tiles.read(4))[0]
Ejemplo n.º 2
0
    def set_on_cooldown(self, casting_spell, start_locked_cooldown=False):
        spell = casting_spell.spell_entry

        if spell.RecoveryTime == 0 and spell.CategoryRecoveryTime == 0:
            return

        timestamp = time.time()

        if start_locked_cooldown:
            data = pack('<IQ', spell.ID, self.unit_mgr.guid)
            self.unit_mgr.enqueue_packet(
                PacketWriter.get_packet(OpCode.SMSG_COOLDOWN_EVENT, data))
            for cooldown in self.cooldowns:
                if cooldown.spell_id == spell.ID:
                    cooldown.unlock(timestamp)
                    return
            Logger.warning(
                f'[SpellManager]: Attempted to unlock cooldown for spell {spell.ID}, but the cooldown didn\'t exist.'
            )

        cooldown_entry = CooldownEntry(
            spell, timestamp, casting_spell.trigger_cooldown_on_aura_remove())
        self.cooldowns.append(cooldown_entry)

        if self.unit_mgr.get_type() != ObjectTypes.TYPE_PLAYER:
            return

        data = pack('<IQI', spell.ID, self.unit_mgr.guid,
                    cooldown_entry.cooldown_length)
        self.unit_mgr.enqueue_packet(
            PacketWriter.get_packet(OpCode.SMSG_SPELL_COOLDOWN, data))
Ejemplo n.º 3
0
    def handle_mod_base_resistance(aura, effect_target, remove):
        # This handler is a slight exception to the usual handling of aura stat modifiers.
        # Only this effect modifies base stats and is used by the Toughness talent which increases armor.
        # Since this is a slight exception, handle this case more specifically by changing *one* base stat of the unit.

        amount = aura.get_effect_points()
        if aura.spell_effect.misc_value == -1:
            # stat_type = UnitStats.ALL_RESISTANCES
            stat_type = UnitStats.RESISTANCE_PHYSICAL

            # This case shouldn't exist with an unmodified database.
            Logger.warning(
                "[AuraEffectHandler]: Unsupported behaviour in handle_mod_base_resistance."
            )
        else:
            stat_type = UnitStats.RESISTANCE_START << aura.spell_effect.misc_value

        base_stat = effect_target.stat_manager.get_base_stat(stat_type)

        if remove:
            new_value = max(base_stat - amount,
                            0)  # Avoid <0, though it should never occur.
        else:
            new_value = base_stat + amount

        effect_target.stat_manager.base_stats[stat_type] = new_value
Ejemplo n.º 4
0
 def process_incoming(self):
     while self.keep_alive:
         reader = self.incoming_pending.get(block=True, timeout=None)
         if reader:  # Can be None if we shutdown the thread.
             if reader.opcode:
                 handler, found = Definitions.get_handler_from_packet(
                     self, reader.opcode)
                 if handler:
                     res = handler(self, self.request, reader)
                     if res == 0:
                         Logger.debug(
                             f'[{self.client_address[0]}] Handling {OpCode(reader.opcode).name}'
                         )
                     elif res == 1:
                         Logger.debug(
                             f'[{self.client_address[0]}] Ignoring {OpCode(reader.opcode).name}'
                         )
                     elif res < 0:
                         self.disconnect()
                         break
                 elif not found:
                     Logger.warning(
                         f'[{self.client_address[0]}] Received unknown data: {reader.data}'
                     )
         else:
             self.disconnect()
Ejemplo n.º 5
0
    def find_loot_by_loot_id(loot_id):
        loot = WorldDatabaseManager.CreatureLootTemplateHolder.creature_loot_template_get_by_creature(
            loot_id)
        if loot:
            return loot
        loot = WorldDatabaseManager.PickPocketingLootTemplateHolder.pickpocketing_loot_template_get_by_entry(
            loot_id)
        if loot:
            return loot
        loot = WorldDatabaseManager.ReferenceLootTemplateHolder.reference_loot_template_get_by_entry(
            loot_id)
        if loot:
            return loot
        loot = WorldDatabaseManager.FishingLootTemplateHolder.fishing_loot_template_get_by_entry(
            loot_id)
        if loot:
            return loot
        loot = WorldDatabaseManager.GameObjectLootTemplateHolder.gameobject_loot_template_get_by_entry(
            loot_id)
        if loot:
            return loot
        loot = WorldDatabaseManager.ItemLootTemplateHolder.item_loot_template_get_by_entry(
            loot_id)
        if loot:
            return loot

        if not loot:
            Logger.warning(
                f'Unable to locate referenced loot for id {loot_id}.')

        return None
Ejemplo n.º 6
0
    def _check_tile_load(map_id, location_x, location_y, map_tile_x,
                         map_tile_y):
        if not config.Server.Settings.use_map_tiles:
            return False

        # Check if the map is valid first.
        if map_id not in MAPS:
            Logger.warning(f'Wrong map, {map_id} not found.')
            return False

        tile = MAPS[map_id].tiles[map_tile_x][map_tile_y]

        # Tile exists and has been initialized, return if it's already valid (finished loading) or not.
        if tile is not None and tile.initialized:
            return tile.is_valid

        # Tile does not exist, try to load it.
        if tile is None:
            MapManager.load_map_tiles(map_id, location_x, location_y)

        # Grab the tile again.
        tile = MAPS[map_id].tiles[map_tile_x][map_tile_y]

        # Tile exist, its initialized and has loaded its internal data.
        return tile is not None and tile.initialized and tile.is_valid
Ejemplo n.º 7
0
    def load(self):
        # Set as initialized to avoid another load() call from another thread.
        self.initialized = True

        filename = f'{self.cell_map:03}{self.cell_x:02}{self.cell_y:02}.map'
        maps_path = PathManager.get_map_file_path(filename)
        Logger.debug(
            f'[Maps] Loading map file: {filename}, Map:{self.cell_map} Tile:{self.cell_x},{self.cell_y}'
        )

        if not path.exists(maps_path):
            Logger.warning(
                f'Unable to locate map file: {filename}, Map:{self.cell_map} Tile:{self.cell_x},{self.cell_y}'
            )
            return
        else:
            with open(maps_path, "rb") as map_tiles:
                version = PacketReader.read_string(map_tiles.read(10), 0)
                if version != MapTile.EXPECTED_VERSION:
                    Logger.error(
                        f'Unexpected map version. Expected "{MapTile.EXPECTED_VERSION}", found "{version}".'
                    )
                    return

                # Height Map
                for x in range(RESOLUTION_ZMAP):
                    for y in range(RESOLUTION_ZMAP):
                        self.z_height_map[x][y] = unpack(
                            '<f', map_tiles.read(4))[0]

                # ZoneID, AreaNumber, AreaFlags, AreaLevel, AreaExploreFlag(Bit), AreaFactionMask
                for x in range(RESOLUTION_AREA_INFO):
                    for y in range(RESOLUTION_AREA_INFO):
                        zone_id = unpack('<i', map_tiles.read(4))[0]
                        if zone_id == -1:  # No area information.
                            continue
                        area_number = unpack('<I', map_tiles.read(4))[0]
                        area_flags = unpack('<B', map_tiles.read(1))[0]
                        area_level = unpack('<B', map_tiles.read(1))[0]
                        area_explore_bit = unpack('<H', map_tiles.read(2))[0]
                        area_faction_mask = unpack('<B', map_tiles.read(1))[0]
                        # noinspection PyTypeChecker
                        self.area_information[x][y] = AreaInformation(
                            zone_id, area_number, area_flags, area_level,
                            area_explore_bit, area_faction_mask)

                # Liquids
                for x in range(RESOLUTION_LIQUIDS):
                    for y in range(RESOLUTION_LIQUIDS):
                        liquid_type = unpack('<b', map_tiles.read(1))[0]
                        if liquid_type == -1:  # No liquid information / not rendered.
                            continue
                        height = unpack('<f', map_tiles.read(4))[0]
                        # noinspection PyTypeChecker
                        self.liquid_information[x][y] = LiquidInformation(
                            liquid_type, height)

        # This is a valid tile, set as loaded.
        self.is_valid = True
Ejemplo n.º 8
0
 def get_handler_from_packet(opcode):
     try:
         opcode_name = OpCode(opcode)
         if opcode_name in HANDLER_DEFINITIONS:
             return HANDLER_DEFINITIONS.get(OpCode(opcode))
         else:
             Logger.warning('Received %s OpCode but is not handled.' % opcode_name)
     except ValueError:
         Logger.error('Received unknown OpCode (%u)' % opcode)
     return None
Ejemplo n.º 9
0
    def resolve_effect_select(casting_spell, target_effect):
        if target_effect.effect_type == SpellEffects.SPELL_EFFECT_SCHOOL_DAMAGE:  # Hellfire, aura of rot
            units = EffectTargets.resolve_all_around_caster(
                casting_spell, target_effect)
            return EffectTargets.get_enemies_from_unit_list(
                units, casting_spell.spell_caster)

        Logger.warning(
            f'Unimplemented implicit target called for spell {casting_spell.spell_entry.ID}'
        )
Ejemplo n.º 10
0
 def get_handler_from_packet(world_session, opcode):
     try:
         opcode_name = OpCode(opcode)
         if opcode_name in HANDLER_DEFINITIONS:
             return HANDLER_DEFINITIONS.get(OpCode(opcode)), 1
         else:
             Logger.warning('[%s] Received %s OpCode but is not handled.' %
                            (world_session.client_address[0], opcode_name))
     except ValueError:
         return None, -1
     return None, 0
Ejemplo n.º 11
0
    def load_items(self):
        character_inventory = RealmDatabaseManager.character_get_inventory(
            self.owner.guid)

        # First load bags
        for item_instance in character_inventory:
            item_template = WorldDatabaseManager.ItemTemplateHolder.item_template_get_by_entry(
                item_instance.item_template)
            if item_template and item_template.inventory_type == InventoryTypes.BAG:
                container_mgr = ContainerManager(owner=self.owner.guid,
                                                 item_template=item_template,
                                                 item_instance=item_instance)
                if self.is_bag_pos(container_mgr.current_slot):
                    if item_instance.bag > 23:
                        low_guid = container_mgr.guid & ~HighGuid.HIGHGUID_CONTAINER
                        Logger.warning(
                            f'Invalid bag slot {item_instance.bag} for guid {low_guid} owner {self.owner.guid}'
                        )
                        continue
                    self.containers[item_instance.bag].sorted_slots[
                        container_mgr.current_slot] = container_mgr
                    self.containers[container_mgr.current_slot] = container_mgr

        # Then load items
        for item_instance in character_inventory:
            item_template = WorldDatabaseManager.ItemTemplateHolder.item_template_get_by_entry(
                item_instance.item_template)
            if item_template:
                if item_template.display_id > MAX_3368_ITEM_DISPLAY_ID and \
                        self.is_equipment_pos(item_instance.bag, item_instance.slot):
                    Logger.error(
                        f'Character {self.owner.player.name} has an equipped item ({item_template.entry} - {item_template.name}) '
                        f'with out of bounds display_id ({item_template.display_id}), '
                        f'deleting in order to prevent crashes.')
                    RealmDatabaseManager.character_inventory_delete(
                        item_instance)
                    continue

                if item_template.inventory_type == InventoryTypes.BAG:
                    if self.is_bag_pos(item_instance.slot):
                        continue

                    item_mgr = ContainerManager(owner=self.owner.guid,
                                                item_template=item_template,
                                                item_instance=item_instance)
                else:
                    item_mgr = ItemManager(item_template=item_template,
                                           item_instance=item_instance)

                if item_instance.bag in self.containers and self.containers[
                        item_instance.bag]:
                    self.containers[item_instance.bag].sorted_slots[
                        item_mgr.current_slot] = item_mgr
Ejemplo n.º 12
0
 def add_threat(self, source: UnitManager, threat: float):
     if source != self:
         source_holder = self.holders.get(source.guid)
         if source_holder:
             new_threat = source_holder.total_threat + threat
             source_holder.total_threat = max(new_threat, 0.0)
         elif threat > 0.0:
             self.holders[source.guid] = ThreatHolder(source, threat)
         else:
             Logger.warning(
                 f'Passed non positive threat {threat} from {source.guid & ~HighGuid.HIGHGUID_UNIT}'
             )
Ejemplo n.º 13
0
 def _handle_use_goober(self, player):
     # Deadmines IronClad door (After triggering cannon)
     # TODO: This should be moved somewhere else to avoid hardcoding entries in the core GameObject manager.
     #  Future instance/map scripts?
     if self.entry == 16398:  # Cannon.
         # TODO, scripting, instancing, etc.
         iron_clad_doors = [go for go in MapManager.get_surrounding_gameobjects(self).values() if go.entry == 16397]
         if len(iron_clad_doors) > 0:
             self.send_custom_animation(0)
             iron_clad_doors[0].set_active()
     else:
         Logger.warning(f'Unimplemented gameobject use for type Goober entry {self.entry} name {self.gobject_template.name}')
     pass
Ejemplo n.º 14
0
 def receive(self, sck):
     try:
         data = sck.recv(1024)
         reader = PacketReader(data)
         if reader.opcode:
             handler = Definitions.get_handler_from_packet(reader.opcode)
             if handler:
                 Logger.debug('Handling %s' % OpCode(reader.opcode))
                 if handler(self, sck, reader) != 0:
                     return -1
     except OSError:
         Logger.warning('Tried to interact with a closed socket.')
         return -1
Ejemplo n.º 15
0
 def get_handler_from_packet(world_session, opcode):
     try:
         opcode = OpCode(opcode)
         if opcode in HANDLER_DEFINITIONS:
             return HANDLER_DEFINITIONS.get(OpCode(opcode)), True
         Logger.warning(
             f'[{world_session.client_address[0]}] Received {opcode.name} OpCode but is not handled.'
         )
     except ValueError:
         # No handler, OpCode not found
         return None, False
     # No handler, but OpCode found
     return None, True
Ejemplo n.º 16
0
    def resolve_table_coordinates(casting_spell, target_effect):
        target_position = WorldDatabaseManager.spell_target_position_get_by_spell(
            casting_spell.spell_entry.ID)
        if not target_position:
            Logger.warning(
                f'Unimplemented target spell position for spell {casting_spell.spell_entry.ID}.'
            )
            return []

        return target_position.target_map, Vector(
            target_position.target_position_x,
            target_position.target_position_y,
            target_position.target_position_z,
            target_position.target_orientation)
Ejemplo n.º 17
0
    def resolve_implicit_targets_reference(self, implicit_target):
        target = self.simple_targets[
            implicit_target] if implicit_target in self.simple_targets else TARGET_RESOLVERS[
                implicit_target](self.casting_spell)

        if target is None and implicit_target != 0:  # Avoid crash on unfinished implementation while target resolving isn't finished TODO
            Logger.warning(
                f'Implicit target {implicit_target} resolved to None. Falling back to initial target or self.'
            )
            target = self.initial_target if self.casting_spell.initial_target_is_object(
            ) else self.caster

        if type(target) is not list:
            return [target]
        return target
Ejemplo n.º 18
0
 def receive_all(self, sck, expected_size):
     # Try to fill at once.
     received = sck.recv(expected_size)
     if not received:
         return b''
     # We got what we expect, return buffer.
     if received == expected_size:
         return received
     # If we got incomplete data, request missing payload.
     buffer = bytearray(received)
     while len(buffer) < expected_size:
         Logger.warning('Got incomplete data from client, requesting missing payload.')
         received = sck.recv(expected_size - len(buffer))
         if not received:
             return b''
         buffer.extend(received)  # Keep appending to our buffer until we're done.
     return buffer
Ejemplo n.º 19
0
    def update_object(world_object, check_pending_changes=False):
        if world_object.current_cell:
            old_map = int(world_object.current_cell.split(':')[-1])
            old_grid_manager = MapManager.get_grid_manager_by_map_id(old_map)
        else:
            old_grid_manager = None

        grid_manager = MapManager.get_grid_manager_by_map_id(world_object.map_)
        if grid_manager:
            grid_manager.update_object(
                world_object,
                old_grid_manager,
                check_pending_changes=check_pending_changes)
        else:
            Logger.warning(
                f'Warning, did not find grid_manager for map: {world_object.map_}'
            )
Ejemplo n.º 20
0
 def receive(self, sck):
     try:
         data = sck.recv(2048)
         if len(data) > 0:
             reader = PacketReader(data)
             if reader.opcode:
                 handler, res = Definitions.get_handler_from_packet(self, reader.opcode)
                 if handler:
                     Logger.debug('[%s] Handling %s' % (self.client_address[0], OpCode(reader.opcode)))
                     if handler(self, sck, reader) != 0:
                         return -1
                 elif res == -1:
                     Logger.warning('[%s] Received unknown data: %s' % (self.client_address[0], data))
         else:
             return -1
     except OSError:
         self.disconnect()
         return -1
Ejemplo n.º 21
0
    def resolve_implicit_targets_reference(
            self,
            implicit_target) -> Optional[list[Union[ObjectManager, Vector]]]:
        target = self.simple_targets[
            implicit_target] if implicit_target in self.simple_targets else TARGET_RESOLVERS[
                implicit_target](self.casting_spell, self.target_effect)

        # Avoid crash on unfinished implementation while target resolving isn't finished TODO
        # Implemented handlers should always return [] if no targets are found
        if target is None:
            Logger.warning(
                f'Implicit target {implicit_target} resolved to None. Falling back to initial target or self.'
            )
            target = self.initial_target if self.casting_spell.initial_target_is_object(
            ) else self.casting_spell.spell_caster

        if type(target) is not list:
            return [target]
        return target
Ejemplo n.º 22
0
    def calculate_z(map_id, x, y, current_z=0.0):
        try:
            map_tile_x, map_tile_y, tile_local_x, tile_local_y = MapManager.calculate_tile(
                x, y, RESOLUTION_ZMAP)
            x_normalized = RESOLUTION_ZMAP * (32.0 - (x / SIZE) -
                                              map_tile_x) - tile_local_x
            y_normalized = RESOLUTION_ZMAP * (32.0 - (y / SIZE) -
                                              map_tile_y) - tile_local_y

            if map_id not in MAPS or not MAPS[map_id].tiles[map_tile_x][
                    map_tile_y]:
                Logger.warning(
                    f'Tile [{map_tile_x},{map_tile_y}] information not found.')
                return current_z if current_z else 0.0
            else:
                try:
                    val_1 = MapManager.get_height(map_id, map_tile_x,
                                                  map_tile_y, tile_local_x,
                                                  tile_local_y)
                    val_2 = MapManager.get_height(map_id, map_tile_x,
                                                  map_tile_y, tile_local_x + 1,
                                                  tile_local_y)
                    top_height = MapManager._lerp(val_1, val_2, x_normalized)
                    val_3 = MapManager.get_height(map_id, map_tile_x,
                                                  map_tile_y, tile_local_x,
                                                  tile_local_y + 1)
                    val_4 = MapManager.get_height(map_id, map_tile_x,
                                                  map_tile_y, tile_local_x + 1,
                                                  tile_local_y + 1)
                    bottom_height = MapManager._lerp(val_3, val_4,
                                                     x_normalized)
                    return MapManager._lerp(top_height, bottom_height,
                                            y_normalized)  # Z
                except:
                    return MAPS[map_id].tiles[map_tile_x][map_tile_y].z_coords[
                        tile_local_x][tile_local_x]
        except:
            Logger.error(traceback.format_exc())
            return current_z if current_z else 0.0
Ejemplo n.º 23
0
    def handle_item_cast_attempt(self, item, caster):
        for spell_info in item.spell_stats:
            if spell_info.spell_id == 0:
                break
            spell = DbcDatabaseManager.SpellHolder.spell_get_by_id(
                spell_info.spell_id)
            if not spell:
                Logger.warning(
                    f'Spell {spell_info.spell_id} tied to item {item.item_template.entry} ({item.item_template.name}) could not be found in the spell database.'
                )
                continue

            casting_spell = self.try_initialize_spell(
                spell, caster, caster, SpellTargetMask.SELF,
                item)  # TODO item spells targeting others?
            if not casting_spell:
                continue
            if casting_spell.is_refreshment_spell(
            ):  # Food/drink items don't send sit packet - handle here
                caster.set_stand_state(StandState.UNIT_SITTING)

            self.start_spell_cast(spell, caster, caster, SpellTargetMask.SELF,
                                  item)
Ejemplo n.º 24
0
 def load_area_triggers(self):
     if self.quest.entry in WorldDatabaseManager.QuestRelationHolder.AREA_TRIGGER_RELATION:
         self.area_triggers = WorldDatabaseManager.QuestRelationHolder.AREA_TRIGGER_RELATION[self.quest.entry]
     else:
         Logger.warning(f'Unable to locate area trigger/s for quest {self.quest.entry}')
Ejemplo n.º 25
0
 def resolve_all_hostile_around_caster(
         casting_spell, target_effect):  # TODO Charge effects only?
     Logger.warning(
         f'Unimplemented implicit target called for spell {casting_spell.spell_entry.ID}'
     )
Ejemplo n.º 26
0
    def send_trainer_list(self, world_session):
        if not self.can_train(world_session.player_mgr):
            Logger.anticheat(f'send_trainer_list called from NPC {self.entry} by player with GUID {world_session.player_mgr.guid} but this unit does not train that player\'s class. Possible cheating')
            return

        train_spell_bytes: bytes = b''
        train_spell_count: int = 0

        trainer_ability_list: list[TrainerTemplate] = WorldDatabaseManager.TrainerSpellHolder.trainer_spells_get_by_trainer(self.entry)

        if not trainer_ability_list or trainer_ability_list.count == 0:
            Logger.warning(f'send_trainer_list called from NPC {self.entry} but no trainer spells found!')
            return

        for trainer_spell in trainer_ability_list:  # trainer_spell: The spell the trainer uses to teach the player.
            player_spell_id = trainer_spell.playerspell
            
            ability_spell_chain: SpellChain = WorldDatabaseManager.SpellChainHolder.spell_chain_get_by_spell(player_spell_id)

            spell_level: int = trainer_spell.reqlevel  # Use this and not spell data, as there are differences between data source (2003 Game Guide) and what is in spell table.
            spell_rank: int = ability_spell_chain.rank
            prev_spell: int = ability_spell_chain.prev_spell

            spell_is_too_high_level: bool = spell_level > world_session.player_mgr.level

            if player_spell_id in world_session.player_mgr.spell_manager.spells:
                status = TrainerServices.TRAINER_SERVICE_USED
            else:
                if prev_spell in world_session.player_mgr.spell_manager.spells and spell_rank > 1 and not spell_is_too_high_level:
                    status = TrainerServices.TRAINER_SERVICE_AVAILABLE
                elif spell_rank == 1 and not spell_is_too_high_level:
                    status = TrainerServices.TRAINER_SERVICE_AVAILABLE
                else:
                    status = TrainerServices.TRAINER_SERVICE_UNAVAILABLE

            data: bytes = pack(
                '<IBI3B6I',
                player_spell_id,  # Spell id
                status,  # Status
                trainer_spell.spellcost,  # Cost
                trainer_spell.talentpointcost,  # Talent Point Cost
                trainer_spell.skillpointcost,  # Skill Point Cost
                spell_level,  # Required Level
                trainer_spell.reqskill,  # Required Skill Line
                trainer_spell.reqskillvalue,  # Required Skill Rank
                0,  # Required Skill Step
                prev_spell,  # Required Ability (1)
                0,  # Required Ability (2)
                0  # Required Ability (3)
            )
            train_spell_bytes += data
            train_spell_count += 1

        # TODO: Temp placeholder.
        greeting: str = f'Hello, {world_session.player_mgr.player.name}! Ready for some training?'
        greeting_bytes = PacketWriter.string_to_bytes(greeting)
        greeting_bytes = pack(
                    f'<{len(greeting_bytes)}s', 
                    greeting_bytes
        )

        data = pack('<Q2I', self.guid, TrainerTypes.TRAINER_TYPE_GENERAL, train_spell_count) + train_spell_bytes + greeting_bytes
        world_session.player_mgr.enqueue_packet(PacketWriter.get_packet(OpCode.SMSG_TRAINER_LIST, data))
Ejemplo n.º 27
0
 def resolve_aoe_party(casting_spell, target_effect):
     Logger.warning(
         f'Unimplemented implicit target called for spell {casting_spell.spell_entry.ID}'
     )
Ejemplo n.º 28
0
    def init_stats(self):
        base_stats = WorldDatabaseManager.player_get_class_level_stats(self.unit_mgr.class_, self.unit_mgr.level)

        if not base_stats:
            if self.unit_mgr.level > 60:
                # Default to max available base stats, level 60.
                base_stats = WorldDatabaseManager.player_get_class_level_stats(self.unit_mgr.class_, 60)
                Logger.warning(f'Unsupported base stats for level ({self.unit_mgr.level})'
                               f' Unit class ({Classes(self.unit_mgr.class_).name})'
                               f' Unit type ({ObjectTypeIds(self.unit_mgr.get_type_id()).name})'
                               f' Using level 60 base stats.')
            else:
                Logger.error(
                    f'Unsupported base stats for level ({self.unit_mgr.level})'
                    f' Unit class ({Classes(self.unit_mgr.class_).name})'
                    f' Unit type ({ObjectTypeIds(self.unit_mgr.get_type_id()).name}).')
                return

        # Player specific.
        if self.unit_mgr.get_type_id() == ObjectTypeIds.ID_PLAYER:
            base_attrs = WorldDatabaseManager.player_get_level_stats(self.unit_mgr.class_,
                                                                     self.unit_mgr.level,
                                                                     self.unit_mgr.race)
            if not base_attrs:
                if self.unit_mgr.level > 60:
                    # Default to max available attributes, level 60.
                    base_attrs = WorldDatabaseManager.player_get_level_stats(self.unit_mgr.class_,
                                                                             60,
                                                                             self.unit_mgr.race)
                    Logger.warning(f'Unsupported base attributes for level ({self.unit_mgr.level})'
                                   f' Unit type ({ObjectTypeIds(self.unit_mgr.get_type_id()).name})'
                                   f' Unit class ({Classes(self.unit_mgr.class_).name})'
                                   f' Unit race ({Races(self.unit_mgr.race).name})'
                                   f' Using level 60 attributes.')
                else:
                    Logger.error(f'Unsupported base attributes for level ({self.unit_mgr.level})'
                                 f' Unit type ({ObjectTypeIds(self.unit_mgr.get_type_id()).name})'
                                 f' Unit class ({Classes(self.unit_mgr.class_).name})'
                                 f' Unit race ({Races(self.unit_mgr.race).name})')
                    return

            self.base_stats[UnitStats.HEALTH] = base_stats.basehp
            self.base_stats[UnitStats.MANA] = base_stats.basemana
            self.base_stats[UnitStats.STRENGTH] = base_attrs.str
            self.base_stats[UnitStats.AGILITY] = base_attrs.agi
            self.base_stats[UnitStats.STAMINA] = base_attrs.sta
            self.base_stats[UnitStats.INTELLECT] = base_attrs.inte
            self.base_stats[UnitStats.SPIRIT] = base_attrs.spi
            self.unit_mgr.base_hp = base_stats.basehp
            self.unit_mgr.base_mana = base_stats.basemana
        # Creatures.
        else:
            self.base_stats[UnitStats.HEALTH] = self.unit_mgr.max_health
            self.base_stats[UnitStats.MANA] = self.unit_mgr.max_power_1
            self.base_stats[UnitStats.SPIRIT] = 1
            # Players don't have a flat dodge/block chance.
            self.base_stats[UnitStats.DODGE_CHANCE] = BASE_DODGE_CHANCE_CREATURE / 100
            # Players have block scaling, assign flat 5% to creatures.
            self.base_stats[UnitStats.BLOCK_CHANCE] = BASE_BLOCK_PARRY_CHANCE / 100
            self.base_stats[UnitStats.CRITICAL] = BASE_MELEE_CRITICAL_CHANCE / 100
            self.unit_mgr.base_hp = self.unit_mgr.max_health
            self.unit_mgr.base_mana = self.unit_mgr.max_power_1

        # Don't overwrite base speed if it has been modified.
        self.base_stats[UnitStats.SPEED_RUNNING] = self.base_stats.get(UnitStats.SPEED_RUNNING, config.Unit.Defaults.run_speed)

        # Players and creatures have an unchanging base 5% chance to block and parry (before defense skill differences).
        # As block chance also scales with strength, the value is calculated in update_base_block_chance.
        self.base_stats[UnitStats.PARRY_CHANCE] = BASE_BLOCK_PARRY_CHANCE / 100

        self.send_attributes()

        self.update_base_health_regen()
        self.update_base_mana_regen()

        self.update_base_proc_chance()
        self.update_base_melee_critical_chance()
        self.update_defense_bonuses()
Ejemplo n.º 29
0
 def resolve_gameobject_script_near_caster(casting_spell, target_effect):
     Logger.warning(
         f'Unimplemented implicit target called for spell {casting_spell.spell_entry.ID}'
     )
Ejemplo n.º 30
0
 def resolve_random_enemy_chain_in_area(casting_spell, target_effect):
     Logger.warning(
         f'Unimplemented implicit target called for spell {casting_spell.spell_entry.ID}'
     )