public void SetConversation(byte arg1, int npcId, string script, int delay, byte arg5, Align align) { if (npcId == 0) { IFieldActor <Player> player = Field.State.Players.Values.FirstOrDefault(); if (player is null) { return; } Field.BroadcastPacket(CinematicPacket.BalloonTalk(player.ObjectId, false, script, delay * 1000, 0)); return; } if (arg1 == 1) // Use npc object id? { Npc npc = Field.State.Npcs.Values.FirstOrDefault(x => x.SpawnPointId == npcId); if (npc is null) { return; } Field.BroadcastPacket(CinematicPacket.BalloonTalk(npc.ObjectId, false, script, delay * 1000, 0)); return; } Field.BroadcastPacket(CinematicPacket.Conversation(npcId, npcId.ToString(), script, delay * 1000, align)); }
public static void HandleEffect(GameSession session, SkillCast skillCast, int attackIndex) { Player player = session.Player; IFieldActor <Player> fieldPlayer = player.FieldPlayer; skillCast.EffectCoords = GetEffectCoords(skillCast, fieldPlayer.Coord, player.MapId, fieldPlayer.LookDirection, attackIndex); session.FieldManager.AddRegionSkillEffect(skillCast); Task removeEffectTask = RemoveEffects(session, skillCast); // TODO: Vibrate objects around skill if (skillCast.Interval <= 0) { HandleRegionSkill(session, skillCast); return; } // Task to loop trough all entities in range to do damage/heal Task.Run(async() => { while (!removeEffectTask.IsCompleted) { HandleRegionSkill(session, skillCast); // TODO: Find the correct delay for the skill await Task.Delay(skillCast.Interval); } }); }
public static PacketWriter RemoveNpc(IFieldActor <NpcMetadata> npc) { PacketWriter pWriter = PacketWriter.Of(SendOp.FieldRemoveNPC); pWriter.WriteInt(npc.ObjectId); return(pWriter); }
public void DestroyMonster(int[] rangeId, bool arg2) { foreach (int spawnPointId in rangeId) { MapEventNpcSpawnPoint spawnPoint = MapEntityStorage.GetMapEventNpcSpawnPoint(Field.MapId, spawnPointId); if (spawnPoint is null) { continue; } foreach (string npcId in spawnPoint.NpcIds) { if (!int.TryParse(npcId, out int id)) { continue; } IFieldActor <NpcMetadata> fieldNpc = Field.State.Npcs.Values.FirstOrDefault(x => x.Value.Id == id); if (fieldNpc is null) { continue; } Field.RemoveNpc(fieldNpc); } } }
public void MoveNpc(int spawnTriggerId, string patrolDataName) { (PatrolData, List <WayPoint>)patrolData = MapEntityStorage.GetPatrolData(Field.MapId, patrolDataName); MapEventNpcSpawnPoint spawnPoint = MapEntityStorage.GetMapEventNpcSpawnPoint(Field.MapId, spawnTriggerId); if (spawnPoint is null) { return; } foreach (string npcId in spawnPoint.NpcIds) { if (!int.TryParse(npcId, out int id)) { continue; } IFieldActor <NpcMetadata> fieldNpc = Field.State.Npcs.Values.FirstOrDefault(x => x.Value.Id == id); if (fieldNpc is null) { continue; } // Just setting the coord as the last waypoint for now, replace with moveTo later // fieldNpc.MoveTo(patrolData.Item2.Last().Position); fieldNpc.Coord = patrolData.Item2.Last().Position.ToFloat(); } }
private DamageHandler(IFieldActor source, IFieldActor target, double damage, HitType hitType) { Source = source; Target = target; Damage = damage; HitType = hitType; }
public static PacketWriter ControlNpc(IFieldActor <NpcMetadata> mob) { PacketWriter npcBuffer = new(); npcBuffer.WriteInt(mob.ObjectId); npcBuffer.WriteByte(); npcBuffer.Write(mob.Coord.ToShort()); npcBuffer.WriteShort(mob.LookDirection); npcBuffer.Write(mob.Velocity.ToShort()); // Target Position's Displacement npcBuffer.WriteShort(100); // Unknown if (mob.Value.IsBoss()) { npcBuffer.WriteInt(); // Player target id, only used for bosses. Agro? } npcBuffer.WriteByte(1); // Flag ? npcBuffer.WriteShort(mob.Animation); npcBuffer.WriteShort(1); // counter (increments every packet) // There can be more to this packet, probably dependent on Flag. PacketWriter pWriter = PacketWriter.Of(SendOp.NpcControl); pWriter.WriteShort(1); // Segments pWriter.WriteShort((short)npcBuffer.Length); pWriter.WriteBytes(npcBuffer.ToArray()); return(pWriter); }
public static PacketWriter AddNpc(IFieldActor <NpcMetadata> npc) { PacketWriter pWriter = PacketWriter.Of(SendOp.FieldAddNPC); pWriter.WriteInt(npc.ObjectId); pWriter.WriteInt(npc.Value.Id); pWriter.Write(npc.Coord); pWriter.Write(npc.Rotation); if (npc.Value.IsBoss()) { pWriter.WriteString(npc.Value.NpcMetadataModel.Model); } // If NPC is not valid, the packet seems to stop here pWriter.DefaultStatsMob(npc); pWriter.WriteByte(); short count = 0; pWriter.WriteShort(count); for (int i = 0; i < count; i++) { pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); // usually 90000814 (skill id)?? pWriter.WriteShort(); pWriter.WriteInt(); pWriter.WriteByte(); pWriter.WriteLong(); } pWriter.WriteLong(); pWriter.WriteByte(); pWriter.WriteInt(npc.Value.Level); if (npc.Value.IsBoss()) { pWriter.WriteInt(); pWriter.WriteUnicodeString(); int skillCount = 0; pWriter.WriteInt(skillCount); for (int i = 0; i < skillCount; i++) { pWriter.WriteInt(); // skill id pWriter.WriteShort(); // skill level } } pWriter.WriteInt(); pWriter.WriteByte(); return(pWriter); }
public static DamageHandler CalculateDamage(SkillCast skill, IFieldActor <Player> source, IFieldActor target) { if (source.Value.GmFlags.Contains("oneshot")) { return(new(source, target, target.Stats[StatAttribute.Hp].Total, HitType.Critical)); } // get luck coefficient from class. new stat recommended, can be refactored away like isCrit was return(CalculateDamage(skill, source, target, 1)); }
public static PacketWriter Save(IFieldActor <Player> fieldPlayer, HashSet <int> newSkillIds = null) { PacketWriter pWriter = PacketWriter.Of(SendOp.Job); pWriter.WriteInt(fieldPlayer.ObjectId); pWriter.Write(JobMode.Save); pWriter.WriteJobInfo(fieldPlayer.Value, newSkillIds); return(pWriter); }
public static void DefaultStatsMob(this PacketWriter pWriter, IFieldActor mob) { pWriter.Write(StatsMode.SendStats); pWriter.WriteLong(mob.Stats[StatId.Hp].Bonus); pWriter.WriteInt(100); // Move speed (?) pWriter.WriteLong(mob.Stats[StatId.Hp].Base); pWriter.WriteInt(100); // Move speed (?) pWriter.WriteLong(mob.Stats[StatId.Hp].Total); pWriter.WriteInt(100); // Move speed (?) }
public static PacketWriter Close(IFieldActor <Player> fieldPlayer) { PacketWriter pWriter = PacketWriter.Of(SendOp.Job); pWriter.WriteInt(fieldPlayer.ObjectId); pWriter.Write(JobMode.Close); pWriter.WriteJobInfo(fieldPlayer.Value); return(pWriter); }
public static PacketWriter UpdateFieldStats(IFieldActor <Player> player) { PacketWriter pWriter = PacketWriter.Of(SendOp.STAT); pWriter.WriteInt(player.ObjectId); pWriter.WriteByte(); // Unknown (0x00/0x01) pWriter.Write(StatsMode.SendStats); pWriter.WriteFieldStats(player.Stats); return(pWriter); }
public static PacketWriter UpdateMobStats(IFieldActor mob) { PacketWriter pWriter = PacketWriter.Of(SendOp.STAT); pWriter.WriteInt(mob.ObjectId); pWriter.WriteByte(); pWriter.WriteByte(1); pWriter.Write(StatsMode.UpdateMobStats); pWriter.WriteStat(mob.Stats, StatId.Hp); return(pWriter); }
private static void HandleCast(GameSession session, PacketReader packet) { long skillSN = packet.ReadLong(); int serverTick = packet.ReadInt(); int skillId = packet.ReadInt(); short skillLevel = packet.ReadShort(); byte attackPoint = packet.ReadByte(); CoordF position = packet.Read <CoordF>(); CoordF direction = packet.Read <CoordF>(); CoordF rotation = packet.Read <CoordF>(); packet.ReadFloat(); int clientTick = packet.ReadInt(); packet.ReadBool(); packet.ReadLong(); bool flag = packet.ReadBool(); if (flag) { packet.ReadInt(); string unkString = packet.ReadUnicodeString(); } IFieldActor <Player> fieldPlayer = session.Player.FieldPlayer; SkillCast skillCast = new(skillId, skillLevel, skillSN, serverTick, fieldPlayer.ObjectId, clientTick, attackPoint) { Position = position, Direction = direction, Rotation = rotation, LookDirection = fieldPlayer.LookDirection }; /* HOW TO HANDLE ADDITIONAL EFFECTS BY MAYGI: * when handling an additional effect: + loop through all SkillMotion items in the skill ++ loop through all SkillAttacks in the attacks in the SkillMotion +++ grab a list of ConditionSkills from each SkillAttack +++ check for a cube magic path id on each SkillAttack and handle it if it exists ++++ if a cube magic path exists, you can grab a ConditionSkill reference from any index of the list, it doesn't matter in this case ++++ handle magic path move processing for square based abilities +++ loop through all ConditionSkills ++++ loop through all SkillData on each ConditionSkill and check the SkillInfo on each Condition Skill ID +++++ check if each SkillInfo has an additional skill ++++++ if an additional skill exists, check the proc and requirements (proc is a chance, requirement is a buff ID), and determine whether or not to proc additional effects for said proc) + also handle Splash Skills which trigger region effects */ // TODO: Check BeginCondition fieldPlayer.Cast(skillCast); }
public override void Execute(GameCommandTrigger trigger) { Player player = trigger.Session.Player; IFieldActor <Player> fieldPlayer = player.FieldPlayer; FieldManager fieldManager = trigger.Session.FieldManager; bool mapIsHome = player.MapId == (int)Map.PrivateResidence; if (!mapIsHome) { return; } Home home = GameServer.HomeManager.GetHomeById(player.VisitingHomeId); if (home.AccountId != player.AccountId) { return; } IFieldObject <GuideObject> ballObject = fieldManager.State.Guide.Values.FirstOrDefault(x => x.Value.IsBall); if (ballObject is not null) { fieldManager.RemoveGuide(ballObject); fieldManager.BroadcastPacket(HomeActionPacket.RemoveBall(ballObject)); return; } int size = trigger.Get <int>("size"); size = Math.Min(30 + size * 30, 330); if (size < 0) { size = 60; } GuideObject ball = new(0, player.CharacterId) { IsBall = true }; IFieldObject <GuideObject> fieldObject = fieldManager.RequestFieldObject(ball); fieldObject.Coord = CoordF.From(fieldPlayer.Coord.X, fieldPlayer.Coord.Y, fieldPlayer.Coord.Z + Block.BLOCK_SIZE * 2); fieldObject.Rotation = CoordF.From(0, 0, size); fieldManager.AddGuide(fieldObject); fieldManager.BroadcastPacket(HomeActionPacket.AddBall(fieldObject)); } }
public static PacketWriter Pickup(IFieldActor <Player> fieldPlayer, int weaponId, CoordB coords) { PacketWriter pWriter = PacketWriter.Of(SendOp.ResponseCube); pWriter.Write(ResponseCubePacketMode.Pickup); pWriter.WriteZero(1); pWriter.WriteInt(fieldPlayer.ObjectId); pWriter.Write(coords); pWriter.WriteZero(1); pWriter.WriteInt(weaponId); pWriter.WriteInt(GuidGenerator.Int()); // Item uid return(pWriter); }
public static PacketWriter SetStats(IFieldActor <Player> player) { PacketWriter pWriter = PacketWriter.Of(SendOp.STAT); pWriter.WriteInt(player.ObjectId); pWriter.WriteByte(); // Unknown (0x00/0x01) pWriter.Write(StatsMode.SendStats); foreach ((StatId statId, Stat _) in player.Stats.Data) { pWriter.WriteStat(player.Stats, statId); } return(pWriter); }
/// <summary> /// Update specific stats. /// </summary> public static PacketWriter UpdateStats(IFieldActor actor, params StatAttribute[] attributes) { PacketWriter pWriter = PacketWriter.Of(SendOp.Stat); pWriter.WriteInt(actor.ObjectId); pWriter.WriteByte(); // Unknown when to use 0 or 1 pWriter.WriteByte((byte)attributes.Length); foreach (StatAttribute attribute in attributes) { pWriter.WriteByte((byte)attribute); pWriter.WriteStat(attribute, actor.Stats[attribute]); } return(pWriter); }
private static void HandlePickUp(GameSession session, PacketReader packet) { string id = packet.ReadString(); IFieldActor <Player> fieldPlayer = session.Player.FieldPlayer; if (id.Contains('_')) { string coordHexa = long.Parse(id.Split('_')[1]).ToString("X2"); if (coordHexa.Length == 5) { coordHexa = "0" + coordHexa; } CoordB coordB = CoordB.From( (sbyte)Convert.ToByte(coordHexa[4..], 16),
/// <summary> /// Update all stats. /// </summary> public static PacketWriter SetStats(IFieldActor actor) { PacketWriter pWriter = PacketWriter.Of(SendOp.Stat); pWriter.WriteInt(actor.ObjectId); pWriter.WriteByte(); // Unknown (0x00/0x01) pWriter.Write(StatsMode.SendAllStats); for (int i = 0; i < (int)StatsMode.SendAllStats; i++) { StatAttribute statAttribute = (StatAttribute)i; pWriter.WriteStat(statAttribute, actor.Stats.Data[statAttribute]); } return(pWriter); }
public static PacketWriter UpdateStats(IFieldActor <Player> player, IEnumerable <StatId> statIds) { PacketWriter pWriter = PacketWriter.Of(SendOp.STAT); pWriter.WriteInt(player.ObjectId); pWriter.Write(StatsMode.UpdateStats); pWriter.WriteByte((byte)statIds.Count()); foreach (StatId statId in statIds) { pWriter.Write(statId); pWriter.WriteStat(player.Stats, statId); } return(pWriter); }
public static PacketWriter RequestEnter(IFieldActor <Player> fieldPlayer) { PacketWriter pWriter = PacketWriter.Of(SendOp.REQUEST_FIELD_ENTER); pWriter.WriteByte(); pWriter.WriteInt(fieldPlayer.Value.MapId); pWriter.WriteByte(); pWriter.WriteByte(); pWriter.WriteInt(); pWriter.WriteInt(); pWriter.Write(fieldPlayer.Coord); pWriter.Write(fieldPlayer.Rotation); pWriter.WriteInt(); // Whatever is here seems to be repeated by client in FIELD_ENTER response. return(pWriter); }
public static PacketWriter UpdatePlayer(IFieldActor <Player> player) { FieldObjectUpdate flag = FieldObjectUpdate.Move | FieldObjectUpdate.Animate; PacketWriter pWriter = PacketWriter.Of(SendOp.FIELD_OBJECT); pWriter.Write(FieldObjectMode.UpdateEntity); pWriter.WriteInt(player.ObjectId); pWriter.WriteByte((byte)flag); if (flag.HasFlag(FieldObjectUpdate.Type1)) { pWriter.WriteByte(); } if (flag.HasFlag(FieldObjectUpdate.Move)) { pWriter.Write(player.Coord); } if (flag.HasFlag(FieldObjectUpdate.Level)) { pWriter.WriteShort(player.Value.Levels.Level); } if (flag.HasFlag(FieldObjectUpdate.Type4)) { pWriter.WriteShort(); pWriter.WriteInt(); } if (flag.HasFlag(FieldObjectUpdate.Type5)) { pWriter.WriteUnicodeString("Unknown"); } if (flag.HasFlag(FieldObjectUpdate.Type6)) { pWriter.WriteInt(); } if (flag.HasFlag(FieldObjectUpdate.Animate)) { pWriter.WriteShort(player.Animation); } return(pWriter); }
private static bool RollCrit(IFieldActor source, IFieldActor target, double luckCoefficient) { // used to weigh crit rate in the formula, like how class luck coefficients weigh luck const double CritConstant = 5.3; // used to convert a percent value to a decimal value const double PercentageConversion = 0.015; const double MaxCritRate = 0.4; double luck = source.Stats[StatAttribute.Luk].Total * luckCoefficient; double critRate = source.Stats[StatAttribute.CritRate].Total * CritConstant; double critEvasion = Math.Max(target.Stats[StatAttribute.CritEvasion].Total, 1) * 2; double critChance = Math.Min(critRate / critEvasion * PercentageConversion, MaxCritRate); return(Random.Shared.Next(1000) < 1000 * critChance); }
public static PacketWriter UpdateStats(IFieldActor player, StatId statId, params StatId[] otherIds) { PacketWriter pWriter = PacketWriter.Of(SendOp.STAT); pWriter.WriteInt(player.ObjectId); pWriter.Write(StatsMode.UpdateStats); pWriter.WriteByte((byte)(1 + otherIds.Length)); pWriter.Write(statId); pWriter.WriteStat(player.Stats, statId); foreach (StatId otherId in otherIds) { pWriter.Write(otherId); pWriter.WriteStat(player.Stats, statId); } return(pWriter); }
public static PacketWriter AddBoss(IFieldActor <NpcMetadata> mob) { PacketWriter pWriter = PacketWriter.Of(SendOp.FIELD_ADD_NPC); pWriter.WriteInt(mob.ObjectId); pWriter.WriteInt(mob.Value.Id); pWriter.Write(mob.Coord); pWriter.Write(mob.Rotation); pWriter.WriteString(mob.Value.Model); // StrA - kfm model string // If NPC is not valid, the packet seems to stop here pWriter.DefaultStatsMob(mob); pWriter.WriteByte(); pWriter.WriteLong(); pWriter.WriteLong(); pWriter.WriteInt(); pWriter.WriteByte(); short count = 0; pWriter.WriteShort(count); for (int i = 0; i < count; i++) { pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); pWriter.WriteInt(); // usually 90000814 (skill id)?? pWriter.WriteShort(); pWriter.WriteInt(); pWriter.WriteByte(); pWriter.WriteLong(); } pWriter.WriteLong(); pWriter.WriteByte(); pWriter.WriteInt(1); pWriter.WriteInt(); pWriter.WriteByte(); return(pWriter); }
public static void UpdatePlayer(GameSession session, SyncState[] syncStates) { Player player = session.Player; IFieldActor <Player> fieldPlayer = player.FieldPlayer; CoordF coord = syncStates[0].Coord.ToFloat(); CoordF coordUnderneath = coord; coordUnderneath.Z -= 50; CoordF blockUnderneath = Block.ClosestBlock(coordUnderneath); if (IsCoordSafe(player, syncStates[0].Coord, blockUnderneath)) { CoordF safeBlock = Block.ClosestBlock(coord); // TODO: Knowing the state of the player using the animation is probably not the correct way to do this // we will need to know the state of the player for other things like counting time spent on ropes/running/walking/swimming if (syncStates[0].Animation2 is 7 or 132) // swimming { safeBlock.Z += Block.BLOCK_SIZE; // Without this player will spawn under the water } safeBlock.Z += 10; // Without this player will spawn inside the block player.SafeBlock = safeBlock; } fieldPlayer.Coord = coord; fieldPlayer.Rotation = new() { Z = syncStates[0].Rotation / 10 }; if (IsOutOfBounds(fieldPlayer.Coord, session.FieldManager.BoundingBox)) { player.Move(player.SafeBlock, fieldPlayer.Rotation); player.FallDamage(); } // not sure if this needs to be synced here fieldPlayer.Animation = syncStates[0].BoreAnimation; }
public static PacketWriter AddMob(IFieldActor <NpcMetadata> mob) { PacketWriter pWriter = PacketWriter.Of(SendOp.FIELD_ADD_NPC); pWriter.WriteInt(mob.ObjectId); pWriter.WriteInt(mob.Value.Id); pWriter.Write(mob.Coord); pWriter.Write(mob.Rotation); // If NPC is not valid, the packet seems to stop here pWriter.DefaultStatsMob(mob); pWriter.WriteLong(); pWriter.WriteInt(); pWriter.WriteInt(0x0E); // NPC level pWriter.WriteInt(); pWriter.WriteByte(); return(pWriter); }
public static PacketWriter ControlNpc(IFieldActor <NpcMetadata> npc) { PacketWriter npcBuffer = new(); npcBuffer.WriteInt(npc.ObjectId); npcBuffer.WriteByte(); npcBuffer.Write(npc.Coord.ToShort()); npcBuffer.WriteShort(npc.LookDirection); npcBuffer.Write(npc.Velocity.ToShort()); // Target Position's Displacement npcBuffer.WriteShort(100); // Unknown npcBuffer.WriteByte(1); // Flag ? npcBuffer.WriteShort(npc.Animation); npcBuffer.WriteShort(1); // counter (increments every packet) // There can be more to this packet, probably dependent on Flag. PacketWriter pWriter = PacketWriter.Of(SendOp.NPC_CONTROL); pWriter.WriteShort(1); // Segments pWriter.WriteShort((short)npcBuffer.Length); pWriter.WriteBytes(npcBuffer.ToArray()); return(pWriter); }