Пример #1
0
    def send_spell_go(self, casting_spell):
        data = [self.unit_mgr.guid, self.unit_mgr.guid,
                casting_spell.spell_entry.ID, 0]  # TODO Flags

        sign = '<2QIH'

        hit_count = 0
        if len(casting_spell.target_results.keys()) > 0:
            hit_count += 1
        sign += 'B'
        data.append(hit_count)

        for target, reason in casting_spell.target_results.items():
            if reason == SpellMissReason.MISS_REASON_NONE:
                data.append(target)
                sign += 'Q'

        data.append(0)  # miss count
        sign += 'B'

        sign += 'H'  # SpellTargetMask
        data.append(casting_spell.spell_target_mask)

        # write initial target
        if casting_spell.spell_target_mask & SpellTargetMask.UNIT == SpellTargetMask.UNIT:
            sign += 'Q'
            data.append(casting_spell.initial_target_unit.guid)

        packed = pack(sign, *data)
        GridManager.send_surrounding(PacketWriter.get_packet(OpCode.SMSG_SPELL_GO, packed), self.unit_mgr,
                                     include_self=self.unit_mgr.get_type() == ObjectTypes.TYPE_PLAYER)
Пример #2
0
 def send_melee_attack_stop(self, victim_guid):
     # Last uint32 is "deceased"; can be either 1 (self is dead), or 0, (self is alive).
     # Forces the unit to face the corpse and disables clientside
     # turning (UnitFlags.DisableMovement) CGUnit_C::OnAttackStop
     data = pack('<2QI', self.guid, victim_guid, 0 if self.is_alive else 1)
     GridManager.send_surrounding(
         PacketWriter.get_packet(OpCode.SMSG_ATTACKSTOP, data), self)
Пример #3
0
    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))
Пример #4
0
    def deal_damage(self, target, damage):
        if not target or damage < 1:
            return

        if not self.in_combat:
            self.enter_combat(force_update=True)

        if not target.in_combat:
            target.enter_combat(force_update=True)

        if not target.in_combat:
            target.enter_combat()

        new_health = target.health - damage
        if new_health <= 0:
            target.die(self)
        else:
            target.set_health(new_health)

        update_packet = target.generate_proper_update_packet(
            is_self=target.get_type() == ObjectTypes.TYPE_PLAYER)
        GridManager.send_surrounding(
            update_packet,
            target,
            include_self=target.get_type() == ObjectTypes.TYPE_PLAYER)
Пример #5
0
 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)
Пример #6
0
    def update(self):
        # Prevent updates while teleporting
        if self.is_teleporting:
            return

        now = time.time()
        if now > self.last_tick > 0:
            elapsed = now - self.last_tick

            # Update played time
            self.player.totaltime += elapsed
            self.player.leveltime += elapsed

            # Regeneration
            self.regenerate(now)
            # Attack update
            self.attack_update(elapsed)

            # Release spirit timer
            if not self.is_alive:
                if self.spirit_release_timer < 300:  # 5 min
                    self.spirit_release_timer += elapsed
                else:
                    self.repop()
        self.last_tick = now

        if self.dirty:
            self.send_update_self()
            self.send_update_surrounding(self.generate_proper_update_packet())
            GridManager.update_object(self)
            self.reset_fields()

            self.set_dirty(is_dirty=False, dirty_inventory=False)
Пример #7
0
    def send_attack_state_update(self, damage_info):
        data = pack(
            '<I2QIBIf7I',
            damage_info.hit_info,
            damage_info.attacker.guid,
            damage_info.target.guid,
            damage_info.total_damage,
            # Sub damage count
            1,
            damage_info.damage_school_mask,
            damage_info.total_damage,
            damage_info.damage,
            damage_info.absorb,
            damage_info.target_state,
            damage_info.resist,
            0,
            0,
            damage_info.blocked_amount)
        GridManager.send_surrounding(
            PacketWriter.get_packet(OpCode.SMSG_ATTACKERSTATEUPDATE, data),
            self,
            include_self=self.get_type() == ObjectTypes.TYPE_PLAYER)

        # Damage effects
        self.deal_damage(damage_info.target, damage_info.total_damage)
Пример #8
0
    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
    def handle(world_session, socket, reader):
        if len(reader.data
               ) >= 8:  # Avoid handling empty quest giver status packet
            quest_giver_guid = unpack('<Q', reader.data[:8])[0]
            quest_giver = None
            # NPC
            if quest_giver_guid & HighGuid.HIGHGUID_UNIT:
                quest_giver = GridManager.get_surrounding_unit_by_guid(
                    world_session.player_mgr, quest_giver_guid)
            # Gameobject
            elif quest_giver_guid & HighGuid.HIGHGUID_GAMEOBJECT:
                quest_giver = GridManager.get_surrounding_gameobject_by_guid(
                    world_session.player_mgr, quest_giver_guid)
            if not quest_giver:
                return 0

            quest_giver_status = QuestGiverStatus.QUEST_GIVER_NONE
            if world_session.player_mgr:
                if quest_giver.get_type() == ObjectTypes.TYPE_UNIT:
                    quest_giver_status = world_session.player_mgr.quest_manager.get_dialog_status(
                        quest_giver)
                elif quest_giver.get_type() == ObjectTypes.TYPE_GAMEOBJECT:
                    # TODO: Proper handling for game object
                    quest_giver_status = QuestGiverStatus.QUEST_GIVER_NONE
                else:
                    Logger.error(
                        f'Error in CMSG_QUESTGIVER_STATUS_QUERY, quest giver was an unexpected type of: {quest_giver.object_type}'
                    )

                world_session.player_mgr.quest_manager.send_quest_giver_status(
                    quest_giver_guid, quest_giver_status)

        return 0
Пример #10
0
    def handle(world_session, socket, reader):
        if len(reader.data) >= 8:  # Avoid handling empty debug AI state packet
            guid = unpack('<Q', reader.data[:8])[0]
            world_object = GridManager.get_surrounding_unit_by_guid(
                world_session.player_mgr, guid, include_players=True)

            # If no Unit or Player, try to get a Gameobject.
            if not world_object:
                world_object = GridManager.get_surrounding_gameobject_by_guid(
                    world_session.player_mgr, guid)

            # Still no object with that Guid? Return.
            if not world_object:
                return 0

            messages = world_object.get_debug_messages()
            data = pack('<QI', guid, len(messages))

            for message in messages:
                message_bytes = PacketWriter.string_to_bytes(
                    message[:127])  # Max length is 128 (127 + null byte).
                data += pack(f'<{len(message_bytes)}s', message_bytes)

            world_session.enqueue_packet(
                PacketWriter.get_packet(OpCode.SMSG_DEBUG_AISTATE, data))

        return 0
Пример #11
0
 def send_chat_message(world_session, guid, chat_flags, message, chat_type,
                       lang, range_):
     GridManager.send_surrounding_in_range(ChatManager._get_message_packet(
         guid, chat_flags, message, chat_type, lang),
                                           world_session.player_mgr,
                                           range_,
                                           use_ignore=True)
Пример #12
0
    def handle(world_session, socket, reader):
        if world_session.player_mgr.is_alive and len(reader.data) >= 12:
            emote_text_id, guid = unpack('<IQ', reader.data)
            emote = DbcDatabaseManager.emote_text_get_by_id(emote_text_id)

            if emote:
                data = pack('<QI', world_session.player_mgr.guid,
                            emote_text_id)
                target = GridManager.get_surrounding_unit_by_guid(
                    world_session.player_mgr, guid, include_players=True)

                if not target:
                    data += pack('<B', 0)
                elif target.get_type() == ObjectTypes.TYPE_PLAYER:
                    player_name_bytes = PacketWriter.string_to_bytes(
                        target.player.name)
                    data += pack('<%us' % len(player_name_bytes),
                                 player_name_bytes)
                elif target.get_type(
                ) == ObjectTypes.TYPE_UNIT and target.creature_template:
                    unit_name_bytes = PacketWriter.string_to_bytes(
                        target.creature_template.name)
                    data += pack('<%us' % len(unit_name_bytes),
                                 unit_name_bytes)
                else:
                    data += pack('<B', 0)

                GridManager.send_surrounding_in_range(
                    PacketWriter.get_packet(OpCode.SMSG_TEXT_EMOTE,
                                            data), world_session.player_mgr,
                    config.World.Chat.ChatRange.emote_range)

                # Perform visual emote action if needed

                emote_id = emote.EmoteID
                state = StandState.UNIT_STANDING
                needs_broadcast = True

                if emote_text_id == Emotes.SIT:
                    if not world_session.player_mgr.is_sitting:
                        state = StandState.UNIT_SITTING
                        world_session.player_mgr.stand_state = state
                elif emote_text_id == Emotes.STAND:
                    world_session.player_mgr.stand_state = state
                elif emote_text_id == Emotes.SLEEP:
                    if world_session.player_mgr.stand_state != StandState.UNIT_SLEEPING:
                        state = StandState.UNIT_SLEEPING
                    world_session.player_mgr.stand_state = state
                elif emote_text_id == Emotes.KNEEL:
                    if world_session.player_mgr.stand_state != StandState.UNIT_KNEEL:
                        state = StandState.UNIT_KNEEL
                    world_session.player_mgr.stand_state = state
                else:
                    needs_broadcast = False
                    world_session.player_mgr.play_emote(emote_id)

                if needs_broadcast:
                    world_session.player_mgr.flagged_for_update = True

        return 0
Пример #13
0
    def handle_ack(world_session, socket, reader):
        world_session.player_mgr.send_update_self()
        world_session.player_mgr.send_update_surrounding()
        GridManager.update_object(world_session.player_mgr)

        world_session.player_mgr.is_teleporting = False

        return 0
Пример #14
0
 def send_chat_message(world_session, guid, chat_flags, message, chat_type,
                       lang, range_):
     GridManager.send_surrounding_in_range(
         ChatManager._get_message_packet(guid, chat_flags, message,
                                         chat_type,
                                         0),  # TODO Handle language
         world_session.player_mgr,
         range_)
Пример #15
0
    def complete_login(self):
        self.is_online = True

        GridManager.update_object(self)
        self.send_update_surrounding(
            self.generate_proper_update_packet(create=True),
            include_self=False,
            create=True)
Пример #16
0
    def update_surrounding(self):
        self.send_update_surrounding()
        GridManager.send_surrounding(NameQueryHandler.get_query_details(
            self.player),
                                     self,
                                     include_self=True)

        players, creatures, gobjects = GridManager.get_surrounding_objects(
            self, [
                ObjectTypes.TYPE_PLAYER, ObjectTypes.TYPE_UNIT,
                ObjectTypes.TYPE_GAMEOBJECT
            ])

        for guid, player in players.items():
            if self.guid != guid:
                if guid not in self.objects_in_range:
                    update_packet = UpdatePacketFactory.compress_if_needed(
                        PacketWriter.get_packet(
                            OpCode.SMSG_UPDATE_OBJECT,
                            player.get_update_packet(
                                update_type=UpdateTypes.UPDATE_FULL,
                                is_self=False)))
                    self.session.request.sendall(update_packet)
                    self.session.request.sendall(
                        NameQueryHandler.get_query_details(player.player))
                self.objects_in_range[guid] = {'object': player, 'near': True}

        for guid, creature in creatures.items():
            if guid not in self.objects_in_range:
                update_packet = UpdatePacketFactory.compress_if_needed(
                    PacketWriter.get_packet(
                        OpCode.SMSG_UPDATE_OBJECT,
                        creature.get_update_packet(
                            update_type=UpdateTypes.UPDATE_FULL,
                            is_self=False)))
                self.session.request.sendall(update_packet)
                self.session.request.sendall(creature.query_details())
            self.objects_in_range[guid] = {'object': creature, 'near': True}

        for guid, gobject in gobjects.items():
            if guid not in self.objects_in_range:
                update_packet = UpdatePacketFactory.compress_if_needed(
                    PacketWriter.get_packet(
                        OpCode.SMSG_UPDATE_OBJECT,
                        gobject.get_update_packet(
                            update_type=UpdateTypes.UPDATE_FULL,
                            is_self=False)))
                self.session.request.sendall(update_packet)
                self.session.request.sendall(gobject.query_details())
            self.objects_in_range[guid] = {'object': gobject, 'near': True}

        for guid, object_info in list(self.objects_in_range.items()):
            if not object_info['near']:
                self.session.request.sendall(
                    self.objects_in_range[guid]['object'].get_destroy_packet())
                del self.objects_in_range[guid]
            else:
                self.objects_in_range[guid]['near'] = False
Пример #17
0
    def handle_ack(world_session, socket, reader):
        world_session.player_mgr.send_update_self(create=True)
        world_session.player_mgr.send_update_surrounding(world_session.player_mgr.generate_proper_update_packet(
            create=True), include_self=False, create=True)
        GridManager.update_object(world_session.player_mgr)

        world_session.player_mgr.is_teleporting = False

        return 0
Пример #18
0
    def send_move_to(self, waypoints, speed, spline_flag):
        self.reset()
        self.speed = speed

        start_time = int(WorldManager.get_seconds_since_startup() * 1000)

        data = pack('<Q12sIBI', self.unit.guid,
                    self.unit.location.to_bytes(include_orientation=False),
                    start_time, 0, spline_flag)

        waypoints_data = b''
        waypoints_length = len(waypoints)
        last_waypoint = self.unit.location
        total_distance = 0
        total_time = 0
        current_id = 0
        for waypoint in waypoints:
            waypoints_data += waypoint.to_bytes(include_orientation=False)
            current_distance = last_waypoint.distance(waypoint)
            current_time = current_distance / speed
            total_distance += current_distance
            total_time += current_time

            self.pending_waypoints.append(
                PendingWaypoint(current_id, total_time, waypoint))
            last_waypoint = waypoint
            current_id += 1

        data += pack('<2I%us' % len(waypoints_data), int(total_time * 1000),
                     waypoints_length, waypoints_data)

        GridManager.send_surrounding(PacketWriter.get_packet(
            OpCode.SMSG_MONSTER_MOVE, data),
                                     self.unit,
                                     include_self=self.is_player)

        # Player should dismount after some seconds have passed since FP destination is reached (Blizzlike).
        # This is also kind of a hackfix (at least for now) since the client always takes a bit more time to reach
        # the actual destination than the time you specify in SMSG_MONSTER_MOVE.
        if self.is_player and spline_flag == SplineFlags.SPLINEFLAG_FLYING:
            self.total_waypoint_time = total_time + (0.15 * waypoints_length)
        else:
            self.total_waypoint_time = total_time

        # Generate the spline
        spline = MovementSpline()
        spline.flags = spline_flag
        spline.spot = self.unit.location
        spline.guid = self.unit.guid
        spline.facing = self.unit.location.o
        spline.elapsed = 0
        spline.total_time = int(self.total_waypoint_time * 1000)
        spline.points = waypoints
        self.unit.movement_spline = spline

        self.last_position = self.unit.location
        self.should_update_waypoints = True
    def handle(world_session, socket, reader):
        if len(reader.data) >= 4:  # Avoid handling empty player macro packet
            category = unpack('<I', reader.data[:4])[0]
            if 0x0 <= category <= 0xD:
                voice_packet = PacketWriter.get_packet(OpCode.SMSG_PLAYER_MACRO,
                                                       pack('<QI', world_session.player_mgr.guid,
                                                            category))
                GridManager.send_surrounding(voice_packet, world_session.player_mgr, include_self=True)

        return 0
Пример #20
0
 def send_single_item_update(self, world_session, item, is_self):
     update_packet = UpdatePacketFactory.compress_if_needed(PacketWriter.get_packet(
         OpCode.SMSG_UPDATE_OBJECT, item.get_full_update_packet(is_self=False)))
     if is_self:
         world_session.request.sendall(update_packet)
         world_session.request.sendall(item.query_details())
     else:
         GridManager.send_surrounding(update_packet, world_session.player_mgr, include_self=False)
         GridManager.send_surrounding(item.query_details(), world_session.player_mgr,
                                      include_self=False)
Пример #21
0
    def send_move_to(self, waypoints, speed, spline_flag):
        self.reset()
        self.speed = speed

        start_time = int(WorldManager.get_seconds_since_startup() * 1000)

        location_bytes = self.unit.location.to_bytes(include_orientation=False)
        data = pack(f'<Q{len(location_bytes)}sIBI', self.unit.guid,
                    location_bytes, start_time, 0, spline_flag)

        waypoints_data = b''
        waypoints_length = len(waypoints)
        last_waypoint = self.unit.location
        total_distance = 0
        total_time = 0
        current_id = 0
        for waypoint in waypoints:
            waypoints_data += waypoint.to_bytes(include_orientation=False)
            current_distance = last_waypoint.distance(waypoint)
            current_time = current_distance / speed
            total_distance += current_distance
            total_time += current_time

            self.pending_waypoints.append(
                PendingWaypoint(current_id, total_time, waypoint))
            last_waypoint = waypoint
            current_id += 1

        data += pack(f'<2I{len(waypoints_data)}s', int(total_time * 1000),
                     waypoints_length, waypoints_data)

        GridManager.send_surrounding(PacketWriter.get_packet(
            OpCode.SMSG_MONSTER_MOVE, data),
                                     self.unit,
                                     include_self=self.is_player)

        # Player shouldn't instantly dismount after reaching the taxi destination
        if self.is_player and spline_flag == SplineFlags.SPLINEFLAG_FLYING:
            self.total_waypoint_time = total_time + 1.0  # Add 1 extra second
        else:
            self.total_waypoint_time = total_time

        # Generate the spline
        spline = MovementSpline()
        spline.flags = spline_flag
        spline.spot = self.unit.location
        spline.guid = self.unit.guid
        spline.facing = self.unit.location.o
        spline.elapsed = 0
        spline.total_time = int(self.total_waypoint_time * 1000)
        spline.points = waypoints
        self.unit.movement_spline = spline

        self.last_position = self.unit.location
        self.should_update_waypoints = True
Пример #22
0
    def handle(world_session, socket, reader):
        # TODO Not working, wrong packet data, or animation not implemented client side?
        player_guid = pack('<Q', world_session.player_mgr.guid)
        mount_anim_packet = PacketWriter.get_packet(
            OpCode.SMSG_MOUNTSPECIAL_ANIM, player_guid)
        GridManager.send_surrounding(PacketWriter.get_packet(
            OpCode.SMSG_TEXT_EMOTE, mount_anim_packet),
                                     world_session.player_mgr,
                                     include_self=True)

        return 0
Пример #23
0
 def deal_spell_damage(self, target, damage, school,
                       spell_id):  # TODO Spell hit damage visual?
     data = pack('<IQQIIfiii', 1, self.guid, target.guid, spell_id, damage,
                 damage, school, damage, 0)
     packet = PacketWriter.get_packet(
         OpCode.SMSG_ATTACKERSTATEUPDATEDEBUGINFOSPELL, data)
     GridManager.send_surrounding(
         packet,
         target,
         include_self=target.get_type() == ObjectTypes.TYPE_PLAYER)
     self.deal_damage(target, damage)
Пример #24
0
    def logout(self):
        # TODO: Temp hackfix until groups are saved in db
        if self.group_manager:
            self.group_manager.leave_party(
                self, force_disband=self.group_manager.party_leader == self)

        self.session.save_character()
        GridManager.remove_object(self)
        self.session.player_mgr = None
        self.session = None
        self.is_online = False
Пример #25
0
    def change_turn_speed(self, turn_speed=0):
        if turn_speed <= 0:
            turn_speed = config.Unit.Player.Defaults.turn_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))

        GridManager.send_surrounding(
            PacketWriter.get_packet(OpCode.SMSG_UPDATE_OBJECT,
                                    self.get_movement_update_packet()), self)
Пример #26
0
    def change_walk_speed(self, walk_speed=0):
        if walk_speed <= 0:
            walk_speed = config.Unit.Defaults.walk_speed
        elif walk_speed >= 56:
            walk_speed = 56  # Max speed without glitches
        self.walk_speed = walk_speed
        data = pack('<f', walk_speed)
        self.session.request.sendall(
            PacketWriter.get_packet(OpCode.MSG_MOVE_SET_WALK_SPEED, data))

        GridManager.send_surrounding(
            PacketWriter.get_packet(OpCode.SMSG_UPDATE_OBJECT,
                                    self.get_movement_update_packet()), self)
Пример #27
0
    def change_swim_speed(self, swim_speed=0):
        if swim_speed <= 0:
            swim_speed = config.Unit.Defaults.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))

        GridManager.send_surrounding(
            PacketWriter.get_packet(OpCode.SMSG_UPDATE_OBJECT,
                                    self.get_movement_update_packet()), self)
Пример #28
0
    def change_speed(self, speed=0):
        if speed <= 0:
            speed = config.Unit.Defaults.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))

        GridManager.send_surrounding(
            PacketWriter.get_packet(OpCode.SMSG_UPDATE_OBJECT,
                                    self.get_movement_update_packet()), self)
Пример #29
0
    def receive_damage(self, amount, source=None):
        is_player = self.get_type() == ObjectTypes.TYPE_PLAYER

        new_health = self.health - amount
        if new_health <= 0:
            self.die(killer=source)
        else:
            self.set_health(new_health)

        update_packet = self.generate_proper_update_packet(is_self=is_player)
        GridManager.send_surrounding(update_packet,
                                     self,
                                     include_self=is_player)
Пример #30
0
    def send_cast_start(self, casting_spell):
        data = [self.unit_mgr.guid, self.unit_mgr.guid,
                casting_spell.spell_entry.ID, 0, casting_spell.get_base_cast_time(),
                casting_spell.spell_target_mask]

        signature = '<2QIHiH'  # TODO
        if casting_spell.initial_target_unit and casting_spell.spell_target_mask != SpellTargetMask.SELF:  # Some self-cast spells crash client if target is written
            data.append(casting_spell.initial_target_unit.guid)
            signature += 'Q'

        data = pack(signature, *data)
        GridManager.send_surrounding(PacketWriter.get_packet(OpCode.SMSG_SPELL_START, data), self.unit_mgr,
                                     include_self=self.unit_mgr.get_type() == ObjectTypes.TYPE_PLAYER)