public static void HandleSummonMove(Character chr, Packet packet) { var skillId = packet.ReadInt(); if (chr.Summons.GetSummon(skillId, out var summon)) { var movePath = new MovePath(); movePath.DecodeFromPacket(packet, MovePath.MovementSource.Summon); chr.TryTraceMovement(movePath); PacketHelper.ValidateMovePath(summon, movePath); SendMoveSummon(chr, summon, movePath); } }
public static void HandleMove(Character chr, Packet packet) { if (packet.ReadByte() != chr.PortalCount) { return; } var movePath = new MovePath(); movePath.DecodeFromPacket(packet, MovePath.MovementSource.Player); chr.TryTraceMovement(movePath); if (chr.AssertForHack(movePath.Elements.Length == 0, "Received Empty Move Path")) { return; } bool allowed = PacketHelper.ValidateMovePath(chr, movePath); if (!allowed && !chr.IsGM) { //this.Session.Socket.Shutdown(System.Net.Sockets.SocketShutdown.Both); //return; // TODO: Update speed of character // Program.MainForm.LogAppendFormat("Move incorrect: {0}", chr.Name); } SendPlayerMove(chr, movePath); if (!chr.Field.ReallyOutOfBounds.Contains(chr.Position.X, chr.Position.Y)) { if (chr.OutOfMBRCount++ > 5) { // Okay, reset. chr.ChangeMap(chr.MapID, chr.Field.GetClosestStartPoint(chr.Position)); chr.OutOfMBRCount = 0; } } else { chr.OutOfMBRCount = 0; } }
public static void HandleMovePet(Character chr, Packet packet) { // 48 00 00 00 00 03 00 00 00 D1 00 00 00 9E 02 00 00 06 E0 01 00 00 00 D7 00 00 00 00 00 00 00 06 09 00 00 00 00 D7 00 00 00 00 00 88 00 04 15 00 00 var petItem = chr.GetSpawnedPet(); if (petItem == null) { return; } var movePath = new MovePath(); movePath.DecodeFromPacket(packet, MovePath.MovementSource.Pet); chr.TryTraceMovement(movePath); PacketHelper.ValidateMovePath(petItem.MovableLife, movePath); SendMovePet(chr, movePath); }
public static void HandleMobControl(Character victim, Packet packet) { int mobid = packet.ReadInt(); var mob = victim.Field.GetMob(mobid); short moveID = packet.ReadShort(); var x = packet.ReadByte(); bool bNextAttackPossible = (x & 0x0F) != 0; sbyte action = packet.ReadSByte(); int actualAction = action < 0 ? -1 : (byte)(action >> 1); uint dwData = packet.ReadUInt(); var movePath = new MovePath(); movePath.DecodeFromPacket(packet, MovePath.MovementSource.Mob); if (mob == null) { return; } if (mob.Controller != victim && (!bNextAttackPossible || mob.NextAttackPossible || !mob.Field.FindNewController(mob, victim, true))) { SendMobRequestEndControl(victim, mobid); return; } victim.TryTraceMovement(movePath); if (mob.Controller != null && victim.ID != mob.Controller.ID) { Program.MainForm.LogAppend("returning mobpacket"); return; } var lastMoveMillis = MasterThread.CurrentTime - mob.LastMove; bool justStartedControlling = (MasterThread.CurrentTime - mob.LastControllerAssignTime) < 2000; PacketHelper.ValidateMovePath(mob, movePath); //Program.MainForm.LogDebug("[" + DateTime.Now.ToString() + "]" + "Received movement packet from " + victim.Name + ". Original pos: x:" + movePath.OriginalPosition.X + " y: " + movePath.OriginalPosition.Y + "\r\nNew position: x: " + movePath.NewPosition.X + " y: " + movePath.NewPosition.Y); // Skill related? if (actualAction >= 21 && actualAction <= 25) { short attackDelay = (short)(dwData >> 16); byte level = (byte)(dwData >> 8); byte skillId = (byte)(dwData); if (mob.DoSkill(skillId, level, attackDelay) == false) { // invalid return; } } else if (actualAction > 12 && actualAction < 20) { // regular attack? var attackIdx = (byte)(actualAction - 12); if (mob.Data.Attacks == null || !mob.Data.Attacks.ContainsKey(attackIdx)) { Program.MainForm.LogAppend( "Unknown attack for mob: " + mob.MobID + "; " + attackIdx + "; " + packet); } else { var attack = mob.Data.Attacks[attackIdx]; mob.MP = Math.Max(0, mob.MP - attack.MPConsume); mob.LastAttack = MasterThread.CurrentTime; } } if ((MasterThread.CurrentTime - mob.LastAttack) > 5000) { // Reassign controller! MobDamageInfo lastHitCharacter; if (mob.IsControlled) { var currentControllerID = mob.Controller.ID; lastHitCharacter = mob.DamageLog.Log.FirstOrDefault(mobDamageInfo => { if (mobDamageInfo.CharacterID == currentControllerID) { return(false); } if (mob.Field.GetPlayer(mobDamageInfo.CharacterID) == null) { return(false); } return((MasterThread.CurrentDate - mobDamageInfo.Time).TotalSeconds <= 5.0); }); } else { lastHitCharacter = mob.DamageLog.Log.FirstOrDefault(mobDamageInfo => { if (mob.Field.GetPlayer(mobDamageInfo.CharacterID) == null) { return(false); } return((MasterThread.CurrentDate - mobDamageInfo.Time).TotalSeconds <= 5.0); }); } if (lastHitCharacter != null) { Program.MainForm.LogDebug("Setting new controller: " + Server.Instance.GetCharacter(lastHitCharacter.CharacterID)); mob.SetController(mob.Field.GetPlayer(lastHitCharacter.CharacterID), true, false); return; } } mob.NextAttackPossible = bNextAttackPossible; // Prepare next skill byte forceControllerSkillLevel = 0; if (mob.NextAttackPossible == false || mob.SkillCommand != 0 || (mob.HasAnyStatus && mob.Status.BuffSealSkill.IsSet()) || mob.Data.Skills == null || mob.Data.Skills.Count == 0 || (MasterThread.CurrentTime - mob.LastSkillUse) < 3000) { // No skill } else { var availableSkills = mob.Data.Skills.Where(skill => { Dictionary <byte, MobSkillLevelData> msdLevels; if (!DataProvider.MobSkills.TryGetValue(skill.SkillID, out msdLevels) || !msdLevels.ContainsKey(skill.Level)) { return(false); } // Handle HP restriction var msd = msdLevels[skill.Level]; if (msd.HPLimit > 0 && (mob.HP / (double)mob.MaxHP * 100.0) > msd.HPLimit) { return(false); } // Skip if we already used a skill and it was not yet cooled down if (mob.SkillsInUse.TryGetValue(msd.SkillID, out long lastUse) && (lastUse + (msd.Cooldown * 1000)) > MasterThread.CurrentTime) { return(false); } // Do not reach the summon limit if (skill.SkillID == (byte)Constants.MobSkills.Skills.Summon && mob.SummonCount + msd.Summons.Count > msd.SummonLimit) { return(false); } // Can we boost stats? if (mob.HasAnyStatus) { short currentX = 0; int maxX = Math.Abs(100 - msd.X); switch ((Constants.MobSkills.Skills)skill.SkillID) { case Constants.MobSkills.Skills.WeaponAttackUp: case Constants.MobSkills.Skills.WeaponAttackUpAoe: currentX = mob.Status.BuffPowerUp.N; break; case Constants.MobSkills.Skills.MagicAttackUp: case Constants.MobSkills.Skills.MagicAttackUpAoe: currentX = mob.Status.BuffMagicUp.N; break; case Constants.MobSkills.Skills.WeaponDefenseUp: case Constants.MobSkills.Skills.WeaponDefenseUpAoe: currentX = mob.Status.BuffPowerGuardUp.N; break; case Constants.MobSkills.Skills.MagicDefenseUp: case Constants.MobSkills.Skills.MagicDefenseUpAoe: currentX = mob.Status.BuffMagicGuardUp.N; break; } if (currentX == 0) { return(true); } if (Math.Abs(100 - currentX) >= maxX) { return(false); } } return(true); }).ToArray(); if (availableSkills.Length > 0) { var randomSkill = availableSkills[Rand32.Next() % availableSkills.Length]; mob.SkillCommand = randomSkill.SkillID; forceControllerSkillLevel = randomSkill.Level; } } byte forceControllerSkillID = mob.SkillCommand; // Fix crash (zero level skill) if (forceControllerSkillLevel == 0) { forceControllerSkillID = 0; } SendMobControlResponse(victim, mobid, moveID, bNextAttackPossible, (short)mob.MP, forceControllerSkillID, forceControllerSkillLevel); SendMobControlMove(victim, mob, bNextAttackPossible, (byte)action, dwData, movePath); mob.CheckVacHack(lastMoveMillis, movePath.OriginalPosition, movePath.NewPosition, victim); // Good luck on getting less. if (lastMoveMillis < 500 && !justStartedControlling && !victim.IsAFK) { if (victim.AssertForHack(mob.HackReportCounter++ > 5, $"Movement speed too high! {lastMoveMillis}ms since last movement.")) { mob.HackReportCounter = 0; } } }