public void Fire(Player player, ushort targetID, ushort targetX, ushort targetY, ushort targetZ, ushort zoneId, ushort power) { if (!HasPlayer(player) || !_weapon.AbtInterface.CanCastCooldown(_abilityId)) { return; } // RB 6/25/2016 Reset timer before death every time the siege is fired _deathTime = TCPManager.GetTimeStampMS() + 300 * 1000; switch (Type) { case SiegeType.GTAOE: Point3D targetPos = ZoneService.GetWorldPosition(_weapon.Zone.Info, targetX, targetY, targetZ); if (!ArcHit(zoneId, new Point3D(targetX, targetY, targetZ), targetPos)) { player.SendClientMessage("Can't hit that position from here", ChatLogFilters.CHATLOGFILTERS_C_ABILITY_ERROR); return; } Siege artillery = _weapon as Siege; if (artillery != null && !artillery.CanFire(player)) { return; } // 72675 is the orcapult - catapults player rather than a stone! if (this._weapon.Entry == 72675) { var targetPosition = ZoneService.GetWorldPosition(_weapon.Zone.Info, targetX, targetY, targetZ); float speed = 6400f; float flightTimePuntee = 4; //(float)this._leader.GetDistanceSquare(new Point3D(targetPosition.X, targetPosition.Y, targetPosition.Z)) / speed / 1000f; this._leader.Catapult(_weapon.Zone, new Point3D(targetPosition.X, targetPosition.Y, targetPosition.Z), (ushort)flightTimePuntee, (ushort)340); this._leader.AbtInterface.Cancel(true); SendSiegeResponse(_leader, Type, SiegeControlType.Leader, 1); } else { _weapon.AbtInterface.StartCastAtPos(player, _abilityId, ZoneService.GetWorldPosition(_weapon.Zone.Info, targetX, targetY, targetZ), _weapon.Zone.ZoneId, 0); } break; case SiegeType.OIL: _weapon.AbtInterface.StartCastAtPos(player, _abilityId, ZoneService.GetWorldPosition(_weapon.Zone.Info, targetX, targetY, targetZ), _weapon.Zone.ZoneId, 0); break; case SiegeType.SNIPER: Unit target = _weapon.Region.GetObject(targetID) as Unit; if (target == null || !CombatInterface.CanAttack(player, target)) { return; } Siege cannon = _weapon as Siege; if (cannon != null && !cannon.CanFire(player)) { return; } _weapon.CbtInterface.SetTarget(targetID, TargetTypes.TARGETTYPES_TARGET_ENEMY); _weapon.AbtInterface.StartCast(player, _abilityId, 0, 0, Math.Max((byte)1, (byte)(_weapon.Level * power * 0.01f))); break; case SiegeType.RAM: Unit ramTarget = null; foreach (Object obj in _Owner.ObjectsInRange) { KeepDoor.KeepGameObject door = obj as KeepDoor.KeepGameObject; if (door == null) { continue; } if (!CombatInterface.CanAttack(player, door)) { continue; } if (!_Owner.IsObjectInFront(door, 90) || !door.IsWithinRadiusFeet(_Owner, 20)) { continue; } ramTarget = door; break; } //Unit target = _weapon.Region.GetObject(targetID) as Unit; if (ramTarget != null) { _weapon.CbtInterface.SetTarget(ramTarget.Oid, TargetTypes.TARGETTYPES_TARGET_ENEMY); _weapon.AbtInterface.StartCast(player, _abilityId, 0, 0, Math.Max((byte)1, (byte)(_weapon.Level * power * 0.01f))); } else { foreach (var plrInfo in Players) { plrInfo.Key.SendClientMessage("No target", ChatLogFilters.CHATLOGFILTERS_C_ABILITY_ERROR); } } break; } SendSiegeCooldown(); // Disable Firing? /* * Out = new PacketOut((byte)Opcodes.F_UPDATE_STATE); * Out.WriteUInt16(_Owner.Oid); * Out.WriteByte(0x1C); * Out.WriteByte(2); * Out.Fill(0, 6); * player.SendPacket(Out); */ SendSiegeUserUpdate(); /* * Out = new PacketOut((byte)Opcodes.F_UPDATE_STATE); * Out.WriteUInt16(_Owner.Oid); * Out.WriteByte(0x1E); * Out.WriteUInt16(0); * Out.WriteByte((byte)_Owner.Name.Length); * Out.WriteUInt16(0); * Out.WriteCString(_Owner.Name); * Out.WriteByte(0); * player.SendPacket(Out); */ SendSiegeIdleTimer(player); }
/// <summary> /// Builds a list of targets which would be hit by a line attack performed by a siege cannon. /// </summary> /// <param name="instigator">The player firing the cannon.</param> /// <returns>The farthest target from the siege weapon which would be struck by the attack, for use as the target of the ability.</returns> public Unit BuildTargetList(Unit instigator) { CurrentTargetList.Clear(); Unit initialTarget = _weapon.CbtInterface.GetTarget(TargetTypes.TARGETTYPES_TARGET_ENEMY); Unit bestTarget = initialTarget; int bestDist = _weapon.GetDistanceToObject(initialTarget); CurrentTargetList.Add(initialTarget); Vector3 unitDir = new Vector3(initialTarget.WorldPosition.X - _weapon.WorldPosition.X, initialTarget.WorldPosition.Y - _weapon.WorldPosition.Y, initialTarget.WorldPosition.Z - _weapon.WorldPosition.Z); unitDir.Normalize(); Vector3 toTarget = new Vector3(); Vector3 projection = new Vector3(); foreach (Object obj in _weapon.ObjectsInRange) { Unit unit = obj as Unit; if (unit == null || unit == initialTarget || unit.Realm == instigator.Realm || !_weapon.IsObjectInFront(unit, 45) || !CombatInterface.CanAttack(instigator, unit)) { continue; } // Determine whether this unit is within 5ft on either side of the cannon's attack. // Unit vector in direction of cannon's view projection.X = unitDir.X; projection.Y = unitDir.Y; projection.Z = unitDir.Z; toTarget.X = unit.WorldPosition.X - _weapon.WorldPosition.X; toTarget.Y = unit.WorldPosition.Y - _weapon.WorldPosition.Y; toTarget.Z = unit.WorldPosition.Z - _weapon.WorldPosition.Z; // Vector projection ((a dot ^b) ^b) projection.Multiply(Vector3.DotProduct3D(toTarget, unitDir)); // Vector rejection (a - (a dot ^b) ^b) toTarget.X -= projection.X; toTarget.Y -= projection.Y; toTarget.Z -= projection.Z; if (toTarget.MagnitudeSquare < 60 * 60 && _weapon.LOSHit(unit)) // 5ft either side { CurrentTargetList.Add(unit); // Select the target furthest away as the target of the ability, for the projectile effect to look best if (!_weapon.IsWithinRadiusFeet(unit, bestDist)) { bestTarget = unit; bestDist = _weapon.GetDistanceToObject(bestTarget); } } } return(bestTarget); }