public static PacketWriter SyncDamage(long skillSN, CoordF position, CoordF rotation, IFieldObject <Player> player, List <int> sourceId, byte count, List <int> atkCount, List <int> entityId, List <short> animation) { PacketWriter pWriter = PacketWriter.Of(SendOp.SKILL_DAMAGE); SkillCast skillCast = SkillUsePacket.SkillCastMap[skillSN]; pWriter.Write(SkillDamageMode.SyncDamage); pWriter.WriteLong(skillSN); pWriter.WriteInt(player.ObjectId); pWriter.WriteInt(skillCast.SkillId); pWriter.WriteShort(skillCast.SkillLevel); pWriter.WriteByte(skillCast.MotionPoint); pWriter.WriteByte(skillCast.AttackPoint); pWriter.Write(position.ToShort()); pWriter.Write(rotation); pWriter.WriteByte(); pWriter.WriteInt(skillCast.ServerTick); pWriter.WriteByte(count); for (int i = 0; i < count; i++) { pWriter.WriteLong(); pWriter.WriteInt(atkCount[i]); pWriter.WriteInt(sourceId[i]); pWriter.WriteInt(entityId[i]); // objectId of the Impact pWriter.WriteShort(animation[i]); pWriter.WriteByte(); pWriter.WriteByte(); } return(pWriter); }
public static PacketWriter Damage(long skillSN, int unkValue, CoordF position, CoordF rotation, IFieldObject <Player> player, IEnumerable <DamageHandler> effects) { PacketWriter pWriter = PacketWriter.Of(SendOp.SKILL_DAMAGE); SkillCast skillCast = SkillUsePacket.SkillCastMap[skillSN]; pWriter.Write(SkillDamageMode.Damage); pWriter.WriteLong(skillSN); pWriter.WriteInt(unkValue); pWriter.WriteInt(player.ObjectId); pWriter.WriteInt(player.ObjectId); pWriter.WriteInt(skillCast.SkillId); pWriter.WriteShort(skillCast.SkillLevel); // This values appears on some SkillsId, and others like BossSkill, sometimes is 0 pWriter.WriteByte(skillCast.MotionPoint); // The value is not always 0 pWriter.WriteByte(skillCast.AttackPoint); // The value is not always 0, also seems to crash if its not a correct value pWriter.Write(position.ToShort()); pWriter.Write(rotation.ToShort()); // Position of the image effect of the skillUse, seems to be rotation (0, 0, rotation). // TODO: Check if is a player or mob pWriter.WriteByte((byte)effects.Count()); foreach (DamageHandler effect in effects) { pWriter.WriteInt(effect.Target.ObjectId); pWriter.WriteBool(effect.Damage > 0); pWriter.WriteBool(effect.IsCrit); if (effect.Damage != 0) { pWriter.WriteLong(-1 * (long)effect.Damage); } } return(pWriter); }
public static Packet ApplyDamage(IFieldObject <Player> player, long skillSN, int unkValue, CoordF coords, List <IFieldObject <Mob> > mobs) { PacketWriter pWriter = PacketWriter.Of(SendOp.SKILL_DAMAGE); SkillCast skillCast = SkillUsePacket.SkillCastMap[skillSN]; DamageHandler damage = DamageHandler.CalculateSkillDamage(skillCast); pWriter.WriteByte(1); pWriter.WriteLong(skillSN); pWriter.WriteInt(unkValue); pWriter.WriteInt(player.ObjectId); pWriter.WriteInt(player.ObjectId); pWriter.WriteInt(skillCast.SkillId); pWriter.WriteShort(skillCast.SkillLevel); // This values appears on some SkillsId, and others like BossSkill, sometimes is 0 pWriter.WriteByte(); // The value is not always 0 pWriter.WriteByte(); // The value is not always 0, also seems to crash if its not a correct value pWriter.Write(coords.ToShort()); pWriter.Write(CoordS.From(0, 0, 0)); // Position of the image effect of the skillUse, seems to be rotation (0, 0, rotation). // TODO: Check if is a player or mob pWriter.WriteByte((byte)mobs.Count); for (int i = 0; i < mobs.Count; i++) { pWriter.WriteInt(mobs[i].ObjectId); pWriter.WriteByte((byte)damage.GetDamage() > 0 ? 1 : 0); pWriter.WriteBool(damage.IsCritical()); if (damage.GetDamage() != 0) { pWriter.WriteLong(-1 * (long)damage.GetDamage()); } } return(pWriter); }
private static bool IsCoordSafe(Player player, CoordS currentCoord, CoordF closestCoord) { // Check if current coord is safe to be used as a return point when the character falls off the map return(MapMetadataStorage.BlockExists(player.MapId, closestCoord.ToShort()) && !player.OnAirMount && (player.SafeBlock - closestCoord).Length() > 350 && player.FieldPlayer.Coord.Z == currentCoord.Z); }
public static Packet ApplyDamage(IFieldObject <Player> player, long skillUid, int someValue, CoordF coords, List <IFieldObject <Mob> > mobs) { PacketWriter pWriter = PacketWriter.Of(SendOp.SKILL_DAMAGE); pWriter.WriteByte(1); pWriter.WriteLong(skillUid); pWriter.WriteInt(someValue); pWriter.WriteInt(player.ObjectId); pWriter.WriteInt(player.ObjectId); pWriter.WriteInt(player.Value.ActiveSkillId); pWriter.WriteInt(player.Value.ActiveSkillLevel); pWriter.Write(coords.ToShort()); pWriter.Write(CoordS.From(0, 0, 0)); /*pWriter.WriteInt(0); // Set as Int because 2 bytes after will set something. * pWriter.WriteByte(0); // Define is (59 heal) or (9 damage). Not always the case * pWriter.WriteByte(0); // Unknown - count?*/ pWriter.WriteByte((byte)mobs.Count); // Mob count for (int i = 0; i < mobs.Count; i++) { pWriter.WriteInt(mobs[i].ObjectId); pWriter.WriteByte(1); // Unknown pWriter.WriteBool(false); // Crit flag pWriter.WriteLong(-1 * 1); // TODO: Calculate damage } return(pWriter); }
private static bool IsCoordSafe(GameSession session, CoordS currentCoord, CoordF closestCoord) { // Save last coord if player is not falling and not in a air mount return(MapMetadataStorage.BlockExists(session.Player.MapId, closestCoord.ToShort()) && !session.Player.OnAirMount && (session.Player.SafeBlock - closestCoord).Length() > 350 && session.FieldPlayer.Coord.Z == currentCoord.Z); }
private static MapBlock ScanZAxisForLiquidBlock(CoordF checkBlock, int mapId) { for (int zAxis = 0; zAxis < 3; zAxis++) { if (MapMetadataStorage.BlockAboveExists(mapId, checkBlock.ToShort())) { return(null); } MapBlock block = MapMetadataStorage.GetMapBlock(mapId, checkBlock.ToShort()); if (block == null || !IsLiquidBlock(block)) { checkBlock.Z -= Block.BLOCK_SIZE; continue; } return(block); } return(null); }
public static Packet SkillUse(SkillCast skillCast, CoordF position, CoordF direction, CoordF rotation, int entityId) { SkillCastMap[skillCast.SkillSN] = skillCast; PacketWriter pWriter = PacketWriter.Of(SendOp.SKILL_USE); pWriter.WriteLong(skillCast.SkillSN); pWriter.WriteInt(skillCast.ServerTick); pWriter.WriteInt(entityId); pWriter.WriteInt(skillCast.SkillId); pWriter.WriteShort(skillCast.SkillLevel); pWriter.WriteByte(); pWriter.Write(position.ToShort()); pWriter.Write(direction); pWriter.Write(rotation); // rotation pWriter.WriteShort(); pWriter.WriteByte(); pWriter.WriteByte(); return(pWriter); }
public static PacketWriter Damage(SkillCast skillCast, int attackCount, CoordF position, CoordF rotation, List <DamageHandler> damages) { PacketWriter pWriter = PacketWriter.Of(SendOp.SkillDamage); pWriter.Write(SkillDamageMode.Damage); pWriter.WriteLong(skillCast.SkillSn); pWriter.WriteInt(attackCount); pWriter.WriteInt(skillCast.CasterObjectId); pWriter.WriteInt(skillCast.CasterObjectId); pWriter.WriteInt(skillCast.SkillId); pWriter.WriteShort(skillCast.SkillLevel); // This values appears on some SkillsId, and others like BossSkill, sometimes is 0 pWriter.WriteByte(skillCast.MotionPoint); // The value is not always 0 pWriter.WriteByte(skillCast.AttackPoint); // The value is not always 0, also seems to crash if its not a correct value pWriter.Write(position.ToShort()); pWriter.Write(rotation.ToShort()); // TODO: Check if is a player or mob pWriter.WriteByte((byte)damages.Count); foreach (DamageHandler handler in damages) { pWriter.WriteInt(handler.Target.ObjectId); bool flag = handler.Damage > 0; pWriter.WriteBool(flag); if (!flag) { continue; } pWriter.Write(handler.HitType); pWriter.WriteLong(-1 * (long)handler.Damage); } return(pWriter); }
private static void HandleCatch(GameSession session, PacketReader packet) { bool success = packet.ReadBool(); CoordF guideBlock = Block.ClosestBlock(session.Player.Guide.Coord); guideBlock.Z -= Block.BLOCK_SIZE; // get liquid block coord MapBlock block = MapMetadataStorage.GetMapBlock(session.Player.MapId, guideBlock.ToShort()); List <FishMetadata> fishes = FishMetadataStorage.GetValidFishes(session.Player.MapId, block.Attribute); //determine fish rarity List <FishMetadata> selectedFishRarities = FilterFishesByRarity(fishes); Random rnd = RandomProvider.Get(); int randomFishIndex = rnd.Next(selectedFishRarities.Count); FishMetadata fish = selectedFishRarities[randomFishIndex]; //determine fish size int fishSize = rnd.NextDouble() switch {
/// <summary> /// Get the coordinates of the skill's effect, if needed change the offset to match the direction of the player. /// For skills that paint the ground, match the correct height. /// </summary> private static List <CoordF> GetEffectCoords(SkillCast skillCast, int mapId, int attackIndex) { SkillAttack skillAttack = skillCast.SkillAttack; List <MagicPathMove> cubeMagicPathMoves = new(); List <MagicPathMove> magicPathMoves = new(); if (skillAttack.CubeMagicPathId != 0) { cubeMagicPathMoves.AddRange(MagicPathMetadataStorage.GetMagicPath(skillAttack.CubeMagicPathId)?.MagicPathMoves ?? new()); } if (skillAttack.MagicPathId != 0) { magicPathMoves.AddRange(MagicPathMetadataStorage.GetMagicPath(skillAttack.MagicPathId)?.MagicPathMoves ?? new()); } int skillMovesCount = cubeMagicPathMoves.Count + magicPathMoves.Count; List <CoordF> effectCoords = new(); if (skillMovesCount <= 0) { effectCoords.Add(skillCast.Position); return(effectCoords); } // TODO: Handle case where magicPathMoves and cubeMagicPathMoves counts are > 0 // Basically do the next if, with the later for loop if (magicPathMoves.Count > 0) { MagicPathMove magicPathMove = magicPathMoves[attackIndex]; IFieldActor <NpcMetadata> parentSkillTarget = skillCast.ParentSkill.Target; if (parentSkillTarget is not null) { effectCoords.Add(parentSkillTarget.Coord); return(effectCoords); } // Rotate the offset coord and distance based on the look direction CoordF rotatedOffset = CoordF.From(magicPathMove.FireOffsetPosition.Length(), skillCast.LookDirection); CoordF distance = CoordF.From(magicPathMove.Distance, skillCast.LookDirection); // Create new effect coord based on offset rotation and distance effectCoords.Add(rotatedOffset + distance + skillCast.Position); return(effectCoords); } // Adjust the effect on the destination/cube foreach (MagicPathMove cubeMagicPathMove in cubeMagicPathMoves) { CoordF offSetCoord = cubeMagicPathMove.FireOffsetPosition; // If false, rotate the offset based on the look direction. Example: Wizard's Tornado if (!cubeMagicPathMove.IgnoreAdjust) { // Rotate the offset coord based on the look direction CoordF rotatedOffset = CoordF.From(offSetCoord.Length(), skillCast.LookDirection); // Create new effect coord based on offset rotation and source coord effectCoords.Add(rotatedOffset + skillCast.Position); continue; } offSetCoord += Block.ClosestBlock(skillCast.Position); CoordS tempBlockCoord = offSetCoord.ToShort(); // Set the height to the max allowed, which is one block above the cast coord. tempBlockCoord.Z += Block.BLOCK_SIZE * 2; // Find the first block below the effect coord int distanceToNextBlockBelow = MapMetadataStorage.GetDistanceToNextBlockBelow(mapId, offSetCoord.ToShort(), out MapBlock blockBelow); // If the block is null or the distance from the cast effect Z height is greater than two blocks, continue if (blockBelow is null || distanceToNextBlockBelow > Block.BLOCK_SIZE * 2) { continue; } // If there is a block above, continue if (MapMetadataStorage.BlockAboveExists(mapId, blockBelow.Coord)) { continue; } // If block is liquid, continue if (MapMetadataStorage.IsLiquidBlock(blockBelow)) { continue; } // Since this is the block below, add 150 units to the Z coord so the effect is above the block offSetCoord = blockBelow.Coord.ToFloat(); offSetCoord.Z += Block.BLOCK_SIZE; effectCoords.Add(offSetCoord); } return(effectCoords); }
public static void Handle(GameSession session, int sourceId, CoordF coords, SkillCast skillCast) { session.FieldManager.BroadcastPacket(RegionSkillPacket.Send(sourceId, coords.ToShort(), skillCast)); Remove(session, skillCast, sourceId); }