From 2564f944ab1e3f66a892eebb3cfc3760195c432e Mon Sep 17 00:00:00 2001 From: Amber Ehrlich Date: Sat, 15 Jun 2024 12:46:53 -0400 Subject: [PATCH] Import position changes from DOLSharp (https://github.com/Dawn-of-Light/DOLSharp/pull/472) Squashed commit of the following: commit f4d1210d8f66565a6423c646f3e2fff0d26aa7bb Author: Amber Ehrlich Date: Fri Jun 14 20:28:26 2024 -0400 improv: remove old Geometry types commit 0dd00552b0c9b1a0dbbbf592fb299315ceb94c84 Author: Amber Ehrlich Date: Fri Jun 14 20:17:55 2024 -0400 fix: fix OnPlayerMove not being called commit 5eaf744f058e1703cf8c9a1ec7449722aaed707e Author: Amber Ehrlich Date: Fri Jun 14 20:03:24 2024 -0400 fix: tentatively fix failure to interrupt threads on exit commit 4a81eaff7adcd6039db9f08983481a1be6b0d619 Author: Amber Ehrlich Date: Fri Jun 14 18:43:42 2024 -0400 fix: fix exception in format in GameTimer.cs commit a7b55b7ac39dbf467d836b15fe0084bb24a25044 Author: Amber Ehrlich Date: Fri Jun 14 18:43:18 2024 -0400 improv: cache Region in Position commit fd55949a3b980fb7f49fa40c53d5736406c4eec9 Author: Amber Ehrlich Date: Fri Jun 14 18:27:14 2024 -0400 Fix Areas, I think commit 507a7288d3d8b5a56326b34f70695a5d4d20b2cd Author: Amber Ehrlich Date: Fri Jun 14 18:05:23 2024 -0400 Fix overflow when calculating very long distances commit aa3e1e5754ed30fa06eaf6efd3cc47edba339a81 Author: Amber Ehrlich Date: Fri Jun 14 17:11:03 2024 -0400 improv: improve "Zone does not exist" error log in AddToWorld commit dc292cd6e7cc64d9440b3a27b3292ad74cd669f0 Author: Amber Ehrlich Date: Sun Jun 9 18:01:06 2024 -0400 Fix some issues commit f59ed078a737b4697408986b4260fe5d88b9cef7 Author: Amber Ehrlich Date: Sun Jun 9 15:59:17 2024 -0400 Apply position changes to Gondwana code commit b0d12d2395c5909a31f6dacd2e86e021c280afd5 Author: Amber Ehrlich Date: Sat Jun 8 16:14:51 2024 -0400 Last batch of importing the DOLSharp positions - still need to change Gondwana-specific code commit 966394b2945c1d16934ae9ab5f8381822f3663dd Author: Amber Ehrlich Date: Fri Jun 7 19:23:28 2024 -0400 More of the position changes, still not finished commit a873193a91bec1b284e9e03ac7e44c79e033fea7 Author: Amber Ehrlich Date: Sun Jun 2 19:58:37 2024 -0400 positions, part 1 --- DOLServer/ConsolePacketLib.cs | 5 + GameServer/DOL.Geometry/Circle.cs | 33 - GameServer/DOL.Geometry/IPoint2D.cs | 30 - GameServer/DOL.Geometry/IPoint3D.cs | 29 - GameServer/DOL.Geometry/Point2D.cs | 168 -- GameServer/DOL.Geometry/Point3D.cs | 154 -- GameServer/DOL.Geometry/Vector3.cs | 1667 ----------------- GameServer/GameClient.cs | 14 +- GameServer/Geometry/Angle.cs | 60 + GameServer/Geometry/Coordinate.cs | 70 + .../Geometry/DataObjectPositionExtensions.cs | 45 + GameServer/Geometry/LinePath.cs | 23 + GameServer/Geometry/Motion.cs | 32 + GameServer/Geometry/Position.cs | 82 + GameServer/Geometry/Vector.cs | 86 + GameServer/Territory/AreaCoordinate.cs | 29 - GameServer/Territory/RvRTerritory.cs | 5 +- GameServer/Territory/Territory.cs | 28 +- GameServer/Territory/TerritoryManager.cs | 17 +- .../GameObjects/Coffre/CoffrexPlayer.cs | 14 - .../GameObjects/Coffre/GameCoffre.cs | 12 +- .../AmteScripts/GameObjects/CustomVault.cs | 2 +- .../GameObjects/FollowingFriendMob.cs | 69 +- .../AmteScripts/GameObjects/FollowingMob.cs | 28 +- .../AmteScripts/GameObjects/GameBoatAmte.cs | 9 +- .../GameObjects/MageMob/MageMobBrain.cs | 10 +- .../AmteScripts/GameObjects/NightMob.cs | 2 +- .../AmteScripts/GameObjects/PlaceAssise.cs | 6 +- .../AmteScripts/GameObjects/SplitMob.cs | 6 +- .../AmteScripts/Managers/AmtenaelRules.cs | 8 +- .../_scripts/AmteScripts/PvP/PvpManager.cs | 7 +- .../_scripts/AmteScripts/RvR/RvrManager.cs | 27 +- .../SpecialItems/FeuArtificeItem.cs | 31 +- .../AmteScripts/Spells/GuarksTeleport.cs | 1 - GameServer/ai/brain/BD Pets/BDPetBrain.cs | 39 +- GameServer/ai/brain/ControlledNpcBrain.cs | 19 +- GameServer/ai/brain/DragonBrain.cs | 2 +- GameServer/ai/brain/Guards/KeepGuardBrain.cs | 10 +- GameServer/ai/brain/Npcs/AggressiveBrain.cs | 2 +- GameServer/ai/brain/RoundsBrain.cs | 2 +- GameServer/ai/brain/StandardMobBrain.cs | 50 +- GameServer/behaviour/Actions/MoveToAction.cs | 13 +- .../behaviour/Actions/TeleportAction.cs | 19 +- GameServer/behaviour/Actions/WalkToAction.cs | 16 +- .../commands/gmcommands/AddHookPoint.cs | 10 +- .../commands/gmcommands/GMTerritories.cs | 13 +- GameServer/commands/gmcommands/GMinfo.cs | 20 +- GameServer/commands/gmcommands/Instance.cs | 29 +- .../commands/gmcommands/KeepComponent.cs | 55 +- GameServer/commands/gmcommands/Minorelic.cs | 28 +- GameServer/commands/gmcommands/Player.cs | 26 +- GameServer/commands/gmcommands/Teleport.cs | 10 +- GameServer/commands/gmcommands/addbind.cs | 8 +- GameServer/commands/gmcommands/area.cs | 6 +- GameServer/commands/gmcommands/cast.cs | 3 +- GameServer/commands/gmcommands/checklos.cs | 6 +- GameServer/commands/gmcommands/debugjump.cs | 30 +- GameServer/commands/gmcommands/door.cs | 32 +- GameServer/commands/gmcommands/earthquake.cs | 8 +- GameServer/commands/gmcommands/gmappeal.cs | 11 +- GameServer/commands/gmcommands/gmrelic.cs | 10 +- GameServer/commands/gmcommands/gmrelicpad.cs | 2 - GameServer/commands/gmcommands/jump.cs | 78 +- GameServer/commands/gmcommands/keep.cs | 50 +- GameServer/commands/gmcommands/keepguard.cs | 11 +- GameServer/commands/gmcommands/merchant.cs | 4 - GameServer/commands/gmcommands/mob.cs | 43 +- GameServer/commands/gmcommands/npc.cs | 13 +- GameServer/commands/gmcommands/object.cs | 8 +- GameServer/commands/gmcommands/path.cs | 10 +- GameServer/commands/gmcommands/siegeweapon.cs | 8 - GameServer/commands/gmcommands/tppoint.cs | 5 +- GameServer/commands/gmcommands/walk.cs | 5 +- GameServer/commands/gmcommands/xmob.cs | 22 +- GameServer/commands/gmcommands/zone.cs | 10 +- GameServer/commands/playercommands/Boat.cs | 20 - .../commands/playercommands/GroundAssist.cs | 18 +- .../commands/playercommands/facegloc.cs | 4 +- GameServer/commands/playercommands/faceloc.cs | 10 +- GameServer/commands/playercommands/gtrange.cs | 5 +- GameServer/commands/playercommands/guild.cs | 8 +- GameServer/commands/playercommands/house.cs | 2 +- .../commands/playercommands/houseface.cs | 3 +- GameServer/commands/playercommands/knock.cs | 2 +- GameServer/commands/playercommands/range.cs | 2 +- GameServer/commands/playercommands/where.cs | 27 +- GameServer/commands/playercommands/yell.cs | 20 +- GameServer/craft/SiegeCrafting.cs | 2 - GameServer/database/converters/Version002.cs | 3 +- .../events/gameobjects/WalkToEventArgs.cs | 5 +- GameServer/gameobjects/Animist/TurretPet.cs | 4 +- .../CustomNPC/ConsignmentMerchant.cs | 72 +- .../CustomNPC/GameBoatStableMaster.cs | 7 +- .../gameobjects/CustomNPC/GameStableMaster.cs | 7 +- .../gameobjects/CustomNPC/GameSummoner.cs | 7 +- .../gameobjects/CustomNPC/GuildPortalNPC.cs | 14 +- GameServer/gameobjects/CustomNPC/Hastener.cs | 2 +- GameServer/gameobjects/CustomNPC/ShadowNPC.cs | 36 +- GameServer/gameobjects/Dragons/Cuuldurach.cs | 32 +- GameServer/gameobjects/Dragons/GameDragon.cs | 35 +- GameServer/gameobjects/Dragons/Gjalpinulva.cs | 33 +- GameServer/gameobjects/Dragons/Golestandt.cs | 4 +- GameServer/gameobjects/FeuDeCamp.cs | 12 +- GameServer/gameobjects/GameDoor.cs | 29 +- GameServer/gameobjects/GameGravestone.cs | 5 +- GameServer/gameobjects/GameHouseVault.cs | 10 +- GameServer/gameobjects/GameInventoryItem.cs | 8 +- GameServer/gameobjects/GameLiving.cs | 140 +- GameServer/gameobjects/GameMerchant.cs | 12 +- GameServer/gameobjects/GameMoney.cs | 2 - GameServer/gameobjects/GameNPC.cs | 532 ++---- GameServer/gameobjects/GameObject.cs | 354 ++-- GameServer/gameobjects/GamePlayer.cs | 415 ++-- GameServer/gameobjects/GameSiegeWeapon.cs | 34 +- GameServer/gameobjects/GameStaticItem.cs | 22 +- GameServer/gameobjects/GameTeleporter.cs | 46 +- GameServer/gameobjects/GuildBannerItem.cs | 5 +- .../GameInventorySiegeBallista.cs | 3 +- .../GameInventorySiegeCatapult.cs | 3 +- .../InventoryItem/GameInventorySiegeRam.cs | 3 +- .../GameInventorySiegeTrebuchet.cs | 3 +- .../SiegeWeapon/gamesiegecatapult.cs | 7 +- .../SiegeWeapon/gamesiegecauldron.cs | 6 +- GameServer/gameobjects/Spawner.cs | 7 +- GameServer/gameutils/DoorMgr.cs | 3 +- GameServer/gameutils/GameMath.cs | 97 +- GameServer/gameutils/GamePlayerUtils.cs | 96 +- GameServer/gameutils/GameTimer.cs | 4 +- GameServer/gameutils/GuildBanner.cs | 1 - GameServer/gameutils/IDoor.cs | 5 +- GameServer/gameutils/InventoryLogging.cs | 2 +- GameServer/gameutils/MovementMgr.cs | 25 +- GameServer/gameutils/PathPoint.cs | 127 +- GameServer/gameutils/RegionTimersResync.cs | 12 +- GameServer/gameutils/TPPoint.cs | 23 +- GameServer/gameutils/Util.cs | 7 +- GameServer/gameutils/WarMapMgr.cs | 25 +- GameServer/housing/House.cs | 173 +- GameServer/housing/HouseMgr.cs | 18 +- GameServer/housing/LotMarker.cs | 6 +- GameServer/keeps/AbstractGameKeep.cs | 64 +- GameServer/keeps/GameKeepComponent.cs | 35 +- .../keeps/Gameobjects/FrontiersPortalStone.cs | 18 +- .../keeps/Gameobjects/GameKeepBanner.cs | 12 +- GameServer/keeps/Gameobjects/GameKeepDoor.cs | 23 +- GameServer/keeps/Gameobjects/GameRelicDoor.cs | 21 +- .../keeps/Gameobjects/Guards/GameKeepGuard.cs | 18 +- GameServer/keeps/Gameobjects/Guards/Patrol.cs | 30 +- GameServer/keeps/Gameobjects/IKeepItem.cs | 4 +- GameServer/keeps/HookPointInventory.cs | 2 - GameServer/keeps/IGameKeep.cs | 4 +- GameServer/keeps/IKeepManager.cs | 15 +- GameServer/keeps/KeepArea.cs | 9 +- GameServer/keeps/KeepHookPoint.cs | 43 +- GameServer/keeps/KeepManager.cs | 117 +- GameServer/keeps/Managers/Position Manager.cs | 185 +- GameServer/keeps/Relics/GameRelic.cs | 21 +- GameServer/keeps/Relics/GameRelicPad.cs | 2 +- GameServer/language/LanguageMgr.cs | 18 + .../managers/worldmanager/RegionWeather.cs | 4 +- GameServer/minotaurrelics/MinotaurRelic.cs | 73 +- .../minotaurrelics/MinotaurRelicManager.cs | 2 +- .../Protectors/ArrektosProtector.cs | 5 +- .../Protectors/BaseProtector.cs | 2 - .../Client/168/DialogResponseHandler.cs | 2 +- .../packets/Client/168/DoorRequestHandler.cs | 11 +- .../Client/168/HousingPlaceItemHandler.cs | 26 +- .../Client/168/PlayerGroundTargetHandler.cs | 7 +- .../Client/168/PlayerHeadingUpdateHandler.cs | 5 +- .../Client/168/PlayerInitRequestHandler.cs | 10 +- .../Client/168/PlayerPositionUpdateHandler.cs | 140 +- .../Client/168/RegionChangeRequestHandler.cs | 7 +- .../packets/Client/168/UseSkillHandler.cs | 17 +- .../packets/Client/168/UseSlotHandler.cs | 18 +- .../packets/Client/168/UseSpellHandler.cs | 27 +- .../Client/168/warmapshowrequesthandler.cs | 46 +- GameServer/packets/Server/IPacketLib.cs | 7 + GameServer/packets/Server/PacketLib1104.cs | 4 +- GameServer/packets/Server/PacketLib1110.cs | 21 +- GameServer/packets/Server/PacketLib1112.cs | 15 +- GameServer/packets/Server/PacketLib1115.cs | 4 +- GameServer/packets/Server/PacketLib1124.cs | 37 +- GameServer/packets/Server/PacketLib1125.cs | 3 +- GameServer/packets/Server/PacketLib1126.cs | 3 +- GameServer/packets/Server/PacketLib168.cs | 196 +- GameServer/packets/Server/PacketLib170.cs | 5 +- GameServer/packets/Server/PacketLib171.cs | 16 +- GameServer/packets/Server/PacketLib172.cs | 20 +- GameServer/packets/Server/PacketLib173.cs | 11 +- GameServer/packets/Server/PacketLib174.cs | 21 +- GameServer/packets/Server/PacketLib175.cs | 6 +- GameServer/packets/Server/PacketLib176.cs | 6 +- GameServer/packets/Server/PacketLib180.cs | 6 +- GameServer/packets/Server/PacketLib186.cs | 11 +- GameServer/packets/Server/PacketLib189.cs | 4 +- GameServer/packets/Server/PacketLib190.cs | 14 +- GameServer/packets/Server/PacketLib199.cs | 4 +- .../JsonQuests/Goals/BringAFriendGoal.cs | 11 +- .../quests/JsonQuests/Goals/EnterAreaGoal.cs | 7 +- .../quests/JsonQuests/Goals/KillGoal.cs | 9 +- .../JsonQuests/Goals/KillGroupMobGoal.cs | 11 +- .../quests/JsonQuests/Goals/KillPlayerGoal.cs | 9 +- .../quests/JsonQuests/Goals/UseItemGoal.cs | 9 +- GameServer/quests/JsonQuests/IQuest.cs | 11 +- GameServer/quests/Tasks/KillTask.cs | 26 +- .../realmabilities/Statics/GenericBase.cs | 31 +- .../effects/rr5/BoilingCauldronEffect.cs | 4 +- .../effects/rr5/MinionRescueEffect.cs | 8 +- .../realmabilities/handlers/DecimationTrap.cs | 16 +- .../handlers/NegativeMaelstromAbility.cs | 5 +- .../handlers/PerfectRecoveryAbility.cs | 2 +- .../handlers/StaticTempestAbility.cs | 2 +- .../handlers/ThornweedFieldAbility.cs | 7 +- .../handlers/rr5/WallOfFlameAbility.cs | 2 +- GameServer/relics/RelicPad.cs | 2 +- GameServer/serverrules/AbstractServerRules.cs | 37 +- .../serverrules/AdventureWingJumpPoint.cs | 20 +- GameServer/serverrules/IServerRules.cs | 20 +- GameServer/serverrules/PvPServerRules.cs | 6 +- .../serverrules/TaskDungeonJumpPoint.cs | 17 +- GameServer/spells/Animist/SummonAnimistFnF.cs | 4 +- GameServer/spells/Animist/SummonAnimistPet.cs | 17 +- .../spells/Animist/TurretSpellHandler.cs | 2 +- GameServer/spells/Archery/Archery.cs | 4 +- GameServer/spells/Artifacts/bracerofzo.cs | 13 +- GameServer/spells/AstralPetSummon.cs | 9 +- GameServer/spells/CommonAstralSpells.cs | 8 +- GameServer/spells/EarthquakeSpellHandler.cs | 43 +- GameServer/spells/Masterlevel/Convoker.cs | 49 +- .../spells/Masterlevel/MasterLevelBase.cs | 20 +- GameServer/spells/Masterlevel/Perfecter.cs | 8 - GameServer/spells/Masterlevel/Sojourner.cs | 18 +- GameServer/spells/Masterlevel/Spymaster.cs | 9 +- GameServer/spells/Masterlevel/Stormlord.cs | 20 +- GameServer/spells/PlayerPortal.cs | 8 +- GameServer/spells/ResurrectSpellHandler.cs | 2 +- GameServer/spells/SpellHandler.cs | 18 +- GameServer/spells/SummonIllusionBlade.cs | 10 +- GameServer/spells/SummonSpellHandler.cs | 29 +- .../spells/Teleport/GatewayPersonalBind.cs | 2 +- GameServer/spells/TeleportSpellHandler.cs | 4 +- .../spells/Theurgist/SummonTheurgistPet.cs | 9 +- GameServer/spells/negative/FearBrain.cs | 9 +- GameServer/spells/negative/SuperFearBrain.cs | 12 +- GameServer/styles/StyleProcessor.cs | 8 +- GameServer/world/AbstractArea.cs | 25 +- GameServer/world/Area.cs | 150 +- GameServer/world/GameLocation.cs | 142 +- GameServer/world/IArea.cs | 17 +- GameServer/world/IGameLocation.cs | 18 +- GameServer/world/Instance/BaseInstance.cs | 10 +- GameServer/world/Instance/Instance.cs | 18 +- GameServer/world/Instance/RegionInstance.cs | 14 - GameServer/world/Region.cs | 264 ++- GameServer/world/TeleportArea.cs | 8 +- GameServer/world/WorldMgr.cs | 295 +-- GameServer/world/WorldUpdateThread.cs | 6 +- GameServer/world/Zone.cs | 149 +- GameServer/world/ZonePointEffects.cs | 6 +- GameServer/world/geometry/AABoundingBox.cs | 2 +- GameServer/world/geometry/LosCheckMgr.cs | 22 +- GameServer/world/pathing/GamePath.cs | 13 +- GameServer/world/pathing/IPathingMgr.cs | 23 +- GameServer/world/pathing/LocalPathingMgr.cs | 170 +- GameServer/world/pathing/NullPathingMgr.cs | 18 +- GameServer/world/pathing/PathCalculator.cs | 249 +-- GameServer/world/pathing/PathingMgr.cs | 2 +- GameServer/world/pathing/Structs.cs | 19 - .../GameServer/gameutils/RegionTest.cs | 187 +- Tests/IntegrationTests/TestPacketLib.cs | 17 +- Tests/Tests.csproj | 2 +- Tests/UnitTests/Geometry/UT_Angle.cs | 92 + Tests/UnitTests/Geometry/UT_Motion.cs | 44 + Tests/UnitTests/Geometry/UT_Vector.cs | 115 ++ 274 files changed, 3760 insertions(+), 6622 deletions(-) delete mode 100644 GameServer/DOL.Geometry/Circle.cs delete mode 100644 GameServer/DOL.Geometry/IPoint2D.cs delete mode 100644 GameServer/DOL.Geometry/IPoint3D.cs delete mode 100644 GameServer/DOL.Geometry/Point2D.cs delete mode 100644 GameServer/DOL.Geometry/Point3D.cs delete mode 100644 GameServer/DOL.Geometry/Vector3.cs create mode 100644 GameServer/Geometry/Angle.cs create mode 100644 GameServer/Geometry/Coordinate.cs create mode 100644 GameServer/Geometry/DataObjectPositionExtensions.cs create mode 100644 GameServer/Geometry/LinePath.cs create mode 100644 GameServer/Geometry/Motion.cs create mode 100644 GameServer/Geometry/Position.cs create mode 100644 GameServer/Geometry/Vector.cs delete mode 100644 GameServer/Territory/AreaCoordinate.cs create mode 100644 Tests/UnitTests/Geometry/UT_Angle.cs create mode 100644 Tests/UnitTests/Geometry/UT_Motion.cs create mode 100644 Tests/UnitTests/Geometry/UT_Vector.cs diff --git a/DOLServer/ConsolePacketLib.cs b/DOLServer/ConsolePacketLib.cs index d3a5af50..1eebccc8 100644 --- a/DOLServer/ConsolePacketLib.cs +++ b/DOLServer/ConsolePacketLib.cs @@ -32,6 +32,7 @@ using DOL.Database; using System.Numerics; using DOL.GS.Profession; +using DOL.GS.Geometry; namespace DOLGameServerConsole { @@ -162,6 +163,7 @@ public void SendDisableSkill(ICollection> skills) { } public void SendUpdateIcons(IList changedEffects, ref int lastUpdateEffectsCount) { } public void SendLevelUpSound() { } public void SendRegionEnterSound(byte soundId) { } + public void SendSoundEffect(ushort soundId, Position position, ushort radius) { } public void SendSoundEffect(ushort soundId, ushort zoneId, ushort x, ushort y, ushort z, ushort radius) { } public void SendDebugMessage(string format, params object[] parameters) { } public void SendDebugPopupMessage(string format, params object[] parameters) { } @@ -178,7 +180,9 @@ public void SendQuestUpdate(IQuestPlayerData quest) { } public void SendConcentrationList() { } public void SendUpdateCraftingSkills() { } public void SendChangeTarget(GameObject newTarget) { } + [Obsolete("Use .SendChangeGroundTarget(Coordinate) instead!")] public void SendChangeGroundTarget(Vector3 newTarget) { } + public void SendChangeGroundTarget(Coordinate newTarget) { } public void SendPetWindow(GameLiving pet, ePetWindowAction windowAction, eAggressionState aggroState, eWalkState walkState) { } public void SendKeepInfo(IGameKeep keep) { } public void SendKeepRealmUpdate(IGameKeep keep) { } @@ -242,6 +246,7 @@ public void SendMarketExplorerWindow(IList items, byte page, byte public void SendConsignmentMerchantMoney(long money) { } public void SendMinotaurRelicMapRemove(byte id) { } public void SendMinotaurRelicMapUpdate(byte id, ushort region, int x, int y, int z) { } + public void SendMinotaurRelicMapUpdate(byte id, Position position) { } public virtual void SendMinotaurRelicWindow(GamePlayer player, int spell, bool flag) { } public virtual void SendMinotaurRelicBarUpdate(GamePlayer player, int xp) { } public virtual void SendBlinkPanel(byte flag) { } diff --git a/GameServer/DOL.Geometry/Circle.cs b/GameServer/DOL.Geometry/Circle.cs deleted file mode 100644 index dfe819de..00000000 --- a/GameServer/DOL.Geometry/Circle.cs +++ /dev/null @@ -1,33 +0,0 @@ -using DOL.Numbers; - -namespace DOL.Geometry -{ - /// - /// Geometry utilities for circles - /// - public class Circle - { - /// - /// Gets a uniformly picked random point in the entire circle area - /// - /// - /// - /// - public static Vector3 GetRandomPosition(Vector3 center, int radius) - { - // http://stackoverflow.com/questions/5837572/generate-a-random-point-within-a-circle-uniformly - // We need to use rejection sampling to uniformly end up with a point - - // Pick a random point in the area of the unit circle - // on avg this should terminate in 1.42 tries - Vector3 vector; - do - { - vector = new Vector3(Rand.Double() * 2 - 1, Rand.Double() * 2 - 1, 0); - } while (vector.SumComponentSqrs() > 1); // x^2 + y^2 > 1^2 - - // Use the point from the unit circle to pick our point - return center + vector * radius; - } - } -} \ No newline at end of file diff --git a/GameServer/DOL.Geometry/IPoint2D.cs b/GameServer/DOL.Geometry/IPoint2D.cs deleted file mode 100644 index 28235951..00000000 --- a/GameServer/DOL.Geometry/IPoint2D.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * DAWN OF LIGHT - The first free open source DAoC server emulator - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -namespace DOL.Geometry -{ - /// - /// interface for classes that represent a point in 2d space - /// - public interface IPoint2D - { - int X { get; } - int Y { get; } - } -} \ No newline at end of file diff --git a/GameServer/DOL.Geometry/IPoint3D.cs b/GameServer/DOL.Geometry/IPoint3D.cs deleted file mode 100644 index 87b850e4..00000000 --- a/GameServer/DOL.Geometry/IPoint3D.cs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * DAWN OF LIGHT - The first free open source DAoC server emulator - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -namespace DOL.Geometry -{ - /// - /// interface for classes that represent a point in 3d space - /// - public interface IPoint3D - { - Vector3 Position { get; } - } -} \ No newline at end of file diff --git a/GameServer/DOL.Geometry/Point2D.cs b/GameServer/DOL.Geometry/Point2D.cs deleted file mode 100644 index c05e3cfc..00000000 --- a/GameServer/DOL.Geometry/Point2D.cs +++ /dev/null @@ -1,168 +0,0 @@ -/* - * DAWN OF LIGHT - The first free open source DAoC server emulator - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -using System; - -namespace DOL.Geometry -{ - /// - /// represents a point in 2 dimensional space - /// - public class Point2D : IPoint2D - { - /// - /// The factor to convert a heading value to radians - /// - /// - /// Heading to degrees = heading * (360 / 4096) - /// Degrees to radians = degrees * (PI / 180) - /// - public const double HEADING_TO_RADIAN = 360.0 / 4096.0 * (Math.PI / 180.0); - - public const double HEADING_TO_DEGREES = 360.0 / 4096.0; - - public const double DEGREES_TO_HEADING = 4096.0 / 360.0; - - /// - /// The factor to convert radians to a heading value - /// - /// - /// Radians to degrees = radian * (180 / PI) - /// Degrees to heading = degrees * (4096 / 360) - /// - public const double RADIAN_TO_HEADING = 180.0 / Math.PI * (4096.0 / 360.0); - - /// - /// The X coord of this point - /// - protected int m_x; - - /// - /// The Y coord of this point - /// - protected int m_y; - - /// - /// Constructs a new 2D point object - /// - public Point2D() : this(0, 0) - { - } - - /// - /// Constructs a new 2D point object - /// - /// The X coord - /// The Y coord - public Point2D(int x, int y) - { - m_x = x; - m_y = y; - } - - /// - /// Constructs a new 2D point object - /// - /// The 2D point - public Point2D(IPoint2D point) : this(point.X, point.Y) - { - } - - /// - /// X coord of this point - /// - public int X - { - get { return m_x; } - set { m_x = value; } - } - - /// - /// Y coord of this point - /// - public int Y - { - get { return m_y; } - set { m_y = value; } - } - - /// - /// Calculates the hashcode of this point - /// - /// The hashcode - public override int GetHashCode() - { - return m_x ^ m_y; - } - - /// - /// Creates the string representation of this point - /// - /// - public override string ToString() - { - return string.Format("({0}, {1})", m_x, m_y); - } - - /// - /// Compares this point to any object - /// - /// The object to compare - /// True if object is IPoint2D and equals this point - public override bool Equals(object obj) - { - var point = obj as IPoint2D; - if (point == null) - { - return false; - } - return point.X == m_x && point.Y == m_y; - } - - /// - /// calculate heading from point1 to point2 - /// - /// - /// - /// - public static ushort GetHeadingToLocation(IPoint2D p1, IPoint2D p2) - { - float dx = (long)p2.X - p1.X; - float dy = (long)p2.Y - p1.Y; - var heading = (ushort)(Math.Atan2(-dx, dy) * RADIAN_TO_HEADING); - if (heading < 0) - { - heading += 0x1000; - } - return heading; - } - - public static ushort GetHeadingToLocation(Vector3 p1, Vector3 p2) - { - var dx = p2.X - p1.X; - var dy = p2.Y - p1.Y; - double heading = (ushort)(Math.Atan2(-dx, dy) * RADIAN_TO_HEADING); - if (heading < 0) - { - heading += 0x1000; - } - return (ushort)heading; - } - } -} \ No newline at end of file diff --git a/GameServer/DOL.Geometry/Point3D.cs b/GameServer/DOL.Geometry/Point3D.cs deleted file mode 100644 index 689b9ecb..00000000 --- a/GameServer/DOL.Geometry/Point3D.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* - * DAWN OF LIGHT - The first free open source DAoC server emulator - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -using System; - -namespace DOL.Geometry -{ - /// - /// Defines a 3D point - /// - public class Point3D : IPoint3D - { - /// - /// Constructs a new 3D point object - /// - public Point3D() - { - } - - /// - /// Constructs a new 3D point object - /// - /// The X coord - /// The Y coord - /// The Z coord - public Point3D(int x, int y, int z) : this(new Vector3(x, y, z)) - { - } - - /// - /// Constructs a new 3D point object - /// - /// 2D point - /// Z coord - public Point3D(IPoint2D point, int z) : this(point.X, point.Y, z) - { - } - - /// - /// Constructs a new 3D point object - /// - /// 3D point - public Point3D(IPoint3D point) : this(point.Position) - { - } - - /// - /// Constructs a new 3D point object - /// - /// 3D point - public Point3D(Vector3 pos) - { - Position = pos; - } - - public Vector3 Position { get; set; } - - /// - /// Calculates the hashcode of this point - /// - /// The hashcode - public override int GetHashCode() - { - return (int)Position.X ^ (int)Position.Y ^ (int)Position.Z; - } - - /// - /// Creates the string representation of this point - /// - /// - public override string ToString() - { - return Position.ToString(); - } - - /// - /// Compares this point to any object - /// - /// The object to compare - /// True if object is IPoint3D and equals this point - public override bool Equals(object obj) - { - var point = obj as IPoint3D; - if (point == null) - { - return false; - } - return point.Position == Position; - } - - /// - /// calculates distance between 2 points - /// - /// - /// - /// - public static int GetDistance(IPoint3D p1, IPoint3D p2) - { - return (int)p1.Position.Distance(p2.Position); - } - - /// - /// The factor to convert radians to a heading value - /// - /// - /// Radians to degrees = radian * (180 / PI) - /// Degrees to heading = degrees * (4096 / 360) - /// - public const double RADIAN_TO_HEADING = (180.0 / Math.PI) * (4096.0 / 360.0); - /// - /// Get the heading to a point - /// - /// Target point - /// Heading to target point - public ushort GetHeading(IPoint3D point) - { - double dx = point.Position.X - Position.X; - double dy = point.Position.Y - Position.Y; - - double heading = Math.Atan2(-dx, dy) * RADIAN_TO_HEADING; - - if (heading < 0) - heading += 4096; - - return (ushort)heading; - } - - /// - /// checks if the given points are in a certain distance. - /// - /// - /// - /// - public static bool InRange(IPoint3D p1, IPoint3D p2, int dist) - { - return p1.Position.IsInRange(p2.Position, dist); - } - } -} \ No newline at end of file diff --git a/GameServer/DOL.Geometry/Vector3.cs b/GameServer/DOL.Geometry/Vector3.cs deleted file mode 100644 index 3223dd63..00000000 --- a/GameServer/DOL.Geometry/Vector3.cs +++ /dev/null @@ -1,1667 +0,0 @@ -#region Imports - -using System; -using System.Xml.Serialization; - -// for various Xml attributes - -#endregion - -namespace DOL.Geometry -{ - /// - /// vector of doubles with three components (x,y,z) - /// - /// Richard Potter BSc(Hons) - /// Jun-04 - /// Feb-07 - /// 1.20 - /// - /// Magnitude is now a property - /// Abs(...) now returns magnitude, Recommend: use magnitude property instead - /// Equality opeartions now have a tolerance (note that greater and less than type operations do not) - /// IsUnit methods also have a tolerence - /// Generic IEquatable and IComparable interfaces implemented - /// IFormattable interface (ToString(format, format provider) implemented - /// Mixed product function implemented - /// - [Serializable] - public struct Vector3 - : IComparable, IComparable, IEquatable, IFormattable - { - #region Class Variables - - /// - /// The X component of the vector - /// - public double X; - - /// - /// The Y component of the vector - /// - public double Y; - - /// - /// The Z component of the vector - /// - public double Z; - - #endregion - - #region Constructors - - /// - /// Constructor for the Vector3 class accepting three doubles - /// - /// The new x value for the Vector3 - /// The new y value for the Vector3 - /// The new z value for the Vector3 - /// - /// Uses the mutator properties for the Vector3 components to allow verification of input (if implemented) - /// This results in the need for pre-initialisation initialisation of the Vector3 components to 0 - /// Due to the necessity for struct's variables to be set in the constructor before moving control - /// - public Vector3(double x, double y, double z) - { - // Pre-initialisation initialisation - // Implemented because a struct's variables always have to be set in the constructor before moving control - this.X = x; - this.Y = y; - this.Z = z; - } - - /// - /// Constructor for the Vector3 class from another Vector3 object - /// - /// Vector3 representing the new values for the Vector3 - /// - /// Copies values from Vector3 v1 to this vector, does not hold a reference to object v1 - /// - public Vector3(Vector3 v1) - { - // Pre-initialisation initialisation - // Implemented because a struct's variables always have to be set in the constructor before moving control - X = v1.X; - Y = v1.Y; - Z = v1.Z; - } - - #endregion - - #region Accessors & Mutators - - /// - /// Property for the magnitude (aka. length or absolute value) of the Vector3 - /// - public double Magnitude - { - get - { - return - Math.Sqrt(SumComponentSqrs()); - } - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException("value", value, NEGATIVE_MAGNITUDE); - } - - if (this == new Vector3(0, 0, 0)) - { - throw new ArgumentException(ORAGIN_VECTOR_MAGNITUDE, "this"); - } - - this = this * (value / Magnitude); - } - } - - /// - /// An index accessor - /// Mapping index [0] -> X, [1] -> Y and [2] -> Z. - /// - /// The array index referring to a component within the vector (i.e. x, y, z) - /// - /// Thrown if the array argument does not contain exactly three components - /// - public double this[int index] - { - get - { - switch (index) - { - case 0: - { - return X; - } - case 1: - { - return Y; - } - case 2: - { - return Z; - } - default: - throw new ArgumentException(THREE_COMPONENTS, "index"); - } - } - set - { - switch (index) - { - case 0: - { - X = value; - break; - } - case 1: - { - Y = value; - break; - } - case 2: - { - Z = value; - break; - } - default: - throw new ArgumentException(THREE_COMPONENTS, "index"); - } - } - } - - #endregion - - #region Operators - - /// - /// Addition of two Vectors - /// - /// Vector3 to be added to - /// Vector3 to be added - /// Vector3 representing the sum of two Vectors - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - public static Vector3 operator +(Vector3 v1, Vector3 v2) - { - return - new Vector3 - ( - v1.X + v2.X, - v1.Y + v2.Y, - v1.Z + v2.Z - ); - } - - /// - /// Subtraction of two Vectors - /// - /// Vector3 to be subtracted from - /// Vector3 to be subtracted - /// Vector3 representing the difference of two Vectors - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - public static Vector3 operator -(Vector3 v1, Vector3 v2) - { - return - new Vector3 - ( - v1.X - v2.X, - v1.Y - v2.Y, - v1.Z - v2.Z - ); - } - - /// - /// Product of a Vector3 and a scalar value - /// - /// Vector3 to be multiplied - /// Scalar value to be multiplied by - /// Vector3 representing the product of the vector and scalar - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - public static Vector3 operator *(Vector3 v1, double s2) - { - return - new Vector3 - ( - v1.X * s2, - v1.Y * s2, - v1.Z * s2 - ); - } - - /// - /// Product of a scalar value and a Vector3 - /// - /// Scalar value to be multiplied - /// Vector3 to be multiplied by - /// Vector3 representing the product of the scalar and Vector3 - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - /// - /// Using the commutative law 'scalar x vector'='vector x scalar'. - /// Thus, this function calls 'operator*(Vector3 v1, double s2)'. - /// This avoids repetition of code. - /// - public static Vector3 operator *(double s1, Vector3 v2) - { - return v2 * s1; - } - - /// - /// Division of a Vector3 and a scalar value - /// - /// Vector3 to be divided - /// Scalar value to be divided by - /// Vector3 representing the division of the vector and scalar - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - public static Vector3 operator /(Vector3 v1, double s2) - { - return - new Vector3 - ( - v1.X / s2, - v1.Y / s2, - v1.Z / s2 - ); - } - - /// - /// Negation of a Vector3 - /// Invert the direction of the Vector3 - /// Make Vector3 negative (-vector) - /// - /// Vector3 to be negated - /// Negated vector - /// This code is adapted from Exocortex - Ben Houston - public static Vector3 operator -(Vector3 v1) - { - return - new Vector3 - ( - -v1.X, - -v1.Y, - -v1.Z - ); - } - - /// - /// Reinforcement of a Vector3 - /// Make Vector3 positive (+vector) - /// - /// Vector3 to be reinforced - /// Reinforced vector - /// This code is adapted from Exocortex - Ben Houston - /// - /// Using the rules of Addition (i.e. '+-x' = '-x' and '++x' = '+x') - /// This function actually does nothing but return the argument as given - /// - public static Vector3 operator +(Vector3 v1) - { - return - new Vector3 - ( - +v1.X, - +v1.Y, - +v1.Z - ); - } - - /// - /// Compare the magnitude of two Vectors (less than) - /// - /// Vector3 to be compared - /// Vector3 to be compared with - /// True if v1 less than v2 - public static bool operator <(Vector3 v1, Vector3 v2) - { - return v1.SumComponentSqrs() < v2.SumComponentSqrs(); - } - - /// - /// Compare the magnitude of two Vectors (greater than) - /// - /// Vector3 to be compared - /// Vector3 to be compared with - /// True if v1 greater than v2 - public static bool operator >(Vector3 v1, Vector3 v2) - { - return v1.SumComponentSqrs() > v2.SumComponentSqrs(); - } - - /// - /// Compare the magnitude of two Vectors (less than or equal to) - /// - /// Vector3 to be compared - /// Vector3 to be compared with - /// True if v1 less than or equal to v2 - public static bool operator <=(Vector3 v1, Vector3 v2) - { - return v1.SumComponentSqrs() <= v2.SumComponentSqrs(); - } - - /// - /// Compare the magnitude of two Vectors (greater than or equal to) - /// - /// Vector3 to be compared - /// Vector3 to be compared with - /// True if v1 greater than or equal to v2 - public static bool operator >=(Vector3 v1, Vector3 v2) - { - return v1.SumComponentSqrs() >= v2.SumComponentSqrs(); - } - - /// - /// Compare two Vectors for equality. - /// Are two Vectors equal. - /// - /// Vector3 to be compared for equality - /// Vector3 to be compared to - /// Boolean decision (truth for equality) - /// - /// Checks the equality of each pair of components, all pairs must be equal - /// A tolerence to the equality operator is applied - /// - public static bool operator ==(Vector3 v1, Vector3 v2) - { - return - Math.Abs(v1.X - v2.X) <= EqualityTolerence && - Math.Abs(v1.Y - v2.Y) <= EqualityTolerence && - Math.Abs(v1.Z - v2.Z) <= EqualityTolerence; - } - - /// - /// Negative comparator of two Vectors. - /// Are two Vectors different. - /// - /// Vector3 to be compared for in-equality - /// Vector3 to be compared to - /// Boolean decision (truth for in-equality) - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - /// - /// Uses the equality operand function for two vectors to prevent code duplication - /// - public static bool operator !=(Vector3 v1, Vector3 v2) - { - return !(v1 == v2); - } - - #endregion - - #region Functions - - /// - /// calculate heading from point1 to point2 - /// - /// - /// - /// - public ushort GetHeadingToLocation(Vector3 p2) - { - var dx = (long)p2.X - X; - var dy = (long)p2.Y - Y; - var heading = (ushort)(Math.Atan2(-dx, dy) * Point2D.RADIAN_TO_HEADING); - if (heading < 0) - { - heading += 0x1000; - } - return heading; - } - - /// - /// Determine the cross product of two Vectors - /// Determine the vector product - /// Determine the normal vector (Vector3 90° to the plane) - /// - /// The vector to multiply - /// The vector to multiply by - /// Vector3 representing the cross product of the two vectors - /// - /// Cross products are non commutable - /// - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - public static Vector3 CrossProduct(Vector3 v1, Vector3 v2) - { - return - new Vector3 - ( - v1.Y * v2.Z - v1.Z * v2.Y, - v1.Z * v2.X - v1.X * v2.Z, - v1.X * v2.Y - v1.Y * v2.X - ); - } - - /// - /// 2D Vector3 with Z=0 - /// - /// - public Vector3 To2D() - { - return new Vector3(X, Y, 0); - } - - /// - /// Determine the cross product of this Vector3 and another - /// Determine the vector product - /// Determine the normal vector (Vector3 90° to the plane) - /// - /// The vector to multiply by - /// Vector3 representing the cross product of the two vectors - /// - /// Uses the CrossProduct function to avoid code duplication - /// - /// - public Vector3 CrossProduct(Vector3 other) - { - return CrossProduct(this, other); - } - - /// - /// Determine the dot product of two Vectors - /// - /// The vector to multiply - /// The vector to multiply by - /// Scalar representing the dot product of the two vectors - /// - /// - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - public static double DotProduct(Vector3 v1, Vector3 v2) - { - return - v1.X * v2.X + - v1.Y * v2.Y + - v1.Z * v2.Z; - } - - /// - /// Determine the dot product of this Vector3 and another - /// - /// The vector to multiply by - /// Scalar representing the dot product of the two vectors - /// - /// - /// - public double DotProduct(Vector3 other) - { - return DotProduct(this, other); - } - - /// - /// Determine the mixed product of three Vectors - /// Determine volume (with sign precision) of parallelepiped spanned on given vectors - /// Determine the scalar triple product of three vectors - /// - /// The first vector - /// The second vector - /// The third vector - /// Scalar representing the mixed product of the three vectors - /// - /// Mixed products are non commutable - /// - /// - /// - /// This code was provided by Michał Bryłka - public static double MixedProduct(Vector3 v1, Vector3 v2, Vector3 v3) - { - return DotProduct(CrossProduct(v1, v2), v3); - } - - /// - /// Determine the mixed product of three Vectors - /// Determine volume (with sign precision) of parallelepiped spanned on given vectors - /// Determine the scalar triple product of three vectors - /// - /// The second vector - /// The third vector - /// Scalar representing the mixed product of the three vectors - /// - /// Mixed products are non commutable - /// - /// Uses MixedProduct(Vector3, Vector3, Vector3) to avoid code duplication - /// - public double MixedProduct(Vector3 other_v1, Vector3 other_v2) - { - return DotProduct(CrossProduct(this, other_v1), other_v2); - } - - /// - /// Get the normalized vector - /// Get the unit vector - /// Scale the Vector3 so that the magnitude is 1 - /// - /// The vector to be normalized - /// The normalized Vector3 - /// - /// Uses the Magnitude function to avoid code duplication - /// - /// - /// Thrown when the normalisation of a zero magnitude vector is attempted - /// - /// This code is adapted from Exocortex - Ben Houston - public static Vector3 Normalize(Vector3 v1) - { - // Check for divide by zero errors - if (v1.Magnitude == 0) - { - throw new DivideByZeroException(NORMALIZE_0); - } - // find the inverse of the vectors magnitude - var inverse = 1 / v1.Magnitude; - return - new Vector3 - ( - // multiply each component by the inverse of the magnitude - v1.X * inverse, - v1.Y * inverse, - v1.Z * inverse - ); - } - - public void Negate() - { - X = -X; - Y = -Y; - Z = -Z; - } - - /// - /// Get the normalized vector - /// Get the unit vector - /// Scale the Vector3 so that the magnitude is 1 - /// - /// The normalized Vector3 - /// - /// Uses the Magnitude and Normalize function to avoid code duplication - /// - /// - /// Thrown when the normalisation of a zero magnitude vector is attempted - /// - /// This code is adapted from Exocortex - Ben Houston - public void Normalize() - { - this = Normalize(this); - } - - /// - /// Take an interpolated value from between two Vectors or an extrapolated value if allowed - /// - /// The Vector3 to interpolate from (where control ==0) - /// The Vector3 to interpolate to (where control ==1) - /// - /// The interpolated point between the two vectors to retrieve (fraction between 0 and 1), or an - /// extrapolated point if allowed - /// - /// True if the control may represent a point not on the vertex between v1 and v2 - /// - /// The value at an arbitrary distance (interpolation) between two vectors or an extrapolated point on the - /// extended virtex - /// - /// - /// Thrown when the control is not between values of 0 and 1 and extrapolation is not allowed - /// - /// This code is adapted from Exocortex - Ben Houston - public static Vector3 Interpolate(Vector3 v1, Vector3 v2, double control, bool allowExtrapolation) - { - if (!allowExtrapolation && (control > 1 || control < 0)) - { - // Error message includes information about the actual value of the argument - throw new ArgumentOutOfRangeException - ( - "control", - control, - INTERPOLATION_RANGE + "\n" + ARGUMENT_VALUE + control - ); - } - return - new Vector3 - ( - v1.X * (1 - control) + v2.X * control, - v1.Y * (1 - control) + v2.Y * control, - v1.Z * (1 - control) + v2.Z * control - ); - } - - /// - /// Take an interpolated value from between two Vectors - /// - /// The Vector3 to interpolate from (where control ==0) - /// The Vector3 to interpolate to (where control ==1) - /// The interpolated point between the two vectors to retrieve (fraction between 0 and 1) - /// The value at an arbitrary distance (interpolation) between two vectors - /// - /// - /// Uses the Interpolate(Vector3,Vector3,double,bool) method to avoid code duplication - /// - /// - /// Thrown when the control is not between values of 0 and 1 - /// - /// This code is adapted from Exocortex - Ben Houston - public static Vector3 Interpolate(Vector3 v1, Vector3 v2, double control) - { - return Interpolate(v1, v2, control, false); - } - - - /// - /// Take an interpolated value from between two Vectors - /// - /// The Vector3 to interpolate to (where control ==1) - /// The interpolated point between the two vectors to retrieve (fraction between 0 and 1) - /// The value at an arbitrary distance (interpolation) between two vectors - /// - /// - /// Overload for Interpolate method, finds an interpolated value between this Vector3 and another - /// Uses the Interpolate(Vector3,Vector3,double) method to avoid code duplication - /// - public Vector3 Interpolate(Vector3 other, double control) - { - return Interpolate(this, other, control); - } - - /// - /// Take an interpolated value from between two Vectors or an extrapolated value if allowed - /// - /// The Vector3 to interpolate to (where control ==1) - /// - /// The interpolated point between the two vectors to retrieve (fraction between 0 and 1), or an - /// extrapolated point if allowed - /// - /// True if the control may represent a point not on the vertex between v1 and v2 - /// - /// The value at an arbitrary distance (interpolation) between two vectors or an extrapolated point on the - /// extended virtex - /// - /// - /// - /// Uses the Interpolate(Vector3,Vector3,double,bool) method to avoid code duplication - /// - /// - /// Thrown when the control is not between values of 0 and 1 and extrapolation is not allowed - /// - public Vector3 Interpolate(Vector3 other, double control, bool allowExtrapolation) - { - return Interpolate(this, other, control); - } - - /// - /// Find the distance between two Vectors - /// Pythagoras theorem on two Vectors - /// - /// The Vector3 to find the distance from - /// The Vector3 to find the distance to - /// The distance between two Vectors - /// - /// - public static double Distance(Vector3 v1, Vector3 v2) - { - var dx = v1.X - v2.X; - var dy = v1.Y - v2.Y; - return - v1.Z != 0 && v2.Z != 0 - ? // ignore Z if one is 0 - Math.Sqrt - ( - dx * dx + dy * dy + - (v1.Z - v2.Z) * (v1.Z - v2.Z) - ) - : Math.Sqrt - ( - dx * dx + dy * dy - ); - } - - /// - /// Find the distance between two Vectors but no Sqrt on it - /// Pythagoras theorem on two but no Sqrt on it - /// - /// The Vector3 to find the distance from - /// The Vector3 to find the distance to - /// The squared distance between two Vectors - /// - /// - public static double DistanceSquared(Vector3 v1, Vector3 v2) - { - var dx = v1.X - v2.X; - var dy = v1.Y - v2.Y; - return - v1.Z != 0 && v2.Z != 0 - ? // ignore Z if one is 0 - dx * dx + dy * dy + (v1.Z - v2.Z) * (v1.Z - v2.Z) - : dx * dx + dy * dy; - } - - /// - /// Find the distance between two Vectors ignoring Z - /// Pythagoras theorem on two Vectors - /// - /// The Vector3 to find the distance from - /// The Vector3 to find the distance to - /// The distance between two Vectors - /// - /// - public static double Distance2D(Vector3 v1, Vector3 v2) - { - var dx = v1.X - v2.X; - var dy = v1.Y - v2.Y; - return Math.Sqrt(dx * dx + dy * dy); - } - - /// - /// Find the distance between two Vectors ignoring Z - /// Pythagoras theorem on two Vectors - /// - /// The Vector3 to find the distance to - /// The distance between two Vectors - /// - /// - /// Overload for Distance method, finds distance between this Vector3 and another - /// Uses the Distance(Vector3,Vector3) method to avoid code duplication - /// - public double Distance2D(Vector3 other) - { - return Distance2D(this, other); - } - - /// - /// Find the distance between two Vectors - /// Pythagoras theorem on two Vectors - /// - /// The Vector3 to find the distance to - /// The distance between two Vectors - /// - /// - /// Overload for Distance method, finds distance between this Vector3 and another - /// Uses the Distance(Vector3,Vector3) method to avoid code duplication - /// - public double Distance(Vector3 other) - { - return Distance(this, other); - } - - /// - /// Find the squared distance between two Vectors - /// Pythagoras theorem on two Vectors but no qert on it - /// - /// The Vector3 to find the distance to - /// The distance between two Vectors - /// - /// - /// Overload for DistanceSquared method, finds squared distance between this Vector3 and another - /// Uses the DistanceSquared(Vector3,Vector3) method to avoid code duplication - /// - public double DistanceSquared(Vector3 other) - { - return DistanceSquared(this, other); - } - - /// - /// Find the angle between two Vectors - /// - /// The Vector3 to discern the angle from - /// The Vector3 to discern the angle to - /// The angle between two positional Vectors - /// - /// - /// F.Hill, 2001, Computer Graphics using OpenGL, 2ed - public static double Angle(Vector3 v1, Vector3 v2) - { - return - Math.Acos - ( - Normalize(v1).DotProduct(Normalize(v2)) - ); - } - - /// - /// Find the angle between this Vector3 and another - /// - /// The Vector3 to discern the angle to - /// The angle between two positional Vectors - /// - /// - /// Uses the Angle(Vector3,Vector3) method to avoid code duplication - /// - public double Angle(Vector3 other) - { - return Angle(this, other); - } - - /// - /// compares the magnitude of two Vectors and returns the greater Vector3 - /// - /// The vector to compare - /// The vector to compare with - /// - /// The greater of the two Vectors (based on magnitude) - /// - /// This code is adapted from Exocortex - Ben Houston - public static Vector3 Max(Vector3 v1, Vector3 v2) - { - if (v1 >= v2) - { - return v1; - } - return v2; - } - - /// - /// compares the magnitude of two Vectors and returns the greater Vector3 - /// - /// The vector to compare with - /// - /// The greater of the two Vectors (based on magnitude) - /// - /// - /// - /// Uses function Max(Vector3, Vector3) to avoid code duplication - /// - public Vector3 Max(Vector3 other) - { - return Max(this, other); - } - - /// - /// compares the magnitude of two Vectors and returns the lesser Vector3 - /// - /// The vector to compare - /// The vector to compare with - /// - /// The lesser of the two Vectors (based on magnitude) - /// - /// This code is adapted from Exocortex - Ben Houston - public static Vector3 Min(Vector3 v1, Vector3 v2) - { - if (v1 <= v2) - { - return v1; - } - return v2; - } - - /// - /// Compares the magnitude of two Vectors and returns the greater Vector3 - /// - /// The vector to compare with - /// - /// The lesser of the two Vectors (based on magnitude) - /// - /// - /// - /// Uses function Min(Vector3, Vector3) to avoid code duplication - /// - public Vector3 Min(Vector3 other) - { - return Min(this, other); - } - - /// - /// Rotates a Vector3 around the Y axis - /// Change the yaw of a Vector3 - /// - /// The Vector3 to be rotated - /// The angle to rotate the Vector3 around in degrees - /// Vector3 representing the rotation around the Y axis - public static Vector3 Yaw(Vector3 v1, double degree) - { - var x = v1.Z * Math.Sin(degree) + v1.X * Math.Cos(degree); - var y = v1.Y; - var z = v1.Z * Math.Cos(degree) - v1.X * Math.Sin(degree); - return new Vector3(x, y, z); - } - - /// - /// Rotates the Vector3 around the Y axis - /// Change the yaw of the Vector3 - /// - /// The angle to rotate the Vector3 around in degrees - /// Vector3 representing the rotation around the Y axis - /// - /// - /// Uses function Yaw(Vector3, double) to avoid code duplication - /// - public void Yaw(double degree) - { - this = Yaw(this, degree); - } - - /// - /// Rotates a Vector3 around the X axis - /// Change the pitch of a Vector3 - /// - /// The Vector3 to be rotated - /// The angle to rotate the Vector3 around in degrees - /// Vector3 representing the rotation around the X axis - public static Vector3 Pitch(Vector3 v1, double degree) - { - var x = v1.X; - var y = v1.Y * Math.Cos(degree) - v1.Z * Math.Sin(degree); - var z = v1.Y * Math.Sin(degree) + v1.Z * Math.Cos(degree); - return new Vector3(x, y, z); - } - - /// - /// Rotates a Vector3 around the X axis - /// Change the pitch of a Vector3 - /// - /// The angle to rotate the Vector3 around in degrees - /// Vector3 representing the rotation around the X axis - /// - /// - /// Uses function Pitch(Vector3, double) to avoid code duplication - /// - public void Pitch(double degree) - { - this = Pitch(this, degree); - } - - /// - /// Rotates a Vector3 around the Z axis - /// Change the roll of a Vector3 - /// Important: In DAoC coord system this will rotate clockwise! - /// - /// The Vector3 to be rotated - /// The angle to rotate the Vector3 around in degrees - /// Vector3 representing the rotation around the Z axis - public static Vector3 RotateOnZ(Vector3 v1, double degree) - { - var radian = degree * DegreeToRadian; - var cos = Math.Cos(radian); - var sin = Math.Sin(radian); - var x = v1.X * cos - v1.Y * sin; - var y = v1.X * sin + v1.Y * cos; - var z = v1.Z; - return new Vector3(x, y, z); - } - - /// - /// Rotates a Vector3 around the Z axis - /// Change the roll of a Vector3 - /// Important: In DAoC coord system this will rotate clockwise! - /// - /// The angle to rotate the Vector3 around in degrees - /// Vector3 representing the rotation around the Z axis - /// - /// - /// Uses function Roll(Vector3, double) to avoid code duplication - /// - public void RotateOnZ(double degree) - { - this = RotateOnZ(this, degree); - } - - public Vector3 Offset(int dx, int dy, int dz) - { - return new Vector3(X + dx, Y + dy, Z + dz); - } - - /* /// - /// Reflect a Vector3 about a given normal - /// - /// The normal Vector3 to reflect about - /// - /// The reflected Vector3 - /// - public Vector3 Reflection(Vector3 normal) - { - return - ( - ( - this.Normalize() - - ( - normal * - 2 * - this.Normalize().DotProduct(normal) - ) - ) * - this.Magnitude() * - this - ); - } - */ - - /// - /// Find the absolute value of a Vector3 - /// Find the magnitude of a Vector3 - /// - /// A Vector3 representing the absolute values of the vector - /// - /// An alternative interface to the magnitude property - /// - public static double Abs(Vector3 v1) - { - return v1.Magnitude; - } - - /// - /// Find the absolute value of a Vector3 - /// Find the magnitude of a Vector3 - /// - /// A Vector3 representing the absolute values of the vector - /// - /// An alternative interface to the magnitude property - /// - public double Abs() - { - return Magnitude; - } - - #endregion - - #region Component Operations - - /// - /// The sum of a Vector3's components - /// - /// The vector whose scalar components to sum - /// The sum of the Vectors X, Y and Z components - public static double SumComponents(Vector3 v1) - { - return v1.X + v1.Y + v1.Z; - } - - /// - /// The sum of this Vector3's components - /// - /// The sum of the Vectors X, Y and Z components - /// - /// - /// The Components.SumComponents(Vector3) function has been used to prevent code duplication - /// - public double SumComponents() - { - return SumComponents(this); - } - - /// - /// The sum of a Vector3's squared components - /// - /// The vector whose scalar components to square and sum - /// The sum of the Vectors X^2, Y^2 and Z^2 components - public static double SumComponentSqrs(Vector3 v1) - { - var v2 = SqrComponents(v1); - return v2.SumComponents(); - } - - /// - /// The sum of this Vector3's squared components - /// - /// The sum of the Vectors X^2, Y^2 and Z^2 components - /// - /// - /// The Components.SumComponentSqrs(Vector3) function has been used to prevent code duplication - /// - public double SumComponentSqrs() - { - return SumComponentSqrs(this); - } - - /// - /// The individual multiplication to a power of a Vector3's components - /// - /// The vector whose scalar components to multiply by a power - /// The power by which to multiply the components - /// The multiplied Vector3 - public static Vector3 PowComponents(Vector3 v1, double power) - { - return - new Vector3 - ( - Math.Pow(v1.X, power), - Math.Pow(v1.Y, power), - Math.Pow(v1.Z, power) - ); - } - - /// - /// The individual multiplication to a power of this Vector3's components - /// - /// The power by which to multiply the components - /// The multiplied Vector3 - /// - /// - /// The Components.PowComponents(Vector3, double) function has been used to prevent code duplication - /// - public void PowComponents(double power) - { - this = PowComponents(this, power); - } - - /// - /// The individual square root of a Vector3's components - /// - /// The vector whose scalar components to square root - /// The rooted Vector3 - public static Vector3 SqrtComponents(Vector3 v1) - { - return - new Vector3 - ( - Math.Sqrt(v1.X), - Math.Sqrt(v1.Y), - Math.Sqrt(v1.Z) - ); - } - - /// - /// The individual square root of this Vector3's components - /// - /// The rooted Vector3 - /// - /// - /// The Components.SqrtComponents(Vector3) function has been used to prevent code duplication - /// - public void SqrtComponents() - { - this = SqrtComponents(this); - } - - /// - /// The Vector3's components squared - /// - /// The vector whose scalar components are to square - /// The squared Vector3 - public static Vector3 SqrComponents(Vector3 v1) - { - return - new Vector3 - ( - v1.X * v1.X, - v1.Y * v1.Y, - v1.Z * v1.Z - ); - } - - /// - /// The Vector3's components squared - /// - /// The squared Vector3 - /// - /// - /// The Components.SqrComponents(Vector3) function has been used to prevent code duplication - /// - public void SqrComponents() - { - this = SqrtComponents(this); - } - - #endregion - - #region Standard Functions - - /// - /// Textual description of the Vector3 - /// - /// - /// Uses ToString(string, IFormatProvider) to avoid code duplication - /// - /// Text (String) representing the vector - public override string ToString() - { - return ToString(null, null); - } - - public string ToPositionString() - { - return string.Format("({0}, {1}, {2})", (int)X, (int)Y, (int)Z); - } - - /// - /// Verbose textual description of the Vector3 - /// - /// Text (string) representing the vector - public string ToVerbString() - { - string output = null; - - if (IsUnitVector()) - { - output += UNIT_VECTOR; - } - else - { - output += POSITIONAL_VECTOR; - } - - output += string.Format("( x={0}, y={1}, z={2} )", (int)X, (int)Y, (int)Z); - output += MAGNITUDE + Magnitude; - - return output; - } - - /// - /// Textual description of the Vector3 - /// - /// - /// Formatting string: 'x','y','z' or '' followed by standard numeric format string characters valid - /// for a double precision floating point - /// - /// The culture specific fromatting provider - /// Text (String) representing the vector - public string ToString(string format, IFormatProvider formatProvider) - { - // If no format is passed - if (format == null || format == "") - { - return string.Format("({0}, {1}, {2})", (int)X, (int)Y, (int)Z); - } - - var firstChar = format[0]; - string remainder = null; - - if (format.Length > 1) - { - remainder = format.Substring(1); - } - - switch (firstChar) - { - case 'x': - return X.ToString(remainder, formatProvider); - case 'y': - return Y.ToString(remainder, formatProvider); - case 'z': - return Z.ToString(remainder, formatProvider); - default: - return string.Format - ( - "({0}, {1}, {2})", - X.ToString(format, formatProvider), - Y.ToString(format, formatProvider), - Z.ToString(format, formatProvider) - ); - } - } - - /// - /// Get the hashcode - /// - /// Hashcode for the object instance - /// - /// Required in order to implement comparator operations (i.e. ==, !=) - /// - /// This code is adapted from CSOpenGL - Lucas Viñas Livschitz - public override int GetHashCode() - { - return - (int)((X + Y + Z) % int.MaxValue); - } - - /// - /// Comparator - /// - /// The other object (which should be a vector) to compare to - /// Truth if two vectors are equal within a tolerence - /// - /// Checks if the object argument is a Vector3 object - /// Uses the equality operator function to avoid code duplication - /// Required in order to implement comparator operations (i.e. ==, !=) - /// - public override bool Equals(object other) - { - // Check object other is a Vector3 object - if (other is Vector3) - { - // Convert object to Vector3 - var otherVector = (Vector3)other; - - // Check for equality - return otherVector == this; - } - return false; - } - - /// - /// Comparator - /// - /// The other Vector3 to compare to - /// Truth if two vectors are equal within a tolerence - /// - /// Uses the equality operator function to avoid code duplication - /// - public bool Equals(Vector3 other) - { - return other == this; - } - - /// - /// compares the magnitude of this instance against the magnitude of the supplied vector - /// - /// The vector to compare this instance with - /// - /// -1: The magnitude of this instance is less than the others magnitude - /// 0: The magnitude of this instance equals the magnitude of the other - /// 1: The magnitude of this instance is greater than the magnitude of the other - /// - /// - /// Implemented to fulfil the IComparable interface - /// - /// This code is adapted from Exocortex - Ben Houston - public int CompareTo(Vector3 other) - { - if (this < other) - { - return -1; - } - if (this > other) - { - return 1; - } - return 0; - } - - /// - /// compares the magnitude of this instance against the magnitude of the supplied vector - /// - /// The vector to compare this instance with - /// - /// -1: The magnitude of this instance is less than the others magnitude - /// 0: The magnitude of this instance equals the magnitude of the other - /// 1: The magnitude of this instance is greater than the magnitude of the other - /// - /// - /// Implemented to fulfil the IComparable interface - /// - /// - /// Throws an exception if the type of object to be compared is not known to this class - /// - /// This code is adapted from Exocortex - Ben Houston - public int CompareTo(object other) - { - if (other is Vector3) - { - return CompareTo((Vector3)other); - } - // Error condition: other is not a Vector3 object - throw new ArgumentException - ( - // Error message includes information about the actual type of the argument - NON_VECTOR_COMPARISON + "\n" + ARGUMENT_TYPE + other.GetType(), - "other" - ); - } - - #endregion - - #region Decisions - - /// - /// Checks if a vector a unit vector - /// Checks if the Vector3 has been normalized - /// Checks if a vector has a magnitude of 1 - /// - /// - /// The vector to be checked for Normalization - /// - /// Truth if the vector is a unit vector - /// - /// - /// Uses the Magnitude property in the check to avoid code duplication - /// Within a tolerence - /// - public static bool IsUnitVector(Vector3 v1) - { - return Math.Abs(v1.Magnitude - 1) <= EqualityTolerence; - } - - /// - /// Checks if the vector a unit vector - /// Checks if the Vector3 has been normalized - /// Checks if the vector has a magnitude of 1 - /// - /// Truth if this vector is a unit vector - /// - /// - /// Uses the isUnitVector(Vector3) property in the check to avoid code duplication - /// Within a tolerence - /// - public bool IsUnitVector() - { - return IsUnitVector(this); - } - - public bool IsZero - { - get { return X == 0 && Y == 0 && Z == 0; } - } - - /// - /// Check distance to other point - /// If in range it gives true - /// A bit better performance than calculating distance as it saves the Sqrt call - /// - /// - /// - /// - public bool IsInRange(Vector3 pos, int range) - { - var squaredRange = (double)range * range; - - var dx = X - pos.X; - var dy = Y - pos.Y; - //SH: Removed Z checks when one of the two Z values is zero(on ground) - if (Z == 0 || pos.Z == 0) - { - return dx * dx + dy * dy <= squaredRange; - } - - var dz = Z - pos.Z; - return dx * dx + dy * dy + dz * dz <= squaredRange; - } - - /// - /// Check distance to other point, no Z involved - /// If in range it gives true - /// A bit better performance than calculating distance as it saves the Sqrt call - /// - /// - /// - /// - public bool IsInRange2D(Vector3 pos, int range) - { - var dx = X - pos.X; - var dy = Y - pos.Y; - return dx * dx + dy * dy <= (double)range * range; - } - - - /// - /// Checks if a face normal vector represents back face - /// Checks if a face is visible, given the line of sight - /// - /// - /// The vector representing the face normal Vector3 - /// - /// - /// The unit vector representing the direction of sight from a virtual camera - /// - /// Truth if the vector (as a normal) represents a back face - /// - /// Uses the DotProduct function in the check to avoid code duplication - /// - public static bool IsBackFace(Vector3 normal, Vector3 lineOfSight) - { - return normal.DotProduct(lineOfSight) < 0; - } - - /// - /// Checks if a face normal vector represents back face - /// Checks if a face is visible, given the line of sight - /// - /// - /// The unit vector representing the direction of sight from a virtual camera - /// - /// Truth if the vector (as a normal) represents a back face - /// - /// - /// Uses the isBackFace(Vector3, Vector3) function in the check to avoid code duplication - /// - public bool IsBackFace(Vector3 lineOfSight) - { - return IsBackFace(this, lineOfSight); - } - - /// - /// Checks if two Vectors are perpendicular - /// Checks if two Vectors are orthogonal - /// Checks if one Vector3 is the normal of the other - /// - /// - /// The vector to be checked for orthogonality - /// - /// - /// The vector to be checked for orthogonality to - /// - /// Truth if the two Vectors are perpendicular - /// - /// Uses the DotProduct function in the check to avoid code duplication - /// - public static bool IsPerpendicular(Vector3 v1, Vector3 v2) - { - return v1.DotProduct(v2) == 0; - } - - /// - /// Checks if two Vectors are perpendicular - /// Checks if two Vectors are orthogonal - /// Checks if one Vector3 is the Normal of the other - /// - /// - /// The vector to be checked for orthogonality - /// - /// Truth if the two Vectors are perpendicular - /// - /// Uses the isPerpendicualr(Vector3, Vector3) function in the check to avoid code duplication - /// - public bool IsPerpendicular(Vector3 other) - { - return IsPerpendicular(this, other); - } - - #endregion - - #region Cartesian Vectors - - /// - /// Vector3 representing the Cartesian origin - /// - /// This code is adapted from Exocortex - Ben Houston - public static readonly Vector3 origin = new Vector3(0, 0, 0); - - /// - /// Vector3 representing the Cartesian XAxis - /// - /// This code is adapted from Exocortex - Ben Houston - public static readonly Vector3 xAxis = new Vector3(1, 0, 0); - - /// - /// Vector3 representing the Cartesian YAxis - /// - /// This code is adapted from Exocortex - Ben Houston - public static readonly Vector3 yAxis = new Vector3(0, 1, 0); - - /// - /// Vector3 representing the Cartesian ZAxis - /// - /// This code is adapted from Exocortex - Ben Houston - public static readonly Vector3 zAxis = new Vector3(0, 0, 1); - - #endregion - - #region Messages - - /// - /// Exception message descriptive text - /// Used for a failure for an array argument to have three components when three are needed - /// - private const string THREE_COMPONENTS = "Array must contain exactly three components , (x,y,z)"; - - /// - /// Exception message descriptive text - /// Used for a divide by zero event caused by the normalization of a vector with magnitude 0 - /// - private const string NORMALIZE_0 = "Can not normalize a vector when it's magnitude is zero"; - - /// - /// Exception message descriptive text - /// Used when interpolation is attempted with a control parameter not between 0 and 1 - /// - private const string INTERPOLATION_RANGE = "Control parameter must be a value between 0 & 1"; - - /// - /// Exception message descriptive text - /// Used when attempting to compare a Vector3 to an object which is not a type of Vector3 - /// - private const string NON_VECTOR_COMPARISON = "Cannot compare a Vector3 to a non-Vector3"; - - /// - /// Exception message additional information text - /// Used when adding type information of the given argument into an error message - /// - private const string ARGUMENT_TYPE = "The argument provided is a type of "; - - /// - /// Exception message additional information text - /// Used when adding value information of the given argument into an error message - /// - private const string ARGUMENT_VALUE = "The argument provided has a value of "; - - /// - /// Exception message additional information text - /// Used when adding length (number of components in an array) information of the given argument into an error message - /// - private const string ARGUMENT_LENGTH = "The argument provided has a length of "; - - /// - /// Exception message descriptive text - /// Used when attempting to set a Vectors magnitude to a negative value - /// - private const string NEGATIVE_MAGNITUDE = - "The magnitude of a Vector3 must be a positive value, (i.e. greater than 0)"; - - /// - /// Exception message descriptive text - /// Used when attempting to set a Vectors magnitude where the Vector3 represents the origin - /// - private const string ORAGIN_VECTOR_MAGNITUDE = "Cannot change the magnitude of Vector3(0,0,0)"; - - /////////////////////////////////////////////////////////////////////////////// - - private const string UNIT_VECTOR = "Unit vector composing of "; - - private const string POSITIONAL_VECTOR = "Positional vector composing of "; - - private const string MAGNITUDE = " of magnitude "; - - /////////////////////////////////////////////////////////////////////////////// - - #endregion - - #region Constants - - /// - /// The tolerence used when determining the equality of two vectors - /// - public const double EqualityTolerence = double.Epsilon; - - /// - /// The smallest vector possible (based on the double precision floating point structure) - /// - public static readonly Vector3 MinValue = new Vector3(double.MinValue, double.MinValue, double.MinValue); - - /// - /// The largest vector possible (based on the double precision floating point structure) - /// - public static readonly Vector3 MaxValue = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue); - - public static readonly Vector3 Zero = new Vector3(0, 0, 0); - - /// - /// The smallest positive (non-zero) vector possible (based on the double precision floating point structure) - /// - public static readonly Vector3 Epsilon = new Vector3(double.Epsilon, double.Epsilon, double.Epsilon); - - public const double DegreeToRadian = 2 * Math.PI / 360; - public const double RadianToDegree = 1 / DegreeToRadian; - - #endregion - } -} \ No newline at end of file diff --git a/GameServer/GameClient.cs b/GameServer/GameClient.cs index b5284069..c4c23f41 100644 --- a/GameServer/GameClient.cs +++ b/GameServer/GameClient.cs @@ -27,6 +27,7 @@ using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.ServerProperties; using DOL.Language; @@ -748,16 +749,9 @@ public void SavePlayer() { //Time playing var connectedtime = DateTime.Now.Subtract(m_account.LastLogin).TotalMinutes; - //Lets get our player from DB. - var getp = GameServer.Database.FindObjectByKey(m_player.InternalID); - //Let get saved poistion from DB. - int[] oldloc = { getp.Xpos, getp.Ypos, getp.Zpos, getp.Direction, getp.Region }; - //Lets get current player Gloc. - int[] currentloc = { (int)m_player.Position.X, (int)m_player.Position.Y, (int)m_player.Position.Z, m_player.Heading, m_player.CurrentRegionID }; - //Compapre Old and Current. - bool check = oldloc.SequenceEqual(currentloc); - //If match - if (check) + var dbCharacter = GameServer.Database.FindObjectByKey(m_player.InternalID); + + if (dbCharacter.GetPosition() == Player.Position) { if (connectedtime > Properties.KICK_IDLE_PLAYER_TIME) { diff --git a/GameServer/Geometry/Angle.cs b/GameServer/Geometry/Angle.cs new file mode 100644 index 00000000..d1cf60b9 --- /dev/null +++ b/GameServer/Geometry/Angle.cs @@ -0,0 +1,60 @@ +using System; + +namespace DOL.GS.Geometry; + +public struct Angle +{ + private const int STEPS_TO_CIRCUMVOLUTION = 360 * 4096; + private const int HEADING_TO_STEPS = STEPS_TO_CIRCUMVOLUTION / 4096; + private const int DEGREE_TO_STEPS = STEPS_TO_CIRCUMVOLUTION / 360; + private const double RADIANS_TO_STEPS = STEPS_TO_CIRCUMVOLUTION / 2 / Math.PI; + + private int steps; + + ///for internal use only + private static Angle Steps(int steps) + { + steps %= STEPS_TO_CIRCUMVOLUTION; + if (steps < 0) steps += STEPS_TO_CIRCUMVOLUTION; + return new() { steps = steps }; + } + + public static Angle Heading(int heading) + => Steps(heading * HEADING_TO_STEPS); + + public static Angle Degrees(int degrees) + => Steps(degrees * DEGREE_TO_STEPS); + + public static Angle Radians(double radians) + => Steps((int)Math.Round(radians * RADIANS_TO_STEPS)); + + public double InRadians => steps / RADIANS_TO_STEPS; + public ushort InDegrees => (ushort)(steps / DEGREE_TO_STEPS); + public ushort InHeading => (ushort)(steps / HEADING_TO_STEPS); + + public override bool Equals(object obj) + { + if (obj is Angle angle) return angle.steps == steps; + return false; + } + + public override int GetHashCode() + => base.GetHashCode(); + + public override string ToString() + => steps.ToString(); + + public static bool operator ==(Angle a, Angle b) + => a.Equals(b); + + public static bool operator !=(Angle a, Angle b) + => !a.Equals(b); + + public static Angle operator +(Angle a, Angle b) + => Steps(a.steps + b.steps); + + public static Angle operator -(Angle a, Angle b) + => Steps(a.steps - b.steps); + + public static readonly Angle Zero = new() { steps = 0 }; +} \ No newline at end of file diff --git a/GameServer/Geometry/Coordinate.cs b/GameServer/Geometry/Coordinate.cs new file mode 100644 index 00000000..9ff4b0d9 --- /dev/null +++ b/GameServer/Geometry/Coordinate.cs @@ -0,0 +1,70 @@ +namespace DOL.GS.Geometry; + +public struct Coordinate +{ + private Vector coordinate { get; init; } + + public int X => coordinate.X; + public int Y => coordinate.Y; + public int Z => coordinate.Z; + + public static Coordinate Create(System.Numerics.Vector3 v) => new () { coordinate = Vector.Create((int)v.X, (int)v.Y, (int)v.Z) }; + + public static Coordinate Create(int x = 0, int y = 0, int z = 0) + => new() { coordinate = Vector.Create(x, y, z) }; + + public Coordinate With(int? x = null, int? y = null, int? z = null) + => new() { coordinate = Vector.Create(x ?? X, y ?? Y, z ?? Z) }; + + public double DistanceTo(Position pos, bool ignoreZ = false) + => DistanceTo(pos.Coordinate, ignoreZ); + + public double DistanceTo(Coordinate loc, bool ignoreZ = false) + { + if (Equals(Nowhere) || loc.Equals(Nowhere)) return double.PositiveInfinity; + + if (ignoreZ) return (loc - this).Length2D; + else return (loc - this).Length; + } + + public Angle GetOrientationTo(Coordinate loc) + => (loc - this).Orientation; + + public static Coordinate operator +(Coordinate loc, Vector v) + => new() { coordinate = loc.coordinate + v }; + + public static Coordinate operator -(Coordinate loc, Vector v) + => new() { coordinate = loc.coordinate - v }; + + public static Vector operator -(Coordinate locA, Coordinate locB) + => Vector.Create(x: locA.X - locB.X, y: locA.Y - locB.Y, z: locA.Z - locB.Z); + + public static bool operator ==(Coordinate a, Coordinate b) + => a.Equals(b); + + public static bool operator !=(Coordinate a, Coordinate b) + => !a.Equals(b); + + public override bool Equals(object obj) + { + if (obj is Coordinate loc) + { + return X == loc.X && Y == loc.Y && Z == loc.Z; + } + return false; + } + + public override int GetHashCode() + => base.GetHashCode(); + + public override string ToString() + => $"{X}, {Y}, {Z}"; + + public System.Numerics.Vector3 ToSysVector3() + { + return new System.Numerics.Vector3(X, Y, Z); + } + + public readonly static Coordinate Nowhere = Create(-1, -1, -1); + public readonly static Coordinate Zero = Create(0, 0, 0); +} diff --git a/GameServer/Geometry/DataObjectPositionExtensions.cs b/GameServer/Geometry/DataObjectPositionExtensions.cs new file mode 100644 index 00000000..6be47cd9 --- /dev/null +++ b/GameServer/Geometry/DataObjectPositionExtensions.cs @@ -0,0 +1,45 @@ +using DOL.Database; + +namespace DOL.GS.Geometry; + +public static class DataObjectPositionExtensions +{ + public static Position GetPosition(this Mob mob) + => Position.Create(mob.Region, mob.X, mob.Y, mob.Z, Angle.Heading(mob.Heading)); + + public static Position GetPosition(this Teleport teleport) + => Position.Create((ushort)teleport.RegionID, teleport.X, teleport.Y, teleport.Z, Angle.Heading(teleport.Heading)); + + public static Position GetSourcePosition(this ZonePoint zonePoint) + => Position.Create(zonePoint.SourceRegion, zonePoint.SourceX, zonePoint.SourceY, zonePoint.SourceZ); + + public static Position GetTargetPosition(this ZonePoint zonePoint) + => Position.Create(zonePoint.TargetRegion, zonePoint.TargetX, zonePoint.TargetY, zonePoint.TargetZ, Angle.Heading(zonePoint.TargetHeading)); + + public static Position GetPosition(this DOLCharacters dolc) + => Position.Create((ushort)dolc.Region, dolc.Xpos, dolc.Ypos, dolc.Zpos, Angle.Heading(dolc.Direction)); + + public static void SetPosition(this DOLCharacters dolc, Position pos) + { + dolc.Region = pos.RegionID; + dolc.Xpos = pos.X; + dolc.Ypos = pos.Y; + dolc.Zpos = pos.Z; + dolc.Direction = pos.Orientation.InHeading; + } + + public static Position GetBindPosition(this DOLCharacters dolc) + => Position.Create((ushort)dolc.BindRegion, dolc.BindXpos, dolc.BindYpos, dolc.BindZpos, Angle.Heading(dolc.BindHeading)); + + public static Position GetPosition(this DBKeep dbKeep) + => Position.Create(dbKeep.Region, dbKeep.X, dbKeep.Y, dbKeep.Z, Angle.Degrees(dbKeep.Heading)); + + public static void SetPosition(this DBKeep dbKeep, Position pos) + { + dbKeep.Region = pos.RegionID; + dbKeep.X = pos.X; + dbKeep.Y = pos.Y; + dbKeep.Z = pos.Z; + dbKeep.Heading = (ushort)pos.Orientation.InDegrees; + } +} \ No newline at end of file diff --git a/GameServer/Geometry/LinePath.cs b/GameServer/Geometry/LinePath.cs new file mode 100644 index 00000000..e6676623 --- /dev/null +++ b/GameServer/Geometry/LinePath.cs @@ -0,0 +1,23 @@ +using System; +using System.Linq; + +namespace DOL.GS.Geometry; + +public class LinePath +{ + private Coordinate[] wayPoints = Array.Empty(); + private int indexCounter = 0; + + public static LinePath Create(Coordinate[] wayPoints) + => new LinePath() { wayPoints = wayPoints }; + + public Coordinate Start => wayPoints.Length == 0 ? Coordinate.Nowhere : wayPoints.First(); + + public Coordinate End => wayPoints.Length == 0 ? Coordinate.Nowhere : wayPoints.Last(); + + public void SelectNextWayPoint() => indexCounter++; + + public Coordinate CurrentWayPoint => (indexCounter < PointCount - 1) ? wayPoints[indexCounter] : Coordinate.Nowhere; + + public int PointCount => wayPoints.Length; +} \ No newline at end of file diff --git a/GameServer/Geometry/Motion.cs b/GameServer/Geometry/Motion.cs new file mode 100644 index 00000000..f3d15296 --- /dev/null +++ b/GameServer/Geometry/Motion.cs @@ -0,0 +1,32 @@ +using System; + +namespace DOL.GS.Geometry; + +public class Motion +{ + public static Motion Create(Position start, Coordinate destination, short withSpeed) + => new Motion() { Start = start, Destination = destination, Speed = withSpeed }; + + public int StartTimeInMilliSeconds { get; } = Environment.TickCount; + public Position Start { get; init; } = Position.Nowhere; + public Coordinate Destination { get; init; } = Coordinate.Nowhere; + public short Speed { get; init; } = 0; + + public Position CurrentPosition + => GetPositonAfter(Environment.TickCount - StartTimeInMilliSeconds); + public double FullDistance => Destination.DistanceTo(Start, ignoreZ: true); + public double RemainingDistance => Destination.DistanceTo(CurrentPosition, ignoreZ: true); + + public Position GetPositonAfter(int elapsedTimeInMilliSeconds) + { + if (Speed == 0 || Start.Coordinate == Destination) return Start; + + var distanceTravelled = Speed * elapsedTimeInMilliSeconds * 0.001; + if (Destination == Coordinate.Nowhere) return Start + Vector.Create(Start.Orientation, distanceTravelled); + + var movementVector = Destination - Start.Coordinate; + if (distanceTravelled > FullDistance) return Position.Create(Start.RegionID, Destination, movementVector.Orientation); + + return Start.With(movementVector.Orientation) + movementVector * (distanceTravelled / FullDistance); + } +} \ No newline at end of file diff --git a/GameServer/Geometry/Position.cs b/GameServer/Geometry/Position.cs new file mode 100644 index 00000000..a3cbb3de --- /dev/null +++ b/GameServer/Geometry/Position.cs @@ -0,0 +1,82 @@ +namespace DOL.GS.Geometry; + +public struct Position +{ + public ushort RegionID { get; init; } = 0; + public Coordinate Coordinate { get; init; } = Coordinate.Zero; + public Angle Orientation { get; init; } = Angle.Zero; + + public int X => Coordinate.X; + public int Y => Coordinate.Y; + public int Z => Coordinate.Z; + + public Region Region { get; init; } = null; + + public Position() { } + + public static Position Create(ushort regionID, int x, int y, int z, ushort heading) + => new() { RegionID = regionID, Coordinate = Coordinate.Create(x, y, z), Orientation = Angle.Heading(heading), Region = WorldMgr.GetRegion(regionID) }; + + public static Position Create(ushort regionID, int x = 0, int y = 0, int z = 0, Angle? orientation = null) + => new() { RegionID = regionID, Coordinate = Coordinate.Create(x, y, z), Orientation = orientation ?? Angle.Zero, Region = WorldMgr.GetRegion(regionID) }; + + public static Position CreateInZone(ushort zoneID, int x = 0, int y = 0, int z = 0, ushort heading = 0) + { + var zone = WorldMgr.GetZone(zoneID); + return Create(zone.ZoneRegion.ID, x + zone.Offset.X, y + zone.Offset.Y, z + zone.Offset.Z, heading); + } + + public static Position Create(ushort regionID, Coordinate coordinate, ushort heading = 0) + => new() { RegionID = regionID, Coordinate = coordinate, Orientation = Angle.Heading(heading), Region = WorldMgr.GetRegion(regionID) }; + + public static Position Create(ushort regionID, Coordinate coordinate, Angle orientation) + => new() { RegionID = regionID, Coordinate = coordinate, Orientation = orientation, Region = WorldMgr.GetRegion(regionID) }; + + public Position With(ushort? regionID = null, int? x = null, int? y = null, int? z = null, ushort? heading = null) + { + var newOrientation = heading != null ? Angle.Heading((ushort)heading) : Orientation; + var newRegionID = regionID ?? RegionID; + return Create(newRegionID, Coordinate.With(x, y, z), newOrientation); + } + + public Position With(Coordinate coordinate) + => Create(RegionID, coordinate, Orientation); + + public Position With(Angle orientation) + => Create(RegionID, Coordinate, orientation); + + public Position TurnedAround() + => With(orientation: Orientation + Angle.Degrees(180)); + + public static Position operator +(Position a, Vector b) + => a.With(coordinate: a.Coordinate + b); + + public static Position operator -(Position a, Vector b) + => a.With(coordinate: a.Coordinate - b); + + public static bool operator ==(Position a, Position b) + => a.Equals(b); + + public static bool operator !=(Position a, Position b) + => !a.Equals(b); + + public override bool Equals(object obj) + { + if (obj is Position otherPos) + { + return otherPos.RegionID == RegionID + && otherPos.Coordinate.Equals(Coordinate) + && otherPos.Orientation == Orientation; + } + return false; + } + + public override int GetHashCode() + => base.GetHashCode(); + + public override string ToString() + => $"({Coordinate}, {Orientation.InHeading})"; + + public readonly static Position Nowhere = Create(regionID: ushort.MaxValue, Coordinate.Nowhere, Angle.Zero); + public readonly static Position Zero = new(); +} diff --git a/GameServer/Geometry/Vector.cs b/GameServer/Geometry/Vector.cs new file mode 100644 index 00000000..05d868a3 --- /dev/null +++ b/GameServer/Geometry/Vector.cs @@ -0,0 +1,86 @@ +using System; + +namespace DOL.GS.Geometry; + +public struct Vector +{ + public int X { get; init; } + public int Y { get; init; } + public int Z { get; init; } + + public double Length => Math.Sqrt((double)X * X + (double)Y * Y + (double)Z * Z); + public double Length2D => Math.Sqrt((double)X * X + (double)Y * Y); + public Angle Orientation => Angle.Radians(-Math.Atan2(X,Y)); + + public static Vector Create(int x = 0, int y = 0, int z = 0) + => new() { X = x, Y = y, Z = z }; + + // Coordinate calculation functions in DOL are standard trigonometric functions, but + // with some adjustments to account for the different coordinate system that DOL uses + // compared to the standard Cartesian coordinates used in trigonometry. + // + // DOL Heading grid: + // 2048/180° + // | + // 1024/90° ------- 3072/270° (+x) + // | + // 0 (+y) + // + // The Cartesian grid is 0 at the right side of the X-axis and increases counter-clockwise. + // The DOL Heading grid is 0 at the bottom of the Y-axis and increases clockwise. + // General trigonometry and the System.Math library use the Cartesian grid. + public static Vector Create(Angle orientation, double length, int z = 0) + { + var distanceXY = Math.Sqrt(length * length - z * z); + if(length < 0) distanceXY *= -1; + return Create( + x: (int)Math.Round(Math.Sin(-orientation.InRadians) * distanceXY), + y: (int)Math.Round(Math.Cos(orientation.InRadians) * distanceXY), + z: z); + } + + public Vector RotatedClockwise(Angle angle) + { + var cos = Math.Cos(angle.InRadians); + var sin = Math.Sin(angle.InRadians); + return Create( + x: (int)Math.Round(cos * X - sin * Y), + y: (int)Math.Round(cos * Y + sin * X), + z: Z); + } + + public override string ToString() + => $"{X}, {Y}, {Z}"; + + public override bool Equals(object obj) + { + if(obj is Vector vector) + { + return vector.X == X && vector.Y == Y && vector.Z == Z; + } + else return false; + } + + public override int GetHashCode() + => base.GetHashCode(); + + public static Vector operator *(Vector vec, double factor) + => Create((int)(vec.X * factor), (int)(vec.Y * factor), (int)(vec.Z * factor)); + + public static Vector operator *(double factor, Vector vec) + => vec * factor; + + public static Vector operator /(Vector vec, double factor) + => Create((int)(vec.X / factor), (int)(vec.Y / factor), (int)(vec.Z / factor)); + + public static Vector operator /(double factor, Vector vec) + => vec / factor; + + public static Vector operator +(Vector vecA, Vector vecB) + => Create(vecA.X + vecB.X, vecA.Y + vecB.Y, vecA.Z + vecB.Z); + + public static Vector operator -(Vector vecA, Vector vecB) + => Create(vecA.X - vecB.X, vecA.Y - vecB.Y, vecA.Z - vecB.Z); + + public static readonly Vector Zero = Vector.Create(0, 0, 0); +} \ No newline at end of file diff --git a/GameServer/Territory/AreaCoordinate.cs b/GameServer/Territory/AreaCoordinate.cs deleted file mode 100644 index 49d8f354..00000000 --- a/GameServer/Territory/AreaCoordinate.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DOL.Territories -{ - public class AreaCoordinate - { - public float X - { - get; - set; - } - - public float Y - { - get; - set; - } - - public float Z - { - get; - set; - } - } -} \ No newline at end of file diff --git a/GameServer/Territory/RvRTerritory.cs b/GameServer/Territory/RvRTerritory.cs index 3fac75de..b0ef5572 100644 --- a/GameServer/Territory/RvRTerritory.cs +++ b/GameServer/Territory/RvRTerritory.cs @@ -1,5 +1,6 @@ using DOL.Database; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.Keeps; using DOL.MobGroups; using DOLDatabase.Tables; @@ -16,7 +17,7 @@ public class RvRTerritory : Territory { /// - public RvRTerritory(Zone zone, List areas, string name, GameNPC boss, Vector3? portalPosition, ushort regionID, MobGroup group) : base(eType.Normal, zone, areas, name, boss, portalPosition, regionID, group) + public RvRTerritory(Zone zone, List areas, string name, GameNPC boss, Coordinate? portalCoordinate, ushort regionID, MobGroup group) : base(eType.Normal, zone, areas, name, boss, portalCoordinate, regionID, group) { //add new areas to region //only in memory @@ -50,7 +51,7 @@ public void Reset() { OwnerGuild = null; // reset keep - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(RegionId, Boss.Position, 100000); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(Boss.Position, 100000); keep.TempRealm = eRealm.None; keep.Reset(keep.TempRealm); // reset all doors diff --git a/GameServer/Territory/Territory.cs b/GameServer/Territory/Territory.cs index 5b5e36db..f23ab081 100644 --- a/GameServer/Territory/Territory.cs +++ b/GameServer/Territory/Territory.cs @@ -3,6 +3,7 @@ using DOL.GameEvents; using DOL.gameobjects.CustomNPC; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.PropertyCalc; using DOL.GS.ServerProperties; @@ -37,11 +38,11 @@ public Territory(Zone zone, List areas, GameNPC boss, TerritoryDb db) this.Areas = areas; if (db.PortalX == null || db.PortalY == null || db.PortalZ == null) { - this.PortalPosition = null; + this.PortalCoordinate = null; } else { - this.PortalPosition = new Vector3(db.PortalX.Value, db.PortalY.Value, db.PortalZ.Value); + this.PortalCoordinate = Coordinate.Create(db.PortalX.Value, db.PortalY.Value, db.PortalZ.Value); } this.Zone = zone; this.RegionId = db.RegionId; @@ -106,11 +107,11 @@ public Territory(Zone zone, List areas, GameNPC boss, TerritoryDb db) } } - public Territory(eType type, Zone zone, List areas, string name, GameNPC boss, Vector3? portalPosition, ushort regionID, MobGroup group = null) + public Territory(eType type, Zone zone, List areas, string name, GameNPC boss, Coordinate? portalCoordinate, ushort regionID, MobGroup group = null) { this.Type = type; this.Areas = areas; - this.PortalPosition = portalPosition; + this.PortalCoordinate = portalCoordinate; this.Zone = zone; this.RegionId = regionID; this.Name = name; @@ -207,7 +208,7 @@ public List Areas get; } - public Vector3? PortalPosition + public Coordinate? PortalCoordinate { get; set; @@ -624,7 +625,7 @@ private void ToggleBannerUnsafe(bool add) if (area is Circle circle) { - Zone.GetObjectsInRadius(Zone.eGameObjectType.ITEM, circle.Position.X, circle.Position.Y, circle.Position.Z, (ushort)circle.Radius, new ArrayList(), true).OfType().ForEach(i => i.Emblem = add && m_ownerGuild != null ? m_ownerGuild.Emblem : i.OriginalEmblem); + Zone.GetObjectsInRadius(Zone.eGameObjectType.ITEM, circle.Coordinate, (ushort)circle.Radius, new ArrayList(), true).OfType().ForEach(i => i.Emblem = add && m_ownerGuild != null ? m_ownerGuild.Emblem : i.OriginalEmblem); } else { @@ -932,7 +933,7 @@ public void AddArea(AbstractArea area) IEnumerable mobs; if (area is Circle circle) { - mobs = region.GetNPCsInRadius(circle.Position, (ushort)circle.Radius, false, true).Cast().Where(n => !n.IsCannotTarget && n is not ShadowNPC); + mobs = region.GetNPCsInRadius(circle.Coordinate, (ushort)circle.Radius, false, true).Cast().Where(n => !n.IsCannotTarget && n is not ShadowNPC); } else { @@ -962,7 +963,7 @@ private void GatherMobsInTerritory() if (area is Circle circle) { - region.GetNPCsInRadius(circle.Position, (ushort)circle.Radius, false, true).Cast().Where(n => !n.IsCannotTarget && n is not ShadowNPC).Foreach(n => n.CurrentTerritory = this); + region.GetNPCsInRadius(circle.Coordinate, (ushort)circle.Radius, false, true).Cast().Where(n => !n.IsCannotTarget && n is not ShadowNPC).Foreach(n => n.CurrentTerritory = this); } else { @@ -1077,10 +1078,7 @@ public GameNPC AddMercenary(GamePlayer buyer, NpcTemplate template) npc = (GameNPC)gasm.CreateInstance(template.ClassType, false); // Propagate exception to the caller npc.LoadTemplate(template); } - npc.CurrentRegion = buyer.CurrentRegion; - npc.CurrentRegionID = buyer.CurrentRegionID; npc.Position = buyer.Position; - npc.Heading = buyer.Heading; npc.GuildName = OwnerGuild?.Name ?? template.GuildName ?? string.Empty; npc.Flags |= GameNPC.eFlags.MERCENARY | GameNPC.eFlags.NORESPAWN; npc.FlagsDb = (uint)npc.Flags; @@ -1168,11 +1166,11 @@ protected virtual void SaveIntoDatabaseUnsafe() db.ClaimedTime = ClaimedTime; db.Expiration = Expiration; db.Type = (int)Type; - if (this.PortalPosition != null) + if (this.PortalCoordinate != null) { - db.PortalX = (int)this.PortalPosition.Value.X; - db.PortalY = (int)this.PortalPosition.Value.Y; - db.PortalZ = (int)this.PortalPosition.Value.Z; + db.PortalX = (int)this.PortalCoordinate.Value.X; + db.PortalY = (int)this.PortalCoordinate.Value.Y; + db.PortalZ = (int)this.PortalCoordinate.Value.Z; } else { diff --git a/GameServer/Territory/TerritoryManager.cs b/GameServer/Territory/TerritoryManager.cs index 9f113051..d172b79f 100644 --- a/GameServer/Territory/TerritoryManager.cs +++ b/GameServer/Territory/TerritoryManager.cs @@ -4,6 +4,7 @@ using DOL.GameEvents; using DOL.GS; using DOL.GS.Commands; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.PropertyCalc; using DOL.GS.ServerProperties; @@ -428,18 +429,18 @@ public Territory AddTerritory(Territory.eType type, IArea area, string areaId, u } var coords = GetCoordinates(area); - if (coords == null) + if (coords == Coordinate.Nowhere) { return null; } - var zone = region.GetZone(coords.X, coords.Y); + var zone = region.GetZone(coords); if (zone == null) { return null; } - var territory = new Territory(type, zone, new List{area}, (area as AbstractArea)?.Description ?? "New territory", boss, new Vector3(coords.X, coords.Y, coords.Z), regionId, group); + var territory = new Territory(type, zone, new List{area}, (area as AbstractArea)?.Description ?? "New territory", boss, coords, regionId, group); try { @@ -455,14 +456,14 @@ public Territory AddTerritory(Territory.eType type, IArea area, string areaId, u return territory; } - public static AreaCoordinate GetCoordinates(IArea area) + public static Coordinate GetCoordinates(IArea area) { return area switch { - DOL.GS.Area.Circle circle => new AreaCoordinate() { X = circle.Position.X, Y = circle.Position.Y, Z = circle.Position.Z }, - Square sq => new AreaCoordinate() { X = sq.Position.X, Y = sq.Position.Y, Z = sq.Position.Z }, - Polygon poly => new AreaCoordinate() { X = poly.Position.X, Y = poly.Position.Y, Z = poly.Position.Z }, - _ => null + DOL.GS.Area.Circle circle => circle.Coordinate, + Square sq => sq.Coordinate, + Polygon poly => poly.Coordinate, + _ => Coordinate.Nowhere }; } diff --git a/GameServer/_scripts/AmteScripts/GameObjects/Coffre/CoffrexPlayer.cs b/GameServer/_scripts/AmteScripts/GameObjects/Coffre/CoffrexPlayer.cs index 8774ac61..dcda774c 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/Coffre/CoffrexPlayer.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/Coffre/CoffrexPlayer.cs @@ -56,20 +56,6 @@ public string CoffreID } } - [DataElement(AllowDbNull = false)] - public DateTime LastTimeRowUpdated - { - get - { - return m_lasttimerowupdated; - } - set - { - Dirty = true; - m_lasttimerowupdated = value; - } - } - public CoffrexPlayer() { } diff --git a/GameServer/_scripts/AmteScripts/GameObjects/Coffre/GameCoffre.cs b/GameServer/_scripts/AmteScripts/GameObjects/Coffre/GameCoffre.cs index 62ba0978..048015a0 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/Coffre/GameCoffre.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/Coffre/GameCoffre.cs @@ -13,6 +13,7 @@ using DOL.MobGroups; using DOL.Events; using DOL.GS.GameEvents; +using DOL.GS.Geometry; namespace DOL.GS.Scripts { @@ -486,7 +487,7 @@ private TPPoint GetSmartNextTPPoint(IList tpPoints) foreach (var tpPoint in tpPoints) { - int playerCount = WorldMgr.GetPlayersCloseToSpot(tpPoint.Region, (float)tpPoint.X, (float)tpPoint.Y, (float)tpPoint.Z, 1500).OfType().Count(); // Using 1500 directly + int playerCount = WorldMgr.GetPlayersCloseToSpot(Position.Create(tpPoint.Region, tpPoint.X, tpPoint.Y, tpPoint.Z), 1500).OfType().Count(); // Using 1500 directly if (playerCount > maxPlayerCount) { maxPlayerCount = playerCount; @@ -820,10 +821,7 @@ private void HandlePopMob() { var mob = new AmteMob(new NpcTemplate(template)) { - Position = new Vector3(Position.X, Position.Y, Position.Z), - Heading = Heading, - CurrentRegionID = CurrentRegionID, - CurrentRegion = CurrentRegion, + Position = this.Position, Size = 50, Name = template.Name }; @@ -1022,10 +1020,8 @@ public override void LoadFromDatabase(DataObject obj) DBCoffre coffre = obj as DBCoffre; if (coffre == null) return; Name = coffre.Name; - Position = new Vector3(coffre.X, coffre.Y, coffre.Z); - Heading = (ushort)(coffre.Heading & 0xFFF); + Position = Position.Create(coffre.Region, coffre.X, coffre.Y, coffre.Z, coffre.Heading); HasPickableAnim = coffre.HasPickableAnim; - CurrentRegionID = coffre.Region; Model = coffre.Model; LastOpen = coffre.LastOpen; ItemInterval = coffre.ItemInterval; diff --git a/GameServer/_scripts/AmteScripts/GameObjects/CustomVault.cs b/GameServer/_scripts/AmteScripts/GameObjects/CustomVault.cs index de66b799..7afbd24b 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/CustomVault.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/CustomVault.cs @@ -59,7 +59,7 @@ public override bool Interact(GamePlayer player) return true; } - protected void AddObserver(GamePlayer player) + public override void AddObserver(GamePlayer player) { lock (_vaultLock) { diff --git a/GameServer/_scripts/AmteScripts/GameObjects/FollowingFriendMob.cs b/GameServer/_scripts/AmteScripts/GameObjects/FollowingFriendMob.cs index 25d0b0d7..822b5889 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/FollowingFriendMob.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/FollowingFriendMob.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Numerics; using System.Timers; using DOL.AI.Brain; using DOL.Database; using DOL.Events; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.Scripts; using DOL.MobGroups; @@ -59,7 +59,7 @@ public override bool Interact(GamePlayer player) { if (!base.Interact(player) && (IsPeaceful || WaitingInArea || (((StandardMobBrain)Brain).AggroLevel == 0 && ((StandardMobBrain)Brain).AggroRange == 0)) - && CurrentRegion.GetAreasOfSpot(Position).OfType().FirstOrDefault(a => a.DbArea != null && a.DbArea.ObjectId == AreaToEnter) != null) + && CurrentRegion.GetAreasOfSpot(Coordinate).OfType().FirstOrDefault(a => a.DbArea != null && a.DbArea.ObjectId == AreaToEnter) != null) return false; if (PlayerFollow != null && PlayerFollow == player) { @@ -93,7 +93,7 @@ public override bool WhisperReceive(GameLiving source, string str) player.Out.SendMessage(text, eChatType.CT_System, eChatLoc.CL_PopupWindow); } Notify(GameNPCEvent.FollowLostTarget, this, new FollowLostTargetEventArgs(player)); - Reset(); + ResetFollow(); } } else @@ -112,6 +112,7 @@ public override bool WhisperReceive(GameLiving source, string str) } return true; } + public override bool AddToWorld() { WaitingInArea = false; @@ -213,10 +214,10 @@ public override void DeleteFromDatabase() private void ResetTimer_Elapsed(object sender, ElapsedEventArgs e) { - ResetFriendMobs(); + ResetFollow(); } - public void ResetFriendMobs() + public void ResetFollow() { if (MobGroups != null) { @@ -225,15 +226,15 @@ public void ResetFriendMobs() foreach (FollowingFriendMob mob in group.NPCs.OfType()) { if (mob.PlayerFollow != null) - mob.ResetFriendMob(); + mob.ResetSelf(); } } } - - ResetFriendMob(); + + ResetSelf(); } - public void ResetFriendMob() + private void ResetSelf() { if (WaitingInArea == true && PlayerFollow != null) { @@ -248,16 +249,12 @@ public void ResetFriendMob() AddToWorld(); } - public void Reset() - { - ResetFriendMobs(); - } - public override void Die(GameObject killer) { base.Die(killer); - ResetFriendMobs(); + ResetFollow(); } + public override void SaveIntoDatabase() { base.SaveIntoDatabase(); @@ -316,7 +313,7 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) if (PlayerFollow == null) { Notify(GameNPCEvent.FollowLostTarget, this, new FollowLostTargetEventArgs(null)); - Reset(); + ResetFollow(); return 0; } @@ -330,7 +327,7 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) PlayerFollow = null; StopFollowing(); Notify(GameNPCEvent.FollowLostTarget, this, new FollowLostTargetEventArgs(playerFollow)); - Reset(); + ResetFollow(); return 0; } @@ -340,20 +337,20 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) PlayerFollow = null; StopFollowing(); Notify(GameNPCEvent.FollowLostTarget, this, new FollowLostTargetEventArgs(playerFollow)); - Reset(); + ResetFollow(); return 0; } } //Calculate the difference between our position and the players position - var diff = followTarget.Position - Position; - + var diff = followTarget.Coordinate - Coordinate; + //SH: Removed Z checks when one of the two Z values is zero(on ground) float distanceToTarget; if (followTarget.Position.Z == 0 || Position.Z == 0) - distanceToTarget = (float)Math.Sqrt(diff.X * diff.X + diff.Y * diff.Y); + distanceToTarget = GetDistance2DTo(followTarget); else - distanceToTarget = (float)Math.Sqrt(diff.X * diff.X + diff.Y * diff.Y + diff.Z * diff.Z); + distanceToTarget = GetDistanceTo(followTarget); //Are we in range still? if (followTarget == PlayerFollow) @@ -361,7 +358,7 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) if (distanceToTarget <= m_followMinDist) { // Within minimum distance, nothing to do - //StopMoving(); + StopMoving(); TurnTo(followTarget); if (!wasInRange) @@ -387,6 +384,7 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) if (distanceToTarget <= m_followMinDist) { // Within minimum distance, nothing to do + StopMoving(); TurnTo(followTarget); if (!wasInRange) @@ -405,13 +403,13 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) if (area != null && !WaitingInArea) { StopFollowing(); - var targetPos = new Vector3(area.DbArea.X, area.DbArea.Y, area.DbArea.Z); + var targetPos = Coordinate.Create(area.DbArea.X, area.DbArea.Y, area.DbArea.Z); var angle = Math.Atan2(targetPos.Y - Position.Y, targetPos.X - Position.X); - targetPos.X = area.DbArea.X + (float)Math.Cos(angle) * Util.Random(200, 300); - targetPos.Y = area.DbArea.Y + (float)Math.Sin(angle) * Util.Random(200, 300); + + targetPos += Vector.Create(Angle.Radians(angle), Util.Random(200, 300)); WaitingInArea = true; followTarget.Notify(GameLivingEvent.BringAFriend, followTarget, new BringAFriendArgs(this, true)); - PathTo(targetPos, 130); + WalkTo(targetPos, 130); return 0; } else if (WaitingInArea) @@ -420,18 +418,19 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) } // follow on distance - diff = (diff / distanceToTarget) * m_followMinDist; - var newPos = followTarget.Position - diff; + var distanceFactor = m_followMinDist / distanceToTarget; + var followOffset = diff * distanceFactor; + var newPos = followTarget.Coordinate - followOffset; if (followTarget == PlayerFollow) { var speed = MaxSpeed; - if (GameMath.GetDistance2D(Position, followTarget.Position) < 200) + if (IsWithinRadius(followTarget, 200)) speed = 0; - PathTo(newPos, speed); + WalkTo(newPos, speed); } else - PathTo(newPos, MaxSpeed); + WalkTo(newPos, MaxSpeed); return ServerProperties.Properties.GAMENPC_FOLLOWCHECK_TIME; } @@ -509,9 +508,9 @@ public override void Think() FollowingFriendMob body = (FollowingFriendMob)Body; //if player quits the game - if (body.PlayerFollow != null && body.PlayerFollow.ObjectState == eObjectState.Deleted) + if (body.PlayerFollow is { ObjectState: eObjectState.Deleted }) { - body.ResetFriendMobs(); + body.ResetFollow(); return; } if (!Body.IsCasting && CheckSpells(eCheckSpellType.Defensive)) @@ -524,7 +523,7 @@ public override void Think() } if (!Body.AttackState && !Body.IsCasting && !Body.IsMoving - && Body.Heading != Body.SpawnHeading && Body.Position == Body.SpawnPoint) + && Body.Heading != Body.SpawnHeading && Body.Position == Body.SpawnPosition) Body.TurnTo(Body.SpawnHeading); if (!Body.InCombat) diff --git a/GameServer/_scripts/AmteScripts/GameObjects/FollowingMob.cs b/GameServer/_scripts/AmteScripts/GameObjects/FollowingMob.cs index b9d492d2..58c80012 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/FollowingMob.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/FollowingMob.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; -using System.Numerics; using DOL.AI.Brain; using DOL.Database; using DOL.Events; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.Scripts; namespace DOL.GS.Scripts @@ -27,8 +27,8 @@ public GameNPC MobFollow if (value == null) return; - double DX = SpawnPoint.X - value.SpawnPoint.X; - double DY = SpawnPoint.Y - value.SpawnPoint.Y; + double DX = SpawnPosition.X - value.SpawnPosition.X; + double DY = SpawnPosition.Y - value.SpawnPosition.Y; m_DistMob = (int)Math.Sqrt(DX * DX + DY * DY); if (m_DistMob > 0) @@ -130,14 +130,15 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) } //Calculate the difference between our position and the players position - var diff = followTarget.Position - Position; + var diff = followTarget.Coordinate - Coordinate; //SH: Removed Z checks when one of the two Z values is zero(on ground) float distance; if (followTarget.Position.Z == 0 || Position.Z == 0) - distance = (float)Math.Sqrt(diff.X * diff.X + diff.Y * diff.Y); + distance = GetDistance2DTo(followTarget); else - distance = (float)Math.Sqrt(diff.X * diff.X + diff.Y * diff.Y + diff.Z * diff.Z); + distance = GetDistanceTo(followTarget); + //if distance is greater then the max follow distance, stop following and return home if (distance > m_followMaxDist) @@ -188,22 +189,21 @@ protected override int FollowTimerCallback(RegionTimer callingTimer) // follow on distance diff = (diff / distance) * m_followMinDist; - var newPos = followTarget.Position - diff; + var newCoordinate = followTarget.Coordinate - diff; if (followTarget == MobFollow) { var angle = (m_Angle + followTarget.Heading / GameMath.RADIAN_TO_HEADING) % (Math.PI * 2); + Vector direction = Vector.Create(Angle.Radians(angle), m_DistMob); - newPos.X = followTarget.Position.X + (float)Math.Cos(angle) * m_DistMob; - newPos.Y = followTarget.Position.Y + (float)Math.Sin(angle) * m_DistMob; - + newCoordinate += direction; var speed = MaxSpeed; - if (GameMath.GetDistance2D(Position, newPos) < 500) + if (GameMath.GetDistance2D(Coordinate, newCoordinate) < 500) speed = (short)Math.Min(MaxSpeed, MobFollow.CurrentSpeed + 6); - PathTo(newPos, speed); + PathTo(newCoordinate, speed); } else - PathTo(newPos, MaxSpeed); + PathTo(newCoordinate, MaxSpeed); return ServerProperties.Properties.GAMENPC_FOLLOWCHECK_TIME; } @@ -267,7 +267,7 @@ public override void Think() } if (!Body.AttackState && !Body.IsCasting && !Body.IsMoving - && Body.Heading != Body.SpawnHeading && Body.Position == Body.SpawnPoint) + && Body.Heading != Body.SpawnHeading && Body.Position == Body.SpawnPosition) Body.TurnTo(Body.SpawnHeading); if (!Body.InCombat) diff --git a/GameServer/_scripts/AmteScripts/GameObjects/GameBoatAmte.cs b/GameServer/_scripts/AmteScripts/GameObjects/GameBoatAmte.cs index 56ee031e..87f1d23f 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/GameBoatAmte.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/GameBoatAmte.cs @@ -1,8 +1,8 @@ -using System.Numerics; using DOL.AI.Brain; using DOL.Database; using DOL.GS.PacketHandler; using DOL.GS.Movement; +using DOL.GS.Geometry; namespace DOL.GS { @@ -79,11 +79,10 @@ public override bool AddToWorld() { if (!base.AddToWorld()) return false; SetOwnBrain(new BlankBrain()); - Reset(); return true; } - public void Reset() + public override void Reset() { if (IsMoving) StopMoving(); @@ -104,13 +103,11 @@ public override void LoadFromDatabase(DataObject obj) Mob npc = (Mob)obj; Name = npc.Name; GuildName = npc.Guild; - Position = new Vector3(npc.X, npc.Y, npc.Z); - m_Heading = (ushort)(npc.Heading & 0xFFF); + Position = Position.Create(npc.Region, npc.X, npc.Y, npc.Z, npc.Heading); m_maxSpeedBase = (short)npc.Speed; // TODO db has currently senseless information here, mob type db required if (m_maxSpeedBase == 0) m_maxSpeedBase = 600; m_currentSpeed = 0; - CurrentRegionID = npc.Region; Realm = (eRealm)npc.Realm; Model = npc.Model; Size = npc.Size; diff --git a/GameServer/_scripts/AmteScripts/GameObjects/MageMob/MageMobBrain.cs b/GameServer/_scripts/AmteScripts/GameObjects/MageMob/MageMobBrain.cs index f45e3621..8fc10f3c 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/MageMob/MageMobBrain.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/MageMob/MageMobBrain.cs @@ -4,6 +4,8 @@ using DOL.GS; using DOL.GS.Scripts; using System.Numerics; +using DOL.GS.Geometry; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.AI.Brain { @@ -38,13 +40,13 @@ public override void Think() ///The target to flee. protected virtual void CalculateFleeTarget(GameLiving target) { - ushort TargetAngle = (ushort)((Body.GetHeading(target) + 2048) % 4096); + var TargetAngle = Body.GetAngleTo(target.Coordinate); - var fleePoint = Body.GetPointFromHeading(TargetAngle, 300); - var point = PathingMgr.Instance.GetClosestPoint(Body.CurrentZone, new Vector3(fleePoint, Body.Position.Z), 128, 128, 256); + var fleePoint = Body.Coordinate + Vector.Create(TargetAngle, 300); + var point = PathingMgr.Instance.GetClosestPointAsync(Body.CurrentZone, Coordinate.Create(fleePoint.X, fleePoint.Y, Body.Position.Z), 128, 128, 256); Body.StopFollowing(); Body.StopAttack(); - Body.PathTo(point.HasValue ? point.Value : new Vector3(fleePoint, Body.Position.Z), Body.MaxSpeed); + Body.PathTo(point.HasValue ? Coordinate.Create(point.Value) : Coordinate.Create(fleePoint.X, fleePoint.Y, Body.Position.Z), Body.MaxSpeed); } } diff --git a/GameServer/_scripts/AmteScripts/GameObjects/NightMob.cs b/GameServer/_scripts/AmteScripts/GameObjects/NightMob.cs index 2c766bf8..8895cbf1 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/NightMob.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/NightMob.cs @@ -46,7 +46,7 @@ private int ScanHour(RegionTimer callingTimer) if (add && IsAlive && ObjectState != eObjectState.Active) { - Position = SpawnPoint; + Position = SpawnPosition; Heading = SpawnHeading; AddToWorld(); } diff --git a/GameServer/_scripts/AmteScripts/GameObjects/PlaceAssise.cs b/GameServer/_scripts/AmteScripts/GameObjects/PlaceAssise.cs index 37648682..82b601cf 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/PlaceAssise.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/PlaceAssise.cs @@ -3,6 +3,7 @@ using DOL.Database; using DOL.GS.PacketHandler; using DOL.Language; +using DOL.GS.Geometry; namespace DOL.GS.Scripts { @@ -59,8 +60,7 @@ public override void LoadFromDatabase(DataObject obj) Mob npc = (Mob)obj; Name = npc.Name; GuildName = npc.Guild; - Position = new Vector3(npc.X, npc.Y, npc.Z); - m_Heading = (ushort)(npc.Heading & 0xFFF); + Position = Position.Create(npc.Region, npc.X, npc.Y, npc.Z, (ushort)(npc.Heading & 0xFFF)); m_maxSpeedBase = (short)npc.Speed; // TODO db has currently senseless information here, mob type db required if (m_maxSpeedBase == 0) m_maxSpeedBase = 600; @@ -86,7 +86,7 @@ public override void SaveIntoDatabase() mob.X = (int)Position.X; mob.Y = (int)Position.Y; mob.Z = (int)Position.Z; - mob.Heading = Heading; + mob.Heading = Position.Orientation.InHeading; mob.Speed = MaxSpeedBase; mob.Region = CurrentRegionID; mob.Realm = (byte)Realm; diff --git a/GameServer/_scripts/AmteScripts/GameObjects/SplitMob.cs b/GameServer/_scripts/AmteScripts/GameObjects/SplitMob.cs index dc188af6..a32f1cbe 100644 --- a/GameServer/_scripts/AmteScripts/GameObjects/SplitMob.cs +++ b/GameServer/_scripts/AmteScripts/GameObjects/SplitMob.cs @@ -8,6 +8,7 @@ using DOL.Events; using DOL.Database; using DOL.GS.PacketHandler; +using DOL.GS.Geometry; using log4net; namespace DOL.GS.Scripts @@ -56,11 +57,10 @@ public void Split(GamePlayer player) } + public void SetVariables(GameNPC mob) { - mob.Position = new System.Numerics.Vector3(this.Position.X + 10, this.Position.Y + 10, this.Position.Z); - mob.CurrentRegion = this.CurrentRegion; - mob.Heading = this.Heading; + mob.Position = Position.With(Coordinate.Create(this.Coordinate.X + 10, this.Coordinate.Y + 10, this.Coordinate.Z)); mob.Level = this.Level; mob.Realm = this.Realm; mob.Name = "Split's Minion"; diff --git a/GameServer/_scripts/AmteScripts/Managers/AmtenaelRules.cs b/GameServer/_scripts/AmteScripts/Managers/AmtenaelRules.cs index eb078b73..a747c447 100644 --- a/GameServer/_scripts/AmteScripts/Managers/AmtenaelRules.cs +++ b/GameServer/_scripts/AmteScripts/Managers/AmtenaelRules.cs @@ -156,15 +156,15 @@ public override void OnRegionChanged(DOLEvent e, object sender, EventArgs args) /// /// /// - public override void OnPlayerTeleport(GamePlayer player, GameLocation source, Teleport destination) + public override void OnPlayerTeleport(GamePlayer player, Teleport destination) { // Since region change already starts an immunity timer we only want to do this if a player // is teleporting within the same region - if (source.RegionID == destination.RegionID) + if (player.CurrentRegionID == destination.RegionID) { StartPVEImmunityTimer(player, Properties.TIMER_PVE_TELEPORT * 1000); } - base.OnPlayerTeleport(player, source, destination); + base.OnPlayerTeleport(player, destination); } /// @@ -1073,7 +1073,7 @@ public override void OnPlayerKilled(GamePlayer killedPlayer, GameObject killer) if (!BG && living is GamePlayer) { - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(living.CurrentRegionID, living.Position, 16000); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(living.Position, 16000); if (keep != null) { byte bonus = 0; diff --git a/GameServer/_scripts/AmteScripts/PvP/PvpManager.cs b/GameServer/_scripts/AmteScripts/PvP/PvpManager.cs index a29bc591..44a81d7e 100644 --- a/GameServer/_scripts/AmteScripts/PvP/PvpManager.cs +++ b/GameServer/_scripts/AmteScripts/PvP/PvpManager.cs @@ -7,6 +7,7 @@ using DOL.Database; using DOL.Events; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using log4net; @@ -17,7 +18,7 @@ public class PvpManager private static readonly TimeSpan _startTime = new TimeSpan(14, 0, 0); private static readonly TimeSpan _endTime = _startTime.Add(TimeSpan.FromHours(8)); private const int _checkInterval = 30 * 1000; // 30 seconds - private static readonly GameLocation _stuckSpawn = new GameLocation("", 51, 434303, 493165, 3088, 1069); + private static readonly Position _stuckSpawn = Position.Create(51, 434303, 493165, 3088, 1069); #region Static part private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -57,7 +58,7 @@ public static void OnServerStopped(DOLEvent e, object sender, EventArgs args) /// /// <regionID, Tuple<TPs, spawnAlb, spawnMid, spawnHib>> /// - private readonly Dictionary> _maps = new Dictionary>(); + private readonly Dictionary> _maps = new(); private PvpManager() { @@ -83,7 +84,7 @@ public IEnumerable FindPvPMaps() var spawn = WorldMgr.GetNPCsByNameFromRegion("SPAWN", id, eRealm.None).FirstOrDefault(); if (spawn == null) continue; - _maps.Add(id, new Tuple(spawn, new GameLocation("Spawn", spawn))); + _maps.Add(id, new Tuple(spawn, spawn.Position)); } return (from m in _maps select m.Key); } diff --git a/GameServer/_scripts/AmteScripts/RvR/RvrManager.cs b/GameServer/_scripts/AmteScripts/RvR/RvrManager.cs index f04649ae..b77157b1 100644 --- a/GameServer/_scripts/AmteScripts/RvR/RvrManager.cs +++ b/GameServer/_scripts/AmteScripts/RvR/RvrManager.cs @@ -8,6 +8,7 @@ using DOL.Database; using DOL.Events; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.ServerProperties; using DOL.Language; @@ -51,7 +52,7 @@ public class RvrManager private static DateTime _startTime = DateTime.Today.AddHours(23D).Add(TimeSpan.FromMinutes(5)); //20H00 private static DateTime _endTime = _startTime.Add(TimeSpan.FromMinutes(20)); //2H00 + 1 private const int _checkInterval = 30 * 1000; // 30 seconds - private static readonly GameLocation _stuckSpawn = new GameLocation("", 51, 434303, 493165, 3088, 1069); + private static readonly Position _stuckSpawn = Position.Create(51, 434303, 493165, 3088, 1069); private Dictionary> RvrStats = new Dictionary>(); private Dictionary Scores = new Dictionary(); private Dictionary kills = new Dictionary(); @@ -172,7 +173,7 @@ public void OnControlChange(string lordId, Guild guild) m.Realm = guild.Realm; }); map.RvRTerritory.Boss.Realm = guild.Realm; - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(map.RvRTerritory.RegionId, map.RvRTerritory.Boss.Position, 100000); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(map.RvRTerritory.Boss.Position, 100000); keep.TempRealm = guild.Realm; keep.Reset(guild.Realm); keep.Guild = guild; @@ -186,7 +187,7 @@ public void OnControlChange(string lordId, Guild guild) public RvRTerritory GetRvRTerritory(ushort regionId) { - var map = this._maps.Values.FirstOrDefault(v => v.RvRTerritory != null && v.Location.RegionID.Equals(regionId)); + var map = this._maps.Values.FirstOrDefault(v => v.RvRTerritory != null && v.Position.RegionID.Equals(regionId)); if (map == null) { @@ -348,16 +349,16 @@ public IEnumerable InitMapsAndTerritories() // _maps.Add(name, map); //}); - _regions = _maps.Values.GroupBy(v => v.Location.RegionID).Select(v => v.Key).OrderBy(v => v); + _regions = _maps.Values.GroupBy(v => v.Position.RegionID).Select(v => v.Key).OrderBy(v => v); _regions.Foreach(r => this.RvrStats.Add(r, new string[] { })); - return from m in _maps select m.Value.Location.RegionID; + return from m in _maps select m.Value.Position.RegionID; } private RvRMap BuildRvRMap(GameNPC initNpc) { RvRTerritory rvrTerritory = null; - if (!_maps.Values.Any(v => v.Location.RegionID.Equals(initNpc.CurrentRegionID))) + if (!_maps.Values.Any(v => v.Position.RegionID.Equals(initNpc.CurrentRegionID))) { var lord = (LordRvR)(initNpc.CurrentRegion.Objects.FirstOrDefault(o => o is LordRvR)); @@ -369,12 +370,12 @@ private RvRMap BuildRvRMap(GameNPC initNpc) var areaName = string.IsNullOrEmpty(lord.GuildName) ? initNpc.Name : lord.GuildName; var area = new Area.Circle(areaName, lord.Position.X, lord.Position.Y, lord.Position.Z, RVR_RADIUS); - rvrTerritory = new RvRTerritory(lord.CurrentZone, new List{area}, area.Description, lord, area.Position, lord.CurrentRegionID, null); + rvrTerritory = new RvRTerritory(lord.CurrentZone, new List{area}, area.Description, lord, area.Coordinate, lord.CurrentRegionID, null); } return new RvRMap() { - Location = new GameLocation(initNpc.Name, initNpc.CurrentRegionID, initNpc.Position.X, initNpc.Position.Y, initNpc.Position.Z), + Position = initNpc.Position, RvRTerritory = rvrTerritory }; } @@ -610,7 +611,7 @@ public bool Close() m.RvRTerritory.Reset(); }); - this._maps.Values.GroupBy(v => v.Location.RegionID).ForEach(region => + this._maps.Values.GroupBy(v => v.Position.RegionID).ForEach(region => { var characters = GameServer.Database.SelectObjects(c => c.Region == +region.Key); foreach (DOLCharacters chr in characters) @@ -815,7 +816,7 @@ private bool AddPlayerToCorrectZone(GamePlayer player, string realm) // } //} - player.MoveTo(_maps[key].Location); + player.MoveTo(_maps[key].Position); player.Bind(true); return true; } @@ -922,7 +923,7 @@ public IList GetStatistics(GamePlayer player) long prHib = clients.Where(c => c.Player.Realm == eRealm.Hibernia).Sum(c => c.Player.Guild.RealmPoints); long prMid = clients.Where(c => c.Player.Realm == eRealm.Midgard).Sum(c => c.Player.Guild.RealmPoints); - var maps = this._maps.Values.Where(m => m.RvRTerritory != null && m.Location.RegionID.Equals(player.CurrentRegionID)); + var maps = this._maps.Values.Where(m => m.RvRTerritory != null && m.Position.RegionID.Equals(player.CurrentRegionID)); if (maps != null) { @@ -977,7 +978,7 @@ public bool IsAllowedToAttack(GameLiving attacker, GameLiving defender, bool qui public bool IsRvRRegion(ushort id) { - return _maps.Values.Any(v => v.Location.RegionID.Equals(id)); + return _maps.Values.Any(v => v.Position.RegionID.Equals(id)); } private static void _MessageToLiving(GameLiving living, string message) @@ -990,6 +991,6 @@ private static void _MessageToLiving(GameLiving living, string message) public class RvRMap { public RvRTerritory RvRTerritory { get; set; } - public GameLocation Location { get; set; } + public Position Position { get; set; } } } diff --git a/GameServer/_scripts/AmteScripts/SpecialItems/FeuArtificeItem.cs b/GameServer/_scripts/AmteScripts/SpecialItems/FeuArtificeItem.cs index 1b59e479..1570d1e7 100644 --- a/GameServer/_scripts/AmteScripts/SpecialItems/FeuArtificeItem.cs +++ b/GameServer/_scripts/AmteScripts/SpecialItems/FeuArtificeItem.cs @@ -14,6 +14,7 @@ using DOL.Database; using DOL.Events; using DOL.Language; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.GS.Scripts { @@ -158,7 +159,7 @@ private static Dictionary CreateMobs(GameObject obj) Level = 1, Model = 1, Realm = 0, - Position = obj.Position + new Vector3(0, 0, 800), + Position = obj.Position + Vector.Create(0, 0, 800), CurrentRegion = obj.CurrentRegion }; @@ -171,26 +172,26 @@ private static Dictionary CreateMobs(GameObject obj) //Pyramide: //Base - mobs[2].Position += new Vector3(250, 250, 0); - mobs[3].Position += new Vector3(250, 0, 0); - mobs[4].Position += new Vector3(250, -250, 0); - mobs[5].Position += new Vector3(0, -250, 0); - mobs[6].Position -= new Vector3(250, 250, 0); - mobs[7].Position -= new Vector3(250, 0, 0); - mobs[8].Position += new Vector3(-250, 250, 0); - mobs[9].Position += new Vector3(0, 250, 0); + mobs[2].Position += Vector.Create(250, 250, 0); + mobs[3].Position += Vector.Create(250, 0, 0); + mobs[4].Position += Vector.Create(250, -250, 0); + mobs[5].Position += Vector.Create(0, -250, 0); + mobs[6].Position -= Vector.Create(250, 250, 0); + mobs[7].Position -= Vector.Create(250, 0, 0); + mobs[8].Position += Vector.Create(-250, 250, 0); + mobs[9].Position += Vector.Create(0, 250, 0); //2e étage - mobs[10].Position += new Vector3(+125, +125, 250); - mobs[11].Position += new Vector3(+125, -125, 250); - mobs[12].Position += new Vector3(-125, -125, 250); - mobs[13].Position += new Vector3(-125, +125, 250); + mobs[10].Position += Vector.Create(+125, +125, 250); + mobs[11].Position += Vector.Create(+125, -125, 250); + mobs[12].Position += Vector.Create(-125, -125, 250); + mobs[13].Position += Vector.Create(-125, +125, 250); - mobs[14].Position += new Vector3(0, 0, 250); + mobs[14].Position += Vector.Create(0, 0, 250); mobs[14].Size = 75; //Sommet - mobs[15].Position += new Vector3(0, 0, 500); + mobs[15].Position += Vector.Create(0, 0, 500); mobs[15].Size = 100; foreach (KeyValuePair mob in mobs) diff --git a/GameServer/_scripts/AmteScripts/Spells/GuarksTeleport.cs b/GameServer/_scripts/AmteScripts/Spells/GuarksTeleport.cs index 1529ee9b..b997349b 100644 --- a/GameServer/_scripts/AmteScripts/Spells/GuarksTeleport.cs +++ b/GameServer/_scripts/AmteScripts/Spells/GuarksTeleport.cs @@ -22,7 +22,6 @@ using DOL.Language; using DOL.GS.PacketHandler; using AmteScripts.Managers; -using DOL.Language; namespace DOL.GS.Spells { diff --git a/GameServer/ai/brain/BD Pets/BDPetBrain.cs b/GameServer/ai/brain/BD Pets/BDPetBrain.cs index 4190c4cd..35e7ca27 100644 --- a/GameServer/ai/brain/BD Pets/BDPetBrain.cs +++ b/GameServer/ai/brain/BD Pets/BDPetBrain.cs @@ -19,6 +19,7 @@ using System; using DOL.Events; using DOL.GS; +using DOL.GS.Geometry; namespace DOL.AI.Brain { @@ -101,12 +102,13 @@ public override void FollowOwner() /// /// /// - public override bool CheckFormation(ref float x, ref float y, ref float z) + public override bool CheckFormation(ref int x, ref int y, ref int z) { if (!Body.AttackState && Body.Attackers.Count == 0) { GameNPC commander = (GameNPC)Owner; - var heading = commander.Heading * GameMath.HEADING_TO_RADIAN; + var heading = commander.Orientation.InRadians; + var commanderOrientation = commander.Orientation; //Get which place we should put minion int i = 0; //How much do we want to slide back and left/right @@ -117,31 +119,38 @@ public override bool CheckFormation(ref float x, ref float y, ref float z) if (commander.ControlledNpcList[i] == this) break; } + var offset = Vector.Zero; + var spacing = BASEFORMATIONDIST * commander.FormationSpacing; switch (commander.Formation) { case GameNPC.eFormationType.Triangle: - par_slide = BASEFORMATIONDIST; - perp_slide = BASEFORMATIONDIST; - if (i != 0) - par_slide = BASEFORMATIONDIST * 2; + switch (i) + { + case 0: offset = Vector.Create(0, -spacing); break; + case 1: offset = Vector.Create(spacing, -spacing * 2); break; + case 2: offset = Vector.Create(-spacing, -spacing * 2); break; + } break; case GameNPC.eFormationType.Line: - par_slide = BASEFORMATIONDIST * (i + 1); + switch (i) + { + case 0: offset = Vector.Create(0, -spacing); break; + case 1: offset = Vector.Create(0, -spacing * 2); break; + case 2: offset = Vector.Create(0, -spacing * 3); break; + } break; case GameNPC.eFormationType.Protect: switch (i) { - case 0: - par_slide = -BASEFORMATIONDIST * 2; - break; - case 1: - case 2: - par_slide = -BASEFORMATIONDIST; - perp_slide = BASEFORMATIONDIST; - break; + case 0: offset = Vector.Create(0, spacing * 2); break; + case 1: offset = Vector.Create(spacing, spacing); break; + case 2: offset = Vector.Create(-spacing, spacing); break; } break; } + offset = offset.RotatedClockwise(commanderOrientation); + x += offset.X; + y += offset.Y; //Slide backwards - every pet will need to do this anyways x += (int)(((double)commander.FormationSpacing * par_slide) * Math.Cos(heading - Math.PI / 2)); y += (int)(((double)commander.FormationSpacing * par_slide) * Math.Sin(heading - Math.PI / 2)); diff --git a/GameServer/ai/brain/ControlledNpcBrain.cs b/GameServer/ai/brain/ControlledNpcBrain.cs index a006bf49..3420a948 100644 --- a/GameServer/ai/brain/ControlledNpcBrain.cs +++ b/GameServer/ai/brain/ControlledNpcBrain.cs @@ -24,6 +24,7 @@ using DOL.GS; using DOL.GS.Spells; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.RealmAbilities; using DOL.GS.SkillHandler; @@ -49,7 +50,7 @@ public class ControlledNpcBrain : StandardMobBrain, IControlledBrain public static readonly short MIN_ENEMY_FOLLOW_DIST = 90; public static readonly short MAX_ENEMY_FOLLOW_DIST = 512; - protected Vector3 m_temp = Vector3.Zero; + protected Coordinate m_temp = Coordinate.Nowhere; /// /// Holds the controlling player of this brain @@ -196,7 +197,7 @@ public virtual eAggressionState AggressionState Body.TargetObject = null; if (WalkState == eWalkState.Follow) FollowOwner(); - else if (m_temp.X > 0 && m_temp.Y > 0 && m_temp.Z > 0) + else if (m_temp.Equals(Coordinate.Nowhere)) Body.PathTo(m_temp, Body.MaxSpeed); } AttackMostWanted(); @@ -236,7 +237,7 @@ public virtual void Follow(GameObject target) /// public virtual void Stay() { - m_temp = Body.Position; + m_temp = Body.Coordinate; WalkState = eWalkState.Stay; Body.StopFollowing(); } @@ -246,10 +247,10 @@ public virtual void Stay() /// public virtual void ComeHere() { - m_temp = Body.Position; + m_temp = Body.Coordinate; WalkState = eWalkState.ComeHere; Body.StopFollowing(); - Body.PathTo(Owner.Position, Body.MaxSpeed); + Body.PathTo(Owner.Coordinate, Body.MaxSpeed); } /// @@ -258,10 +259,10 @@ public virtual void ComeHere() /// public virtual void Goto(GameObject target) { - m_temp = Body.Position; + m_temp = Body.Coordinate; WalkState = eWalkState.GoTarget; Body.StopFollowing(); - Body.PathTo(target.Position, Body.MaxSpeed); + Body.PathTo(target.Coordinate, Body.MaxSpeed); } public virtual void SetAggressionState(eAggressionState state) @@ -1068,7 +1069,7 @@ owner_npc.TargetObject is GameLiving && { FollowOwner(); } - else if (m_temp.X > 0 && m_temp.Y > 0 && m_temp.Z > 0) + else if (!m_temp.Equals(Coordinate.Nowhere)) { Body.PathTo(m_temp, Body.MaxSpeed); } @@ -1113,8 +1114,6 @@ protected override void BringFriends(GameLiving trigger) // don't } - public override bool CheckFormation(ref float x, ref float y, ref float z) { return false; } - #endregion } } diff --git a/GameServer/ai/brain/DragonBrain.cs b/GameServer/ai/brain/DragonBrain.cs index 5bb84518..c2fd844d 100644 --- a/GameServer/ai/brain/DragonBrain.cs +++ b/GameServer/ai/brain/DragonBrain.cs @@ -218,7 +218,7 @@ private bool CheckTether() { GameDragon dragon = Body as GameDragon; if (dragon == null) return false; - return !dragon.IsWithinRadius(dragon.SpawnPoint, dragon.TetherRange); + return dragon.Coordinate.DistanceTo(dragon.SpawnPosition) > dragon.TetherRange; } #endregion diff --git a/GameServer/ai/brain/Guards/KeepGuardBrain.cs b/GameServer/ai/brain/Guards/KeepGuardBrain.cs index e3474aa9..e1f63908 100644 --- a/GameServer/ai/brain/Guards/KeepGuardBrain.cs +++ b/GameServer/ai/brain/Guards/KeepGuardBrain.cs @@ -75,18 +75,18 @@ public override void Think() // Tolakram - always clear the aggro list so if this is done by mistake the list will correctly re-fill on next think ClearAggroList(); - if (guard.GetDistance2DTo(guard.SpawnPoint) > 50) + if (guard.GetDistance2DTo(guard.SpawnPosition) > 50) { guard.Reset(); } } //Eden - Portal Keeps Guards max distance - if (guard.Level > 200 && !guard.IsWithinRadius(guard.SpawnPoint, 2000)) + if (guard.Level > 200 && !guard.IsWithinRadius(guard.SpawnPosition.Coordinate, 2000)) { ClearAggroList(); guard.Reset(); } - else if (guard.InCombat == false && guard.IsWithinRadius(guard.SpawnPoint, 6000) == false) + else if (guard.InCombat == false && guard.IsWithinRadius(guard.SpawnPosition.Coordinate, 6000) == false) { ClearAggroList(); guard.Reset(); @@ -127,7 +127,7 @@ protected override void CheckPlayerAggro() if (Body is GuardStealther == false && player.IsStealthed) continue; - WarMapMgr.AddGroup((byte)player.CurrentZone.ID, (int)player.Position.X, (int)player.Position.Y, player.Name, (byte)player.Realm); + WarMapMgr.AddGroup(player.Position, player.Name, (byte)player.Realm); if (DOL.GS.ServerProperties.Properties.ENABLE_DEBUG) { @@ -164,7 +164,7 @@ protected override void CheckNPCAggro() continue; } - WarMapMgr.AddGroup((byte)player.CurrentZone.ID, (int)player.Position.X, (int)player.Position.Y, player.Name, (byte)player.Realm); + WarMapMgr.AddGroup(player.Position, player.Name, (byte)player.Realm); if (DOL.GS.ServerProperties.Properties.ENABLE_DEBUG) { diff --git a/GameServer/ai/brain/Npcs/AggressiveBrain.cs b/GameServer/ai/brain/Npcs/AggressiveBrain.cs index 1a5a7b62..221c76d2 100644 --- a/GameServer/ai/brain/Npcs/AggressiveBrain.cs +++ b/GameServer/ai/brain/Npcs/AggressiveBrain.cs @@ -358,7 +358,7 @@ public override void Notify(DOLEvent e, object sender, EventArgs args) { if (e == GameNPCEvent.ArriveAtSpawnPoint) { - Body.TurnTo(Body.SpawnHeading); + Body.TurnTo(Body.SpawnPosition.Orientation); return; } diff --git a/GameServer/ai/brain/RoundsBrain.cs b/GameServer/ai/brain/RoundsBrain.cs index 2a57ce1d..9a2a3913 100644 --- a/GameServer/ai/brain/RoundsBrain.cs +++ b/GameServer/ai/brain/RoundsBrain.cs @@ -52,7 +52,7 @@ public override void AddToAggroList(GameLiving living, int aggroamount, bool che { //save current position in path go to here and reload path point //insert path in pathpoint - PathPoint temporaryPathPoint = new PathPoint(Body.Position, Body.CurrentSpeed, Body.CurrentWayPoint.Type); + PathPoint temporaryPathPoint = new PathPoint(Body.Coordinate, Body.CurrentSpeed, Body.CurrentWayPoint.Type); temporaryPathPoint.Next = Body.CurrentWayPoint; temporaryPathPoint.Prev = Body.CurrentWayPoint.Prev; Body.CurrentWayPoint = temporaryPathPoint; diff --git a/GameServer/ai/brain/StandardMobBrain.cs b/GameServer/ai/brain/StandardMobBrain.cs index bb61cd2f..f74d19e4 100644 --- a/GameServer/ai/brain/StandardMobBrain.cs +++ b/GameServer/ai/brain/StandardMobBrain.cs @@ -29,10 +29,11 @@ using DOL.GS.Keeps; using DOL.Language; using log4net; -using System.Numerics; using DOL.gameobjects.CustomNPC; using DOL.GS.Scripts; using DOL.MobGroups; +using DOL.GS.Geometry; +using Vector3 = System.Numerics.Vector3; namespace DOL.AI.Brain { @@ -147,7 +148,7 @@ public override void Think() // If NPC has a max distance and we are outside, full reset if (Body.MaxDistance != 0) { - var distance = Vector3.Distance(Body.Position, Body.SpawnPoint); + var distance = Body.Position.Coordinate.DistanceTo(Body.SpawnPosition); int maxdistance = Body.MaxDistance > 0 ? Body.MaxDistance : -Body.MaxDistance * AggroRange / 100; if (maxdistance > 0 && distance > maxdistance) { @@ -160,7 +161,7 @@ public override void Think() if (wasInCombat && !Body.InCombat) { Body.Reset(); - if (Body.IsWithinRadius(Body.IsMovingOnPath ? Body.CurrentWayPoint.Position : Body.SpawnPoint, 500)) + if (Body.IsWithinRadius(Body.IsMovingOnPath ? Body.CurrentWayPoint.Coordinate : Body.SpawnPosition.Coordinate, 500)) { // Not very far - keep thinking, aggro, etc Body.IsResetting = false; @@ -213,8 +214,8 @@ public override void Think() //If this NPC can randomly walk around, we allow it to walk around if (CanRandomWalk && !Body.IsRoaming && Util.Chance(DOL.GS.ServerProperties.Properties.GAMENPC_RANDOMWALK_CHANCE)) { - var target = CalcRandomWalkTarget(); - if (Util.IsNearDistance(target, Body.Position, GameNPC.CONST_WALKTOTOLERANCE)) + var target = GetRandomWalkTarget(); + if (Util.IsNearDistance(target, Body.Coordinate, GameNPC.CONST_WALKTOTOLERANCE)) { Body.TurnTo(target.X, target.Y); } @@ -229,6 +230,17 @@ public override void Think() CheckStealth(); } + public virtual Coordinate GetFormationCoordinate(Coordinate loc) + { + var x = loc.X; + var y = loc.Y; + var z = loc.Z; + var isNotInFormation = !CheckFormation(ref x, ref y, ref z); + if(isNotInFormation) return Coordinate.Nowhere; + + return Coordinate.Create(x,y,z); + } + /// /// Check if the NPC can be stealthed /// @@ -375,7 +387,7 @@ public override int ThinkInterval /// The x-coordinate to refer to and change /// The x-coordinate to refer to and change /// The x-coordinate to refer to and change - public virtual bool CheckFormation(ref float x, ref float y, ref float z) + public virtual bool CheckFormation(ref int x, ref int y, ref int z) { return false; } @@ -710,7 +722,7 @@ protected virtual GameLiving CalculateNextAttackTarget() && living.CurrentRegion == Body.CurrentRegion && living.ObjectState == GameObject.eObjectState.Active) { - float distance = Vector3.Distance(Body.Position, living.Position); + float distance = Body.GetDistanceTo(living.Position, 0); int maxAggroDistance = (this is IControlledBrain) ? MAX_PET_AGGRO_DISTANCE : MAX_AGGRO_DISTANCE; if (distance <= maxAggroDistance) @@ -899,7 +911,7 @@ public override void Notify(DOLEvent e, object sender, EventArgs args) { if (target is FollowingFriendMob { PlayerFollow: not null } followMob) { - float range = Body.CurrentRegion.IsDungeon ? Body.GetDistanceTo(target.Position) : Body.GetDistance2DTo(target.Position); + float range = Body.CurrentRegion.IsDungeon ? Body.GetDistanceTo(target) : Body.GetDistance2DTo(target.Position); if (!HasAggro && range < (AggroRange * GetGroupMobRangeMultiplier(followMob.PlayerFollow) * followMob.AggroMultiplier)) { @@ -1742,24 +1754,26 @@ defaut roaming range is defined in CanRandomWalk method return true; } } - - public virtual Vector3 CalcRandomWalkTarget() + + public virtual Coordinate GetRandomWalkTarget() { - if (Body.CurrentZone.IsPathingEnabled) + if (PathCalculator.IsSupported(Body)) { - var pt = PathingMgr.Instance.GetRandomPoint(Body.CurrentZone, Body.SpawnPoint, Body.RoamingRange > 0 ? Body.RoamingRange : 200); - if (pt.HasValue) - return pt.Value; + int radius = Body.RoamingRange > 0 ? Body.RoamingRange : 500; + var target = PathingMgr.Instance.GetRandomPointAsync(Body.CurrentZone, Body.Coordinate, radius); + if (target.HasValue) + return Coordinate.Create(x: (int)target.Value.X, y: (int)target.Value.Y, z: (int)target.Value.Z); } int maxRoamingRadius = Body.CurrentRegion.IsDungeon ? 5 : 500; + if (Body.RoamingRange > 0) maxRoamingRadius = Body.RoamingRange; - var targetX = Body.SpawnPoint.X + Util.Random(-maxRoamingRadius, maxRoamingRadius); - var targetY = Body.SpawnPoint.Y + Util.Random(-maxRoamingRadius, maxRoamingRadius); + double targetX = Body.SpawnPosition.X + Util.Random(-maxRoamingRadius, maxRoamingRadius); + double targetY = Body.SpawnPosition.Y + Util.Random(-maxRoamingRadius, maxRoamingRadius); - return new Vector3(targetX, targetY, Body.SpawnPoint.Z); + return Coordinate.Create(x: (int)targetX, y: (int)targetY, z: Body.SpawnPosition.Z); } #endregion @@ -1768,7 +1782,7 @@ public virtual void DetectDoor() { ushort range = (ushort)((ThinkInterval / 800) * Body.CurrentWayPoint.MaxSpeed); - foreach (IDoor door in Body.CurrentRegion.GetDoorsInRadius(Body.Position, range, false)) + foreach (IDoor door in Body.CurrentRegion.GetDoorsInRadius(Body.Coordinate, range, false)) { if (door is GameKeepDoor) { diff --git a/GameServer/behaviour/Actions/MoveToAction.cs b/GameServer/behaviour/Actions/MoveToAction.cs index 831e7c7f..479faebd 100644 --- a/GameServer/behaviour/Actions/MoveToAction.cs +++ b/GameServer/behaviour/Actions/MoveToAction.cs @@ -23,32 +23,33 @@ using DOL.Events; using DOL.GS.Behaviour.Attributes; using DOL.GS.Behaviour; +using DOL.GS.Geometry; namespace DOL.GS.Behaviour.Actions { [ActionAttribute(ActionType = eActionType.MoveTo)] - public class MoveToAction : AbstractAction + public class MoveToAction : AbstractAction { public MoveToAction(GameNPC defaultNPC, Object p, Object q) : base(defaultNPC, eActionType.MoveTo, p, q) { } - public MoveToAction(GameNPC defaultNPC, GameLocation location, GameLiving npc) - : this(defaultNPC, (object)location, (object)npc) { } + public MoveToAction(GameNPC defaultNPC, Position position, GameLiving npc) + : this(defaultNPC, (object)position, (object)npc) { } public override void Perform(DOLEvent e, object sender, EventArgs args) { GameLiving npc = Q; - if (P is GameLocation location) + if (P is Position position) { - npc.MoveTo(location); + npc.MoveTo(position); } else { GamePlayer player = BehaviourUtils.GuessGamePlayerFromNotify(e, sender, args); - npc.MoveTo(player.CurrentRegionID, player.Position, player.Heading); + npc.MoveTo(player.Position); } } } diff --git a/GameServer/behaviour/Actions/TeleportAction.cs b/GameServer/behaviour/Actions/TeleportAction.cs index b9964daf..01c1b13f 100644 --- a/GameServer/behaviour/Actions/TeleportAction.cs +++ b/GameServer/behaviour/Actions/TeleportAction.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.Database; using System; using System.Collections.Generic; using System.Text; @@ -24,12 +25,12 @@ using DOL.GS.Behaviour.Attributes; using DOL.GS.Behaviour; using DOL.Language; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS.Behaviour.Actions { [ActionAttribute(ActionType = eActionType.Teleport, DefaultValueQ = 0)] - public class TeleportAction : AbstractAction + public class TeleportAction : AbstractAction { public TeleportAction(GameNPC defaultNPC, Object p, Object q) @@ -38,7 +39,7 @@ public TeleportAction(GameNPC defaultNPC, Object p, Object q) } - public TeleportAction(GameNPC defaultNPC, GameLocation location, int fuzzyRadius) + public TeleportAction(GameNPC defaultNPC, Teleport location, int fuzzyRadius) : this(defaultNPC, (object)location, (object)fuzzyRadius) { } @@ -46,16 +47,16 @@ public TeleportAction(GameNPC defaultNPC, GameLocation location, int fuzzyRadius public override void Perform(DOLEvent e, object sender, EventArgs args) { GamePlayer player = BehaviourUtils.GuessGamePlayerFromNotify(e, sender, args); - GameLocation location = P; + Teleport location = P; int radius = Q; - if (location.Name != null) + if (location.TeleportID != null) { - player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "Behaviour.TeleportAction.TeleportedToLoc", player, location.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); + player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "Behaviour.TeleportAction.TeleportedToLoc", player, location.TeleportID), eChatType.CT_System, eChatLoc.CL_SystemWindow); } - - location.Position += new Vector3(Util.Random(-radius, radius), Util.Random(-radius, radius), 0); - player.MoveTo(location); + + var randomOffset = Vector.Create(x: Util.Random(-radius, radius), y: Util.Random(-radius, radius)); + player.MoveTo(location.GetPosition() + randomOffset); } } } diff --git a/GameServer/behaviour/Actions/WalkToAction.cs b/GameServer/behaviour/Actions/WalkToAction.cs index 4b734957..dbc479f9 100644 --- a/GameServer/behaviour/Actions/WalkToAction.cs +++ b/GameServer/behaviour/Actions/WalkToAction.cs @@ -23,7 +23,8 @@ using DOL.Events; using DOL.GS.Behaviour.Attributes; using DOL.GS.Behaviour; -using System.Numerics; +using DOL.GS.Geometry; +using Vector3 = System.Numerics.Vector3; namespace DOL.GS.Behaviour.Actions { @@ -45,8 +46,17 @@ public WalkToAction(GameNPC defaultNPC, Vector3 destination, GameNPC npc) public override void Perform(DOLEvent e, object sender, EventArgs args) { GamePlayer player = BehaviourUtils.GuessGamePlayerFromNotify(e, sender, args); - var location = P.HasValue ? P.Value : player.Position; - Q.PathTo(location, Q.CurrentSpeed); + Coordinate c; + + if (P.HasValue) + { + c = Coordinate.Create((int)P.Value.X, (int)P.Value.Y, (int)P.Value.Z); + } + else + { + c = player.Coordinate; + } + Q.WalkTo(c, Q.CurrentSpeed); } } } diff --git a/GameServer/commands/gmcommands/AddHookPoint.cs b/GameServer/commands/gmcommands/AddHookPoint.cs index c5040308..06383749 100644 --- a/GameServer/commands/gmcommands/AddHookPoint.cs +++ b/GameServer/commands/gmcommands/AddHookPoint.cs @@ -53,11 +53,11 @@ public void OnCommand(GameClient client, string[] args) DBKeepHookPoint dbkeephp = new DBKeepHookPoint(); dbkeephp.HookPointID = id; dbkeephp.KeepComponentSkinID = skin; - var diff = client.Player.Position - comp.Position; - dbkeephp.X = (int)diff.X; - dbkeephp.Y = (int)diff.Y; - dbkeephp.Z = (int)diff.Z; - dbkeephp.Heading = client.Player.Heading - comp.Heading; + var keepComponentOffsetToPlayer = client.Player.Coordinate - comp.Coordinate; + dbkeephp.X = keepComponentOffsetToPlayer.X; + dbkeephp.Y = keepComponentOffsetToPlayer.Y; + dbkeephp.Z = keepComponentOffsetToPlayer.Z; + dbkeephp.Heading = (client.Player.Orientation - comp.Orientation).InHeading; GameServer.Database.AddObject(dbkeephp); } catch (Exception e) diff --git a/GameServer/commands/gmcommands/GMTerritories.cs b/GameServer/commands/gmcommands/GMTerritories.cs index 7420c68c..74be183e 100644 --- a/GameServer/commands/gmcommands/GMTerritories.cs +++ b/GameServer/commands/gmcommands/GMTerritories.cs @@ -1,8 +1,8 @@ using DOL.Database; using DOL.GameEvents; -using DOL.Geometry; using DOL.GS; using DOL.GS.Commands; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.Language; using DOL.MobGroups; @@ -409,12 +409,12 @@ public void OnCommand(GameClient client, string[] args) return; } } - Vector3 position; + Coordinate position; if (args.Length > arg) { if (string.Equals(args[arg], "remove")) { - territory.PortalPosition = null; + territory.PortalCoordinate = null; client.SendTranslation("Commands.GM.GMTerritories.PortalRemoved", eChatType.CT_System, eChatLoc.CL_SystemWindow, territory.Name); return; } @@ -438,14 +438,13 @@ public void OnCommand(GameClient client, string[] args) client.SendTranslation("Commands.GM.GMTerritories.BadCoordinate", eChatType.CT_System, eChatLoc.CL_SystemWindow, args[arg + 2]); return; } - position = new Vector3(x, y, z); + position = Coordinate.Create(x, y, z); } else { - var playerPosition = client.Player.Position; - position = new Vector3((int)playerPosition.X, (int)playerPosition.Y, (int)playerPosition.Z); + position = client.Player.Coordinate; } - territory.PortalPosition = position; + territory.PortalCoordinate = position; territory.SaveIntoDatabase(); client.SendTranslation("Commands.GM.GMTerritories.PortalSet", eChatType.CT_System, eChatLoc.CL_SystemWindow, territory.Name, position.X, position.Y, position.Z); } diff --git a/GameServer/commands/gmcommands/GMinfo.cs b/GameServer/commands/gmcommands/GMinfo.cs index 90a93004..e88b2e0c 100644 --- a/GameServer/commands/gmcommands/GMinfo.cs +++ b/GameServer/commands/gmcommands/GMinfo.cs @@ -148,7 +148,7 @@ public void OnCommand(GameClient client, string[] args) if (respawn.Hours > 0) hours = respawn.Hours + " hours "; info.Add(" + Respawn: " + days + hours + respawn.Minutes + " minutes " + respawn.Seconds + " seconds"); - info.Add(" + SpawnPoint: " + target.SpawnPoint.X + ", " + target.SpawnPoint.Y + ", " + target.SpawnPoint.Z); + info.Add(" + SpawnPoint: " + target.SpawnPosition.X + ", " + target.SpawnPosition.Y + ", " + target.SpawnPosition.Z); } if (target.QuestIdListToGive.Count > 0) @@ -223,8 +223,8 @@ public void OnCommand(GameClient client, string[] args) info.Add(" + Inventory: " + target.Inventory.Count + " items"); info.Add(" "); - info.Add(" + Mob_ID: " + target.InternalID); - info.Add(" + Position: " + target.Position.ToString("F0") + ", " + target.Heading); + info.Add(" + Mob_ID: " + target.InternalID);; + info.Add(" + Position: " + target.Coordinate + ", " + target.Orientation.InHeading); info.Add(" + OID: " + target.ObjectID); info.Add(" + Package ID: " + target.PackageID); @@ -445,7 +445,7 @@ public void OnCommand(GameClient client, string[] args) } info.Add(" "); - info.Add(" Location: " + target.Position.ToString("F0")); + info.Add(" Coordinate: X= " + target.Position.X + " ,Y= " + target.Position.Y + " ,Z= " + target.Position.Z); } #endregion StaticItem @@ -494,7 +494,7 @@ public void OnCommand(GameClient client, string[] args) info.Add(" + Statut : " + statut); info.Add(" + Type : " + DoorRequestHandler.m_handlerDoorID / 100000000); info.Add(" "); - info.Add(" + Position : " + target.Position.ToString("F0")); + info.Add(" + Position : " + target.Coordinate); info.Add(" + Heading : " + target.Heading); } @@ -537,6 +537,8 @@ public void OnCommand(GameClient client, string[] args) info.Add(" "); info.Add(" + Climbing : " + target.Climbing); info.Add(" "); + info.Add(" + X : " + target.Position.X); + info.Add(" + Y : " + target.Position.Y); info.Add(" + ComponentX : " + target.ComponentX); info.Add(" + ComponentY : " + target.ComponentY); info.Add(" + ComponentHeading : " + target.ComponentHeading); @@ -553,10 +555,10 @@ public void OnCommand(GameClient client, string[] args) info.Add(" + Keep Manager : " + GameServer.KeepManager.GetType().FullName); info.Add(" + Frontiers"); } - else if (GameServer.KeepManager.GetBattleground(target.CurrentRegionID) != null) + else if (GameServer.KeepManager.GetBattleground(target.Position.RegionID) != null) { info.Add(" + Keep Manager : " + GameServer.KeepManager.GetType().FullName); - Battleground bg = GameServer.KeepManager.GetBattleground(client.Player.CurrentRegionID); + Battleground bg = GameServer.KeepManager.GetBattleground(client.Player.Position.RegionID); info.Add(" + Battleground (" + bg.MinLevel + " to " + bg.MaxLevel + ", max RL: " + bg.MaxRealmLevel + ")"); } else @@ -682,8 +684,8 @@ public void OnCommand(GameClient client, string[] args) info.Add(" Zone ID: " + client.Player.CurrentZone.ID); info.Add(" Zone IsDungeon: " + client.Player.CurrentZone.IsDungeon); info.Add(" Zone SkinID: " + client.Player.CurrentZone.ZoneSkinID); - info.Add(" Zone X: " + client.Player.CurrentZone.XOffset); - info.Add(" Zone Y: " + client.Player.CurrentZone.YOffset); + info.Add(" Zone X: "+ client.Player.CurrentZone.Offset.X); + info.Add(" Zone Y: "+ client.Player.CurrentZone.Offset.Y); info.Add(" Zone Width: " + client.Player.CurrentZone.Width); info.Add(" Zone Height: " + client.Player.CurrentZone.Height); info.Add(" Zone DivingEnabled: " + client.Player.CurrentZone.IsDivingEnabled); diff --git a/GameServer/commands/gmcommands/Instance.cs b/GameServer/commands/gmcommands/Instance.cs index 5ec5c9fe..a1e60c64 100644 --- a/GameServer/commands/gmcommands/Instance.cs +++ b/GameServer/commands/gmcommands/Instance.cs @@ -21,6 +21,7 @@ using System.Reflection; using System.Collections; using DOL.Database; +using DOL.GS.Geometry; using System.Numerics; //By dinberg - so its him who you blame ;) @@ -89,7 +90,7 @@ public void OnCommand(GameClient client, string[] args) //Create the database entry... DBInstanceXElement element = new DBInstanceXElement(); - element.Heading = client.Player.Heading; + element.Heading = client.Player.Orientation.InHeading; element.X = (int)client.Player.Position.X; element.Y = (int)client.Player.Position.Y; element.Z = (int)client.Player.Position.Z; @@ -156,7 +157,7 @@ public void OnCommand(GameClient client, string[] args) obj.Name = element.ObjectId.Substring(0, 18); obj.GuildName = element.ObjectId.Substring(18); - obj.Position = new Vector3(element.X, element.Y, element.Z); + obj.Position = Position.Create(client.Player.CurrentRegionID, element.X, element.Y, element.Z, element.Heading); obj.Heading = element.Heading; obj.CurrentRegion = client.Player.CurrentRegion; @@ -295,27 +296,25 @@ public void OnCommand(GameClient client, string[] args) else { // start with some generic coordinates that seem to work well in many instance zones - var pos = new Vector3(32361, 31744, 16003); + var entrancePosition = Position.Create(regionID: newInstance.ID, x: 32361, y: 31744, z: 16003, heading: 1075); ushort heading = 1075; // If you're having trouble zoning into an instance then try adding an entrance element so it can be used here - if (newInstance.InstanceEntranceLocation != null) + if (newInstance.EntrancePosition.Coordinate != Coordinate.Nowhere) { - pos = newInstance.InstanceEntranceLocation.Position; - heading = newInstance.InstanceEntranceLocation.Heading; + entrancePosition = newInstance.EntrancePosition; } // save current position for use with /instance exit - GameLocation saveLocation = new GameLocation(player.Name + "_exit", player.CurrentRegionID, player.Position, player.Heading); - player.TempProperties.setProperty(saveLocation.Name, saveLocation); + player.TempProperties.setProperty(player.Name + "_exit", player.Position); bool success = true; - if (!player.MoveTo(newInstance.ID, pos, heading)) + if (!player.MoveTo(entrancePosition)) { SendMessage(client, "MoveTo to entrance failed, now trying to move to current location inside the instance."); - if (!player.MoveTo(newInstance.ID, player.Position, player.Heading)) + if (!player.MoveTo(player.Position.With(regionID: newInstance.ID))) { SendMessage(client, "That failed as well. Either add an entrance to this instance or move in the world to a corresponding instance location."); success = false; @@ -340,18 +339,18 @@ public void OnCommand(GameClient client, string[] args) return; } - GameLocation saveLocation = player.TempProperties.getProperty(player.Name + "_exit", null) as GameLocation; + var savePosition = player.TempProperties.getProperty(player.Name + "_exit", Position.Nowhere); - if (saveLocation == null) + if (savePosition == Position.Nowhere) { ushort sourceRegion = (player.CurrentRegion as BaseInstance).Skin; - if (!player.MoveTo(sourceRegion, player.Position, player.Heading)) - player.MoveToBind(); + var wasZoningSuccessful = player.MoveTo(player.Position.With(regionID: sourceRegion)); + if (!wasZoningSuccessful) player.MoveToBind(); } else { - player.MoveTo(saveLocation.RegionID, saveLocation.Position, saveLocation.Heading); + player.MoveTo(savePosition); } } break; diff --git a/GameServer/commands/gmcommands/KeepComponent.cs b/GameServer/commands/gmcommands/KeepComponent.cs index af8b88d9..2c6018dc 100644 --- a/GameServer/commands/gmcommands/KeepComponent.cs +++ b/GameServer/commands/gmcommands/KeepComponent.cs @@ -20,6 +20,7 @@ using System.Linq; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Keeps; using DOL.GS.PacketHandler; using DOL.Language; @@ -50,7 +51,7 @@ public void OnCommand(GameClient client, string[] args) return; } - AbstractGameKeep myKeep = GameServer.KeepManager.GetKeepCloseToSpot(client.Player.CurrentRegionID, client.Player.Position, WorldMgr.OBJ_UPDATE_DISTANCE); + AbstractGameKeep myKeep = GameServer.KeepManager.GetKeepCloseToSpot(client.Player.Position, WorldMgr.OBJ_UPDATE_DISTANCE); if (myKeep == null) { @@ -112,16 +113,15 @@ public void OnCommand(GameClient client, string[] args) } } - GameKeepComponent component = new GameKeepComponent(); - component.Position = client.Player.Position; - component.ComponentHeading = (client.Player.Heading - myKeep.Heading) / 1024; - component.Heading = (ushort)(component.ComponentHeading * 1024 + myKeep.Heading); + GameKeepComponent component = new GameKeepComponent();component.Position = client.Player.Position + .With(Angle.Degrees(component.ComponentHeading * 90) + myKeep.Orientation); + component.ComponentHeading = (client.Player.Orientation - myKeep.Orientation).InHeading / 1024; component.Keep = myKeep; //todo good formula //component.ComponentX = (component.X - myKeep.X) / 148; //component.ComponentY = (component.Y - myKeep.Y) / 148; - double angle = myKeep.Heading * ((Math.PI * 2) / 360); // angle*2pi/360; + var angle = myKeep.Orientation.InRadians; //component.ComponentX = (int)((148 * Math.Sin(angle) * myKeep.X - 148 * Math.Sin(angle) * client.Player.X + client.Player.Y - myKeep.Y) // / (148 * Math.Sin(angle) - 148 * 148 * 2 * Math.Sin(angle) * Math.Cos(angle))); @@ -145,7 +145,6 @@ so must find an other way to find it.... component.Model = INVISIBLE_MODEL; component.Skin = skin; component.Level = (byte)myKeep.Level; - component.CurrentRegion = client.Player.CurrentRegion; component.Health = component.MaxHealth; component.ID = myKeep.KeepComponents.Count; component.Keep.KeepComponents.Add(component); @@ -161,20 +160,14 @@ so must find an other way to find it.... #region Move case "move": { - GameKeepComponent component = client.Player.TargetObject as GameKeepComponent; - component.Position = client.Player.Position; - component.ComponentHeading = (client.Player.Heading - myKeep.Heading) / 1024; - component.Heading = (ushort)(component.ComponentHeading * 1024 + myKeep.Heading); - component.Keep = myKeep; - //todo good formula - //component.ComponentX = (component.X - myKeep.X) / 148; - //component.ComponentY = (myKeep.Y - component.Y) / 148; - double angle = myKeep.Heading * ((Math.PI * 2) / 360); // angle*2pi/360; - - //component.ComponentX = (int)((148 * Math.Sin(angle) * myKeep.X - 148 * Math.Sin(angle) * client.Player.X + client.Player.Y - myKeep.Y) - // / (148 * Math.Sin(angle) - 148 * 148 * 2 * Math.Sin(angle) * Math.Cos(angle))); - //component.ComponentY = (int)((myKeep.Y - client.Player.Y + 148 * Math.Sin(angle) * component.ComponentX) / (148 * Math.Cos(angle))); + var component = client.Player.TargetObject as GameKeepComponent; + component.Position = client.Player.Position + .With(Angle.Heading(component.ComponentHeading * 1024) + myKeep.Orientation); + component.ComponentHeading = (client.Player.Orientation - myKeep.Orientation).InDegrees / 90; + component.Keep = myKeep; + + var angle = myKeep.Orientation.InRadians; component.ComponentX = CalcCX(client.Player, myKeep, angle); component.ComponentY = CalcCY(client.Player, myKeep, angle); @@ -198,7 +191,7 @@ so must find an other way to find it.... GameKeepComponent component = client.Player.TargetObject as GameKeepComponent; component.ComponentHeading = amount; - component.Heading = (ushort)(component.ComponentHeading * 1024 + myKeep.Heading); + component.Orientation = Angle.Heading(component.ComponentHeading * 1024) + myKeep.Orientation; client.Out.SendKeepInfo(myKeep); client.Out.SendKeepComponentInfo(component); @@ -329,29 +322,33 @@ so must find an other way to find it.... public int CalcCX(GamePlayer player, AbstractGameKeep myKeep, double angle) { + var keepPos = myKeep.Position; + var playerPos = player.Position; if (Math.Abs(Math.Sin(angle)) < 0.0001) //for approximations, == 0 wont work. { - return ((int)player.Position.X - myKeep.X) / 148; + return (playerPos.X - keepPos.X) / 148; } else { - return (int)((148 * Math.Sin(angle) * myKeep.X - 148 * Math.Sin(angle) * player.Position.X + player.Position.Y - myKeep.Y) - / (148 * Math.Sin(angle) - 148 * 148 * 2 * Math.Sin(angle) * Math.Cos(angle))); + return (int)((148 * Math.Sin(angle) * keepPos.X - 148 * Math.Sin(angle) * playerPos.X + playerPos.Y - keepPos.Y) + / (148 * Math.Sin(angle) - 148 * 148 * 2 * Math.Sin(angle) * Math.Cos(angle))); } } public int CalcCY(GamePlayer player, AbstractGameKeep myKeep, double angle) { + var keepPos = myKeep.Position; + var playerPos = player.Position; if (Math.Abs(Math.Sin(angle)) < 0.0001) { - return (myKeep.Y - (int)player.Position.Y) / 148; + return (keepPos.Y - playerPos.Y) / 148; } else { - int cx = (int)((148 * Math.Sin(angle) * myKeep.X - 148 * Math.Sin(angle) * player.Position.X + player.Position.Y - myKeep.Y) - / (148 * Math.Sin(angle) - 148 * 148 * 2 * Math.Sin(angle) * Math.Cos(angle))); - return (int)((myKeep.Y - player.Position.Y + 148 * Math.Sin(angle) * cx) / (148 * Math.Cos(angle))); + int cx = (int)((148 * Math.Sin(angle) * keepPos.X - 148 * Math.Sin(angle) * playerPos.X + playerPos.Y - keepPos.Y) + / (148 * Math.Sin(angle) - 148 * 148 * 2 * Math.Sin(angle) * Math.Cos(angle))); + return (int)((keepPos.Y - playerPos.Y + 148 * Math.Sin(angle) * cx) / (148 * Math.Cos(angle))); } } } -} \ No newline at end of file +} diff --git a/GameServer/commands/gmcommands/Minorelic.cs b/GameServer/commands/gmcommands/Minorelic.cs index 22729b0f..644feff5 100644 --- a/GameServer/commands/gmcommands/Minorelic.cs +++ b/GameServer/commands/gmcommands/Minorelic.cs @@ -68,11 +68,11 @@ public void OnCommand(GameClient client, string[] args) relic.Name = args[2]; - relic.SpawnHeading = client.Player.Heading; - relic.SpawnX = (int)client.Player.Position.X; - relic.SpawnY = (int)client.Player.Position.Y; - relic.SpawnZ = (int)client.Player.Position.Z; - relic.SpawnRegion = client.Player.CurrentRegionID; + relic.SpawnHeading = client.Player.Position.Orientation.InHeading; + relic.SpawnX = client.Player.Position.X; + relic.SpawnY = client.Player.Position.Y; + relic.SpawnZ = client.Player.Position.Z; + relic.SpawnRegion = client.Player.Position.RegionID; relic.relicTarget = args[4].ToLower(); @@ -110,15 +110,7 @@ public void OnCommand(GameClient client, string[] args) MinotaurRelic relic = client.Player.TargetObject as MinotaurRelic; - relic.Heading = client.Player.Heading; relic.Position = client.Player.Position; - relic.CurrentRegionID = client.Player.CurrentRegionID; - - relic.SpawnHeading = client.Player.Heading; - relic.SpawnX = (int)client.Player.Position.X; - relic.SpawnY = (int)client.Player.Position.Y; - relic.SpawnZ = (int)client.Player.Position.Z; - relic.SpawnRegion = client.Player.CurrentRegionID; relic.SaveIntoDatabase(); @@ -244,11 +236,11 @@ public void OnCommand(GameClient client, string[] args) info.Add("==========================="); info.Add(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.MinoRelic.Info.PositionInfo")); info.Add("==========================="); - info.Add(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.MinoRelic.Info.SpawnX", relic.SpawnX)); - info.Add(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.MinoRelic.Info.SpawnY", relic.SpawnX)); - info.Add(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.MinoRelic.Info.SpawnZ", relic.SpawnZ)); - info.Add(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.MinoRelic.Info.SpawnHeading" + relic.SpawnHeading)); - info.Add(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.MinoRelic.Info.SpawnRegion", relic.SpawnRegion)); + info.Add(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.MinoRelic.Info.SpawnX", relic.SpawnPosition.X)); + info.Add(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.MinoRelic.Info.SpawnY", relic.SpawnPosition.Y)); + info.Add(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.MinoRelic.Info.SpawnZ", relic.SpawnPosition.Z)); + info.Add(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.MinoRelic.Info.SpawnHeading" + relic.SpawnPosition.Orientation.InHeading)); + info.Add(LanguageMgr.GetTranslation(client.Account.Language, "GMCommands.MinoRelic.Info.SpawnRegion", relic.SpawnPosition.RegionID)); info.Add("==========================="); info.Add(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.MinoRelic.Info.SpellInfo")); info.Add("==========================="); diff --git a/GameServer/commands/gmcommands/Player.cs b/GameServer/commands/gmcommands/Player.cs index 062183f0..8add1741 100644 --- a/GameServer/commands/gmcommands/Player.cs +++ b/GameServer/commands/gmcommands/Player.cs @@ -1610,7 +1610,7 @@ public void OnCommand(GameClient client, string[] args) { if (!(player.IsAlive)) { - player.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + player.MoveTo(client.Player.Position); client.Out.SendMessage("You resurrected " + player.Name + " successfully!", eChatType.CT_Important, eChatLoc.CL_SystemWindow); @@ -1648,7 +1648,7 @@ public void OnCommand(GameClient client, string[] args) aplayer.Player.Health = aplayer.Player.MaxHealth; aplayer.Player.Mana = aplayer.Player.MaxMana; aplayer.Player.Endurance = aplayer.Player.MaxEndurance; - aplayer.Player.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + aplayer.Player.MoveTo(client.Player.Position); aplayer.Player.StopReleaseTimer(); aplayer.Player.Out.SendPlayerRevive(aplayer.Player); @@ -1671,7 +1671,7 @@ public void OnCommand(GameClient client, string[] args) hplayer.Player.Health = hplayer.Player.MaxHealth; hplayer.Player.Mana = hplayer.Player.MaxMana; hplayer.Player.Endurance = hplayer.Player.MaxEndurance; - hplayer.Player.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + hplayer.Player.MoveTo(client.Player.Position); hplayer.Player.StopReleaseTimer(); hplayer.Player.Out.SendPlayerRevive(hplayer.Player); @@ -1694,7 +1694,7 @@ public void OnCommand(GameClient client, string[] args) mplayer.Player.Health = mplayer.Player.MaxHealth; mplayer.Player.Mana = mplayer.Player.MaxMana; mplayer.Player.Endurance = mplayer.Player.MaxEndurance; - mplayer.Player.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + mplayer.Player.MoveTo(client.Player.Position); mplayer.Player.StopReleaseTimer(); mplayer.Player.Out.SendPlayerRevive(mplayer.Player); @@ -1717,7 +1717,7 @@ public void OnCommand(GameClient client, string[] args) selfplayer.Health = selfplayer.MaxHealth; selfplayer.Mana = selfplayer.MaxMana; selfplayer.Endurance = selfplayer.MaxEndurance; - selfplayer.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + selfplayer.MoveTo(client.Player.Position); selfplayer.Out.SendMessage("You revive yourself.", eChatType.CT_Important, eChatLoc.CL_SystemWindow); @@ -1744,7 +1744,7 @@ public void OnCommand(GameClient client, string[] args) allplayer.Player.Health = allplayer.Player.MaxHealth; allplayer.Player.Mana = allplayer.Player.MaxMana; allplayer.Player.Endurance = allplayer.Player.MaxEndurance; - allplayer.Player.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + allplayer.Player.MoveTo(client.Player.Position); allplayer.Player.StopReleaseTimer(); allplayer.Player.Out.SendPlayerRevive(allplayer.Player); @@ -1918,7 +1918,7 @@ public void OnCommand(GameClient client, string[] args) if (pname.Player.GuildName == guild && guild != "") { count++; - pname.Player.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + pname.Player.MoveTo(client.Player.Position); } } @@ -1944,7 +1944,7 @@ public void OnCommand(GameClient client, string[] args) { foreach (GameLiving groupedplayers in pname.Player.Group.GetMembersInTheGroup()) { - groupedplayers.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + groupedplayers.MoveTo(client.Player.Position); count++; } } @@ -1973,7 +1973,7 @@ public void OnCommand(GameClient client, string[] args) { foreach (GamePlayer cgplayers in cg.Members.Keys) { - cgplayers.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + cgplayers.MoveTo(client.Player.Position); count++; } } @@ -2003,7 +2003,7 @@ public void OnCommand(GameClient client, string[] args) { foreach (GamePlayer cgplayers in cg.Members.Keys) { - cgplayers.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + cgplayers.MoveTo(client.Player.Position); count++; } } @@ -2122,10 +2122,8 @@ public void OnCommand(GameClient client, string[] args) client.Out.SendMessage("\"" + player.Name + "\", " + player.CurrentRegionID + ", " + - player.Position.X.ToString("F0") + ", " + - player.Position.Y.ToString("F0") + ", " + - player.Position.Z.ToString("F0") + ", " + - player.Heading, + player.Coordinate + ", " + + player.Orientation.InHeading, eChatType.CT_System, eChatLoc.CL_SystemWindow); } break; diff --git a/GameServer/commands/gmcommands/Teleport.cs b/GameServer/commands/gmcommands/Teleport.cs index ec78e2d5..3ef77c7c 100644 --- a/GameServer/commands/gmcommands/Teleport.cs +++ b/GameServer/commands/gmcommands/Teleport.cs @@ -115,11 +115,11 @@ private void AddTeleport(GameClient client, String teleportID, String type) Teleport teleport = new Teleport(); teleport.TeleportID = teleportID; teleport.Realm = (int)realm; - teleport.RegionID = player.CurrentRegion.ID; - teleport.X = (int)player.Position.X; - teleport.Y = (int)player.Position.Y; - teleport.Z = (int)player.Position.Z; - teleport.Heading = player.Heading; + teleport.RegionID = player.Position.RegionID; + teleport.X = player.Position.X; + teleport.Y = player.Position.Y; + teleport.Z = player.Position.Z; + teleport.Heading = player.Position.Orientation.InHeading; teleport.Type = type; if (!WorldMgr.AddTeleportLocation(teleport)) diff --git a/GameServer/commands/gmcommands/addbind.cs b/GameServer/commands/gmcommands/addbind.cs index bfe46d2d..b5ac141b 100644 --- a/GameServer/commands/gmcommands/addbind.cs +++ b/GameServer/commands/gmcommands/addbind.cs @@ -46,10 +46,10 @@ public void OnCommand(GameClient client, string[] args) } } BindPoint bp = new BindPoint(); - bp.X = (int)client.Player.Position.X; - bp.Y = (int)client.Player.Position.Y; - bp.Z = (int)client.Player.Position.Z; - bp.Region = client.Player.CurrentRegionID; + bp.X = client.Player.Position.X; + bp.Y = client.Player.Position.Y; + bp.Z = client.Player.Position.Z; + bp.Region = client.Player.Position.RegionID; bp.Radius = bindRadius; GameServer.Database.AddObject(bp); client.Player.CurrentRegion.AddArea(new Area.BindArea("bind point", bp)); diff --git a/GameServer/commands/gmcommands/area.cs b/GameServer/commands/gmcommands/area.cs index da322587..5926e3ca 100644 --- a/GameServer/commands/gmcommands/area.cs +++ b/GameServer/commands/gmcommands/area.cs @@ -77,9 +77,9 @@ public void OnCommand(GameClient client, string[] args) } area.Sound = byte.Parse(args[6]); area.Region = client.Player.CurrentRegionID; - area.X = (int)client.Player.Position.X; - area.Y = (int)client.Player.Position.Y; - area.Z = (int)client.Player.Position.Z; + area.X = client.Player.Position.X; + area.Y = client.Player.Position.Y; + area.Z = client.Player.Position.Z; area.ObjectId = area.Description; if (args.Length == 8 && bool.TryParse(args[7], out bool canVol)) diff --git a/GameServer/commands/gmcommands/cast.cs b/GameServer/commands/gmcommands/cast.cs index df7c623b..18efdd51 100644 --- a/GameServer/commands/gmcommands/cast.cs +++ b/GameServer/commands/gmcommands/cast.cs @@ -23,6 +23,7 @@ using DOL.GS.PacketHandler; using DOL.Language; using DOL.GS.Effects; +using DOL.GS.Geometry; namespace DOL.GS.Commands { @@ -150,7 +151,7 @@ public void OnCommand(GameClient client, string[] args) case "sound": DisplayMessage(client, LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.Cast.SoundPlayed", id.ToString())); - client.Player.Out.SendSoundEffect((ushort)id, 0, 0, 0, 0, 0); + client.Player.Out.SendSoundEffect((ushort)id, Position.Zero, 0); break; #endregion #region Default diff --git a/GameServer/commands/gmcommands/checklos.cs b/GameServer/commands/gmcommands/checklos.cs index 67a9978b..fd3de7ea 100644 --- a/GameServer/commands/gmcommands/checklos.cs +++ b/GameServer/commands/gmcommands/checklos.cs @@ -35,7 +35,7 @@ public class CheckLosCommandHandler : AbstractCommandHandler, ICommandHandler { public async void OnCommand(GameClient client, string[] args) { - if (client.Player?.TargetObject == null && client.Player?.GroundTarget == null) + if (client.Player?.TargetObject == null && client.Player?.GroundTargetPosition == Position.Nowhere) { DisplayMessage(client, "You need a target to use this command."); return; @@ -45,7 +45,7 @@ public async void OnCommand(GameClient client, string[] args) if (client.Player.TargetObject != null) { var target = client.Player.TargetObject; - text.Add($"Target: {target.Name} (OID: {target.ObjectID}, distance: {Vector3.Distance(target.Position, client.Player.Position)})"); + text.Add($"Target: {target.Name} (OID: {target.ObjectID}, distance: {(int)target.Coordinate.DistanceTo(client.Player.Position)})"); text.Add($"Target in view (player's cache): {client.Player.TargetInView}"); var stats = new RaycastStats(); @@ -61,7 +61,7 @@ public async void OnCommand(GameClient client, string[] args) } else { - var ground = client.Player.GroundTarget; + var ground = client.Player.GroundTargetPosition; text.Add($"Ground target: {ground}"); text.Add($"Target in view (player's cache): {client.Player.GroundTargetInView}"); // TODO diff --git a/GameServer/commands/gmcommands/debugjump.cs b/GameServer/commands/gmcommands/debugjump.cs index dacd0937..68e7b2fd 100644 --- a/GameServer/commands/gmcommands/debugjump.cs +++ b/GameServer/commands/gmcommands/debugjump.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; using DOL.GS.PacketHandler; using DOL.Language; @@ -44,23 +45,24 @@ public void OnCommand(GameClient client, string[] args) return; } - Zone z = WorldMgr.GetZone(zoneID); - if (z == null) - { - DisplayMessage(client, LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.DebugJump.UnknownZoneID", args[1])); - return; - } - - ushort RegionID = z.ZoneRegion.ID; - int X = z.XOffset + Convert.ToInt32(args[2]); - int Y = z.YOffset + Convert.ToInt32(args[3]); - int Z = Convert.ToInt32(args[4]); - ushort Heading = Convert.ToUInt16(args[5]); + var zone = WorldMgr.GetZone(zoneID); + if (zone == null) + { + DisplayMessage(client, LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.DebugJump.UnknownZoneID", args[1])); + return; + } - if (!CheckExpansion(client, RegionID)) + if (!CheckExpansion(client, zone.ZoneRegion.ID)) return; - client.Player.MoveTo(RegionID, X, Y, Z, Heading); + var jumpPositionInZone = Position.Create( + x: Convert.ToInt32(args[2]), + y: Convert.ToInt32(args[3]), + z: Convert.ToInt32(args[4]), + heading: Convert.ToUInt16(args[4]), + regionID: zone.ZoneRegion.ID); + var jumpPosition = jumpPositionInZone + zone.Offset; + client.Player.MoveTo(jumpPosition); } public bool CheckExpansion(GameClient client, ushort RegionID) diff --git a/GameServer/commands/gmcommands/door.cs b/GameServer/commands/gmcommands/door.cs index a366cefb..e6d9274a 100644 --- a/GameServer/commands/gmcommands/door.cs +++ b/GameServer/commands/gmcommands/door.cs @@ -293,10 +293,10 @@ private void add(GameClient client, GameDoor targetDoor) door.Type = DoorID / 100000000; door.Level = 20; door.Realm = 6; - door.X = (int)targetDoor.Position.X; - door.Y = (int)targetDoor.Position.Y; - door.Z = (int)targetDoor.Position.Z; - door.Heading = targetDoor.Heading; + door.X = targetDoor.Position.X; + door.Y = targetDoor.Position.Y; + door.Z = targetDoor.Position.Z; + door.Heading = targetDoor.Orientation.InHeading; door.Health = 2545; GameServer.Database.AddObject(door); (targetDoor).AddToWorld(); @@ -327,10 +327,10 @@ private void add(GameClient client, GameKeepDoor targetDoor) door.Type = DoorID / 100000000; door.Level = 20; door.Realm = 6; - door.X = (int)targetDoor.Position.X; - door.Y = (int)targetDoor.Position.Y; - door.Z = (int)targetDoor.Position.Z; - door.Heading = targetDoor.Heading; + door.X = targetDoor.Position.X; + door.Y = targetDoor.Position.Y; + door.Z = targetDoor.Position.Z; + door.Heading = targetDoor.Orientation.InHeading; door.Health = 2545; GameServer.Database.AddObject(door); (targetDoor).AddToWorld(); @@ -359,10 +359,10 @@ private void update(GameClient client, GameDoor targetDoor) door.Realm = (byte)targetDoor.Realm; door.Health = targetDoor.Health; door.Locked = targetDoor.Locked; - door.X = (int)client.Player.Position.X; - door.Y = (int)client.Player.Position.Y; - door.Z = (int)client.Player.Position.Z; - door.Heading = client.Player.Heading; + door.X = client.Player.Position.X; + door.Y = client.Player.Position.Y; + door.Z = client.Player.Position.Z; + door.Heading = client.Player.Orientation.InHeading; GameServer.Database.AddObject(door); (targetDoor).AddToWorld(); client.Player.Out.SendMessage("Added door " + DoorID + " to the database", eChatType.CT_Important, @@ -535,10 +535,10 @@ private void info(GameClient client, GameDoor targetDoor) info.Add(" + Health : " + targetDoor.Health + " / " + targetDoor.MaxHealth); info.Add(" + Statut : " + statut); info.Add(" + Type : " + doorType); - info.Add(" + X : " + targetDoor.Position.X.ToString("F0")); - info.Add(" + Y : " + targetDoor.Position.Y.ToString("F0")); - info.Add(" + Z : " + targetDoor.Position.Z.ToString("F0")); - info.Add(" + Heading : " + targetDoor.Heading); + info.Add(" + X : " + targetDoor.Position.X); + info.Add(" + Y : " + targetDoor.Position.Y); + info.Add(" + Z : " + targetDoor.Position.Z); + info.Add(" + Heading : " + targetDoor.Orientation.InHeading); info.Add(" + Group Mob : " + targetDoor.Group_Mob_Id); info.Add(" + Key : " + targetDoor.Key); info.Add(" + Key Chance : " + targetDoor.Key_Chance); diff --git a/GameServer/commands/gmcommands/earthquake.cs b/GameServer/commands/gmcommands/earthquake.cs index 922b9b89..7b088eba 100644 --- a/GameServer/commands/gmcommands/earthquake.cs +++ b/GameServer/commands/gmcommands/earthquake.cs @@ -1,7 +1,7 @@ using System; using DOL.GS.PacketHandler; using DOL.GS.Commands; -using DOL.Geometry; +using DOL.GS.Geometry; using DOL.Language; namespace DOL.GS.Scripts @@ -23,7 +23,7 @@ public void OnCommand(GameClient client, string[] args) intensity = 50.0f; duration = 1000.0f; int x, y, z = 0; - if (client.Player.GroundTarget == null) + if (client.Player.GroundTargetPosition == Position.Nowhere) { x = (int)client.Player.Position.X; y = (int)client.Player.Position.Y; @@ -31,7 +31,7 @@ public void OnCommand(GameClient client, string[] args) } else { - var tempGroundTarget = client.Player.GroundTarget ?? System.Numerics.Vector3.Zero;// as System.Numerics.Vector3; + var tempGroundTarget = client.Player.GroundTargetPosition;// as System.Numerics.Vector3; x = (int)tempGroundTarget.X; y = (int)tempGroundTarget.Y; z = (int)tempGroundTarget.Z; @@ -97,7 +97,7 @@ public void OnCommand(GameClient client, string[] args) pakBis.WriteIntLowEndian((uint)y); pakBis.WriteIntLowEndian((uint)z); pakBis.Write(BitConverter.GetBytes(radius), 0, sizeof(System.Single)); - int distance = (int)System.Numerics.Vector3.Distance(player.Position, client.Player.Position); + int distance = (int)player.Coordinate.DistanceTo(client.Player.Position); float newIntensity = intensity * (1 - distance / radius); pakBis.Write(BitConverter.GetBytes(newIntensity), 0, sizeof(System.Single)); pakBis.Write(BitConverter.GetBytes(duration), 0, sizeof(System.Single)); diff --git a/GameServer/commands/gmcommands/gmappeal.cs b/GameServer/commands/gmcommands/gmappeal.cs index d6e8a778..cdc6bd0d 100644 --- a/GameServer/commands/gmcommands/gmappeal.cs +++ b/GameServer/commands/gmcommands/gmappeal.cs @@ -23,6 +23,7 @@ using DOL.GS.PacketHandler; using DOL.Language; using DOL.GS.Appeal; +using DOL.GS.Geometry; namespace DOL.GS.Commands { @@ -404,9 +405,9 @@ public void OnCommand(GameClient client, string[] args) GamePlayer p = client.Player.TempProperties.getProperty("AppealAssist"); if (p.ObjectState == GameObject.eObjectState.Active) { - GameLocation oldlocation = new GameLocation("old", client.Player); - client.Player.TempProperties.setProperty("AppealJumpOld", oldlocation); - client.Player.MoveTo(p.CurrentRegionID, p.Position, p.Heading); + var oldPosition = client.Player.Position; + client.Player.TempProperties.setProperty("AppealJumpOld", oldPosition); + client.Player.MoveTo(p.Position); } break; } @@ -418,9 +419,9 @@ public void OnCommand(GameClient client, string[] args) } case "jumpback": { - GameLocation jumpback = client.Player.TempProperties.getProperty("AppealJumpOld"); + var jumpback = client.Player.TempProperties.getProperty("AppealJumpOld", Position.Nowhere); - if (jumpback != null) + if (jumpback != Position.Nowhere) { client.Player.MoveTo(jumpback); //client.Player.TempProperties.removeProperty("AppealJumpOld"); diff --git a/GameServer/commands/gmcommands/gmrelic.cs b/GameServer/commands/gmcommands/gmrelic.cs index f2f0b810..6e4b3faa 100644 --- a/GameServer/commands/gmcommands/gmrelic.cs +++ b/GameServer/commands/gmcommands/gmrelic.cs @@ -40,14 +40,14 @@ public void OnCommand(GameClient client, string[] args) DBRelic relic = new DBRelic(); - relic.Heading = client.Player.Heading; + relic.Heading = client.Player.Orientation.InHeading; relic.OriginalRealm = int.Parse(args[2]); relic.Realm = 0; - relic.Region = client.Player.CurrentRegionID; + relic.Region = client.Player.Position.RegionID; relic.relicType = (args[1] == "strength") ? 0 : 1; - relic.X = (int)client.Player.Position.X; - relic.Y = (int)client.Player.Position.Y; - relic.Z = (int)client.Player.Position.Z; + relic.X = client.Player.Position.X; + relic.Y = client.Player.Position.Y; + relic.Z = client.Player.Position.Z; relic.RelicID = Util.Random(100); GameServer.Database.AddObject(relic); RelicMgr.Init(); diff --git a/GameServer/commands/gmcommands/gmrelicpad.cs b/GameServer/commands/gmcommands/gmrelicpad.cs index c6793955..36f5ef20 100644 --- a/GameServer/commands/gmcommands/gmrelicpad.cs +++ b/GameServer/commands/gmcommands/gmrelicpad.cs @@ -45,9 +45,7 @@ public void OnCommand(GameClient client, string[] args) pad.Name = args[2]; pad.Realm = (eRealm)byte.Parse(args[3]); pad.Emblem = emblem; - pad.CurrentRegionID = client.Player.CurrentRegionID; pad.Position = client.Player.Position; - pad.Heading = client.Player.Heading; pad.AddToWorld(); pad.SaveIntoDatabase(); } diff --git a/GameServer/commands/gmcommands/jump.cs b/GameServer/commands/gmcommands/jump.cs index fa4522f6..80dae7ea 100644 --- a/GameServer/commands/gmcommands/jump.cs +++ b/GameServer/commands/gmcommands/jump.cs @@ -16,12 +16,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; using DOL.GS.Housing; using DOL.GS.PacketHandler; using DOL.Language; using System.Collections.Generic; -using System.Numerics; namespace DOL.GS.Commands { @@ -65,15 +65,14 @@ public void OnCommand(GameClient client, string[] args) { var target = client.Player.TargetObject; var player = client.Player; - player.MoveTo(target.CurrentRegionID, target.Position.X, target.Position.Y, target.Position.Z, target.Heading); + player.MoveTo(target.Position); return; } #endregion #region Jump to GT if (args.Length == 3 && args[1].ToLower() == "to" && args[2].ToLower() == "gt") { - if (client.Player.GroundTarget.HasValue) - client.Player.MoveTo(client.Player.CurrentRegionID, client.Player.GroundTarget.Value, client.Player.Heading); + client.Player.MoveTo(client.Player.GroundTargetPosition.With(orientation: client.Player.Orientation)); return; } #endregion Jump to GT @@ -91,7 +90,7 @@ public void OnCommand(GameClient client, string[] args) } if (house != null) { - client.Player.MoveTo(house.OutdoorJumpPoint); + client.Player.MoveTo(house.OutdoorJumpPosition); } else { @@ -103,7 +102,7 @@ public void OnCommand(GameClient client, string[] args) #region Jump t region # if (args.Length == 4 && args[1] == "to" && args[2] == "region") { - client.Player.MoveTo(Convert.ToUInt16(args[3]), client.Player.Position, client.Player.Heading); + client.Player.MoveTo(client.Player.Position.With(regionID: Convert.ToUInt16(args[3]))); return; } #endregion Jump t region # @@ -152,7 +151,7 @@ public void OnCommand(GameClient client, string[] args) } else { - client.Player.MoveTo(jumpTarget.CurrentRegionID, jumpTarget.Position, jumpTarget.Heading); + client.Player.MoveTo(jumpTarget.Position); } return; } @@ -167,7 +166,7 @@ public void OnCommand(GameClient client, string[] args) if (clientc.Player.CurrentHouse != null && clientc.Player.InHouse) clientc.Player.CurrentHouse.Enter(client.Player); else - client.Player.MoveTo(clientc.Player.CurrentRegionID, clientc.Player.Position, client.Player.Heading); + client.Player.MoveTo(clientc.Player.Position.With(client.Player.Orientation)); return; } @@ -203,7 +202,7 @@ public void OnCommand(GameClient client, string[] args) } client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.Jump.JumpToX", npcs[0].CurrentRegion.Description), eChatType.CT_System, eChatLoc.CL_SystemWindow); - client.Player.MoveTo(jumpTarget.CurrentRegionID, jumpTarget.Position, jumpTarget.Heading); + client.Player.MoveTo(jumpTarget.Position); return; } @@ -221,7 +220,10 @@ public void OnCommand(GameClient client, string[] args) if (clientc.Player.CurrentHouse != null && clientc.Player.InHouse) clientc.Player.CurrentHouse.Enter(client.Player); else - client.Player.MoveTo(clientc.Player.CurrentRegionID, clientc.Player.Position, client.Player.Heading); + { + var jumpPosition = clientc.Player.Position.With(client.Player.Orientation); + client.Player.MoveTo(jumpPosition); + } return; } return; @@ -230,16 +232,21 @@ public void OnCommand(GameClient client, string[] args) #region Jump to X Y Z else if (args.Length == 5 && args[1] == "to") { - client.Player.MoveTo(client.Player.CurrentRegionID, Convert.ToInt32(args[2]), Convert.ToInt32(args[3]), Convert.ToInt32(args[4]), client.Player.Heading); + var jumpPosition = Position.Create( + client.Player.CurrentRegionID, + x: Convert.ToInt32(args[2]), + y: Convert.ToInt32(args[3]), + z: Convert.ToInt32(args[4]), + client.Player.Orientation); + client.Player.MoveTo(jumpPosition); return; } #endregion Jump to X Y Z #region Jump rel +/-X +/-Y +/-Z else if (args.Length == 5 && args[1] == "rel") { - client.Player.MoveTo(client.Player.CurrentRegionID, - client.Player.Position + new Vector3(Convert.ToInt32(args[2]), Convert.ToInt32(args[3]), Convert.ToInt32(args[4])), - client.Player.Heading); + var offset = Vector.Create(x:Convert.ToInt32(args[2]), y: Convert.ToInt32(args[3]), z: Convert.ToInt32(args[4])); + client.Player.MoveTo(client.Player.Position + offset); return; } #endregion Jump rel +/-X +/-Y +/-Z @@ -248,7 +255,13 @@ public void OnCommand(GameClient client, string[] args) { if (CheckExpansion(client, client, (ushort)Convert.ToUInt16(args[5]))) { - client.Player.MoveTo(Convert.ToUInt16(args[5]), Convert.ToInt32(args[2]), Convert.ToInt32(args[3]), Convert.ToInt32(args[4]), client.Player.Heading); + var jumpPosition = Position.Create( + regionID: Convert.ToUInt16(args[5]), + x: Convert.ToInt32(args[2]), + y: Convert.ToInt32(args[3]), + z: Convert.ToInt32(args[4]), + client.Player.Orientation); + client.Player.MoveTo(jumpPosition); return; } return; @@ -280,7 +293,8 @@ public void OnCommand(GameClient client, string[] args) } if (CheckExpansion(clientc, clientc, (ushort)Convert.ToUInt16(args[6]))) { - clientc.Player.MoveTo(Convert.ToUInt16(args[6]), Convert.ToInt32(args[3]), Convert.ToInt32(args[4]), Convert.ToInt32(args[5]), clientc.Player.Heading); + var jumpPosition = Position.Create(clientc.Player.CurrentRegionID, x: Convert.ToInt32(args[3]), y: Convert.ToInt32(args[4]), z: Convert.ToInt32(args[5]), clientc.Player.Orientation); + clientc.Player.MoveTo(jumpPosition); return; } return; @@ -318,7 +332,7 @@ public void OnCommand(GameClient client, string[] args) if (clientto.Player.CurrentHouse != null && clientto.Player.InHouse) clientto.Player.CurrentHouse.Enter(clientc.Player); else - clientc.Player.MoveTo(clientto.Player.CurrentRegionID, clientto.Player.Position, clientto.Player.Heading); + clientc.Player.MoveTo(clientto.Player.Position); return; } return; @@ -328,22 +342,22 @@ public void OnCommand(GameClient client, string[] args) #region push/pop else if (args.Length > 1 && args[1] == "push") { - Stack locations; + Stack positions; - locations = client.Player.TempProperties.getProperty(TEMP_KEY_JUMP, null) as Stack; + positions = client.Player.TempProperties.getProperty(TEMP_KEY_JUMP, null) as Stack; - if (locations == null) + if (positions == null) { - locations = new Stack(3); - client.Player.TempProperties.setProperty(TEMP_KEY_JUMP, locations); + positions = new Stack(3); + client.Player.TempProperties.setProperty(TEMP_KEY_JUMP, positions); } - locations.Push(new GameLocation("temploc", client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading)); + positions.Push(client.Player.Position); string message = LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.Jump.Pushed"); - if (locations.Count > 1) - message += " " + LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.Jump.PushedTotal", locations.Count); + if (positions.Count > 1) + message += " " + LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.Jump.PushedTotal", positions.Count); message += " - " + LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.Jump.PopInstructions"); @@ -351,23 +365,23 @@ public void OnCommand(GameClient client, string[] args) } else if (args.Length > 1 && args[1] == "pop") { - Stack locations; + Stack positions; - locations = client.Player.TempProperties.getProperty(TEMP_KEY_JUMP, null) as Stack; + positions = client.Player.TempProperties.getProperty(TEMP_KEY_JUMP, null) as Stack; - if (locations == null || locations.Count < 1) + if (positions == null || positions.Count < 1) { client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.Jump.NothingPushed"), eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } - GameLocation jumploc = locations.Pop(); + var jumploc = positions.Pop(); // slight abuse of the stack principle, but convenient to always have your last popped loc jumpable - if (locations.Count < 1) - locations.Push(jumploc); + if (positions.Count < 1) + positions.Push(jumploc); - client.Player.MoveTo(jumploc.RegionID, jumploc.Position, jumploc.Heading); + client.Player.MoveTo(jumploc); } #endregion push/pop #region DisplaySyntax diff --git a/GameServer/commands/gmcommands/keep.cs b/GameServer/commands/gmcommands/keep.cs index 095c3ba9..38d3692a 100644 --- a/GameServer/commands/gmcommands/keep.cs +++ b/GameServer/commands/gmcommands/keep.cs @@ -18,6 +18,7 @@ */ using System; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Keeps; using DOL.Language; @@ -93,7 +94,7 @@ public void OnCommand(GameClient client, string[] args) AbstractGameKeep myKeep = (AbstractGameKeep)client.Player.TempProperties.getProperty(TEMP_KEEP_LAST, null); if (myKeep == null) myKeep = (client.Player.TargetObject as GameKeepComponent)?.Keep; - if (myKeep == null) myKeep = GameServer.KeepManager.GetKeepCloseToSpot(client.Player.CurrentRegionID, client.Player.Position, 10000); + if (myKeep == null) myKeep = GameServer.KeepManager.GetKeepCloseToSpot(client.Player.Position, 10000); switch (args[1]) @@ -146,11 +147,7 @@ public void OnCommand(GameClient client, string[] args) keep.Level = (byte)ServerProperties.Properties.STARTING_KEEP_LEVEL; keep.BaseLevel = 50; keep.Realm = client.Player.Realm; - keep.Region = client.Player.CurrentRegionID; - keep.X = (int)client.Player.Position.X; - keep.Y = (int)client.Player.Position.Y; - keep.Z = (int)client.Player.Position.Z; - keep.Heading = client.Player.Heading; + keep.Position = client.Player.Position; if ((int)keepType < 8) { @@ -2044,11 +2041,7 @@ public void OnCommand(GameClient client, string[] args) keep.Name = keepName; keep.KeepID = keepid; keep.Level = 0; - keep.Region = client.Player.CurrentRegionID; - keep.X = (int)client.Player.Position.X; - keep.Y = (int)client.Player.Position.Y; - keep.Z = (int)client.Player.Position.Z; - keep.Heading = client.Player.Heading; + keep.SetPosition(client.Player.Position); keep.BaseLevel = baseLevel; GameServer.Database.AddObject(keep); @@ -2139,11 +2132,7 @@ public void OnCommand(GameClient client, string[] args) keep.Name = keepName; keep.KeepID = keepid; keep.Level = 0; - keep.Region = client.Player.CurrentRegionID; - keep.X = (int)client.Player.Position.X; - keep.Y = (int)client.Player.Position.Y; - keep.Z = (int)client.Player.Position.Z; - keep.Heading = client.Player.Heading; + keep.SetPosition(client.Player.Position); keep.BaseLevel = baselevel; GameServer.Database.AddObject(keep); @@ -2157,10 +2146,8 @@ public void OnCommand(GameClient client, string[] args) { (door as GameObject).RemoveFromWorld(); GameKeepDoor d = new GameKeepDoor(); - d.CurrentRegionID = (ushort)keep.Region; d.Name = door.Name; - d.Heading = (ushort)door.Heading; - d.Position = door.Position; + d.Position = Position.Create(keep.Region, door.Coordinate, door.Orientation); d.Level = 0; d.Model = 0xFFFF; d.DoorID = door.DoorID; @@ -2413,9 +2400,7 @@ public void OnCommand(GameClient client, string[] args) else { FrontiersPortalStone stone = new FrontiersPortalStone(); - stone.CurrentRegion = client.Player.CurrentRegion; stone.Position = client.Player.Position; - stone.Heading = client.Player.Heading; stone.SaveIntoDatabase(); stone.AddToWorld(); } @@ -2450,9 +2435,7 @@ public void OnCommand(GameClient client, string[] args) { GameKeepBanner banner = new GameKeepBanner(); banner.BannerType = bannerType; - banner.CurrentRegion = client.Player.CurrentRegion; banner.Position = client.Player.Position; - banner.Heading = client.Player.Heading; banner.SaveIntoDatabase(); foreach (AbstractArea area in banner.CurrentAreas) @@ -2491,10 +2474,7 @@ public void OnCommand(GameClient client, string[] args) if (args.Length < 3) { // simple move to player location - myKeep.X = (int)client.Player.Position.X; - myKeep.Y = (int)client.Player.Position.Y; - myKeep.Z = (int)client.Player.Position.Z; - myKeep.Heading = client.Player.Heading; + myKeep.Position = client.Player.Position; } else if (args.Length < 4) { @@ -2521,21 +2501,7 @@ public void OnCommand(GameClient client, string[] args) break; case "h": - - if (amount < 0 && myKeep.Heading - Math.Abs(amount) < 0) - { - int diff = myKeep.Heading - Math.Abs(amount); - myKeep.Heading = (ushort)(4095 + diff); - } - else - { - myKeep.Heading += (ushort)amount; - } - - if (myKeep.Heading > 4095) - { - myKeep.Heading = (ushort)(myKeep.Heading - 4095); - } + myKeep.Orientation += Angle.Heading((ushort)amount); break; diff --git a/GameServer/commands/gmcommands/keepguard.cs b/GameServer/commands/gmcommands/keepguard.cs index 787a42c1..5514c6c8 100644 --- a/GameServer/commands/gmcommands/keepguard.cs +++ b/GameServer/commands/gmcommands/keepguard.cs @@ -215,10 +215,7 @@ public void OnCommand(GameClient client, string[] args) } else { - guard.CurrentRegion = client.Player.CurrentRegion; guard.Position = client.Player.Position; - guard.Heading = client.Player.Heading; - guard.Realm = guard.CurrentZone.Realm; guard.LoadedFromScript = false; guard.SaveIntoDatabase(); @@ -342,7 +339,7 @@ public void OnCommand(GameClient client, string[] args) { RemoveAllTempPathObjects(client); - PathPoint startpoint = new PathPoint(client.Player.Position, 5000, ePathType.Once); + PathPoint startpoint = new PathPoint(client.Player.Coordinate, 5000, ePathType.Once); client.Player.TempProperties.setProperty(TEMP_PATH_FIRST, startpoint); client.Player.TempProperties.setProperty(TEMP_PATH_LAST, startpoint); client.Player.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "Commands.GM.KeepGuard.Path.CreationStarted"), eChatType.CT_System, eChatLoc.CL_SystemWindow); @@ -374,7 +371,7 @@ public void OnCommand(GameClient client, string[] args) } } - PathPoint newpp = new PathPoint(client.Player.Position, speedlimit, path.Type); + PathPoint newpp = new PathPoint(client.Player.Coordinate, speedlimit, path.Type); path.Next = newpp; newpp.Prev = path; client.Player.TempProperties.setProperty(TEMP_PATH_LAST, newpp); @@ -450,9 +447,7 @@ public void OnCommand(GameClient client, string[] args) private void CreateTempPathObject(GameClient client, PathPoint pp, string name) { GameStaticItem obj = new GameStaticItem(); - obj.Position = pp.Position; - obj.CurrentRegion = client.Player.CurrentRegion; - obj.Heading = client.Player.Heading; + obj.Position = client.Player.Position.With(coordinate: pp.Coordinate); obj.Name = name; obj.Model = 488; obj.Emblem = 0; diff --git a/GameServer/commands/gmcommands/merchant.cs b/GameServer/commands/gmcommands/merchant.cs index ed05a453..f27e9fcf 100644 --- a/GameServer/commands/gmcommands/merchant.cs +++ b/GameServer/commands/gmcommands/merchant.cs @@ -113,8 +113,6 @@ public void OnCommand(GameClient client, string[] args) } //Fill the object variables merchant.Position = client.Player.Position; - merchant.CurrentRegion = client.Player.CurrentRegion; - merchant.Heading = client.Player.Heading; merchant.Level = 1; merchant.Realm = client.Player.Realm; merchant.Name = LanguageMgr.GetTranslation(ServerProperties.Properties.SERV_LANGUAGE, "Commands.GM.Merchant.NewName"); @@ -440,8 +438,6 @@ public void OnCommand(GameClient client, string[] args) } //Fill the object variables merchant.Position = targetMerchant.Position; - merchant.CurrentRegion = targetMerchant.CurrentRegion; - merchant.Heading = targetMerchant.Heading; merchant.Level = targetMerchant.Level; merchant.Realm = targetMerchant.Realm; merchant.Name = targetMerchant.Name; diff --git a/GameServer/commands/gmcommands/mob.cs b/GameServer/commands/gmcommands/mob.cs index 2126cfdf..5f7fb3a4 100644 --- a/GameServer/commands/gmcommands/mob.cs +++ b/GameServer/commands/gmcommands/mob.cs @@ -20,7 +20,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Numerics; using System.Reflection; using DOL.AI; @@ -28,6 +27,7 @@ using DOL.Database; using DOL.GS; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.Housing; using DOL.GS.Movement; using DOL.GS.PacketHandler; @@ -370,8 +370,6 @@ private void create(GameClient client, string[] args) //Fill the object variables mob.Position = client.Player.Position; - mob.CurrentRegion = client.Player.CurrentRegion; - mob.Heading = client.Player.Heading; mob.Level = 1; mob.Realm = (eRealm)realm; mob.Name = "New Mob"; @@ -434,8 +432,6 @@ private void fastcreate(GameClient client, string[] args) //Fill the object variables mob.Position = client.Player.Position; - mob.CurrentRegion = client.Player.CurrentRegion; - mob.Heading = client.Player.Heading; mob.Level = level; mob.Realm = 0; mob.Name = name; @@ -509,11 +505,8 @@ private void nfastcreate(GameClient client, string[] args) GameNPC mob = new GameNPC(); //Fill the object variables - var x = Math.Abs(client.Player.Position.X + Util.Random(-radius, radius)); - var y = Math.Abs(client.Player.Position.Y + Util.Random(-radius, radius)); - mob.Position = new Vector3(x, y, client.Player.Position.Z); - mob.CurrentRegion = client.Player.CurrentRegion; - mob.Heading = client.Player.Heading; + var offset = Vector.Create(x: DOL.GS.Util.Random(-radius, radius),y: DOL.GS.Util.Random(-radius, radius)); + mob.Position = client.Player.Position + offset; mob.Level = level; mob.Realm = (eRealm)realm; mob.Name = name; @@ -567,11 +560,8 @@ private void nrandcreate(GameClient client, string[] args) GameNPC mob = new GameNPC(); //Fill the object variables - var x = Math.Abs(client.Player.Position.X + DOL.GS.Util.Random(-radius, radius)); - var y = Math.Abs(client.Player.Position.Y + DOL.GS.Util.Random(-radius, radius)); - mob.Position = new Vector3(x, y, client.Player.Position.Z); - mob.CurrentRegion = client.Player.CurrentRegion; - mob.Heading = client.Player.Heading; + var offset = Vector.Create(x: DOL.GS.Util.Random(-radius, radius),y: DOL.GS.Util.Random(-radius, radius)); + mob.Position = client.Player.Position + offset; mob.Level = (byte)Util.Random(10, 50); mob.Realm = (eRealm)Util.Random(1, 3); mob.Name = "rand_" + i; @@ -1057,20 +1047,16 @@ private void damagetype(GameClient client, GameNPC targetMob, string[] args) private void movehere(GameClient client, GameNPC targetMob, string[] args) { - targetMob.MoveTo(client.Player.CurrentRegionID, client.Player.Position, client.Player.Heading); + targetMob.MoveTo(client.Player.Position); targetMob.SaveIntoDatabase(); client.Out.SendMessage("Target Mob '" + targetMob.Name + "' moved to your location!", eChatType.CT_System, eChatLoc.CL_SystemWindow); } + private string PositionToText(Position pos) + => $"{pos.RegionID}, {pos.X}, {pos.Y}, {pos.Z}, {pos.Orientation.InHeading}"; private void location(GameClient client, GameNPC targetMob, string[] args) { - client.Out.SendMessage("\"" + targetMob.Name + "\", " + - targetMob.CurrentRegionID + ", " + - targetMob.Position.X.ToString("F0") + ", " + - targetMob.Position.Y.ToString("F0") + ", " + - targetMob.Position.Z.ToString("F0") + ", " + - targetMob.Heading, - eChatType.CT_System, eChatLoc.CL_SystemWindow); + client.Out.SendMessage("\"" + targetMob.Name + "\", " + PositionToText(targetMob.Position), eChatType.CT_System, eChatLoc.CL_SystemWindow); } private void remove(GameClient client, GameNPC targetMob, string[] args) @@ -1182,8 +1168,7 @@ private void fly(GameClient client, GameNPC targetMob, string[] args) targetMob.Flags ^= GameNPC.eFlags.FLYING; - if (targetMob.IsFlying) - targetMob.MoveTo(targetMob.CurrentRegionID, targetMob.Position + Vector3.UnitZ * height, targetMob.Heading); + if (targetMob.IsFlying) targetMob.MoveTo(targetMob.Position + Vector.Create(z: height)); targetMob.FlagsDb = (uint)targetMob.Flags; @@ -1368,7 +1353,7 @@ private void info(GameClient client, GameNPC targetMob, string[] args) hours = respawn.Hours + " hours "; info.Add(" + Respawn: " + days + hours + respawn.Minutes + " minutes " + respawn.Seconds + " seconds"); - info.Add(" + SpawnPoint: " + targetMob.SpawnPoint.X + " " + targetMob.SpawnPoint.Y + " " + targetMob.SpawnPoint.Z); + info.Add(" + SpawnPoint: " + targetMob.SpawnPosition.X + ", " + targetMob.SpawnPosition.Y + ", " + targetMob.SpawnPosition.Z); } info.Add(" "); @@ -1451,7 +1436,7 @@ private void info(GameClient client, GameNPC targetMob, string[] args) info.Add(" "); - info.Add(" + Position (X, Y, Z, H): " + targetMob.Position.ToString("F0") + ", " + targetMob.Heading); + info.Add(" + Position (X, Y, Z, H): " + targetMob.Position); if (targetMob.GuildName != null && targetMob.GuildName.Length > 0) info.Add(" + Guild: " + targetMob.GuildName); @@ -2446,8 +2431,6 @@ void setClass(GameClient client, GameNPC targetMob, string[] args) targetMob.StopCurrentSpellcast(); mob.Position = targetMob.Position; - mob.CurrentRegion = targetMob.CurrentRegion; - mob.Heading = targetMob.Heading; mob.Level = targetMob.Level; mob.Realm = targetMob.Realm; mob.Name = targetMob.Name; @@ -2610,8 +2593,6 @@ private void copy(GameClient client, GameNPC targetMob, string[] args, bool isTe //Fill the object variables mob.Position = client.Player.Position; - mob.CurrentRegion = client.Player.CurrentRegion; - mob.Heading = client.Player.Heading; mob.Level = targetMob.Level; mob.Realm = targetMob.Realm; mob.Name = targetMob.Name; diff --git a/GameServer/commands/gmcommands/npc.cs b/GameServer/commands/gmcommands/npc.cs index 21d1ed62..0e8d4000 100644 --- a/GameServer/commands/gmcommands/npc.cs +++ b/GameServer/commands/gmcommands/npc.cs @@ -18,6 +18,7 @@ * */ +using DOL.GS.Geometry; using System; using System.Reflection; using System.Collections; @@ -200,12 +201,12 @@ public void OnCommand(GameClient client, string[] args) speed = Convert.ToInt16(args[3]); } - var pos = Vector3.Zero; + var coordinate = Coordinate.Nowhere; switch (args[2].ToLower()) { case "me": { - pos = client.Player.Position; + coordinate = client.Player.Coordinate; break; } @@ -216,7 +217,7 @@ public void OnCommand(GameClient client, string[] args) { if (targetplayer.Name.ToLower() == args[2].ToLower()) { - pos = targetplayer.Position; + coordinate = targetplayer.Coordinate; break; } } @@ -225,7 +226,7 @@ public void OnCommand(GameClient client, string[] args) { if (target.Name.ToLower() == args[2].ToLower()) { - pos = target.Position; + coordinate = target.Coordinate; break; } } @@ -233,13 +234,13 @@ public void OnCommand(GameClient client, string[] args) } } - if (pos == Vector3.Zero) + if (coordinate == Coordinate.Nowhere) { client.Out.SendMessage("Can't find name " + args[2].ToLower() + " near your target.", eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } - npc.PathTo(pos, speed); + npc.PathTo(coordinate, speed); client.Out.SendMessage("Your target is walking to your location!", eChatType.CT_System, eChatLoc.CL_SystemWindow); break; } diff --git a/GameServer/commands/gmcommands/object.cs b/GameServer/commands/gmcommands/object.cs index 21ccbc26..67cddc3c 100644 --- a/GameServer/commands/gmcommands/object.cs +++ b/GameServer/commands/gmcommands/object.cs @@ -106,8 +106,6 @@ void setClass(GameClient client, GameStaticItem targetObj, string[] args) } obj.Position = client.Player.Position; - obj.CurrentRegion = client.Player.CurrentRegion; - obj.Heading = client.Player.Heading; obj.Level = targetObj.Level; obj.Name = targetObj.Name; obj.Model = targetObj.Model; @@ -186,7 +184,7 @@ public void OnCommand(GameClient client, string[] args) } info.Add(" "); - info.Add(" Location: " + targetObject.Position.ToString("F0")); + info.Add(" Coordinate: X= " + targetObject.Position.X + " ,Y= " + targetObject.Position.Y + " ,Z= " + targetObject.Position.Z); client.Out.SendCustomTextWindow("[ " + name + " ]", info); break; @@ -360,8 +358,6 @@ public void OnCommand(GameClient client, string[] args) return; } item.Position = client.Player.Position; - item.CurrentRegion = client.Player.CurrentRegion; - item.Heading = client.Player.Heading; item.Level = targetObject.Level; item.Name = targetObject.Name; item.Model = targetObject.Model; @@ -485,8 +481,6 @@ GameStaticItem CreateItem(GameClient client, string itemClassName) //Fill the object variables obj.LoadedFromScript = false; obj.Position = client.Player.Position; - obj.CurrentRegion = client.Player.CurrentRegion; - obj.Heading = client.Player.Heading; obj.Name = "New Object"; obj.Model = 100; obj.Emblem = 0; diff --git a/GameServer/commands/gmcommands/path.cs b/GameServer/commands/gmcommands/path.cs index d4b82911..29dcb1a7 100644 --- a/GameServer/commands/gmcommands/path.cs +++ b/GameServer/commands/gmcommands/path.cs @@ -19,8 +19,8 @@ using System; using System.Collections; using System.Linq; -using System.Numerics; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Movement; using DOL.GS.PacketHandler; @@ -52,9 +52,7 @@ private void CreateTempPathObject(GameClient client, PathPoint pp, String name) //Create a new object GameStaticItem obj = new GameStaticItem(); //Fill the object variables - obj.Position = pp.Position + Vector3.UnitZ; // raise a bit off of ground level - obj.CurrentRegion = client.Player.CurrentRegion; - obj.Heading = client.Player.Heading; + obj.Position = client.Player.Position.With(coordinate: pp.Coordinate + Vector.Create(z: 1)); // raise a bit off of ground level obj.Name = name; obj.Model = 488; obj.Emblem = 0; @@ -102,7 +100,7 @@ private void PathCreate(GameClient client) //Remove old temp objects RemoveAllTempPathObjects(client); - PathPoint startpoint = new PathPoint(client.Player.Position, 5000, ePathType.Once); + PathPoint startpoint = new PathPoint(client.Player.Coordinate, 5000, ePathType.Once); client.Player.TempProperties.setProperty(TEMP_PATH_FIRST, startpoint); client.Player.TempProperties.setProperty(TEMP_PATH_LAST, startpoint); client.Player.Out.SendMessage("Path creation started! You can add new pathpoints via /path add now!", eChatType.CT_System, eChatLoc.CL_SystemWindow); @@ -145,7 +143,7 @@ private void PathAdd(GameClient client, string[] args) } } - PathPoint newpp = new PathPoint(client.Player.Position, speedlimit, path.Type); + PathPoint newpp = new PathPoint(client.Player.Coordinate, speedlimit, path.Type); newpp.WaitTime = waittime * 10; path.Next = newpp; newpp.Prev = path; diff --git a/GameServer/commands/gmcommands/siegeweapon.cs b/GameServer/commands/gmcommands/siegeweapon.cs index bcf9f1f8..257d5cb7 100644 --- a/GameServer/commands/gmcommands/siegeweapon.cs +++ b/GameServer/commands/gmcommands/siegeweapon.cs @@ -43,7 +43,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeRam ram = new GameSiegeRam(); ram.Position = client.Player.Position; - ram.CurrentRegion = client.Player.CurrentRegion; ram.Model = 2605; ram.Level = 0; ram.Name = "mini ram"; @@ -55,7 +54,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeRam ram = new GameSiegeRam(); ram.Position = client.Player.Position; - ram.CurrentRegion = client.Player.CurrentRegion; ram.Model = 2600; ram.Level = 1; ram.Name = "light ram"; @@ -67,7 +65,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeRam ram = new GameSiegeRam(); ram.Position = client.Player.Position; - ram.CurrentRegion = client.Player.CurrentRegion; ram.Model = 2601; ram.Level = 2; ram.Name = "medium ram"; @@ -79,7 +76,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeRam ram = new GameSiegeRam(); ram.Position = client.Player.Position; - ram.CurrentRegion = client.Player.CurrentRegion; ram.Model = 2602; ram.Level = 3; ram.Name = "heavy ram"; @@ -91,7 +87,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeCatapult cat = new GameSiegeCatapult(); cat.Position = client.Player.Position; - cat.CurrentRegion = client.Player.CurrentRegion; cat.Model = 0xA26; cat.Level = 3; cat.Name = "catapult"; @@ -103,7 +98,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeBallista bal = new GameSiegeBallista(); bal.Position = client.Player.Position; - bal.CurrentRegion = client.Player.CurrentRegion; bal.Model = 0x0A55; bal.Level = 3; bal.Name = "field ballista"; @@ -115,7 +109,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeRam ram = new GameSiegeRam(); ram.Position = client.Player.Position; - ram.CurrentRegion = client.Player.CurrentRegion; ram.Model = 0xA2F; ram.Level = 3; ram.Name = "cauldron of boiling oil"; @@ -127,7 +120,6 @@ public void OnCommand(GameClient client, string[] args) { GameSiegeTrebuchet tre = new GameSiegeTrebuchet(); tre.Position = client.Player.Position; - tre.CurrentRegion = client.Player.CurrentRegion; tre.Model = 0xA2E; tre.Level = 3; tre.Name = "trebuchet"; diff --git a/GameServer/commands/gmcommands/tppoint.cs b/GameServer/commands/gmcommands/tppoint.cs index 21b30297..b1625790 100644 --- a/GameServer/commands/gmcommands/tppoint.cs +++ b/GameServer/commands/gmcommands/tppoint.cs @@ -19,6 +19,7 @@ using System; using System.Collections; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.Language; @@ -47,9 +48,7 @@ private void CreateTempTPPointObject(GameClient client, TPPoint pp, string name) GameStaticItem obj = new GameStaticItem(); // Fill the object variables - obj.Position = new System.Numerics.Vector3((float)pp.Position.X, (float)pp.Position.Y, (float)pp.Position.Z + 1);// raise a bit off of ground level - obj.CurrentRegion = client.Player.CurrentRegion; - obj.Heading = client.Player.Heading; + obj.Position = Position.Create(pp.Region, pp.Position.X, pp.Position.Y, pp.Position.Z + 1);// raise a bit off of ground level obj.Name = name; obj.Model = 488; obj.Emblem = 0; diff --git a/GameServer/commands/gmcommands/walk.cs b/GameServer/commands/gmcommands/walk.cs index b0ad51e9..a9f045aa 100644 --- a/GameServer/commands/gmcommands/walk.cs +++ b/GameServer/commands/gmcommands/walk.cs @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; -using System.Numerics; using DOL.GS.PacketHandler; namespace DOL.GS.Commands @@ -80,7 +80,8 @@ public void OnCommand(GameClient client, string[] args) return; } - targetNPC.PathTo(targetNPC.Position + new Vector3(xoff, yoff, zoff), speed); + var offset = Vector.Create(x: xoff, y: yoff, z: zoff); + targetNPC.WalkTo(targetNPC.Coordinate + offset, speed); } } } \ No newline at end of file diff --git a/GameServer/commands/gmcommands/xmob.cs b/GameServer/commands/gmcommands/xmob.cs index 2b007d23..aedff1bc 100644 --- a/GameServer/commands/gmcommands/xmob.cs +++ b/GameServer/commands/gmcommands/xmob.cs @@ -3,6 +3,7 @@ using System.Reflection; using DOL.AI; using DOL.AI.Brain; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; namespace DOL.GS.Commands @@ -232,14 +233,14 @@ public void OnCommand(GameClient client, string[] args) for (int i = 0; i < setupmobs.Count / 2; i++) { ushort h = (ushort)(4096 / (setupmobs.Count / 2) * i); - System.Numerics.Vector2 loc = client.Player.GetPointFromHeading(h, 150); + var loc = client.Player.Coordinate + Vector.Create(Angle.Heading(h), 150); spawnsetupmob(client, setupmobs[i], realm, (int)loc.X, (int)loc.Y, h); } for (int i = setupmobs.Count / 2; i < setupmobs.Count; i++) { ushort h = (ushort)(4096 / (setupmobs.Count - setupmobs.Count / 2) * i); - System.Numerics.Vector2 loc = client.Player.GetPointFromHeading(h, 250); + var loc = client.Player.Coordinate + Vector.Create(Angle.Heading(h), 250); spawnsetupmob(client, setupmobs[i], realm, (int)loc.X, (int)loc.Y, h); } client.Out.SendMessage(setupmobs.Count + " setup mob spawned!", eChatType.CT_Important, eChatLoc.CL_SystemWindow); @@ -295,9 +296,7 @@ public void OnCommand(GameClient client, string[] args) mob.LoadTemplate(targetMob.NPCTemplate); //Fill the object variables - mob.Position = new System.Numerics.Vector3(Util.Random((int)client.Player.Position.X - 250 / 2, (int)client.Player.Position.X + 250 / 2), Util.Random((int)client.Player.Position.Y - 250 / 2, (int)client.Player.Position.Y + 250 / 2), client.Player.Position.Z); - mob.CurrentRegion = client.Player.CurrentRegion; - mob.Heading = (ushort)Util.Random(1, 4100); + mob.Position = client.Player.Position.With(Angle.Heading(Util.Random(1, 4100))) + Vector.Create(Util.Random(-250, 250), Util.Random(-250, 250), Util.Random(-250, 250)); mob.Level = targetMob.Level; mob.Realm = targetMob.Realm; mob.Name = targetMob.Name; @@ -522,10 +521,8 @@ public void OnCommand(GameClient client, string[] args) private void spawnsetupmob(GameClient client, GameNPC mob, eRealm realm, int x, int y, ushort h) { //Fill the object variables - mob.Position = new System.Numerics.Vector3(x, y, client.Player.Position.Z); - mob.Heading = h; + mob.Position = client.Player.Position.With(null, x, y); - mob.CurrentRegion = client.Player.CurrentRegion; mob.Level = 50; if (mob is GameTrainingDummy) mob.Realm = eRealm.None; @@ -567,9 +564,7 @@ private void copy(GameClient client, GameNPC targetMob, ushort radius) mob.LoadTemplate(targetMob.NPCTemplate); //Fill the object variables - mob.Position = new System.Numerics.Vector3(Util.Random((int)client.Player.Position.X - radius, (int)client.Player.Position.X + radius), Util.Random((int)client.Player.Position.Y - radius, (int)client.Player.Position.Y + radius), client.Player.Position.Z); - mob.CurrentRegion = client.Player.CurrentRegion; - mob.Heading = (ushort)Util.Random(1, 4100); + mob.Position = client.Player.Position.With(Angle.Heading(Util.Random(1, 4100))) + Vector.Create(Util.Random(-250, 250), Util.Random(-250, 250), Util.Random(-250, 250)); mob.Level = targetMob.Level; mob.Realm = targetMob.Realm; mob.Name = targetMob.Name; @@ -655,10 +650,7 @@ private void remove(GameNPC targetMob) private void move(GameClient client, GameNPC targetMob, ushort radius) { - - int X = Util.Random((int)client.Player.Position.X - radius / 2, (int)client.Player.Position.X + radius / 2); - int Y = Util.Random((int)client.Player.Position.Y - radius / 2, (int)client.Player.Position.Y + radius / 2); - targetMob.MoveTo(client.Player.CurrentRegionID, X, Y, client.Player.Position.Z, (ushort)Util.Random(1, 4100)); + targetMob.MoveTo(client.Player.Position.With(Angle.Heading(Util.Random(1, 4100))) + Vector.Create(Util.Random(-radius, radius), Util.Random(-radius, radius), Util.Random(-radius, radius))); targetMob.SaveIntoDatabase(); } diff --git a/GameServer/commands/gmcommands/zone.cs b/GameServer/commands/gmcommands/zone.cs index a6c29160..6c0526e3 100644 --- a/GameServer/commands/gmcommands/zone.cs +++ b/GameServer/commands/gmcommands/zone.cs @@ -23,7 +23,7 @@ using DOL.GS; using DOL.GS.PacketHandler; using DOL.Database; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS.Commands { @@ -60,8 +60,8 @@ public void OnCommand(GameClient client, string[] args) info.Add(" Zone ID: " + client.Player.CurrentZone.ID); info.Add(" Zone IsDungeon: " + client.Player.CurrentZone.IsDungeon); info.Add(" Zone SkinID: " + client.Player.CurrentZone.ZoneSkinID); - info.Add(" Zone X: " + client.Player.CurrentZone.XOffset); - info.Add(" Zone Y: " + client.Player.CurrentZone.YOffset); + info.Add(" Zone X: " + client.Player.CurrentZone.Offset.X); + info.Add(" Zone Y: " + client.Player.CurrentZone.Offset.Y); info.Add(" Zone Width: " + client.Player.CurrentZone.Width); info.Add(" Zone Height: " + client.Player.CurrentZone.Height); info.Add(" Zone DivingEnabled: " + client.Player.CurrentZone.IsDivingEnabled); @@ -132,8 +132,8 @@ public void OnCommand(GameClient client, string[] args) // Update water level and diving flag for the new zone client.Out.SendPlayerPositionAndObjectID(); - - client.Player.MoveTo(client.Player.CurrentRegionID, client.Player.Position + Vector3.UnitZ, client.Player.Heading); + + client.Player.MoveTo(client.Player.Position + Vector.Create(z: 1)); DisplayMessage(client, string.Format("Waterlevel for {0}:{1} changed to {2}.", zone.ID, zone.Description, waterlevel)); return; diff --git a/GameServer/commands/playercommands/Boat.cs b/GameServer/commands/playercommands/Boat.cs index 552b0b01..8f19de1e 100644 --- a/GameServer/commands/playercommands/Boat.cs +++ b/GameServer/commands/playercommands/Boat.cs @@ -64,9 +64,7 @@ public void OnCommand(GameClient client, string[] args) playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Scout_Boat", client.Player.Name); playerBoat.Position = client.Player.Position; playerBoat.Model = 2648; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; - playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; playerBoat.MaxSpeedBase = 500; client.Player.Inventory.RemoveItem(item); @@ -94,9 +92,7 @@ public void OnCommand(GameClient client, string[] args) playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Warship", client.Player.Name); playerBoat.Position = client.Player.Position; playerBoat.Model = 2647; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; - playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; playerBoat.MaxSpeedBase = 400; client.Player.Inventory.RemoveItem(item); @@ -122,9 +118,7 @@ public void OnCommand(GameClient client, string[] args) InventoryItem item = client.Player.Inventory.GetFirstItemByID("galleon", eInventorySlot.Min_Inv, eInventorySlot.Max_Inv); playerBoat.BoatID = System.Guid.NewGuid().ToString(); playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Galleon", client.Player.Name); - playerBoat.Position = client.Player.Position; playerBoat.Model = 2646; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; @@ -152,9 +146,7 @@ public void OnCommand(GameClient client, string[] args) InventoryItem item = client.Player.Inventory.GetFirstItemByID("skiff", eInventorySlot.Min_Inv, eInventorySlot.Max_Inv); playerBoat.BoatID = System.Guid.NewGuid().ToString(); playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Skiff", client.Player.Name); - playerBoat.Position = client.Player.Position; playerBoat.Model = 1616; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; @@ -182,9 +174,7 @@ public void OnCommand(GameClient client, string[] args) InventoryItem item = client.Player.Inventory.GetFirstItemByID("Viking_Longship", eInventorySlot.Min_Inv, eInventorySlot.Max_Inv); playerBoat.BoatID = System.Guid.NewGuid().ToString(); playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Viking_Longship", client.Player.Name); - playerBoat.Position = client.Player.Position; playerBoat.Model = 1615; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; @@ -212,9 +202,7 @@ public void OnCommand(GameClient client, string[] args) InventoryItem item = client.Player.Inventory.GetFirstItemByID("ps_longship", eInventorySlot.Min_Inv, eInventorySlot.Max_Inv); playerBoat.BoatID = System.Guid.NewGuid().ToString(); playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Longship", client.Player.Name); - playerBoat.Position = client.Player.Position; playerBoat.Model = 1595; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; @@ -242,9 +230,7 @@ public void OnCommand(GameClient client, string[] args) InventoryItem item = client.Player.Inventory.GetFirstItemByID("stygian_ship", eInventorySlot.Min_Inv, eInventorySlot.Max_Inv); playerBoat.BoatID = System.Guid.NewGuid().ToString(); playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Stygian_Ship", client.Player.Name); - playerBoat.Position = client.Player.Position; playerBoat.Model = 1612; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; @@ -272,9 +258,7 @@ public void OnCommand(GameClient client, string[] args) InventoryItem item = client.Player.Inventory.GetFirstItemByID("atlantean_ship", eInventorySlot.Min_Inv, eInventorySlot.Max_Inv); playerBoat.BoatID = System.Guid.NewGuid().ToString(); playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.Atlantean_Ship", client.Player.Name); - playerBoat.Position = client.Player.Position; playerBoat.Model = 1613; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; @@ -302,9 +286,7 @@ public void OnCommand(GameClient client, string[] args) InventoryItem item = client.Player.Inventory.GetFirstItemByID("British_Cog", eInventorySlot.Min_Inv, eInventorySlot.Max_Inv); playerBoat.BoatID = System.Guid.NewGuid().ToString(); playerBoat.Name = LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Boat.Name.British_Cog", client.Player.Name); - playerBoat.Position = client.Player.Position; playerBoat.Model = 1614; - playerBoat.Heading = client.Player.Heading; playerBoat.Realm = client.Player.Realm; playerBoat.CurrentRegionID = client.Player.CurrentRegionID; playerBoat.OwnerID = client.Player.InternalID; @@ -344,9 +326,7 @@ public void OnCommand(GameClient client, string[] args) } curBoat.Position = client.Player.Position; - curBoat.Heading = client.Player.Heading; curBoat.Realm = client.Player.Realm; - curBoat.CurrentRegionID = client.Player.CurrentRegionID; curBoat.Riders = new GamePlayer[32]; BlankBrain brain = new BlankBrain(); curBoat.SetOwnBrain(brain); diff --git a/GameServer/commands/playercommands/GroundAssist.cs b/GameServer/commands/playercommands/GroundAssist.cs index 0397d80a..ab9343b0 100644 --- a/GameServer/commands/playercommands/GroundAssist.cs +++ b/GameServer/commands/playercommands/GroundAssist.cs @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using DOL.GS.PacketHandler; -using System.Numerics; using DOL.Language; namespace DOL.GS.Commands @@ -87,21 +87,13 @@ public void OnCommand(GameClient client, string[] args) return; } - if (target.GroundTarget == null || (target.GroundTarget.Value == Vector3.Zero)) + if (target.GroundTargetPosition == Position.Nowhere) { - client.Out.SendMessage( - LanguageMgr.GetTranslation( - client.Account.Language, - "Commands.Players.Groundassist.NoTarget", - target.Name - ), - eChatType.CT_System, - eChatLoc.CL_SystemWindow - ); + client.Out.SendMessage(LanguageMgr.GetTranslation(client, "Scripts.Players.Groundassist.NoTarget", target.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } - client.Player.Out.SendChangeGroundTarget(target.GroundTarget.Value); - client.Player.GroundTarget = target.GroundTarget; + client.Player.Out.SendChangeGroundTarget(target.GroundTargetPosition.Coordinate); + client.Player.GroundTargetPosition = target.GroundTargetPosition; } } } \ No newline at end of file diff --git a/GameServer/commands/playercommands/facegloc.cs b/GameServer/commands/playercommands/facegloc.cs index dacc07a4..6522c7f2 100644 --- a/GameServer/commands/playercommands/facegloc.cs +++ b/GameServer/commands/playercommands/facegloc.cs @@ -23,6 +23,7 @@ * Desc: Implements /facegloc command * */ +using DOL.GS.Geometry; using System; using System.Numerics; using DOL.GS.PacketHandler; @@ -74,8 +75,7 @@ public void OnCommand(GameClient client, string[] args) return; } - ushort direction = client.Player.GetHeading(new Vector2(x, y)); - client.Player.Heading = direction; + client.Player.TurnTo(Coordinate.Create(x: x, y: y )); client.Out.SendPlayerJump(true); } } diff --git a/GameServer/commands/playercommands/faceloc.cs b/GameServer/commands/playercommands/faceloc.cs index 4bf95f85..c7144284 100644 --- a/GameServer/commands/playercommands/faceloc.cs +++ b/GameServer/commands/playercommands/faceloc.cs @@ -23,6 +23,7 @@ * Desc: Implements /faceloc command * */ +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using System.Numerics; using DOL.Language; @@ -84,11 +85,10 @@ public void OnCommand(GameClient client, string[] args) ); return; } - int Xoffset = client.Player.CurrentZone.XOffset; - int Yoffset = client.Player.CurrentZone.YOffset; - Vector2 gloc = new Vector2(Xoffset + x, Yoffset + y); - ushort direction = client.Player.GetHeading(gloc); - client.Player.Heading = direction; + int xOffset = client.Player.CurrentZone.Offset.X; + int yOffset = client.Player.CurrentZone.Offset.Y; + var gloc = Coordinate.Create(x: x + xOffset, y: y + yOffset ); + client.Player.TurnTo(gloc); client.Out.SendPlayerJump(true); } } diff --git a/GameServer/commands/playercommands/gtrange.cs b/GameServer/commands/playercommands/gtrange.cs index 2bc1c8c1..0e62555d 100644 --- a/GameServer/commands/playercommands/gtrange.cs +++ b/GameServer/commands/playercommands/gtrange.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System.Numerics; using DOL.GS.PacketHandler; using DOL.Language; @@ -34,9 +35,9 @@ public void OnCommand(GameClient client, string[] args) if (IsSpammingCommand(client.Player, "gtrange")) return; - if (client.Player.GroundTarget != null) + if (client.Player.GroundTargetPosition != Position.Nowhere) { - var range = (int)Vector3.Distance(client.Player.Position, client.Player.GroundTarget.Value); + var range = (int)client.Player.Coordinate.DistanceTo(client.Player.GroundTargetPosition); client.Out.SendMessage( LanguageMgr.GetTranslation( client.Account.Language, diff --git a/GameServer/commands/playercommands/guild.cs b/GameServer/commands/playercommands/guild.cs index bcc4df50..bd5cd2ca 100644 --- a/GameServer/commands/playercommands/guild.cs +++ b/GameServer/commands/playercommands/guild.cs @@ -1842,7 +1842,7 @@ double GetBuffBonusPercentage(Guild guild) return; } - if (territory.PortalPosition == null) + if (territory.PortalCoordinate == null) { client.SendTranslation("Commands.Players.Guild.TerritoryPortal.NotSupported"); return; @@ -2054,7 +2054,7 @@ double GetBuffBonusPercentage(Guild guild) return; } - if (!target.MoveTo(player.CurrentRegionID, player.Position, player.Heading)) + if (!target.MoveTo(player.Position)) { player.SendTranslatedMessage("Commands.Players.Guild.MoveDefender.BadPosition", eChatType.CT_System, eChatLoc.CL_SystemWindow); } @@ -2135,7 +2135,7 @@ double GetBuffBonusPercentage(Guild guild) if (Properties.GUILD_COMBAT_ZONE_DISTANCE_FROM_AREAS > 0) { - AbstractArea closeArea = (AbstractArea)region.FindAnyAreaInRadius(player.Position, Properties.GUILD_COMBAT_ZONE_DISTANCE_FROM_AREAS, true); + AbstractArea closeArea = (AbstractArea)region.FindAnyAreaInRadius(player.Coordinate, Properties.GUILD_COMBAT_ZONE_DISTANCE_FROM_AREAS, true); if (closeArea != null) { client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Guild.CombatZone.TooCloseToArea", closeArea.GetDescriptionForPlayer(player)), eChatType.CT_System, eChatLoc.CL_SystemWindow); @@ -3323,7 +3323,7 @@ double GetBuffBonusPercentage(Guild guild) client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Guild.NotMember"), eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(client.Player.CurrentRegionID, client.Player.Position, WorldMgr.VISIBILITY_DISTANCE); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(client.Player.Position, WorldMgr.VISIBILITY_DISTANCE); if (keep == null) { client.Out.SendMessage(LanguageMgr.GetTranslation(client.Account.Language, "Commands.Players.Guild.ClaimNotNear"), eChatType.CT_System, eChatLoc.CL_SystemWindow); diff --git a/GameServer/commands/playercommands/house.cs b/GameServer/commands/playercommands/house.cs index 2c32b361..ed7b29ab 100644 --- a/GameServer/commands/playercommands/house.cs +++ b/GameServer/commands/playercommands/house.cs @@ -149,7 +149,7 @@ public void HouseAdmin(GamePlayer player, string[] args) } } - ArrayList houses = (ArrayList)HouseMgr.GetHousesCloseToSpot(player.CurrentRegionID, (int)player.Position.X, (int)player.Position.Y, 700); + ArrayList houses = (ArrayList)HouseMgr.GetHousesCloseToSpot(player.Position, 700); if (houses.Count != 1) { DisplayMessage(player.Client, LanguageMgr.GetTranslation(player.Client, "Commands.Players.House.FarAway")); diff --git a/GameServer/commands/playercommands/houseface.cs b/GameServer/commands/playercommands/houseface.cs index fa9a1b93..2b8d12ef 100644 --- a/GameServer/commands/playercommands/houseface.cs +++ b/GameServer/commands/playercommands/houseface.cs @@ -36,8 +36,7 @@ public void OnCommand(GameClient client, string[] args) House house = HouseMgr.GetHouse(housenumber); - ushort direction = client.Player.GetHeading(house.Position); - client.Player.Heading = direction; + client.Player.TurnTo(house.Position.Coordinate); client.Out.SendPlayerJump(true); DisplayMessage(client, LanguageMgr.GetTranslation(client, "Commands.Players.Houseface.Faced", housenumber)); } diff --git a/GameServer/commands/playercommands/knock.cs b/GameServer/commands/playercommands/knock.cs index 9064463d..6ec97a2f 100644 --- a/GameServer/commands/playercommands/knock.cs +++ b/GameServer/commands/playercommands/knock.cs @@ -53,7 +53,7 @@ public void OnCommand(GameClient client, string[] args) } bool done = false; - foreach (House house in HouseMgr.GetHousesCloseToSpot(client.Player.CurrentRegionID, (int)client.Player.Position.X, (int)client.Player.Position.Y, 650)) + foreach (House house in HouseMgr.GetHousesCloseToSpot(client.Player.Position, 650)) { client.Player.Emote(eEmote.Knock); foreach (GamePlayer player in house.GetAllPlayersInHouse()) diff --git a/GameServer/commands/playercommands/range.cs b/GameServer/commands/playercommands/range.cs index 12844c36..461403bd 100644 --- a/GameServer/commands/playercommands/range.cs +++ b/GameServer/commands/playercommands/range.cs @@ -42,7 +42,7 @@ public void OnCommand(GameClient client, string[] args) "Commands.Players.Range.NeedTarget")); else if (living == null || (living != null && client.Account.PrivLevel > 1)) { - var range = client.Player.GetDistanceTo(client.Player.TargetObject.Position); + var range = client.Player.GetDistanceTo(client.Player.TargetObject); DisplayMessage( client, LanguageMgr.GetTranslation( diff --git a/GameServer/commands/playercommands/where.cs b/GameServer/commands/playercommands/where.cs index ea8f2be9..6be47f8c 100644 --- a/GameServer/commands/playercommands/where.cs +++ b/GameServer/commands/playercommands/where.cs @@ -55,8 +55,8 @@ public void OnCommand(GameClient client, string[] args) return; } GameNPC npc = npcs[0]; - ushort heading = targetnpc.GetHeading(npc); - string directionstring = GetDirectionFromHeading(heading); + var orientation = targetnpc.Coordinate.GetOrientationTo(npc.Coordinate); + string directionstring = LanguageMgr.GetCardinalDirection(client.Account.Language, orientation); directionstring = LanguageMgr.GetTranslation( client.Account.Language, "Commands.Players.Where." + directionstring); @@ -162,28 +162,5 @@ public bool CheckTargetIsGuard(GameLiving target) } return false; } - - public string GetDirectionFromHeading(ushort heading) - { - if (heading < 0) - heading += 4096; - if (heading >= 3840 || heading <= 256) - return "South"; - else if (heading > 256 && heading < 768) - return "South West"; - else if (heading >= 768 && heading <= 1280) - return "West"; - else if (heading > 1280 && heading < 1792) - return "North West"; - else if (heading >= 1792 && heading <= 2304) - return "North"; - else if (heading > 2304 && heading < 2816) - return "North East"; - else if (heading >= 2816 && heading <= 3328) - return "East"; - else if (heading > 3328 && heading < 3840) - return "South East"; - return ""; - } } } \ No newline at end of file diff --git a/GameServer/commands/playercommands/yell.cs b/GameServer/commands/playercommands/yell.cs index 920c8d3d..78da05c0 100644 --- a/GameServer/commands/playercommands/yell.cs +++ b/GameServer/commands/playercommands/yell.cs @@ -58,28 +58,14 @@ public void OnCommand(GameClient client, string[] args) { if (player != client.Player) { - ushort headingtotarget = player.GetHeading(client.Player); - if (headingtotarget < 0) - headingtotarget += 4096; + var directionToTarget = player.Coordinate.GetOrientationTo(client.Player.Coordinate); + var cardinalDirection = LanguageMgr.GetCardinalDirection(player.Client.Account.Language, directionToTarget); - string direction = ""; - if (headingtotarget >= 3840 || headingtotarget <= 256) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.South"); - else if (headingtotarget > 256 && headingtotarget <= 768) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.SouthWest"); - else if (headingtotarget > 768 && headingtotarget <= 1280) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.West"); - else if (headingtotarget > 1280 && headingtotarget <= 1792) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.NorthWest"); - else if (headingtotarget > 1792 && headingtotarget <= 2304) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.North"); - else if (headingtotarget > 2304 && headingtotarget <= 2816) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.NorthEast"); - else if (headingtotarget > 2816 && headingtotarget <= 3328) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.East"); - else if (headingtotarget > 3328 && headingtotarget <= 3840) direction = LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Yell.SouthEast"); - - direction = LanguageMgr.GetTranslation( - client.Account.Language, - "Commands.Players.Yell." + direction); player.Out.SendMessage( LanguageMgr.GetTranslation( player.Client.Account.Language, "Commands.Players.Yell.From", - player.GetPersonalizedName(client.Player), direction), + player.GetPersonalizedName(client.Player), cardinalDirection), eChatType.CT_Help, eChatLoc.CL_SystemWindow); } else diff --git a/GameServer/craft/SiegeCrafting.cs b/GameServer/craft/SiegeCrafting.cs index 627e18dd..4af87e35 100644 --- a/GameServer/craft/SiegeCrafting.cs +++ b/GameServer/craft/SiegeCrafting.cs @@ -100,8 +100,6 @@ public override void BuildCraftedItem(GamePlayer player, Recipe recipe) siegeweapon.ItemId = product.Id_nb; siegeweapon.LoadFromDatabase(product); - siegeweapon.CurrentRegion = player.CurrentRegion; - siegeweapon.Heading = player.Heading; siegeweapon.Position = player.Position; siegeweapon.Realm = player.Realm; siegeweapon.AddToWorld(); diff --git a/GameServer/database/converters/Version002.cs b/GameServer/database/converters/Version002.cs index 3a0dd690..94a7740e 100644 --- a/GameServer/database/converters/Version002.cs +++ b/GameServer/database/converters/Version002.cs @@ -19,6 +19,7 @@ using System; using log4net; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.DatabaseConverters { @@ -63,7 +64,7 @@ public void ConvertDatabase() Region region = WorldMgr.GetRegion(mob.Region); if (region != null) { - Zone zone = region.GetZone(mob.X, mob.Y); + Zone zone = region.GetZone(mob.GetPosition().Coordinate); if (zone != null) { mob.Realm = (byte)zone.Realm; diff --git a/GameServer/events/gameobjects/WalkToEventArgs.cs b/GameServer/events/gameobjects/WalkToEventArgs.cs index ea07b547..e96efc39 100644 --- a/GameServer/events/gameobjects/WalkToEventArgs.cs +++ b/GameServer/events/gameobjects/WalkToEventArgs.cs @@ -19,6 +19,7 @@ using System; using System.Numerics; using DOL.GS; +using DOL.GS.Geometry; namespace DOL.Events { @@ -27,7 +28,7 @@ namespace DOL.Events /// public class WalkToEventArgs : EventArgs { - public WalkToEventArgs(Vector3 target, int speed) + public WalkToEventArgs(Coordinate target, int speed) { Target = target; Speed = speed; @@ -36,7 +37,7 @@ public WalkToEventArgs(Vector3 target, int speed) /// /// The spot to walk to. /// - public Vector3 Target { get; private set; } + public Coordinate Target { get; private set; } /// /// The speed to walk at. diff --git a/GameServer/gameobjects/Animist/TurretPet.cs b/GameServer/gameobjects/Animist/TurretPet.cs index 14454c77..cc16ed1c 100644 --- a/GameServer/gameobjects/Animist/TurretPet.cs +++ b/GameServer/gameobjects/Animist/TurretPet.cs @@ -74,9 +74,9 @@ public override void StartAttack(GameObject attackTarget) TargetObject = attackTarget; if (TargetObject.Realm == 0 || Realm == 0) - m_lastAttackTickPvE = m_CurrentRegion.Time; + m_lastAttackTickPvE = CurrentRegion.Time; else - m_lastAttackTickPvP = m_CurrentRegion.Time; + m_lastAttackTickPvP = CurrentRegion.Time; if (m_attackers.Count == 0) { diff --git a/GameServer/gameobjects/CustomNPC/ConsignmentMerchant.cs b/GameServer/gameobjects/CustomNPC/ConsignmentMerchant.cs index d0be446f..843faf78 100644 --- a/GameServer/gameobjects/CustomNPC/ConsignmentMerchant.cs +++ b/GameServer/gameobjects/CustomNPC/ConsignmentMerchant.cs @@ -22,6 +22,7 @@ using System.Reflection; using DOL.Database; using DOL.GS.Finance; +using DOL.GS.Geometry; using DOL.GS.Housing; using DOL.GS.PacketHandler; using DOL.GS.PacketHandler.Client.v168; @@ -89,47 +90,45 @@ public bool IsVaultInventorySlot(ushort clientSlot) #region Token return - private static readonly Dictionary _itemXdestination = - new Dictionary + private static readonly Dictionary _itemXdestination = + new Dictionary { // Item Id_nb, new Tuple<>(Region, X, Y, Z, Heading) // ALBION - {"entrancehousingalb", new GameLocation("", 2, 584832, 561279, 3576, 2144)}, - {"marketcaerwent", new GameLocation("", 2, 557035, 560048, 3624, 1641)}, - {"marketrilan", new GameLocation("", 2, 559906, 491141, 3392, 1829)}, - {"marketbrisworthy", new GameLocation("", 2, 489474, 489323, 3600, 3633)}, - {"marketstoneleigh", new GameLocation("", 2, 428964, 490962, 3624, 1806)}, - {"marketchiltern", new GameLocation("", 2, 428128, 557606, 3624, 3888)}, - {"marketsherborne", new GameLocation("", 2, 428840, 622221, 3248, 1813)}, - {"marketaylesbury", new GameLocation("", 2, 492794, 621373, 3624, 1643)}, - {"marketoldsarum", new GameLocation("", 2, 560030, 622022, 3624, 1819)}, - {"marketdalton", new GameLocation("", 2, 489334, 559242, 3720, 1821)}, - + {"entrancehousingalb", Position.Create(regionID: 2, x: 584832, y: 561279, z: 3576, heading: 2144)}, + {"marketcaerwent", Position.Create(regionID: 2, x: 557035, y: 560048, z: 3624, heading: 1641)}, + {"marketrilan", Position.Create(regionID: 2, x: 559906, y: 491141, z: 3392, heading: 1829)}, + {"marketbrisworthy", Position.Create(regionID: 2, x: 489474, y: 489323, z: 3600, heading: 3633)}, + {"marketstoneleigh", Position.Create(regionID: 2, x: 428964, y: 490962, z: 3624, heading: 1806)}, + {"marketchiltern", Position.Create(regionID: 2, x: 428128, y: 557606, z: 3624, heading: 3888)}, + {"marketsherborne", Position.Create(regionID: 2, x: 428840, y: 622221, z: 3248, heading: 1813)}, + {"marketaylesbury", Position.Create(regionID: 2, x: 492794, y: 621373, z: 3624, heading: 1643)}, + {"marketoldsarum", Position.Create(regionID: 2, x: 560030, y: 622022, z: 3624, heading: 1819)}, + {"marketdalton", Position.Create(regionID: 2, x: 489334, y: 559242, z: 3720, heading: 1821)}, // MIDGARD - {"entrancehousingmid", new GameLocation("", 102, 526881, 561661, 3633, 80)}, - {"marketerikstaad", new GameLocation("", 102, 554099, 565239, 3624, 504)}, - {"marketarothi", new GameLocation("", 102, 558093, 485250, 3488, 1231)}, - {"marketkaupang", new GameLocation("", 102, 625574, 483303, 3592, 2547)}, - {"marketstavgaard", new GameLocation("", 102, 686901, 490396, 3744, 332)}, - {"marketcarlingford", new GameLocation("", 102, 625056, 557887, 3696, 1366)}, - {"marketholmestrand", new GameLocation("", 102, 686903, 556050, 3712, 313)}, - {"marketnittedal", new GameLocation("", 102, 689199, 616329, 3488, 1252)}, - {"marketfrisia", new GameLocation("", 102, 622620, 615491, 3704, 804)}, - {"marketwyndham", new GameLocation("", 102, 555839, 621432, 3744, 314)}, - + {"entrancehousingmid", Position.Create(regionID: 102, x: 526881, y: 561661, z: 3633, heading: 80)}, + {"marketerikstaad", Position.Create(regionID: 102, x: 554099, y: 565239, z: 3624, heading: 504)}, + {"marketarothi", Position.Create(regionID: 102, x: 558093, y: 485250, z: 3488, heading: 1231)}, + {"marketkaupang", Position.Create(regionID: 102, x: 625574, y: 483303, z: 3592, heading: 2547)}, + {"marketstavgaard", Position.Create(regionID: 102, x: 686901, y: 490396, z: 3744, heading: 332)}, + {"marketcarlingford", Position.Create(regionID: 102, x: 625056, y: 557887, z: 3696, heading: 1366)}, + {"marketholmestrand", Position.Create(regionID: 102, x: 686903, y: 556050, z: 3712, heading: 313)}, + {"marketnittedal", Position.Create(regionID: 102, x: 689199, y: 616329, z: 3488, heading: 1252)}, + {"marketfrisia", Position.Create(regionID: 102, x: 622620, y: 615491, z: 3704, heading: 804)}, + {"marketwyndham", Position.Create(regionID: 102, x: 555839, y: 621432, z: 3744, heading: 314)}, // HIBERNIA - {"entrancehousinghib", new GameLocation("", 202, 555246, 526470, 3008, 1055)}, - {"marketmeath", new GameLocation("", 202, 564448, 559995, 3008, 1024)}, - {"marketkilcullen", new GameLocation("", 202, 618653, 561227, 3032, 3087)}, - {"marketaberillan", new GameLocation("", 202, 615145, 619457, 3008, 3064)}, - {"markettorrylin", new GameLocation("", 202, 566890, 620027, 3008, 1500)}, - {"markettullamore", new GameLocation("", 202, 560999, 692301, 3032, 1030)}, - {"marketbroughshane", new GameLocation("", 202, 618653, 692296, 3032, 3090)}, - {"marketmoycullen", new GameLocation("", 202, 495552, 686733, 2960, 1077)}, - {"marketsaeranthal", new GameLocation("", 202, 493148, 620361, 2952, 2471)}, - {"marketdunshire", new GameLocation("", 202, 495494, 555646, 2960, 1057)}, + {"entrancehousinghib", Position.Create(regionID: 202, x: 555246, y: 526470, z: 3008, heading: 1055)}, + {"marketmeath", Position.Create(regionID: 202, x: 564448, y: 559995, z: 3008, heading: 1024)}, + {"marketkilcullen", Position.Create(regionID: 202, x: 618653, y: 561227, z: 3032, heading: 3087)}, + {"marketaberillan", Position.Create(regionID: 202, x: 615145, y: 619457, z: 3008, heading: 3064)}, + {"markettorrylin", Position.Create(regionID: 202, x: 566890, y: 620027, z: 3008, heading: 1500)}, + {"markettullamore", Position.Create(regionID: 202, x: 560999, y: 692301, z: 3032, heading: 1030)}, + {"marketbroughshane", Position.Create(regionID: 202, x: 618653, y: 692296, z: 3032, heading: 3090)}, + {"marketmoycullen", Position.Create(regionID: 202, x: 495552, y: 686733, z: 2960, heading: 1077)}, + {"marketsaeranthal", Position.Create(regionID: 202, x: 493148, y: 620361, z: 2952, heading: 2471)}, + {"marketdunshire", Position.Create(regionID: 202, x: 495494, y: 555646, z: 2960, heading: 1057)}, }; - + public override bool ReceiveItem(GameLiving source, InventoryItem item) { GamePlayer player = source as GamePlayer; @@ -145,8 +144,7 @@ public override bool ReceiveItem(GameLiving source, InventoryItem item) if (item != null) { - GameLocation destination; - if (_itemXdestination.TryGetValue(item.Id_nb, out destination)) + if (_itemXdestination.TryGetValue(item.Id_nb, out Position destination)) { player.MoveTo(destination); player.Inventory.RemoveItem(item); diff --git a/GameServer/gameobjects/CustomNPC/GameBoatStableMaster.cs b/GameServer/gameobjects/CustomNPC/GameBoatStableMaster.cs index 3df0dfe7..b5674711 100644 --- a/GameServer/gameobjects/CustomNPC/GameBoatStableMaster.cs +++ b/GameServer/gameobjects/CustomNPC/GameBoatStableMaster.cs @@ -26,6 +26,7 @@ using DOL.GS.PacketHandler; using log4net; using DOL.GS.Finance; +using DOL.GS.Geometry; namespace DOL.GS { @@ -137,7 +138,7 @@ public override bool ReceiveItem(GameLiving source, InventoryItem item) String destination = item.Name.Substring(LanguageMgr.GetTranslation(ServerProperties.Properties.DB_LANGUAGE, "GameStableMaster.ReceiveItem.TicketTo").Length); PathPoint path = MovementMgr.LoadPath(item.Id_nb); //PathPoint path = MovementMgr.Instance.LoadPath(this.Name + "=>" + destination); - if ((path != null) && IsWithinRadius2D(path.Position, 500)) + if ((path != null) && ((Math.Abs(path.Coordinate.X - Coordinate.X)) < 500) && ((Math.Abs(path.Coordinate.Y - Coordinate.Y)) < 500)) { player.Inventory.RemoveCountFromStack(item, 1); InventoryLogging.LogInventoryAction(player, this, eInventoryActionType.Merchant, item, 1); @@ -145,9 +146,7 @@ public override bool ReceiveItem(GameLiving source, InventoryItem item) GameTaxiBoat boat = new GameTaxiBoat(); boat.Name = "Boat to " + destination; boat.Realm = source.Realm; - boat.Position = path.Position; - boat.CurrentRegion = CurrentRegion; - boat.Heading = GameMath.GetHeading(path.Position, path.Next.Position); + boat.Position = Position.Create(CurrentRegion.ID, path.Coordinate, path.AngleToNextPathPoint); boat.AddToWorld(); boat.CurrentWayPoint = path; GameEventMgr.AddHandler(boat, GameNPCEvent.PathMoveEnds, new DOLEventHandler(OnHorseAtPathEnd)); diff --git a/GameServer/gameobjects/CustomNPC/GameStableMaster.cs b/GameServer/gameobjects/CustomNPC/GameStableMaster.cs index 6bc2e278..c90d7685 100644 --- a/GameServer/gameobjects/CustomNPC/GameStableMaster.cs +++ b/GameServer/gameobjects/CustomNPC/GameStableMaster.cs @@ -27,6 +27,7 @@ using log4net; using System.Linq; using DOL.GS.Finance; +using DOL.GS.Geometry; namespace DOL.GS { @@ -135,7 +136,7 @@ public override bool ReceiveItem(GameLiving source, InventoryItem item) { PathPoint path = MovementMgr.LoadPath(item.Id_nb); - if ((path != null) && IsWithinRadius2D(path.Position, 500)) + if ((path != null) && ((Math.Abs(path.Coordinate.X - Coordinate.X)) < 500) && ((Math.Abs(path.Coordinate.Y - Coordinate.Y)) < 500)) { player.Inventory.RemoveCountFromStack(item, 1); InventoryLogging.LogInventoryAction(player, this, eInventoryActionType.Merchant, item, 1); @@ -213,9 +214,7 @@ public override bool ReceiveItem(GameLiving source, InventoryItem item) } mount.Realm = source.Realm; - mount.Position = path.Position; - mount.CurrentRegion = CurrentRegion; - mount.Heading = GameMath.GetHeading(path.Position, path.Next.Position); + mount.Position = Position.Create(CurrentRegion.ID, path.Coordinate, path.AngleToNextPathPoint); mount.AddToWorld(); mount.CurrentWayPoint = path; GameEventMgr.AddHandler(mount, GameNPCEvent.PathMoveEnds, new DOLEventHandler(OnHorseAtPathEnd)); diff --git a/GameServer/gameobjects/CustomNPC/GameSummoner.cs b/GameServer/gameobjects/CustomNPC/GameSummoner.cs index f1e0eea2..8738e964 100644 --- a/GameServer/gameobjects/CustomNPC/GameSummoner.cs +++ b/GameServer/gameobjects/CustomNPC/GameSummoner.cs @@ -18,7 +18,7 @@ */ using DOL.AI; using DOL.AI.Brain; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { @@ -147,10 +147,9 @@ protected virtual void SummonPet() ushort sideHeading = (ushort)(Heading + 900); if (Util.Random(1) < 1) sideHeading += 1800; - Vector2 point = GetPointFromHeading(sideHeading, PetSummonDistance); - m_pet.Position = new Vector3(point, Position.Z); + var petOrientationOffset = Util.Random(1) < 1 ? Angle.Heading(1800) : Angle.Heading(900); + m_pet.Position = Position + Vector.Create(Orientation + petOrientationOffset, PetSummonDistance); - m_pet.Heading = Heading; m_pet.Realm = eRealm.None; m_pet.LoadedFromScript = true; m_pet.MaxDistance = PetMaxDistance; diff --git a/GameServer/gameobjects/CustomNPC/GuildPortalNPC.cs b/GameServer/gameobjects/CustomNPC/GuildPortalNPC.cs index 4873e70a..18b55bbf 100644 --- a/GameServer/gameobjects/CustomNPC/GuildPortalNPC.cs +++ b/GameServer/gameobjects/CustomNPC/GuildPortalNPC.cs @@ -10,21 +10,19 @@ using log4net; using DOL.GS.Spells; using DOL.Territories; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { public class GuildPortalNPC : GameNPC { - public readonly record struct SavedCoordinates(ushort RegionID, Vector3 Position, ushort Heading); - public Guild OwningGuild { get; init; } public Territories.Territory LinkedTerritory { get; init; } private readonly object m_coordinatesLockObject = new(); - private Dictionary m_savedCoordinates = new(); + private readonly Dictionary m_savedCoordinates = new(); private GuildPortalNPC(Territories.Territory territory, GamePlayer spawner) : base() { @@ -36,7 +34,7 @@ public static GuildPortalNPC Create(Territories.Territory territory, GamePlayer { GuildPortalNPC portalNpc = new GuildPortalNPC(territory, spawner); portalNpc.LoadedFromScript = true; - portalNpc.Position = territory.PortalPosition.Value; + portalNpc.Position = Position.Create(territory.RegionId, territory.PortalCoordinate.Value, Angle.Zero); portalNpc.CurrentRegionID = territory.RegionId; portalNpc.Heading = 1000; portalNpc.Model = 1438; @@ -54,7 +52,7 @@ public void SummonPlayer(GamePlayer player) pl.Out.SendSpellEffectAnimation(player, player, 4310, 0, false, 1); lock (m_coordinatesLockObject) { - m_savedCoordinates.TryAdd(player, new SavedCoordinates(player.CurrentRegionID, player.Position, player.Heading)); + m_savedCoordinates.TryAdd(player, player.Position); } player.MoveTo(CurrentRegionID, Position.X, Position.Y, Position.Z, Heading); player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "Commands.Players.Guild.TerritoryPortal.Summoned", LinkedTerritory.Name), eChatType.CT_System, eChatLoc.CL_SystemWindow); @@ -62,7 +60,7 @@ public void SummonPlayer(GamePlayer player) public override bool Interact(GamePlayer player) { - SavedCoordinates returnCoordinates; + Position returnCoordinates; lock (m_coordinatesLockObject) { @@ -73,7 +71,7 @@ public override bool Interact(GamePlayer player) } foreach (GamePlayer pl in player.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE)) pl.Out.SendSpellEffectAnimation(player, player, 4310, 0, false, 1); - player.MoveTo(returnCoordinates.RegionID, returnCoordinates.Position.X, returnCoordinates.Position.Y, returnCoordinates.Position.Z, returnCoordinates.Heading); + player.MoveTo(returnCoordinates); return true; } } diff --git a/GameServer/gameobjects/CustomNPC/Hastener.cs b/GameServer/gameobjects/CustomNPC/Hastener.cs index b1c0e06e..14b70f74 100644 --- a/GameServer/gameobjects/CustomNPC/Hastener.cs +++ b/GameServer/gameobjects/CustomNPC/Hastener.cs @@ -104,7 +104,7 @@ public override bool WhisperReceive(GameLiving source, string str) AbstractGameKeep portalKeep = GameServer.KeepManager.GetBGPK(player); if (portalKeep != null) { - player.MoveTo((ushort)portalKeep.Region, portalKeep.X, portalKeep.Y, portalKeep.Z, (ushort)portalKeep.Heading); + player.MoveTo(portalKeep.Position); } } } diff --git a/GameServer/gameobjects/CustomNPC/ShadowNPC.cs b/GameServer/gameobjects/CustomNPC/ShadowNPC.cs index d70ff1b5..606f9bf4 100644 --- a/GameServer/gameobjects/CustomNPC/ShadowNPC.cs +++ b/GameServer/gameobjects/CustomNPC/ShadowNPC.cs @@ -2,15 +2,14 @@ using DOL.commands.playercommands; using DOL.Database; using DOL.Events; -using DOL.Geometry; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.Language; using DOLDatabase.Tables; using System; using System.Collections.Generic; using System.Linq; -using System.Numerics; using System.Text; using System.Threading.Tasks; @@ -60,18 +59,16 @@ public ShadowNPC(GamePlayer player) : base() this.player = player; IControlledBrain brain = new ShadowBrain(player); SetOwnBrain(brain as AI.ABrain); - int x, y, z; - ushort heading; - Region region; - - GetPlayerLocation(out x, out y, out z, out heading, out region); - - Position = new System.Numerics.Vector3(x, y, z); - Heading = heading; - CurrentRegion = region; AddToWorld(); } + /// + public override bool AddToWorld() + { + Position = GetPlayerPosition(); + return base.AddToWorld(); + } + public override string Name { get => "Combine List"; set => base.Name = value; } public string KeyWord { @@ -244,25 +241,14 @@ private string BuildList(string title) return result; } - protected virtual void GetPlayerLocation(out int x, out int y, out int z, out ushort heading, out Region region) + protected virtual Position GetPlayerPosition() { - Vector2 point = player.GetPointFromHeading(player.Heading, 64); - x = (int)point.X; - y = (int)point.Y; - z = (int)player.Position.Z; - heading = (ushort)((player.Heading + 2048) % 4096); - region = player.CurrentRegion; + return Position.Create(player.Position.RegionID, player.Coordinate + Vector.Create(Orientation, 64), player.Orientation.InHeading).TurnedAround(); } public virtual void MoveToPlayer() { - int x, y, z; - ushort heading; - Region region; - - GetPlayerLocation(out x, out y, out z, out heading, out region); - - MoveTo(region.ID, x, y, z, heading); + MoveTo(GetPlayerPosition()); } public void Interact(string message) diff --git a/GameServer/gameobjects/Dragons/Cuuldurach.cs b/GameServer/gameobjects/Dragons/Cuuldurach.cs index a857d35e..d005c60c 100644 --- a/GameServer/gameobjects/Dragons/Cuuldurach.cs +++ b/GameServer/gameobjects/Dragons/Cuuldurach.cs @@ -24,7 +24,7 @@ using System.Reflection; using System.Collections; using DOL.AI.Brain; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { @@ -57,12 +57,12 @@ public override bool CheckAddSpawns() // messengers, who will try to get out of the lair and, if successful, // cause Cuuldurach to spawn a couple of deep purple adds. - for (int glimmer = 1; glimmer <= numAdds; ++glimmer) + for (int glimmer = 1; glimmer <= 10; ++glimmer) { isMessenger = Util.Chance(25); - glimmerSpawn = SpawnTimedAdd((isMessenger) ? 620 : 621 + Util.Random(2), - (isMessenger) ? Util.Random(47, 53) : Util.Random(57, 63), - Position.X + Util.Random(300, 600), Position.Y + Util.Random(300, 600), 60, isMessenger); + var spawnCoordinate = Coordinate + Vector.Create(x: Util.Random(300, 600), y: Util.Random(300, 600)); + glimmerSpawn = SpawnTimedAdd((isMessenger) ? 620 : 621+Util.Random(2), + (isMessenger) ? Util.Random(47, 53) : Util.Random(57, 63), spawnCoordinate, 60, isMessenger); // We got a messenger, tell it who its master is and which exit // to run to. @@ -85,7 +85,7 @@ public override bool CheckAddSpawns() /// 3 = SE, 4 = NE). /// /// Coordinates. - private Vector3 GetExitCoordinates(int exitNo) + private Coordinate GetExitCoordinates(int exitNo) { // Get target coordinates (hardcoded). Yeah I know, this is // ugly, but to get this right NPC pathing is a must; as it @@ -94,11 +94,11 @@ private Vector3 GetExitCoordinates(int exitNo) switch (exitNo) { - case 1: return new Vector3(407292, 704008, 0); - case 2: return new Vector3(406158, 707745, 0); - case 3: return new Vector3(410302, 708563, 0); - case 4: return new Vector3(411117, 704696, 0); - default: return SpawnPoint; + case 1: return Coordinate.Create(x: 407292, y: 704008 ); + case 2: return Coordinate.Create(x: 406158, y: 707745 ); + case 3: return Coordinate.Create(x: 410302, y: 708563 ); + case 4: return Coordinate.Create(x: 411117, y: 704696 ); + default: return SpawnPosition.Coordinate; } } @@ -114,7 +114,7 @@ public override void OnRetrieverArrived(GameNPC sender) // Spawn nasty adds. if (m_messengerList.Contains(sender)) - SpawnGlimmers(Util.Random(7, 10), sender.Position.X, sender.Position.Y); + SpawnGlimmers(Util.Random(7, 10), sender.Coordinate); } /// @@ -122,15 +122,13 @@ public override void OnRetrieverArrived(GameNPC sender) /// retriever has reported back from, then make these spawns aggro the /// raid inside the lair. /// - /// - /// - /// - private void SpawnGlimmers(int numAdds, float x, float y) + private void SpawnGlimmers(int numAdds, Coordinate coordinate) { GameNPC glimmer; for (int add = 0; add < numAdds; ++add) { - glimmer = SpawnTimedAdd(624 + Util.Random(2), Util.Random(62, 68), x + Util.Random(250), y + Util.Random(250), 120, false); + var randomSpawnCoordinate = coordinate + Vector.Create(x: Util.Random(250), y: Util.Random(250)); + glimmer = SpawnTimedAdd(624+Util.Random(2), Util.Random(62, 68), randomSpawnCoordinate, 120, false); if (glimmer != null && glimmer.Brain is StandardMobBrain && this.Brain is DragonBrain) { diff --git a/GameServer/gameobjects/Dragons/GameDragon.cs b/GameServer/gameobjects/Dragons/GameDragon.cs index f0bb2444..0cf93098 100644 --- a/GameServer/gameobjects/Dragons/GameDragon.cs +++ b/GameServer/gameobjects/Dragons/GameDragon.cs @@ -28,8 +28,8 @@ using DOL.GS.ServerProperties; using DOL.AI.Brain; using DOL.gameobjects.CustomNPC; -using System.Numerics; using System.Threading.Tasks; +using DOL.GS.Geometry; namespace DOL.GS { @@ -96,7 +96,7 @@ public override void LoadFromDatabase(DataObject obj) String[] dragonName = Name.Split(new char[] { ' ' }); WorldMgr.GetRegion(CurrentRegionID).AddArea( new Area.Circle(String.Format("{0}'s Lair", dragonName[0]), - Position.X, Position.Y, 0, LairRadius + 200)); + Coordinate, LairRadius + 200)); } public override bool HasAbility(string keyName) @@ -382,11 +382,10 @@ public virtual bool CheckAddSpawns() /// /// /// - /// - /// + /// /// /// - protected GameNPC SpawnTimedAdd(int templateID, int level, float x, float y, int uptime, bool isRetriever) + protected GameNPC SpawnTimedAdd(int templateID, int level, Coordinate coordinate, int uptime, bool isRetriever) { GameNPC add = null; @@ -408,10 +407,8 @@ protected GameNPC SpawnTimedAdd(int templateID, int level, float x, float y, int { add.SetOwnBrain(new RetrieverMobBrain()); } - add.CurrentRegion = this.CurrentRegion; - add.Heading = (ushort)(Util.Random(0, 4095)); + add.Position = Position.Create(CurrentRegion.ID, coordinate, Angle.Heading(Util.Random(0, 4095))); add.Realm = 0; - add.Position = Position; add.Level = (byte)level; add.RespawnInterval = -1; add.AddToWorld(); @@ -616,7 +613,7 @@ private int CastGlare(RegionTimer timer) GameObject oldTarget = TargetObject; TargetObject = GlareTarget; - Position = new Vector3(Position.X, Position.Y, SpawnPoint.Z); // this is a fix to correct Z errors that sometimes happen during dragon fights + Position = Position.With(z: SpawnPosition.Z); // this is a fix to correct Z errors that sometimes happen during dragon fights TurnTo(GlareTarget); CastSpell(Glare, SkillBase.GetSpellLine(GlobalSpellsLines.Mob_Spells)); GlareTarget = null; @@ -764,15 +761,15 @@ private void ThrowLiving(GameLiving target) TurnTo(target); - Vector3 targetPosition = PositionOfTarget(target.Position, 700, Heading, Util.Random(300, 500)); + var throwPosition = GetThrowPosition(target, 700, Orientation, Util.Random(300, 500) ); if (target is GamePlayer) { - target.MoveTo(target.CurrentRegionID, targetPosition.X, targetPosition.Y, targetPosition.Z, target.Heading); + target.MoveTo(throwPosition); } else if (target is GameNPC) { - (target as GameNPC).MoveInRegion(target.CurrentRegionID, targetPosition.X, targetPosition.Y, targetPosition.Z, target.Heading, true); + (target as GameNPC).MoveWithoutRemovingFromWorld(throwPosition, true); target.ChangeHealth(this, eHealthChangeType.Spell, (int)(target.Health * -0.35)); } } @@ -780,17 +777,13 @@ private void ThrowLiving(GameLiving target) /// /// Calculate the target position with given height and displacement. /// - /// Current object X position. - /// Current object Y position. - /// Current object Z position. + /// /// Height the object is to be lifted to. - /// The direction the object is displaced in. - /// The amount the object is displaced by. + /// The direction the object is displaced in. + /// The amount the object is displaced by. /// - private Vector3 PositionOfTarget(Vector3 target, int height, int heading, int displacement) - { - return new Vector3(GameMath.GetPointFromHeading(target, (ushort)heading, displacement), target.Z + height); - } + private Position GetThrowPosition(GameObject target, int height, Angle orientation, int distance) + => target.Position + Vector.Create(orientation, distance) + Vector.Create(z: height); #endregion diff --git a/GameServer/gameobjects/Dragons/Gjalpinulva.cs b/GameServer/gameobjects/Dragons/Gjalpinulva.cs index 13c3505f..b010d18f 100644 --- a/GameServer/gameobjects/Dragons/Gjalpinulva.cs +++ b/GameServer/gameobjects/Dragons/Gjalpinulva.cs @@ -24,7 +24,7 @@ using System.Reflection; using System.Collections; using DOL.AI.Brain; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { @@ -62,14 +62,8 @@ public override bool CheckAddSpawns() for (int dog = 1; dog <= numAdds; ++dog) { isRetriever = Util.Chance(25); - dogSpawn = SpawnTimedAdd( - (isRetriever) ? 610 : 611, - (isRetriever) ? Util.Random(47, 53) : 37, - Position.X + Util.Random(300, 600), - Position.Y + Util.Random(300, 600), - 60, - isRetriever - ); + var spawnCoordinate = Coordinate + Vector.Create(x: Util.Random(300, 600), y: Util.Random(300, 600)); + dogSpawn = SpawnTimedAdd((isRetriever) ? 610 : 611, (isRetriever) ? Util.Random(47, 53) : 37, spawnCoordinate, 60, isRetriever); // We got a retriever, tell it who its master is and which exit // to run to. @@ -92,7 +86,7 @@ public override bool CheckAddSpawns() /// 3 = SE, 4 = NE). /// /// Coordinates. - private Vector3 GetExitCoordinates(int exitNo) + private Coordinate GetExitCoordinates(int exitNo) { // Get target coordinates (hardcoded). Yeah I know, this is // ugly, but to get this right NPC pathing is a must; as it @@ -101,11 +95,11 @@ private Vector3 GetExitCoordinates(int exitNo) switch (exitNo) { - case 1: return new Vector3(707026, 1019564, 0); - case 2: return new Vector3(706924, 1023596, 0); - case 3: return new Vector3(711441, 1023175, 0); - case 4: return new Vector3(710708, 1018894, 0); - default: return SpawnPoint; + case 1: return Coordinate.Create(x: 707026, y: 1019564 ); + case 2: return Coordinate.Create(x: 706924, y: 1023596 ); + case 3: return Coordinate.Create(x: 711441, y: 1023175 ); + case 4: return Coordinate.Create(x: 710708, y: 1018894 ); + default: return SpawnPosition.Coordinate; } } @@ -121,7 +115,7 @@ public override void OnRetrieverArrived(GameNPC sender) // Spawn nasty adds. if (m_retrieverList.Contains(sender)) - SpawnDrakulvs(Util.Random(7, 10), sender.Position.X, sender.Position.Y); + SpawnDrakulvs(Util.Random(7, 10), sender.Coordinate); } /// @@ -130,16 +124,15 @@ public override void OnRetrieverArrived(GameNPC sender) /// raid inside the lair. /// /// - /// - /// - private void SpawnDrakulvs(int numAdds, float x, float y) + private void SpawnDrakulvs(int numAdds, Coordinate coordinate) { GameNPC drakulv; bool isDisciple = false; for (int add = 0; add < numAdds; ++add) { isDisciple = Util.Chance(25); - drakulv = SpawnTimedAdd((isDisciple) ? 613 : 612, Util.Random(62, 68), x + Util.Random(250), y + Util.Random(250), 120, false); + var randomCoordinate = coordinate + Vector.Create(x: Util.Random(250), y: Util.Random(250)); + drakulv = SpawnTimedAdd((isDisciple) ? 613 : 612, Util.Random(62, 68), randomCoordinate, 120, false); if (drakulv != null && drakulv.Brain is StandardMobBrain && this.Brain is DragonBrain) { diff --git a/GameServer/gameobjects/Dragons/Golestandt.cs b/GameServer/gameobjects/Dragons/Golestandt.cs index 1353a010..b8c0f62c 100644 --- a/GameServer/gameobjects/Dragons/Golestandt.cs +++ b/GameServer/gameobjects/Dragons/Golestandt.cs @@ -21,6 +21,7 @@ using System.Text; using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using log4net; using System.Reflection; using System.Collections; @@ -50,7 +51,8 @@ public override bool CheckAddSpawns() int numAdds = Math.Max(1, PlayersInLair * 2 + 1); for (int add = 1; add <= numAdds; ++add) { - SpawnTimedAdd(600, Util.Random(57, 60), Position.X + Util.Random(300, 600), Position.Y + Util.Random(300, 600), 30, false); // granite giant pounder lvl 57-60 + var spawnCoordinate = Coordinate + Vector.Create(x: Util.Random(300, 600), y: Util.Random(300, 600)); + SpawnTimedAdd(600, Util.Random(57, 60), spawnCoordinate, 30, false); // granite giant pounder lvl 57-60 } return true; } diff --git a/GameServer/gameobjects/FeuDeCamp.cs b/GameServer/gameobjects/FeuDeCamp.cs index a0a62ebb..e89941ba 100644 --- a/GameServer/gameobjects/FeuDeCamp.cs +++ b/GameServer/gameobjects/FeuDeCamp.cs @@ -140,10 +140,8 @@ public override bool AddToWorld() m_RealFeu = new GameStaticItem(); m_RealFeu.Name = Name = "Feu de Camp"; - m_RealFeu.Position = new System.Numerics.Vector3(Position.X, Position.Y, Position.Z); + m_RealFeu.Position = Position; m_RealFeu.Model = Model; - m_RealFeu.CurrentRegion = CurrentRegion; - m_RealFeu.Heading = Heading; m_RealFeu.AddToWorld(); @@ -156,7 +154,7 @@ void ProximityCheck(object sender, ElapsedEventArgs e) { - foreach (GamePlayer Player in WorldMgr.GetPlayersCloseToSpot(this.CurrentRegionID, this.Position.X, this.Position.Y, this.Position.Z, Radius)) + foreach (GamePlayer Player in WorldMgr.GetPlayersCloseToSpot(this.Position, Radius)) { if (Player.IsSitting) { @@ -301,12 +299,10 @@ public static void EventPlayerDropItem(DOLEvent e, object sender, ManaTrapDamagePercent = Feu.ManaTrapDamagePercent, HealthTrapDamagePercent = Feu.HealthTrapDamagePercent, IsEnduranceType = Feu.IsEnduranceType, - HealthPercentRate = Feu.HealthPercentRate + HealthPercentRate = Feu.HealthPercentRate, + Position = Player.Position }; - firecamp.Position = new System.Numerics.Vector3(Player.Position.X, Player.Position.Y, Player.Position.Z); - firecamp.CurrentRegion = Player.CurrentRegion; - firecamp.Heading = Player.Heading; firecamp.AddToWorld(); Args.GroundItem.Delete(); diff --git a/GameServer/gameobjects/GameDoor.cs b/GameServer/gameobjects/GameDoor.cs index 83044a9d..8e16eb3f 100644 --- a/GameServer/gameobjects/GameDoor.cs +++ b/GameServer/gameobjects/GameDoor.cs @@ -20,22 +20,8 @@ using DOL.Database; using DOL.GS.PacketHandler; using DOL.Language; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using DOL.GS.Utils; -using DOL.GS.Quests; using System.Threading; -using DOL.AI.Brain; -using DOL.Events; -using DOL.GS.Effects; -using DOL.GS.Keeps; -using DOL.GS.PropertyCalc; -using DOL.GS.SkillHandler; -using DOL.GS.Spells; -using DOL.GS.Styles; -using DOL.GS.PacketHandler.Client.v168; -using System.Numerics; +using DOL.GS.Geometry; using DOL.MobGroups; using System.Linq; @@ -100,8 +86,7 @@ public override void LoadFromDatabase(DataObject obj) if (curZone == null) return; this.CurrentRegion = curZone.ZoneRegion; m_name = m_dbdoor.Name; - m_Heading = (ushort)m_dbdoor.Heading; - Position = new Vector3(m_dbdoor.X, m_dbdoor.Y, m_dbdoor.Z); + Position = Position.Create(regionID: CurrentRegion.ID, x: m_dbdoor.X, y: m_dbdoor.Y, z: m_dbdoor.Z, heading: (ushort)m_dbdoor.Heading ); m_level = 0; m_model = 0xFFFF; m_doorID = m_dbdoor.InternalID; @@ -448,16 +433,6 @@ public override void Die(GameObject killer) StartHealthRegeneration(); } - /// - /// Broadcasts the Door Update to all players around - /// - public override void BroadcastUpdate() - { - base.BroadcastUpdate(); - - m_lastUpdateTickCount = GameTimer.GetTickCount(); - } - private static long m_healthregentimer = 0; private int m_punishSpell; private bool m_isRenaissance; diff --git a/GameServer/gameobjects/GameGravestone.cs b/GameServer/gameobjects/GameGravestone.cs index 23788632..eefef1d8 100644 --- a/GameServer/gameobjects/GameGravestone.cs +++ b/GameServer/gameobjects/GameGravestone.cs @@ -16,11 +16,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ -using System; -using DOL.Database; +using DOL.GS.Geometry; using DOL.Language; -using DOL.GS.PacketHandler; namespace DOL.GS { @@ -44,7 +42,6 @@ public GameGravestone(GamePlayer player, long xpValue) : base() //the same startingspots when we restart! m_saveInDB = false; m_name = LanguageMgr.GetTranslation(player.Client.Account.Language, "GameGravestone.GameGravestone.Grave", player.Name); - m_Heading = player.Heading; Position = player.Position; CurrentRegionID = player.CurrentRegionID; m_level = 0; diff --git a/GameServer/gameobjects/GameHouseVault.cs b/GameServer/gameobjects/GameHouseVault.cs index fb59e958..6f7cb409 100644 --- a/GameServer/gameobjects/GameHouseVault.cs +++ b/GameServer/gameobjects/GameHouseVault.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using DOL.Database; using DOL.GS.Housing; +using DOL.GS.Geometry; namespace DOL.GS { @@ -124,14 +125,11 @@ public bool Attach(House house, DBHouseHookpointItem hookedItem) _hookedItem = hookedItem; - var position = house.GetHookpointLocation(hookedItem.HookpointID); - if (position == null) - return false; + var coordinate = house.GetHookPointCoordinate(hookedItem.HookpointID); + if (coordinate == Coordinate.Nowhere) return false; CurrentHouse = house; - CurrentRegionID = house.RegionID; - Position = position.Value; - Heading = (ushort)(hookedItem.Heading % 4096); + Position = Position.Create(house.RegionID, coordinate, hookedItem.Heading); AddToWorld(); return true; diff --git a/GameServer/gameobjects/GameInventoryItem.cs b/GameServer/gameobjects/GameInventoryItem.cs index bd95b630..903e5f7f 100644 --- a/GameServer/gameobjects/GameInventoryItem.cs +++ b/GameServer/gameobjects/GameInventoryItem.cs @@ -26,7 +26,7 @@ using DOL.GS.Spells; using log4net; -using System.Numerics; +using DOL.GS.Geometry; using DOL.Bonus; using System.Linq; @@ -283,10 +283,8 @@ public virtual WorldInventoryItem Drop(GamePlayer player) { WorldInventoryItem worldItem = new WorldInventoryItem(this); - var itemloc = GameMath.GetPointFromHeading(player.Position, player.Heading, 30); - worldItem.Position = new Vector3(itemloc, player.Position.Z); - worldItem.Heading = player.Heading; - worldItem.CurrentRegionID = player.CurrentRegionID; + var itemPosition = player.Position + Vector.Create(player.Orientation, length: 30); + worldItem.Position = itemPosition; worldItem.AddOwner(player); worldItem.AddToWorld(); diff --git a/GameServer/gameobjects/GameLiving.cs b/GameServer/gameobjects/GameLiving.cs index d2f821b8..0bb8ee68 100644 --- a/GameServer/gameobjects/GameLiving.cs +++ b/GameServer/gameobjects/GameLiving.cs @@ -44,7 +44,9 @@ using static DOL.GS.ScriptMgr; using System.Threading.Tasks; using DOL.GameEvents; +using DOL.GS.Geometry; using System.Collections.Immutable; +using Vector3 = System.Numerics.Vector3; namespace DOL.GS { @@ -2051,8 +2053,8 @@ protected virtual AttackData MakeAttack(GameObject target, InventoryItem weapon, bool preCheck = false; if (ad.Target is GamePlayer) //only start if we are behind the player { - float angle = GameMath.GetAngle(ad.Target, ad.Attacker); - if (angle >= 150 && angle < 210) preCheck = true; + var angle = ad.Target.GetAngleTo(ad.Attacker.Coordinate); + if (angle.InDegrees >= 150 && angle.InDegrees < 210) preCheck = true; } else preCheck = true; @@ -2515,7 +2517,7 @@ protected override void OnTick() } } - ticksToTarget = (int)(1 + Vector3.Distance(owner.Position, attackTarget.Position) * 100 / 150); // 150 units per 1/10s + ticksToTarget = (int)(1 + owner.GetDistanceTo( attackTarget ) * 100 / 150); // 150 units per 1/10s } else { @@ -5860,21 +5862,6 @@ public void CancelAllSpeedOrPulseEffects() /// protected short m_maxSpeedBase; - /// - /// Gets the current direction the Object is facing - /// - public override ushort Heading - { - get { return base.Heading; } - set - { - ushort oldHeading = base.Heading; - base.Heading = value; - if (base.Heading != oldHeading) - UpdateTickSpeed(); - } - } - private bool m_fixedSpeed = false; /// @@ -5889,14 +5876,10 @@ public virtual bool FixedSpeed /// /// Gets or sets the current speed of this living /// - public short CurrentSpeed + public virtual short CurrentSpeed { - get => m_currentSpeed; - protected set - { - m_currentSpeed = value; - UpdateTickSpeed(); - } + get => Motion.Speed; + set => Motion = Geometry.Motion.Create(Position, Motion.Destination, value); } /// @@ -5940,16 +5923,21 @@ public virtual GameObject TargetObject m_targetObjectWeakReference.Target = value; } } + public virtual void TurnTo(Coordinate coordinate, bool sendUpdate = true) + => Orientation = Coordinate.GetOrientationTo(coordinate); + public virtual bool IsSitting { get { return false; } set { } } - /// - /// Gets or Sets the Living's ground-target Coordinate inside the current Region - /// - public virtual Vector3? GroundTarget { get; set; } = new Vector3(0, 0, 0); + [Obsolete("Use GroundTargetPosition_set instead!")] + public virtual void SetGroundTarget(int groundX, int groundY, int groundZ) + => GroundTargetPosition = Position.Create(Position.RegionID, groundX, groundY, groundZ); + + public virtual Position GroundTargetPosition { get; set; } = Position.Nowhere; + /// /// Gets or Sets the current level of the Object /// @@ -5990,32 +5978,6 @@ public virtual int CalculateSkillLevel(Skill skill) #endregion #region Movement - /// - /// The tick speed - /// - public Vector3 Velocity { get; private set; } - - /// - /// Updates tick speed for this living. - /// - protected virtual void UpdateTickSpeed(Vector3? target = null) - { - int speed = CurrentSpeed; - - if (speed == 0) - Velocity = Vector3.Zero; - else - { - // Living will move in the direction it is currently heading. - - var heading = Heading * GameMath.HEADING_TO_RADIAN; - var v = new Vector3(-MathF.Sin(heading), MathF.Cos(heading), 0); - if (target.HasValue && target.Value.Z != 0 && target != Position) - v.Z = (target.Value.Z - Position.Z) / Math.Max(1, Vector2.Distance(target.Value.ToVector2(), Position.ToVector2())); - Debug.Assert(float.IsNormal(v.X) || float.IsNormal(v.Y)); - Velocity = v * speed * 0.001f; - } - } public virtual void UpdateHealthManaEndu() { @@ -6033,64 +5995,34 @@ public virtual void UpdateHealthManaEndu() } /// - /// Set the tick speed, that is the distance covered in one tick. + /// The tick at which the movement started. /// - /// - /// - /// - protected void SetTickSpeed(float dx, float dy, float dz) + public int MovementStartTick + => Motion.StartTimeInMilliSeconds; + + public override Position Position { - Velocity = new Vector3(dx, dy, dz); + get => Motion.CurrentPosition; + set => Motion = Motion.Create(value, Motion.Destination, Motion.Speed); } /// - /// Set the tick speed, that is the distance covered in one tick. + /// True if the living is moving, else false. /// - /// - /// - /// - /// - protected void SetTickSpeed(float dx, float dy, float dz, float speed) + public virtual bool IsMoving => CurrentSpeed != 0; + + protected virtual Motion Motion { get; set; } = new Motion(); + + public override Angle Orientation { - float tickSpeed = speed * 0.001f; - SetTickSpeed(dx * tickSpeed, dy * tickSpeed, dz * tickSpeed); + get => Position.Orientation; + set => Position = Motion.Start.With(orientation: value); } - - protected void SetTickSpeed(Vector3 velocity) => Velocity = velocity; - protected void SetTickSpeed(Vector3 heading, float speed) => Velocity = heading * speed * 0.001f; - - /// - /// The tick at which the movement started. - /// - public uint MovementStartTick { get; set; } - - /// - /// Elapsed ticks since movement started. - /// - protected uint MovementElapsedTicks => GameTimer.GetTickCount() - MovementStartTick; - - /// - /// True if the living is moving, else false. - /// - public virtual bool IsMoving => m_currentSpeed != 0; - - /// - /// Moves the item from one spot to another spot, possible even - /// over region boundaries - /// - /// new regionid - /// new x - /// new y - /// new z - /// new heading - /// true if moved - public override bool MoveTo(ushort regionID, float x, float y, float z, ushort heading) + public override bool MoveTo(Position position) { - if (regionID != CurrentRegionID) - CancelAllConcentrationEffects(); - - return base.MoveTo(regionID, x, y, z, heading); + if (position.RegionID != CurrentRegionID) CancelAllConcentrationEffects(); + return base.MoveTo(position); } #endregion #region Stealth @@ -7160,8 +7092,6 @@ public virtual string GetPersonalizedName(GameObject obj) public GameLiving() : base() { - Velocity = Vector3.Zero; - m_guildName = string.Empty; m_targetObjectWeakReference = new WeakRef(null); diff --git a/GameServer/gameobjects/GameMerchant.cs b/GameServer/gameobjects/GameMerchant.cs index f45f2b39..02029ce7 100644 --- a/GameServer/gameobjects/GameMerchant.cs +++ b/GameServer/gameobjects/GameMerchant.cs @@ -349,13 +349,13 @@ public override void SaveIntoDatabase() merchant = new Mob(); merchant.Name = Name; - merchant.Guild = GuildName; - merchant.X = (int)Position.X; - merchant.Y = (int)Position.Y; - merchant.Z = (int)Position.Z; - merchant.Heading = Heading; + merchant.Guild = GuildName;; + merchant.X = Position.X; + merchant.Y = Position.Y; + merchant.Z = Position.Z; + merchant.Heading = Orientation.InHeading; + merchant.Region = Position.RegionID; merchant.Speed = MaxSpeedBase; - merchant.Region = CurrentRegionID; merchant.Realm = (byte)Realm; merchant.RoamingRange = RoamingRange; merchant.Model = Model; diff --git a/GameServer/gameobjects/GameMoney.cs b/GameServer/gameobjects/GameMoney.cs index 4d70edfe..faa73467 100644 --- a/GameServer/gameobjects/GameMoney.cs +++ b/GameServer/gameobjects/GameMoney.cs @@ -74,8 +74,6 @@ public static bool IsItemMoney(string name) public GameMoney(long copperValue, GameObject dropper) : this(copperValue) { Position = dropper.Position; - Heading = dropper.Heading; - CurrentRegion = dropper.CurrentRegion; } /// /// Returns the number of mithril pieces in this bag diff --git a/GameServer/gameobjects/GameNPC.cs b/GameServer/gameobjects/GameNPC.cs index e4ac4b62..a6b8297a 100644 --- a/GameServer/gameobjects/GameNPC.cs +++ b/GameServer/gameobjects/GameNPC.cs @@ -40,17 +40,18 @@ using DOL.GS.ServerProperties; using System.Threading; using System.Threading.Tasks; -using System.Numerics; using DOL.GameEvents; using DOL.MobGroups; using DOL.Territories; using static DOL.GS.ScriptMgr; using DOL.GS.Finance; +using DOL.GS.Geometry; using DOLDatabase.Tables; using DOL.GS.Scripts; using System.Timers; using System.Text.RegularExpressions; using log4net; +using Vector3 = System.Numerics.Vector3; namespace DOL.GS { @@ -369,17 +370,14 @@ protected override void GainTension(AttackData source) /// /// Gets or sets the heading of this NPC /// - public override ushort Heading + public override Angle Orientation { - get { return base.Heading; } + get { return base.Orientation; } set { if (IsTurningDisabled) return; - ushort oldHeading = base.Heading; - base.Heading = value; - if (base.Heading != oldHeading) - BroadcastUpdate(); + base.Orientation = value; } } @@ -922,15 +920,6 @@ public enum eFlags : uint /// Holds various flags of this npc /// protected eFlags m_flags; - /// - /// Spawn point - /// - protected Vector3 m_spawnPoint; - /// - /// Spawn Heading - /// - protected ushort m_spawnHeading; - /// /// package ID defined form this NPC @@ -943,10 +932,6 @@ public string PackageID set { m_packageID = value; } } - /// - /// The last time this NPC sent the 0x09 update packet - /// - protected volatile uint m_lastUpdateTickCount = uint.MinValue; /// /// The last time this NPC was actually updated to at least one player /// @@ -1023,48 +1008,32 @@ public override void Stealth(bool goStealth) /// /// Gets or sets the spawnposition of this npc /// - public virtual Vector3 SpawnPoint + public virtual Position SpawnPosition { - get { return m_spawnPoint; } - set { m_spawnPoint = value; } - } + get; + set; + } = Position.Nowhere; - /// - /// Gets or sets the spawnposition of this npc - /// - [Obsolete("Use GameNPC.SpawnPoint")] - public float SpawnX + [Obsolete("Use SpawnPosition.Heading instead!")] + public ushort SpawnHeading { - get { return m_spawnPoint.X; } - set { m_spawnPoint.X = value; } + get => SpawnPosition.Orientation.InHeading; + private set => SpawnPosition = Position.With(Angle.Heading(value)); } - /// - /// Gets or sets the spawnposition of this npc - /// - [Obsolete("Use GameNPC.SpawnPoint")] - public float SpawnY - { - get { return m_spawnPoint.Y; } - set { m_spawnPoint.Y = value; } - } - /// - /// Gets or sets the spawnposition of this npc - /// - [Obsolete("Use GameNPC.SpawnPoint")] - public float SpawnZ + + public short ZSpeedFactor + => (short)((Motion.Destination.Z - Motion.Start.Z) / Motion.FullDistance); + + protected override Motion Motion { - get { return m_spawnPoint.Z; } - set { m_spawnPoint.Z = value; } + set + { + base.Motion = value; + BroadcastUpdate(); + } } - /// - /// Gets or sets the spawnheading of this npc - /// - public virtual ushort SpawnHeading - { - get { return m_spawnHeading; } - set { m_spawnHeading = value; } - } + public Coordinate Destination => Motion.Destination; /// /// Stores the currentwaypoint that npc has to wander to @@ -1131,7 +1100,7 @@ public bool IsOutOfTetherRange { if (TetherRange > 0) { - if (this.IsWithinRadius(this.SpawnPoint, TetherRange)) + if (Coordinate.DistanceTo(SpawnPosition) <= TetherRange) return false; else return true; @@ -1235,31 +1204,6 @@ public string PathID set { m_pathID = value; } } - private Vector3 _basePosition = Vector3.Zero; - public override Vector3 Position - { - set => _basePosition = value; - get - { - if (!IsMoving || TargetPosition == Vector3.Zero) - return _basePosition; - if (MovementElapsedTicks > (Vector2.Distance(_basePosition.ToVector2(), TargetPosition.ToVector2()) * 1000 / CurrentSpeed)) - { - return TargetPosition; - } - _basePosition.Z = TargetPosition.Z; - return _basePosition + MovementElapsedTicks * Velocity; - } - } - /// - /// The target position. - /// - public Vector3 TargetPosition - { - get; - private set; - } - /// /// Is allowed to attack anyone? /// @@ -1295,35 +1239,46 @@ public override GameObject TargetObject /// /// True if the mob is at its target position, else false. /// - public bool IsAtTargetPosition => Vector3.DistanceSquared(Position, TargetPosition) < 1.0f; + public bool IsAtTargetLocation => Motion.Destination.Equals(Coordinate); + + public override void TurnTo(Coordinate coordinate, bool sendUpdate = true) + { + if (IsStunned || IsMezzed) return; + + Notify(GameNPCEvent.TurnTo, this, new TurnToEventArgs(coordinate.X, coordinate.Y)); - /// - /// Turns the npc towards a specific heading - /// optionally sends update to client - /// - /// the new heading - public virtual void TurnTo(ushort heading, bool sendUpdate) + if (sendUpdate) Orientation = Coordinate.GetOrientationTo(coordinate); + else base.Orientation = Coordinate.GetOrientationTo(coordinate); + } + + [Obsolete("Use TurnTo(Coordinate[,bool]) instead.")] + public virtual void TurnTo(int tx, int ty, bool sendUpdate = true) + => TurnTo(Coordinate.Create(x: tx, y: ty ), sendUpdate); + + [Obsolete("Use .TurnTo(Angle[,bool]) instead!")] + public virtual void TurnTo(ushort heading, bool sendUpdate = true) + => TurnTo(Angle.Heading(heading), sendUpdate); + + public virtual void TurnTo(Angle newOrientation, bool sendUpdate = true) { if (IsStunned || IsMezzed) return; - Notify(GameNPCEvent.TurnToHeading, this, new TurnToHeadingEventArgs(heading)); + Notify(GameNPCEvent.TurnToHeading, this, new TurnToHeadingEventArgs(newOrientation.InHeading)); - if (sendUpdate && Heading != heading) - Heading = heading; - else - base.Heading = heading; + if (sendUpdate) + { + if (Orientation != newOrientation) Orientation = newOrientation; + else if (base.Orientation != newOrientation) base.Orientation = newOrientation; + } } - public void TurnTo(float tx, float ty) => TurnTo(tx, ty, true); - public void TurnTo(float tx, float ty, bool sendUpdate) => TurnTo(GameMath.GetHeading(Position, new Vector2(tx, ty)), sendUpdate); - public void TurnTo(ushort heading) => TurnTo(heading, true); public void TurnTo(GameObject target) => TurnTo(target, true); public void TurnTo(GameObject target, bool sendUpdate) { if (target == null || target.CurrentRegion != CurrentRegion) return; - - TurnTo(target.Position.X, target.Position.Y, sendUpdate); + + TurnTo(target.Coordinate, sendUpdate); } /// @@ -1362,15 +1317,8 @@ public virtual void TurnTo(GameObject target, int duration) /// protected class RestoreHeadingAction : RegionAction { - /// - /// The NPCs old heading - /// - protected readonly ushort m_oldHeading; - - /// - /// The NPCs old position - /// - protected readonly Vector3 m_oldPosition; + private readonly Angle m_oldOrientation; + protected readonly Coordinate m_oldPosition; /// /// Creates a new TurnBackAction @@ -1379,8 +1327,8 @@ protected class RestoreHeadingAction : RegionAction public RestoreHeadingAction(GameNPC actionSource) : base(actionSource) { - m_oldHeading = actionSource.Heading; - m_oldPosition = actionSource.Position; + m_oldOrientation = actionSource.Orientation; + m_oldPosition = actionSource.Coordinate; } /// @@ -1397,20 +1345,12 @@ protected override void OnTick() if (npc.AttackState) return; if (npc.IsMoving) return; if (npc.Equals(m_oldPosition)) return; - if (npc.Heading == m_oldHeading) return; // already set? oO - - npc.TurnTo(m_oldHeading); + if (npc.Orientation == m_oldOrientation) return; // already set? oO + + npc.TurnTo(m_oldOrientation); } } - /// - /// Gets the last time this mob was updated - /// - public uint LastUpdateTickCount - { - get { return m_lastUpdateTickCount; } - } - /// /// Gets the last this this NPC was actually update to at least one player. /// @@ -1424,12 +1364,16 @@ public uint LastVisibleToPlayersTickCount /// protected class ArriveAtTargetAction : RegionAction { + private Action m_goToNodeCallback; + /// /// Constructs a new ArriveAtTargetAction /// /// The action source - public ArriveAtTargetAction(GameNPC actionSource) : base(actionSource) + public ArriveAtTargetAction(GameNPC actionSource, Action goToNodeCallback = null) + : base(actionSource) { + m_goToNodeCallback = goToNodeCallback; } /// @@ -1440,7 +1384,19 @@ public ArriveAtTargetAction(GameNPC actionSource) : base(actionSource) protected override void OnTick() { GameNPC npc = (GameNPC)m_actionSource; - npc._OnArrivedAtTarget(); + if (m_goToNodeCallback != null) + { + m_goToNodeCallback(npc); + return; + } + + bool arriveAtSpawnPoint = npc.IsReturningHome; + + npc.StopMoving(); + npc.Notify(GameNPCEvent.ArriveAtTarget, npc); + + if (arriveAtSpawnPoint) + npc.Notify(GameNPCEvent.ArriveAtSpawnPoint, npc); } } @@ -1456,42 +1412,20 @@ protected void _OnArrivedAtTarget() public void CancelWalkToTimer() { - _arriveAtPathNodeAction?.Stop(); - _arriveAtPathNodeAction = null; m_arriveAtTargetAction?.Stop(); m_arriveAtTargetAction = null; } - /// - /// Ticks required to arrive at a given spot. - /// - /// - /// - /// - public int GetTicksToArriveAt(Vector3 target, short speed) - { - return (int)(Vector2.Distance(Position.ToVector2(), target.ToVector2()) * 1000 / speed); - } - - /// - /// Walk to a certain spot at a given speed. - /// - /// - /// - /// - /// - [Obsolete("Use .PathTo instead")] - public void WalkTo(float targetX, float targetY, float targetZ, short speed) - { - WalkTo(new Vector3(targetX, targetY, targetZ), speed); - } + [Obsolete("Use WalkTo(Coordinate, short) instead!")] + public virtual void WalkTo(int targetX, int targetY, int targetZ, short speed) + => WalkTo(Coordinate.Create(x: targetX, y: targetY, z: targetZ ), speed); /// /// Walk to a certain spot at a given speed. /// - /// + /// /// - public virtual void WalkTo(Vector3 target, short speed) + public virtual void WalkTo(Coordinate destination, short speed) { if (IsTurningDisabled) return; @@ -1502,17 +1436,18 @@ public virtual void WalkTo(Vector3 target, short speed) if (speed <= 0) return; - if (IsWithinRadius(target, CONST_WALKTOTOLERANCE)) - { + Motion = Motion.Create(Position, destination, speed); - // No need to start walking. - TargetPosition = target; - Position = target; + if ((int)Motion.RemainingDistance == 0) + { _OnArrivedAtTarget(); return; } + + CancelWalkToTimer(); - _StartWalk(target, speed); + Notify(GameNPCEvent.WalkTo, this, new WalkToEventArgs(destination, speed)); + StartArriveAtTargetAction((int)(Motion.RemainingDistance * 1000 / speed)); } private void StartArriveAtTargetAction(int requiredTicks) @@ -1558,9 +1493,9 @@ public virtual void WalkToSpawn(short speed) IsResetting = true; IsReturningHome = true; if (TPPoint != null) - PathTo(new Vector3((float)TPPoint.Position.X, (float)TPPoint.Position.Y, (float)TPPoint.Position.Z), speed); + PathTo(TPPoint.Position.Coordinate, speed); else - PathTo(SpawnPoint, speed); + PathTo(SpawnPosition.Coordinate, speed); } /// @@ -1572,9 +1507,9 @@ public virtual void WalkToSpawn(short speed) /// Finds a valid path to the destination (or picks the direct path otherwise). Uses WalkTo for each of the pathing nodes. /// /// true if a path was found - public void PathTo(float destX, float destY, float destZ, short? speed = null) + public void PathTo(int destX, int destY, int destZ, short speed) { - PathTo(new Vector3(destX, destY, destZ), speed); + PathTo(Coordinate.Create(destX, destY, destZ), speed); } /// /// Finds a valid path to the destination (or picks the direct path otherwise). Uses WalkTo for each of the pathing nodes. @@ -1582,59 +1517,46 @@ public void PathTo(float destX, float destY, float destZ, short? speed = null) /// /// /// true if a path was found - public void PathTo(Vector3 dest, short? speed = null) + public void PathTo(Coordinate destination, short speed) { - if (dest == Position) - return; - if (IsTurningDisabled) - return; - - short walkSpeed = speed ?? MaxSpeed; - if (walkSpeed > MaxSpeed) - walkSpeed = MaxSpeed; - if (walkSpeed <= 0) - return; - if (!PathCalculator.ShouldPath(this, dest)) + if (!PathCalculator.ShouldPath(this, destination)) { - WalkTo(dest, walkSpeed); + WalkTo(destination, speed); return; } + // Initialize pathing if possible and required if (PathCalculator == null) { if (!PathCalculator.IsSupported(this)) { - WalkTo(dest, walkSpeed); + WalkTo(destination, speed); return; } - // TODO: Only make this check once on spawn since it internally calls .CurrentZone + hashtable lookup? PathCalculator = new PathCalculator(this); - PathCalculator.VisualizePath = DebugMode; } - DebugSend("PathTo({0}, {1})", dest, walkSpeed); - - Interlocked.Increment(ref Statistics.PathToCalls); - // Pick the next pathing node, and walk towards it - var (nextNode, reason) = PathCalculator.CalculateNextTarget(dest); - var shouldUseAirPath = reason == NoPathReason.RECAST_FOUND_NO_PATH; + var nextMotionTarget = Coordinate.Nowhere; - if (!nextNode.HasValue) + if (PathCalculator != null) { - // Directly walk towards the target (or call the customly provided action) - if (shouldUseAirPath) - WalkTo(dest, walkSpeed); + nextMotionTarget = PathCalculator.CalculateNextLineSegment(destination); + } + + // Directly walk towards the target (or call the customly provided action) + if (nextMotionTarget.Equals(Coordinate.Nowhere)) + { + WalkTo(destination, speed); return; } - Notify(GameNPCEvent.WalkTo, this, new WalkToEventArgs(dest, walkSpeed)); // Do the actual pathing bit: Walk towards the next pathing node - _WalkToPathNode(nextNode.Value, walkSpeed); + WalkTo(nextMotionTarget, speed, npc => npc.PathTo(destination, speed)); } - - private void _WalkToPathNode(Vector3 node, short speed) + + private void WalkTo(Coordinate destination, short speed, Action goToNextNodeCallback) { if (IsTurningDisabled) return; @@ -1645,71 +1567,26 @@ private void _WalkToPathNode(Vector3 node, short speed) if (speed <= 0) return; - _StartWalk(node, speed); + Motion = Geometry.Motion.Create(Position, destination, speed); - _StartArriveAtPathNodeAction(GetTicksToArriveAt(node, speed)); - - } - - private void _StartWalk(Vector3 target, short speed) - { - CancelWalkToTimer(); - - if (IsMoving) + if ((int)Motion.RemainingDistance == 0) { - Position = Position; + goToNextNodeCallback(this); + return; } - m_Heading = GetHeading(target); - TargetPosition = target; - CurrentSpeed = speed; - MovementStartTick = GameTimer.GetTickCount(); - - UpdateTickSpeed(); - StartArriveAtTargetAction(GetTicksToArriveAt(TargetPosition, speed)); - BroadcastUpdate(); - } - private ArriveAtPathNodeAction _arriveAtPathNodeAction; - private void _StartArriveAtPathNodeAction(int requiredTicks) - { CancelWalkToTimer(); - var action = new ArriveAtPathNodeAction(this); - action.Start(Math.Max(1,requiredTicks)); - _arriveAtPathNodeAction = action; - } - private class ArriveAtPathNodeAction : RegionAction - { - public ArriveAtPathNodeAction(GameObject actionSource) : base(actionSource) - { - } - protected override void OnTick() - { - var npc = (GameNPC)m_actionSource; - npc.DebugSend("calculate next node..." + npc.MovementElapsedTicks + " / " + (uint)(Vector3.Distance(npc._basePosition, npc.TargetPosition) * 1000 / npc.CurrentSpeed)); - // Pick the next pathing node, and walk towards it - var (nextNode, _reason) = npc.PathCalculator.CalculateNextTarget(); - if (!nextNode.HasValue) - { - // Directly walk towards the target (or call the customly provided action) - npc.WalkTo(npc.TargetPosition, npc.CurrentSpeed); - return; - } - npc.DebugSend("Next target for {0} is {1}", npc.TargetPosition, nextNode.Value); - // Do the actual pathing bit: Walk towards the next pathing node - npc._WalkToPathNode(nextNode.Value, npc.CurrentSpeed); - } + StartArriveAtTargetAction((int)(Motion.RemainingDistance * 1000 / speed), goToNextNodeCallback); } - /// - /// Clears all remaining elements in our pathing cache. - /// - public void ClearPathingCache() + + private void StartArriveAtTargetAction(int requiredTicks, Action goToNextNodeCallback = null) { - PathCalculator?.Clear(); + m_arriveAtTargetAction = new ArriveAtTargetAction(this, goToNextNodeCallback); + m_arriveAtTargetAction.Start((requiredTicks > 1) ? requiredTicks : 1); } - /// /// Gets the NPC current follow target /// @@ -1728,42 +1605,12 @@ public void StopMoving() if (IsMoving) { - if (MovementElapsedTicks > (Vector3.Distance(_basePosition, TargetPosition) * 1000 / CurrentSpeed)) - { - Position = TargetPosition; - } - else - Position = _basePosition + MovementElapsedTicks * Velocity; + CurrentSpeed = 0; } if (wasResetting) { Reset(); } - else - { - MovementStartTick = GameTimer.GetTickCount(); - TargetPosition = Vector3.Zero; - CurrentSpeed = 0; - } - BroadcastUpdate(); - } - - protected override void UpdateTickSpeed(Vector3? target = null) - { - if (CurrentSpeed == 0) - { - base.UpdateTickSpeed(target); - return; - } - - if ((target ?? TargetPosition) == Vector3.Zero) - { - CurrentSpeed = 0; - return; - } - - Heading = GetHeading(target ?? TargetPosition); - base.UpdateTickSpeed(target ?? TargetPosition); } public override void UpdateMaxSpeed() @@ -1775,7 +1622,6 @@ public override void UpdateMaxSpeed() { Position = Position; CurrentSpeed = MaxSpeed; - BroadcastUpdate(); } } @@ -1836,8 +1682,8 @@ public virtual void FollowTargetInRange() else if (m_attackers.Count == 0 && this.Spells.Count > 0 && this.TargetObject != null && GameServer.ServerRules.IsAllowedToAttack(this, (this.TargetObject as GameLiving), true)) { if (TargetObject.Realm == 0 || Realm == 0) - m_lastAttackTickPvE = m_CurrentRegion.Time; - else m_lastAttackTickPvP = m_CurrentRegion.Time; + m_lastAttackTickPvE = CurrentRegion.Time; + else m_lastAttackTickPvP = CurrentRegion.Time; if (this.CurrentRegion.Time - LastAttackedByEnemyTick > 5 * 1000) { // Aredhel: Erm, checking for spells in a follow method, what did we create @@ -1880,13 +1726,9 @@ protected virtual int FollowTimerCallback(RegionTimer callingTimer) Notify(GameNPCEvent.FollowLostTarget, this, new FollowLostTargetEventArgs(followTarget)); return 0; } - - //Calculate the difference between our position and the players position - var diff = followTarget.Position - Position; - - //SH: Removed Z checks when one of the two Z values is zero(on ground) - //Tolakram: a Z of 0 does not indicate on the ground. Z varies based on terrain Removed 0 Z check - float distance = diff.Length(); + + var diffVec = followTarget.Coordinate - Coordinate; + var distance = diffVec.Length; //if distance is greater then the max follow distance, stop following and return home if ((int)distance > m_followMaxDist) @@ -1896,7 +1738,6 @@ protected virtual int FollowTimerCallback(RegionTimer callingTimer) Reset(); return 0; } - float newX, newY, newZ; if (this.Brain is StandardMobBrain) { @@ -1920,14 +1761,10 @@ protected virtual int FollowTimerCallback(RegionTimer callingTimer) } } } - - //If we're part of a formation, we can get out early. - newX = followTarget.Position.X; - newY = followTarget.Position.Y; - newZ = followTarget.Position.Z; - if (brain.CheckFormation(ref newX, ref newY, ref newZ)) + var formationCoordinate = brain.GetFormationCoordinate(followTarget.Coordinate); + if (formationCoordinate != Coordinate.Nowhere) { - PathTo(newX, newY, (ushort)newZ, MaxSpeed); + WalkTo(formationCoordinate, MaxSpeed); return ServerProperties.Properties.GAMENPC_FOLLOWCHECK_TIME; } } @@ -1953,14 +1790,19 @@ protected virtual int FollowTimerCallback(RegionTimer callingTimer) } // follow on distance - diff = (diff / distance) * m_followMinDist; - + var distanceFactor = m_followMinDist / distance; + var followOffset = diffVec * distanceFactor; + //Subtract the offset from the target's position to get //our target position + var destination = followTarget.Coordinate - followOffset; if (InCombat || Brain is BomberBrain || !IsWithinRadius(followTarget, MaxSpeed)) - PathTo(followTarget.Position - diff, MaxSpeed); + PathTo(destination, MaxSpeed); else - PathTo(followTarget.Position - diff, (short)((followLiving?.CurrentSpeed ?? 0) + 50)); + { + var speed = (short)Coordinate.DistanceTo(destination, ignoreZ: true); + PathTo(destination, speed); + } return ServerProperties.Properties.GAMENPC_FOLLOWCHECK_TIME; } @@ -2034,7 +1876,7 @@ public void MoveOnPath(short speed) PathingNormalSpeed = speed; - if (this.IsWithinRadius(CurrentWayPoint.Position, 100)) + if (this.IsWithinRadius(CurrentWayPoint.Coordinate, 100)) { // reaching a waypoint can start an ambient sentence FireAmbientSentence(eAmbientTrigger.moving); @@ -2053,7 +1895,7 @@ public void MoveOnPath(short speed) if (CurrentWayPoint != null) { GameEventMgr.AddHandler(this, GameNPCEvent.ArriveAtTarget, OnArriveAtWaypoint); - PathTo(CurrentWayPoint.Position, Math.Min(speed, (short)CurrentWayPoint.MaxSpeed)); + PathTo(CurrentWayPoint.Coordinate, Math.Min(speed, (short)CurrentWayPoint.MaxSpeed)); m_IsMovingOnPath = true; Notify(GameNPCEvent.PathMoveStarts, this); } @@ -2163,7 +2005,7 @@ protected override void OnTick() if (npc.CurrentWayPoint != null) { - npc.PathTo(npc.CurrentWayPoint.Position, (short)Math.Min(npc.PathingNormalSpeed, npc.CurrentWayPoint.MaxSpeed)); + npc.PathTo(npc.CurrentWayPoint.Coordinate, (short)Math.Min(npc.PathingNormalSpeed, npc.CurrentWayPoint.MaxSpeed)); } else { @@ -2288,12 +2130,10 @@ public override void LoadFromDatabase(DataObject obj) GuildName = dbMob.Guild; ExamineArticle = dbMob.ExamineArticle; MessageArticle = dbMob.MessageArticle; - Position = new Vector3(dbMob.X, dbMob.Y, dbMob.Z); - m_Heading = (ushort)(dbMob.Heading & 0xFFF); + Position = Position.Create(dbMob.Region, dbMob.X, dbMob.Y, dbMob.Z, dbMob.Heading); m_maxSpeedBase = (short)dbMob.Speed; m_currentSpeed = 0; m_tension = 0; - CurrentRegionID = dbMob.Region; Realm = (eRealm)dbMob.Realm; Model = dbMob.Model; Size = dbMob.Size; @@ -3011,7 +2851,7 @@ public virtual bool RiderMount(GamePlayer rider, bool forced) if (exists != -1) return false; - rider.MoveTo(CurrentRegionID, Position, Heading); + rider.MoveTo(Position); Notify(GameNPCEvent.RiderMount, this, new RiderMountEventArgs(rider, this)); int slot = GetFreeArrayLocation(); @@ -3164,16 +3004,6 @@ public GamePlayer[] CurrentRiders #region Add/Remove/Create/Remove/Update - /// - /// Broadcasts the NPC Update to all players around - /// - public override void BroadcastUpdate() - { - base.BroadcastUpdate(); - - m_lastUpdateTickCount = GameTimer.GetTickCount(); - } - /// /// callback that npc was updated to the world /// so it must be visible to at least one player @@ -3232,8 +3062,7 @@ public override bool AddToWorld() if (anyPlayer) m_lastVisibleToPlayerTick = GameTimer.GetTickCount(); - m_spawnPoint = Position; - m_spawnHeading = Heading; + SpawnPosition = Position; lock (BrainSync) { ABrain brain = Brain; @@ -3280,7 +3109,7 @@ public override bool AddToWorld() m_teleporterIndicator.Flags ^= eFlags.CANTTARGET; m_teleporterIndicator.Flags ^= eFlags.DONTSHOWNAME; m_teleporterIndicator.Flags ^= eFlags.FLYING; - m_teleporterIndicator.Position = Position + Vector3.UnitZ; + m_teleporterIndicator.Position = Position + Vector.Create(z: 1); m_teleporterIndicator.CurrentRegionID = CurrentRegionID; } @@ -3341,8 +3170,7 @@ public virtual bool Spawn() Health = MaxHealth; Mana = MaxMana; Endurance = MaxEndurance; - Position = m_spawnPoint; - Heading = m_spawnHeading; + Position = SpawnPosition; Tension = 0; ambientXNbUse = new Dictionary(); @@ -3359,14 +3187,14 @@ public virtual void Reset() //If the Mob has a Path assigned he will now walk on it! if (PathID != null && PathID != "" && PathID != "NULL") { - if (!IsMovingOnPath && (CurrentWayPoint == null || !this.IsWithinRadius(CurrentWayPoint.Position, GameNPC.CONST_WALKTOTOLERANCE))) + if (!IsMovingOnPath && (CurrentWayPoint == null || !this.IsWithinRadius(CurrentWayPoint.Coordinate, GameNPC.CONST_WALKTOTOLERANCE))) { IsResetting = true; IsReturningHome = true; PathPoint path = MovementMgr.LoadPath(PathID); if (path != null) { - var p = path.GetNearestNextPoint(Position); + var p = path.GetNearestNextPoint(Position.Coordinate); CurrentWayPoint = p; MoveOnPath((short)p.MaxSpeed); } @@ -3378,7 +3206,7 @@ public virtual void Reset() //Tolerance to check if we need to go home AGAIN, otherwise we might be told to go home //for a few units only and this may end before the next Arrive-At-Target Event is fired and in this case //We would never lose the state "IsReturningHome", which is then followed by other erros related to agro again to players - else if (!Util.IsNearDistance(Position, SpawnPoint, GameNPC.CONST_WALKTOTOLERANCE)) + else if (!IsWithinRadius(SpawnPosition.Coordinate, GameNPC.CONST_WALKTOTOLERANCE)) { WalkToSpawn(); return; @@ -3388,12 +3216,13 @@ public virtual void Reset() if (AttackState) StopAttack(); - MovementStartTick = GameTimer.GetTickCount(); - TargetPosition = Vector3.Zero; CurrentSpeed = 0; - if (Heading != m_spawnHeading) - TurnTo(m_spawnHeading); + if (Orientation != SpawnPosition.Orientation) + TurnTo(SpawnPosition.Orientation); + + IsReturningHome = false; + IsResetting = false; Notify(GameNPCEvent.NPCReset, this, EventArgs.Empty); } @@ -3446,6 +3275,10 @@ public override bool RemoveFromWorld() return true; } + + [Obsolete("Use MoveWithoutRemovingFromWorld(Position,bool) instead!")] + public virtual bool MoveInRegion(ushort regionID, int x, int y, int z, ushort heading, bool forceMove) + => MoveWithoutRemovingFromWorld(Position.Create(regionID, x, y, z, heading), forceMove); /// /// Move an NPC within the same region without removing from world @@ -3457,13 +3290,13 @@ public override bool RemoveFromWorld() /// /// Move regardless of combat check /// true if npc was moved - public virtual bool MoveInRegion(ushort regionID, float x, float y, float z, ushort heading, bool forceMove) + public virtual bool MoveWithoutRemovingFromWorld(Position destination, bool forceMove) { if (m_ObjectState != eObjectState.Active) return false; // pets can't be moved across regions - if (regionID != CurrentRegionID) + if (destination.RegionID != CurrentRegionID) return false; if (forceMove == false) @@ -3479,14 +3312,14 @@ public virtual bool MoveInRegion(ushort regionID, float x, float y, float z, ush return false; } - Region rgn = WorldMgr.GetRegion(regionID); + Region rgn = WorldMgr.GetRegion(destination.RegionID); - if (rgn == null || rgn.GetZone(x, y) == null) + if (rgn == null || rgn.GetZone(destination.Coordinate) == null) return false; // For a pet move simple erase the pet from all clients and redraw in the new location - Notify(GameObjectEvent.MoveTo, this, new MoveToEventArgs(regionID, x, y, z, heading)); + Notify(GameObjectEvent.MoveTo, this, new MoveToEventArgs(destination.RegionID, destination.X, destination.Y, destination.Z, destination.Orientation.InHeading)); if (ObjectState == eObjectState.Active) { @@ -3496,8 +3329,7 @@ public virtual bool MoveInRegion(ushort regionID, float x, float y, float z, ush } } - Position = new Vector3(x, y, z); - m_Heading = heading; + Position = destination; foreach (GamePlayer player in GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE)) { @@ -3514,18 +3346,15 @@ public virtual bool MoveInRegion(ushort regionID, float x, float y, float z, ush return true; } - /// - /// Gets or Sets the current Region of the Object - /// - public override Region CurrentRegion + public override Position Position { - get { return base.CurrentRegion; } + get { return base.Position; } set { - Region oldRegion = CurrentRegion; - base.CurrentRegion = value; - Region newRegion = CurrentRegion; - if (oldRegion != newRegion && newRegion != null) + var oldRegionID = Position.RegionID; + base.Position = value; + var newRegion = value.RegionID; + if (oldRegionID != newRegion && newRegion != 0) { if (m_followTimer != null) m_followTimer.Stop(); m_followTimer = new RegionTimer(this); @@ -4301,9 +4130,9 @@ public void NPCStopRangedAttackCheckLOS(GamePlayer player, ushort response, usho public void SetLastMeleeAttackTick() { if (TargetObject.Realm == 0 || Realm == 0) - m_lastAttackTickPvE = m_CurrentRegion.Time; + m_lastAttackTickPvE = CurrentRegion.Time; else - m_lastAttackTickPvP = m_CurrentRegion.Time; + m_lastAttackTickPvP = CurrentRegion.Time; } private void StartMeleeAttackTimer() @@ -5161,8 +4990,6 @@ public virtual void DropLoot(GameObject killer) loot = new WorldInventoryItem(invitem); loot.Position = Position; - loot.Heading = Heading; - loot.CurrentRegion = CurrentRegion; (loot as WorldInventoryItem).Item.IsCrafted = false; (loot as WorldInventoryItem).Item.Creator = Name; @@ -6031,7 +5858,7 @@ public override void Notify(DOLEvent e, object sender, EventArgs args) { if (IsReturningHome) { - TurnTo(SpawnHeading); + TurnTo(SpawnPosition.Orientation); IsReturningHome = false; } } @@ -6360,13 +6187,13 @@ public void FireAmbientSentence(eAmbientTrigger trigger, GameLiving living = nul if (TPPoint.DbTPPoint.ObjectId != newTPPoint.DbTPPoint.ObjectId) { TPPoint = newTPPoint; - MoveTo(TPPoint.Region, (float)TPPoint.Position.X, (float)TPPoint.Position.Y, (float)TPPoint.Position.Z, TPPoint.GetHeading(TPPoint)); + MoveTo(TPPoint.Position); } } else { TPPoint = TeleportMgr.LoadTP(chosen.MobtoTPpoint); - MoveTo(TPPoint.Region, (float)TPPoint.Position.X, (float)TPPoint.Position.Y, (float)TPPoint.Position.Z, TPPoint.GetHeading(TPPoint)); + MoveTo(TPPoint.Position); } } @@ -6382,13 +6209,13 @@ public void FireAmbientSentence(eAmbientTrigger trigger, GameLiving living = nul if (TPPoint.DbTPPoint.ObjectId != newTPPoint.DbTPPoint.ObjectId) { TPPoint = newTPPoint; - living.MoveTo(TPPoint.Region, (float)TPPoint.Position.X, (float)TPPoint.Position.Y, (float)TPPoint.Position.Z, TPPoint.GetHeading(TPPoint)); + MoveTo(TPPoint.Position); } } else { TPPoint = TeleportMgr.LoadTP(chosen.PlayertoTPpoint); - living.MoveTo(TPPoint.Region, (float)TPPoint.Position.X, (float)TPPoint.Position.Y, (float)TPPoint.Position.Z, TPPoint.GetHeading(TPPoint)); + MoveTo(TPPoint.Position); } } @@ -6415,7 +6242,7 @@ public void FireAmbientSentence(eAmbientTrigger trigger, GameLiving living = nul // broadcasted , yelled or talked ? if (chosen.Voice.StartsWith("b")) { - foreach (GamePlayer player in CurrentRegion.GetPlayersInRadius(Position, 25000, false, false)) + foreach (GamePlayer player in CurrentRegion.GetPlayersInRadius(Coordinate, 25000, false, false)) { player.Out.SendMessage(text, eChatType.CT_Broadcast, eChatLoc.CL_ChatWindow); } @@ -6570,7 +6397,6 @@ public GameNPC Copy(GameNPC copyTarget) copyTarget.CanUseLefthandedWeapon = CanUseLefthandedWeapon; copyTarget.Charisma = Charisma; copyTarget.Constitution = Constitution; - copyTarget.CurrentRegion = CurrentRegion; copyTarget.Dexterity = Dexterity; copyTarget.Empathy = Empathy; copyTarget.Endurance = Endurance; @@ -6581,7 +6407,6 @@ public GameNPC Copy(GameNPC copyTarget) copyTarget.GuildName = GuildName; copyTarget.ExamineArticle = ExamineArticle; copyTarget.MessageArticle = MessageArticle; - copyTarget.Heading = Heading; copyTarget.Intelligence = Intelligence; copyTarget.IsCloakHoodUp = IsCloakHoodUp; copyTarget.IsCloakInvisible = IsCloakInvisible; @@ -6695,7 +6520,6 @@ public GameNPC(ABrain defaultBrain) : base() m_followTarget = new WeakRef(null); m_size = 50; //Default size - TargetPosition = Vector3.Zero; m_followMinDist = 100; m_followMaxDist = 3000; m_flags = 0; diff --git a/GameServer/gameobjects/GameObject.cs b/GameServer/gameobjects/GameObject.cs index 87a78f4f..6e59c7de 100644 --- a/GameServer/gameobjects/GameObject.cs +++ b/GameServer/gameobjects/GameObject.cs @@ -25,6 +25,7 @@ using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.Language; using DOL.GS.Quests; using DOL.GS.Housing; @@ -33,7 +34,6 @@ using DOL.GS.Utils; using log4net; -using System.Numerics; namespace DOL.GS { @@ -99,55 +99,30 @@ public virtual eObjectState ObjectState #region Position - private Vector3 _position = Vector3.Zero; - public virtual Vector3 Position + public virtual Position Position { - get => _position; - set => _position = value; - } + get; + set; + } = Position.Nowhere; - [Obsolete("use Position.X")] - public float X - { - get => Position.X; - set => Position = new System.Numerics.Vector3(value, Position.Y, Position.Z); - } - [Obsolete("use Position.Y")] - public float Y + public Coordinate Coordinate { - get => Position.Y; - set => Position = new System.Numerics.Vector3(Position.X, value, Position.Z); + get => Position.Coordinate; } - [Obsolete("use Position.Z")] - public float Z + + public virtual Angle Orientation { - get => Position.Z; - set => Position = new System.Numerics.Vector3(Position.X, Position.Y, value); + get => Position.Orientation; + set => Position = Position.With(value); } - - /// - /// The Object's current Region - /// - protected Region m_CurrentRegion; - - /// - /// The direction the Object is facing - /// - protected ushort m_Heading; - - /// - /// Holds the realm of this object - /// - protected eRealm m_Realm; - /// - /// Gets or Sets the current Realm of the Object + /// Current direction the Object is facing /// - public virtual eRealm Realm + public virtual ushort Heading { - get { return m_Realm; } - set { m_Realm = value; } + get => Position.Orientation.InHeading; + set => Orientation = Angle.Heading(value); } /// @@ -155,28 +130,8 @@ public virtual eRealm Realm /// public virtual Region CurrentRegion { - get { return m_CurrentRegion; } - set { m_CurrentRegion = value; } - } - - protected string m_ownerID; - - /// - /// Gets or sets the owner ID for this object - /// - public virtual string OwnerID - { - get { return m_ownerID; } - set - { - m_ownerID = value; - } - } - - public bool CanRespawnWithinEvent - { - get; - set; + get => Position.Region; + set => Position = Position.With(regionID: value?.ID ?? 0); } /// @@ -184,10 +139,10 @@ public bool CanRespawnWithinEvent /// public virtual ushort CurrentRegionID { - get { return m_CurrentRegion == null ? (ushort)0 : m_CurrentRegion.ID; } + get => Position.RegionID; set { - CurrentRegion = WorldMgr.GetRegion(value); + Position = Position.With(regionID: value); } } @@ -196,23 +151,7 @@ public virtual ushort CurrentRegionID /// public Zone CurrentZone { - get - { - if (m_CurrentRegion != null) - { - return m_CurrentRegion.GetZone(Position); - } - return null; - } - } - - /// - /// Gets the current direction the Object is facing - /// - public virtual ushort Heading - { - get { return m_Heading; } - set { m_Heading = (ushort)(value & 0xFFF); } + get => CurrentRegion?.GetZone(Coordinate); } /// @@ -224,39 +163,61 @@ public virtual ushort Heading /// Target /// /// Adjusted distance or int.MaxValue if distance cannot be calculated - public float GetDistanceTo(GameObject obj, float Zfactor) + public float GetDistanceTo(GameObject obj, float zFactor = 1.0f) => GetDistanceTo(obj.Position, zFactor); + + public float GetDistanceTo(Position position, float zFactor) { - if (CurrentRegionID != obj?.CurrentRegionID) + if (Position.RegionID != position.RegionID) + { return float.MaxValue; - var diff = Position - obj.Position; - return (float)Math.Sqrt(diff.X * diff.X + diff.Y * diff.Y + diff.Z * diff.Z * Zfactor); + } + var offset = position.Coordinate - Coordinate; + var dz = offset.Z * zFactor; + return (float)(offset.Length2D + Math.Sqrt(dz*dz)); } - public float GetDistanceTo(GameObject obj) + public float GetDistance2DTo(Position position) { - if (CurrentRegionID == obj?.CurrentRegionID) - return Vector3.Distance(Position, obj.Position); - return float.MaxValue; + if (Position.RegionID != position.RegionID) + { + return float.MaxValue; + } + var offset = position.Coordinate - Coordinate; + return (float)(offset.Length2D); } - public float GetDistanceSquaredTo(GameObject obj) + public float GetDistance2DTo(GameObject obj) => GetDistance2DTo(obj.Position); + + public float GetDistanceSquaredTo(Position position, float zFactor) { - if (CurrentRegionID == obj?.CurrentRegionID) - return Vector3.DistanceSquared(Position, obj.Position); - return float.MaxValue; + if (Position.RegionID != position.RegionID) + { + return float.MaxValue; + } + var offset = position.Coordinate - Coordinate; + var dz = offset.Z * zFactor; + return (float)(offset.X * offset.X + offset.Y * offset.Y + dz * dz); } - public float GetDistanceTo(Vector3 target) => Vector3.Distance(Position, target); - public float GetDistance2DTo(Vector3 target) => Vector2.Distance(Position.ToVector2(), target.ToVector2()); + public float GetDistanceSquaredTo(GameObject obj) + { + if (Position.RegionID != obj.CurrentRegionID) + { + return float.MaxValue; + } + var offset = obj.Coordinate - Coordinate; + return (float)(offset.X * offset.X + offset.Y * offset.Y); + } + + public bool IsWithinRadius(Position target, float distance) => Position.Region == this.CurrentRegion && GameMath.IsWithinRadius(Coordinate, target.Coordinate, distance); public bool IsWithinRadius(GameObject target, float distance) => GameMath.IsWithinRadius(this, target, distance); - public bool IsWithinRadius(Vector3 target, float distance) => GameMath.IsWithinRadius(this, target, distance); + public bool IsWithinRadius(Coordinate target, float distance) => GameMath.IsWithinRadius(Position.Coordinate, target, distance); public bool IsWithinRadius2D(GameObject target, float distance) => GameMath.IsWithinRadius2D(this, target, distance); - public bool IsWithinRadius2D(Vector3 target, float distance) => GameMath.IsWithinRadius2D(this, target, distance); - public Vector2 GetPointFromHeading(ushort heading, float distance) => GameMath.GetPointFromHeading(Position, heading, distance); - public ushort GetHeading(GameObject target) => GameMath.GetHeading(Position, target.Position); - public ushort GetHeading(Vector3 target) => GameMath.GetHeading(Position, target); - public ushort GetHeading(Vector2 target) => GameMath.GetHeading(Position, target); - + public ushort GetHeading(GameObject target) => GetHeading(target.Coordinate); + public ushort GetHeading(Coordinate target) => Position.Coordinate.GetOrientationTo(target).InHeading; + public Angle GetAngleTo(Coordinate coordinate) + => Coordinate.GetOrientationTo(coordinate) - Orientation; + /// /// determines wether a target object is front /// in front is defined as north +- viewangle/2 @@ -269,18 +230,49 @@ public virtual bool IsObjectInFront(GameObject target, double viewangle, bool ra { if (target == null) return false; - float angle = GameMath.GetAngle(Position.ToVector2(), Heading, target.Position.ToVector2()); - if (angle >= 360 - viewangle / 2 || angle < viewangle / 2) - return true; + var angle = GetAngleTo(target.Coordinate); + var isInFront = angle.InDegrees >= 360 - viewangle / 2 || angle.InDegrees < viewangle / 2; + if (isInFront) return true; // Dre: WTF?! This check has nothing to do here! // if target is closer than 32 units it is considered always in view // tested and works this way for normal evade, parry, block (in 1.69) if (rangeCheck) - return Vector3.DistanceSquared(Position, target.Position) <= 32 * 32; + return GetDistanceSquaredTo(target) <= 32 * 32; return false; } + + private static readonly ((int X, int Y) BottomLeft, (int X, int Y) TopRight)[] hardcodedUnderWaterAreas = new[] + { + // Mount Collory + ((479000,664000),(488000,670000)), + ((472000,656000),(488000,664000)), + ((468500,624000),(488000,654000)), + ((431000,659000),(466000,683000)), + ((431000,646000),(460000,659001)), + ((431000,624000),(455000,646001)), + ((431000,671000),(471000,683000)), + // Breifine + ((456000,558000),(479000,618000)), + // Cruachan Gorge + ((360000,586000),(424000,618000)), + ((360000,563000),(424000,578000)), + // Emain Macha + ((428000,505000),(444000,555000)), + // Hadrian's Wall + ((603000,500000),(620000,553000)), + // Snowdonia + ((592000,633000),(617000,678000)), + ((581000,662000),(617000,678000)), + // Sauvage Forrest + ((626000,584000),(681000,615000)), + // Uppland + ((610000,297000),(652000,353000)), + // Yggdra + ((671000,408000),(693000,421000)), + ((674000,364000),(716000,394000)) + }; /// /// Checks if object is underwater @@ -294,33 +286,16 @@ public virtual bool IsUnderwater // Special land areas below the waterlevel in NF if (CurrentRegion.ID == 163) { - // Mount Collory - if ((Position.Y > 664000) && (Position.Y < 670000) && (Position.X > 479000) && (Position.X < 488000)) return false; - if ((Position.Y > 656000) && (Position.Y < 664000) && (Position.X > 472000) && (Position.X < 488000)) return false; - if ((Position.Y > 624000) && (Position.Y < 654000) && (Position.X > 468500) && (Position.X < 488000)) return false; - if ((Position.Y > 659000) && (Position.Y < 683000) && (Position.X > 431000) && (Position.X < 466000)) return false; - if ((Position.Y > 646000) && (Position.Y < 659001) && (Position.X > 431000) && (Position.X < 460000)) return false; - if ((Position.Y > 624000) && (Position.Y < 646001) && (Position.X > 431000) && (Position.X < 455000)) return false; - if ((Position.Y > 671000) && (Position.Y < 683000) && (Position.X > 431000) && (Position.X < 471000)) return false; - // Breifine - if ((Position.Y > 558000) && (Position.Y < 618000) && (Position.X > 456000) && (Position.X < 479000)) return false; - // Cruachan Gorge - if ((Position.Y > 586000) && (Position.Y < 618000) && (Position.X > 360000) && (Position.X < 424000)) return false; - if ((Position.Y > 563000) && (Position.Y < 578000) && (Position.X > 360000) && (Position.X < 424000)) return false; - // Emain Macha - if ((Position.Y > 505000) && (Position.Y < 555000) && (Position.X > 428000) && (Position.X < 444000)) return false; - // Hadrian's Wall - if ((Position.Y > 500000) && (Position.Y < 553000) && (Position.X > 603000) && (Position.X < 620000)) return false; - // Snowdonia - if ((Position.Y > 633000) && (Position.Y < 678000) && (Position.X > 592000) && (Position.X < 617000)) return false; - if ((Position.Y > 662000) && (Position.Y < 678000) && (Position.X > 581000) && (Position.X < 617000)) return false; - // Sauvage Forrest - if ((Position.Y > 584000) && (Position.Y < 615000) && (Position.X > 626000) && (Position.X < 681000)) return false; - // Uppland - if ((Position.Y > 297000) && (Position.Y < 353000) && (Position.X > 610000) && (Position.X < 652000)) return false; - // Yggdra - if ((Position.Y > 408000) && (Position.Y < 421000) && (Position.X > 671000) && (Position.X < 693000)) return false; - if ((Position.Y > 364000) && (Position.Y < 394000) && (Position.X > 674000) && (Position.X < 716000)) return false; + foreach(var area in hardcodedUnderWaterAreas) + { + if(Coordinate.X > area.BottomLeft.X + && Coordinate.Y > area.BottomLeft.Y + && Coordinate.X < area.TopRight.X + && Coordinate.Y > area.TopRight.Y) + { + return false; + } + } } return Position.Z < CurrentZone.Waterlevel; @@ -334,7 +309,7 @@ public virtual IList CurrentAreas { get { - return CurrentZone?.GetAreasOfSpot(this.Position) ?? new List(); + return CurrentZone?.GetAreasOfSpot(Coordinate) ?? new List(); } set { } } @@ -371,6 +346,40 @@ public virtual bool IsVisibleTo(GameObject checkObject) } #endregion + + /// + /// Holds the realm of this object + /// + protected eRealm m_Realm; + + /// + /// Gets or Sets the current Realm of the Object + /// + public virtual eRealm Realm + { + get { return m_Realm; } + set { m_Realm = value; } + } + + protected string m_ownerID; + + /// + /// Gets or sets the owner ID for this object + /// + public virtual string OwnerID + { + get { return m_ownerID; } + set + { + m_ownerID = value; + } + } + + public bool CanRespawnWithinEvent + { + get; + set; + } #region Level/Name/Model/GetName/GetPronoun/GetExamineMessage @@ -751,9 +760,7 @@ public virtual bool Create(ushort regionID, int x, int y, int z, ushort heading) { if (m_ObjectState == eObjectState.Active) return false; - CurrentRegionID = regionID; - Position = new Vector3(x, y, z); - m_Heading = heading; + Position = Position.Create(regionID, x, y, z, heading); return AddToWorld(); } @@ -766,14 +773,18 @@ public virtual bool AddToWorld() if (!float.IsNormal(Position.X) || !float.IsNormal(Position.Y) || !float.IsNormal(Position.Z)) return false; /****** MODIFIED BY KONIK & WITCHKING *******/ - Zone currentZone = CurrentZone; // CurrentZone checks for null Region. // Should it be the case, currentZone will be null as well. - if (currentZone == null || m_ObjectState == eObjectState.Active) + if (CurrentZone == null || m_ObjectState == eObjectState.Active) + { + log.Error($"AddToWorld: Zone does not exist ({this.GetType()} ID: {InternalID} Coordinate: {Coordinate} Region: {CurrentRegionID})"); return false; + } - if (!m_CurrentRegion.AddObject(this)) + if (!CurrentRegion.AddObject(this)) + { return false; + } Notify(GameObjectEvent.AddToWorld, this); ObjectState = eObjectState.Active; @@ -790,19 +801,15 @@ public virtual bool AddToWorld() /// public virtual bool RemoveFromWorld() { - if (m_CurrentRegion == null || ObjectState != eObjectState.Active) + if (CurrentRegion == null || ObjectState != eObjectState.Active) return false; Notify(GameObjectEvent.RemoveFromWorld, this); ObjectState = eObjectState.Inactive; - m_CurrentRegion.RemoveObject(this); + CurrentRegion.RemoveObject(this); return true; } - /// - /// Move this object to a GameLocation - /// - /// - /// + [Obsolete("Use MoveTo(Position) instead!")] public bool MoveTo(GameLocation loc) { return MoveTo(loc.RegionID, loc.Position.X, loc.Position.Y, loc.Position.Z, loc.Heading); @@ -818,27 +825,34 @@ public bool MoveTo(GameLocation loc) /// new z /// new heading /// true if moved - public virtual bool MoveTo(ushort regionID, float x, float y, float z, ushort heading) + [Obsolete("Use MoveTo(Position) instead!")] + public bool MoveTo(ushort regionID, float x, float y, float z, ushort heading) => MoveTo(Position.Create(regionID, (int)x, (int)y, (int)z, heading)); + + + /// + /// Moves the item from one spot to another spot, possible even + /// over region boundaries + /// + /// New position + /// true if moved + public virtual bool MoveTo(Position position) { - Region rgn = WorldMgr.GetRegion(regionID); + Region? rgn = WorldMgr.GetRegion(position.RegionID); if (rgn == null) return false; - if (rgn.GetZone(x, y) == null) + if (rgn.GetZone(position.Coordinate) == null) return false; if (m_ObjectState == eObjectState.Active) { - Notify(GameObjectEvent.MoveTo, this, new MoveToEventArgs(regionID, x, y, z, heading)); + Notify(GameObjectEvent.MoveTo, this, new MoveToEventArgs(position.RegionID, position.X, position.Y, position.Z, position.Orientation.InHeading)); if (!RemoveFromWorld()) return false; } - - Position = new Vector3(x, y, z); - m_Heading = heading; - CurrentRegionID = regionID; + + Position = position; return AddToWorld(); } - public bool MoveTo(ushort regionID, Vector3 pos, ushort heading) => MoveTo(regionID, pos.X, pos.Y, pos.Z, heading); /// /// Marks this object as deleted! @@ -1060,16 +1074,15 @@ public IEnumerable GetPlayersInRadius(bool useCache, ushort radiusToCheck, bool //Eden - avoid server freeze if (CurrentZone == null) { - if (this is GamePlayer && (this as GamePlayer).Client.Account.PrivLevel < 3 && !(this as GamePlayer).TempProperties.getProperty("isbeingbanned", false)) + if (this is GamePlayer player && player.TempProperties.getProperty("isbeingbanned", false)) { - GamePlayer player = this as GamePlayer; player.TempProperties.setProperty("isbeingbanned", true); player.MoveToBind(); } } else { - return CurrentRegion.GetPlayersInRadius(Position, radiusToCheck, withDistance, ignoreZ); + return CurrentRegion.GetPlayersInRadius(Coordinate, radiusToCheck, withDistance, ignoreZ); } } return new Region.EmptyEnumerator(); @@ -1118,18 +1131,17 @@ public IEnumerable GetNPCsInRadius(bool useCache, ushort radiusToCheck, bool wit if (CurrentRegion != null) { //Eden - avoid server freeze - if (CurrentRegion.GetZone(Position) == null) + if (CurrentZone == null) { - if (this is GamePlayer && !(this as GamePlayer).TempProperties.getProperty("isbeingbanned", false)) + if (this is GamePlayer player && player.TempProperties.getProperty("isbeingbanned", false)) { - GamePlayer player = this as GamePlayer; player.TempProperties.setProperty("isbeingbanned", true); player.MoveToBind(); } } else { - IEnumerable result = CurrentRegion.GetNPCsInRadius(Position, radiusToCheck, withDistance, ignoreZ); + IEnumerable result = CurrentRegion.GetNPCsInRadius(Coordinate, radiusToCheck, withDistance, ignoreZ); return result; } } @@ -1161,18 +1173,17 @@ public IEnumerable GetItemsInRadius(ushort radiusToCheck, bool withDistance) if (CurrentRegion != null) { //Eden - avoid server freeze - if (CurrentRegion.GetZone(Position) == null) + if (CurrentZone == null) { - if (this is GamePlayer && !(this as GamePlayer).TempProperties.getProperty("isbeingbanned", false)) + if (this is GamePlayer player && player.TempProperties.getProperty("isbeingbanned", false)) { - GamePlayer player = this as GamePlayer; player.TempProperties.setProperty("isbeingbanned", true); player.MoveToBind(); } } else { - return CurrentRegion.GetItemsInRadius(Position, radiusToCheck, withDistance); + return CurrentRegion.GetItemsInRadius(Coordinate, radiusToCheck, withDistance); } } return new Region.EmptyEnumerator(); @@ -1200,18 +1211,17 @@ public IEnumerable GetDoorsInRadius(ushort radiusToCheck, bool withDistance) if (CurrentRegion != null) { //Eden : avoid server freeze - if (CurrentRegion.GetZone(Position) == null) + if (CurrentZone == null) { - if (this is GamePlayer && !(this as GamePlayer).TempProperties.getProperty("isbeingbanned", false)) + if (this is GamePlayer player && player.TempProperties.getProperty("isbeingbanned", false)) { - GamePlayer player = this as GamePlayer; player.TempProperties.setProperty("isbeingbanned", true); player.MoveToBind(); } } else { - return CurrentRegion.GetDoorsInRadius(Position, radiusToCheck, withDistance); + return CurrentRegion.GetDoorsInRadius(Coordinate, radiusToCheck, withDistance); } } return new Region.EmptyEnumerator(); @@ -1320,7 +1330,7 @@ public override string ToString() .Append(" oid=").Append(ObjectID.ToString()) .Append(" state=").Append(ObjectState.ToString()) .Append(" reg=").Append(reg == null ? "null" : reg.ID.ToString()) - .Append(" loc=").Append(Position.X.ToString("F0")).Append(',').Append(Position.Y.ToString("F0")).Append(',').Append(Position.Z.ToString("F0")) + .Append(" loc=").Append(Coordinate) .ToString(); } diff --git a/GameServer/gameobjects/GamePlayer.cs b/GameServer/gameobjects/GamePlayer.cs index 23bd72c0..11206558 100644 --- a/GameServer/gameobjects/GamePlayer.cs +++ b/GameServer/gameobjects/GamePlayer.cs @@ -21,7 +21,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Numerics; using System.Reflection; using System.Text; @@ -56,6 +55,7 @@ using DOL.GS.Scripts; using log4net; using System.Collections.Immutable; +using DOL.GS.Geometry; namespace DOL.GS { @@ -557,54 +557,66 @@ public bool UsedLevelCommand set { if (DBCharacter != null) DBCharacter.UsedLevelCommand = value; } } + public Position BindHousePosition + { + get + { + if (DBCharacter == null) return Position.Zero; + + return Position.Create( + (ushort)DBCharacter.BindHouseRegion, + DBCharacter.BindHouseXpos, + DBCharacter.BindHouseYpos, + DBCharacter.BindHouseZpos, + (ushort)DBCharacter.BindHouseHeading); + } + set + { + DBCharacter.BindHouseRegion = value.RegionID; + DBCharacter.BindHouseXpos = value.X; + DBCharacter.BindHouseYpos = value.Y; + DBCharacter.BindHouseZpos = value.Z; + DBCharacter.BindHouseHeading = value.Orientation.InHeading; + } + } + /// /// Gets or sets the BindHouseRegion for this player /// (delegate to property in DBCharacter) /// + [Obsolete("Use BindHousePosition instead!")] public int BindHouseRegion { - get { return DBCharacter != null ? DBCharacter.BindHouseRegion : 0; } - set { if (DBCharacter != null) DBCharacter.BindHouseRegion = value; } + get => BindHousePosition.RegionID; + set => BindHousePosition.With(regionID: (ushort)value); } - - /// - /// Gets or sets the BindHouseXpos for this player - /// (delegate to property in DBCharacter) - /// + + [Obsolete("Use BindHousePosition instead!")] public int BindHouseXpos { - get { return DBCharacter != null ? DBCharacter.BindHouseXpos : 0; } - set { if (DBCharacter != null) DBCharacter.BindHouseXpos = value; } + get => BindHousePosition.X; + set => BindHousePosition.With(x: value); } - - /// - /// Gets or sets the BindHouseYpos for this player - /// (delegate to property in DBCharacter) - /// + + [Obsolete("Use BindHousePosition instead!")] public int BindHouseYpos { - get { return DBCharacter != null ? DBCharacter.BindHouseYpos : 0; } - set { if (DBCharacter != null) DBCharacter.BindHouseYpos = value; } + get => BindHousePosition.Y; + set => BindHousePosition.With(y: value); } - /// - /// Gets or sets BindHouseZpos for this player - /// (delegate to property in DBCharacter) - /// + [Obsolete("Use BindHousePosition instead!")] public int BindHouseZpos { - get { return DBCharacter != null ? DBCharacter.BindHouseZpos : 0; } - set { if (DBCharacter != null) DBCharacter.BindHouseZpos = value; } + get => BindHousePosition.Z; + set => BindHousePosition.With(z: value); } - /// - /// Gets or sets the BindHouseHeading for this player - /// (delegate to property in DBCharacter) - /// + [Obsolete("Use BindHousePosition instead!")] public int BindHouseHeading { - get { return DBCharacter != null ? DBCharacter.BindHouseHeading : 0; } - set { if (DBCharacter != null) DBCharacter.BindHouseHeading = value; } + get => BindHousePosition.Orientation.InHeading; + set => BindHousePosition.With(Angle.Heading(value)); } /// @@ -647,10 +659,27 @@ public bool ShowXFireInfo set { if (DBCharacter != null) DBCharacter.ShowXFireInfo = value; } } - /// - /// Gets or sets the BindRegion for this player - /// (delegate to property in DBCharacter) - /// + public Position BindPosition + { + get + { + if(DBCharacter == null) return Position.Zero; + + return DBCharacter.GetBindPosition(); + } + set + { + if (DBCharacter == null) return; + + DBCharacter.BindRegion = value.RegionID; + DBCharacter.BindXpos = value.X; + DBCharacter.BindYpos = value.Y; + DBCharacter.BindZpos = value.Z; + DBCharacter.BindHeading = value.Orientation.InHeading; + } + } + + [Obsolete("Use BindPosition instead!")] public int BindRegion { get { return DBCharacter != null ? DBCharacter.BindRegion : 0; } @@ -661,6 +690,7 @@ public int BindRegion /// Gets or sets the BindXpos for this player /// (delegate to property in DBCharacter) /// + [Obsolete("Use BindPosition instead!")] public int BindXpos { get { return DBCharacter != null ? DBCharacter.BindXpos : 0; } @@ -671,6 +701,7 @@ public int BindXpos /// Gets or sets the BindYpos for this player /// (delegate to property in DBCharacter) /// + [Obsolete("Use BindPosition instead!")] public int BindYpos { get { return DBCharacter != null ? DBCharacter.BindYpos : 0; } @@ -681,6 +712,7 @@ public int BindYpos /// Gets or sets the BindZpos for this player /// (delegate to property in DBCharacter) /// + [Obsolete("Use BindPosition instead!")] public int BindZpos { get { return DBCharacter != null ? DBCharacter.BindZpos : 0; } @@ -691,6 +723,7 @@ public int BindZpos /// Gets or sets the BindHeading for this player /// (delegate to property in DBCharacter) /// + [Obsolete("Use BindPosition instead!")] public int BindHeading { get { return DBCharacter != null ? DBCharacter.BindHeading : 0; } @@ -954,7 +987,7 @@ public void OnLinkdeath() private void CheckIfNearEnemyKeepAndAddToRvRLinkDeathListIfNecessary() { - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(this.CurrentRegionID, this.Position, WorldMgr.VISIBILITY_DISTANCE); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(Position, WorldMgr.VISIBILITY_DISTANCE); if (keep != null && this.Client.Account.PrivLevel == 1 && GameServer.KeepManager.IsEnemy(keep, this)) { if (WorldMgr.RvRLinkDeadPlayers.ContainsKey(this.m_InternalID)) @@ -1030,11 +1063,7 @@ protected virtual void CleanupOnDisconnect() // DamienOphyr: Overwrite current position with Bind position in database, MoveTo() is inoperant if (CurrentRegion.IsInstance) { - DBCharacter.Region = BindRegion; - DBCharacter.Xpos = BindXpos; - DBCharacter.Ypos = BindYpos; - DBCharacter.Zpos = BindZpos; - DBCharacter.Direction = BindHeading; + Position = BindPosition; } if (!this.CurrentRegion.IsRvR) @@ -1321,11 +1350,7 @@ public virtual void Bind(bool forced) if (forced) { - BindRegion = CurrentRegionID; - BindHeading = Heading; - BindXpos = (int)Position.X; - BindYpos = (int)Position.Y; - BindZpos = (int)Position.Z; + BindPosition = Position; if (DBCharacter != null) GameServer.Database.SaveObject(DBCharacter); return; @@ -1346,7 +1371,8 @@ public virtual void Bind(bool forced) return; } - string description = string.Format("in {0}", this.GetBindSpotDescription()); + var spotDescription = WorldMgr.GetRegion(BindPosition.RegionID).GetTranslatedSpotDescription(Client, BindPosition.Coordinate); + string description = string.Format("in {0}", spotDescription); Out.SendMessage(LanguageMgr.GetTranslation(Client.Account.Language, "GameObjects.GamePlayer.Bind.LastBindPoint", description), eChatType.CT_System, eChatLoc.CL_SystemWindow); bool bound = false; @@ -1355,11 +1381,7 @@ public virtual void Bind(bool forced) if (bindarea != null) { bound = true; - BindRegion = CurrentRegionID; - BindHeading = Heading; - BindXpos = (int)Position.X; - BindYpos = (int)Position.Y; - BindZpos = (int)Position.Z; + BindPosition = Position; if (DBCharacter != null) GameServer.Database.SaveObject(DBCharacter); } @@ -1393,11 +1415,7 @@ public virtual void Bind(bool forced) int outsideX = (int)(house.Position.X + (0 * Math.Cos(angle) + 500 * Math.Sin(angle))); int outsideY = (int)(house.Position.Y - (500 * Math.Cos(angle) - 0 * Math.Sin(angle))); ushort outsideHeading = (ushort)((house.Heading < 180 ? house.Heading + 180 : house.Heading - 180) / 0.08789); - BindHouseRegion = CurrentRegionID; - BindHouseHeading = outsideHeading; - BindHouseXpos = outsideX; - BindHouseYpos = outsideY; - BindHouseZpos = (int)house.Position.Z; + BindHousePosition = house.OutdoorJumpPosition; if (DBCharacter != null) GameServer.Database.SaveObject(DBCharacter); } @@ -1611,27 +1629,18 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) { m_releaseType = releaseCommand; } - - int relX = 0, relY = 0, relZ = 0; - ushort relRegion = 0, relHeading = 0; + + var releasePosition = Position.Zero; switch (m_releaseType) { case eReleaseType.Duel: { - relRegion = (ushort)character.Region; - relX = character.Xpos; - relY = character.Ypos; - relZ = character.Zpos; - relHeading = 2048; + releasePosition = character.GetPosition().With(Angle.Degrees(180)); break; } case eReleaseType.House: { - relRegion = (ushort)BindHouseRegion; - relX = BindHouseXpos; - relY = BindHouseYpos; - relZ = BindHouseZpos; - relHeading = (ushort)BindHouseHeading; + releasePosition = BindHousePosition; break; } @@ -1639,27 +1648,18 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) { if (Realm == eRealm.Hibernia) { - relRegion = 51; // Hibernia - relX = 426733; - relY = 416856; - relZ = 5712; - relHeading = 2605; + // Hibernia + releasePosition = Position.Create(51, 426733, 416856, 5712, 2605); } else if (Realm == eRealm.Midgard) { - relRegion = 51; // Midgard - relX = 403717; - relY = 503227; - relZ = 4680; - relHeading = 434; + // Midgard + releasePosition = Position.Create(51, 403717, 503227, 4680, 434); } else { - relRegion = 51; // Albion - relX = 526529; - relY = 541975; - relZ = 3168; - relHeading = 1861; + // Albion + releasePosition = Position.Create(51, 526529, 541975, 3168, 1861); } break; } @@ -1669,18 +1669,14 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) { if (keep.IsPortalKeep && keep.OriginalRealm == Realm) { - relRegion = keep.CurrentRegion.ID; - relX = keep.X; - relY = keep.Y; - relZ = keep.Z; + releasePosition = Position.Create(keep.CurrentRegion.ID, keep.X, keep.Y, keep.Z); } } //if we aren't releasing anywhere, release to the border keeps - if (relX == 0) + if (releasePosition.Coordinate == Coordinate.Zero) { - relRegion = CurrentRegion.ID; - GameServer.KeepManager.GetBorderKeepLocation(((byte)Realm * 2) / 1, out relX, out relY, out relZ, out relHeading); + releasePosition = GameServer.KeepManager.GetBorderKeepPosition(((byte)Realm * 2) / 1); } break; } @@ -1695,26 +1691,20 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) { case eRealm.Albion: { - relRegion = 1; // Cotswold - relX = 8192 + 553251; - relY = 8192 + 502936; - relZ = 2280; + // Cotswold + releasePosition = Position.Create(regionID: 1, x: 8192 + 553251, y: 8192 + 502936, z: 2280); break; } case eRealm.Midgard: { - relRegion = 100; // Mularn - relX = 8192 + 795621; - relY = 8192 + 719590; - relZ = 4680; + // Mularn + releasePosition = Position.Create(regionID: 100, x: 8192 + 795621, y: 8192 + 719590, z: 4680); break; } case eRealm.Hibernia: { - relRegion = 200; // MagMell - relX = 8192 + 338652; - relY = 8192 + 482335; - relZ = 5200; + // MagMell + releasePosition = Position.Create(regionID: 200, x: 8192 + 338652, y: 8192 + 482335, z: 5200); break; } } @@ -1749,10 +1739,7 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) { if (keep.DBKeep.BaseLevel > 50 && keep.Realm == Realm) { - relRegion = (ushort)keep.Region; - relX = keep.X; - relY = keep.Y; - relZ = keep.Z; + releasePosition = Position.Create((ushort)keep.Region, x: keep.X, y: keep.Y, z: keep.Z); break; } } @@ -1763,22 +1750,21 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) { if (BindRegion != 163) { - relRegion = 163; switch (Realm) { case eRealm.Albion: { - GameServer.KeepManager.GetBorderKeepLocation(1, out relX, out relY, out relZ, out relHeading); + releasePosition = GameServer.KeepManager.GetBorderKeepPosition(1); break; } case eRealm.Midgard: { - GameServer.KeepManager.GetBorderKeepLocation(3, out relX, out relY, out relZ, out relHeading); + releasePosition = GameServer.KeepManager.GetBorderKeepPosition(3); break; } case eRealm.Hibernia: { - GameServer.KeepManager.GetBorderKeepLocation(5, out relX, out relY, out relZ, out relHeading); + releasePosition = GameServer.KeepManager.GetBorderKeepPosition(5); break; } } @@ -1786,11 +1772,7 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) } else { - relRegion = (ushort)BindRegion; - relX = BindXpos; - relY = BindYpos; - relZ = BindZpos; - relHeading = (ushort)BindHeading; + releasePosition = BindPosition; } break; }/* @@ -1801,11 +1783,7 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) }*/ default: { - relRegion = (ushort)BindRegion; - relX = BindXpos; - relY = BindYpos; - relZ = BindZpos; - relHeading = (ushort)BindHeading; + releasePosition = BindPosition; break; } } @@ -1878,7 +1856,7 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) StartEnduranceRegeneration(); Region region = null; - if ((region = WorldMgr.GetRegion((ushort)BindRegion)) != null && region.GetZone(BindXpos, BindYpos) != null) + if ((region = WorldMgr.GetRegion(BindPosition.RegionID)) != null && region.GetZone(BindPosition.Coordinate) != null) { Out.SendMessage(LanguageMgr.GetTranslation(Client.Account.Language, "GameObjects.GamePlayer.Release.SurroundingChange"), eChatType.CT_YouDied, eChatLoc.CL_SystemWindow); } @@ -1890,12 +1868,12 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) int oldRegion = CurrentRegionID; - if (oldRegion != relRegion) + if (oldRegion != releasePosition.RegionID) { Out.SendPlayerRevive(this); Out.SendUpdatePoints(); if (m_releaseType != eReleaseType.Jail) - MoveTo(relRegion, relX, relY, relZ, relHeading); + MoveTo(releasePosition); } else { @@ -1904,7 +1882,7 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) if (m_releaseType != eReleaseType.Jail) { - MoveTo(relRegion, relX, relY, relZ, relHeading); + MoveTo(releasePosition); } //It is enough if we revive the player on this client only here @@ -1927,18 +1905,6 @@ public virtual void Release(eReleaseType releaseCommand, bool forced) TempProperties.removeProperty(DEATH_CONSTITUTION_LOSS_PROPERTY); - //Reset last valide position array to prevent /stuck avec /release - lock (m_lastUniqueLocations) - { - for (int i = 0; i < m_lastUniqueLocations.Length; i++) - { - GameLocation loc = m_lastUniqueLocations[i]; - loc.Position = Position; - loc.Heading = Heading; - loc.RegionID = CurrentRegionID; - } - } - if (m_releaseType == eReleaseType.Jail) { GameEventMgr.Notify(GamePlayerEvent.SendToJail, new SendToJailEventArgs() { GamePlayer = this, OriginalReputation = this.Reputation }); @@ -10842,7 +10808,7 @@ public override bool RemoveFromWorld() if (ObjectState == eObjectState.Active) { DismountSteed(true); - if (CurrentRegion.GetZone(Position) == null) + if (CurrentZone == null) { if (this is GamePlayer && this.Client.Account.PrivLevel < 3 && !(this as GamePlayer).TempProperties.getProperty("isbeingbanned", false)) { @@ -10927,11 +10893,11 @@ public override void Delete() /// Z target coordinate (0 to put player on floor) /// Target heading /// true if move succeeded, false if failed - public override bool MoveTo(ushort regionID, float x, float y, float z, ushort heading) + public override bool MoveTo(Position position) { //if we are jumping somewhere away from our house not using house.Exit //we need to make the server know we have left the house - if ((CurrentHouse != null || InHouse) && CurrentHouse.RegionID != regionID) + if ((CurrentHouse != null || InHouse) && CurrentHouse.RegionID != position.RegionID) { CurrentHouse = null; } @@ -10939,21 +10905,23 @@ public override bool MoveTo(ushort regionID, float x, float y, float z, ushort h if (IsOnHorse) IsOnHorse = false; //Get the destination region based on the ID - Region rgn = WorldMgr.GetRegion(regionID); + Region rgn = WorldMgr.GetRegion(position.RegionID); //If the region doesn't exist, return false or if they aren't allowed to zone here if (rgn == null || !GameServer.ServerRules.IsAllowedToZone(this, rgn)) return false; //If the x,y inside this region doesn't point to a zone //return false - if (rgn.GetZone(x, y) == null) + if (rgn.GetZone(position.Coordinate) == null) return false; Diving(waterBreath.Normal); if (SiegeWeapon != null) SiegeWeapon.ReleaseControl(); + + var positionBeforePort = Position; - if (regionID != CurrentRegionID) + if (position.RegionID != positionBeforePort.RegionID) { GameEventMgr.Notify(GamePlayerEvent.RegionChanging, this); if (!RemoveFromWorld()) @@ -10984,8 +10952,6 @@ public override bool MoveTo(ushort regionID, float x, float y, float z, ushort h IsJumping = true; } bool hasPetToMove = false; - //Remove the last update tick property, to prevent speedhack messages during zoning and teleporting! - LastPositionUpdateTick = 0; if (ControlledBrain != null && ControlledBrain.WalkState != eWalkState.Stay) { @@ -10997,19 +10963,13 @@ public override bool MoveTo(ushort regionID, float x, float y, float z, ushort h //Set the new destination //Current Speed = 0 when moved ... else X,Y,Z continue to be modified CurrentSpeed = 0; - MovementStartTick = GameTimer.GetTickCount(); - Vector3 originalPoint = Position; - Position = new Vector3(x, y, z); - Heading = heading; + Position = position; //Remove the last update tick property, to prevent speedhack messages during zoning and teleporting! TempProperties.removeProperty(PlayerPositionUpdateHandler.LASTMOVEMENTTICK); //If the destination is in another region - if (regionID != CurrentRegionID) + if (position.RegionID != positionBeforePort.RegionID) { - //Set our new region - CurrentRegionID = regionID; - //Send the region update packet, the rest will be handled //by the packethandlers Out.SendRegionChanged(); @@ -11020,7 +10980,7 @@ public override bool MoveTo(ushort regionID, float x, float y, float z, ushort h Out.SendPlayerJump(false); // are we jumping far enough to force a complete refresh? - if (Vector3.Distance(Position, originalPoint) > WorldMgr.REFRESH_DISTANCE) + if (Coordinate.DistanceTo(positionBeforePort) > WorldMgr.REFRESH_DISTANCE) { RefreshWorld(); } @@ -11045,17 +11005,16 @@ public override bool MoveTo(ushort regionID, float x, float y, float z, ushort h if (hasPetToMove) { - Vector2 point = GameMath.GetPointFromHeading(Position, Heading, 64); - if (ControlledBody is GameNPC petBody) { - petBody.MoveInRegion(CurrentRegionID, point.X, point.Y, this.Position.Z + 10, (ushort)((this.Heading + 2048) % 4096), false); + var destination = Position.TurnedAround() + Vector.Create(Orientation, length: 64, z: 10); + petBody.MoveWithoutRemovingFromWorld(destination, false); if (petBody.ControlledNpcList != null) foreach (IControlledBrain icb in petBody.ControlledNpcList) if (icb != null && icb.Body is GameNPC petBody2 - && petBody2.IsWithinRadius(originalPoint, 500)) - petBody2.MoveInRegion(CurrentRegionID, point.X, point.Y, this.Position.Z + 10, (ushort)((this.Heading + 2048) % 4096), false); + && petBody2.Coordinate.DistanceTo(positionBeforePort) < 500) + petBody2.MoveWithoutRemovingFromWorld(destination, false); } } shadowNPC.MoveToPlayer(); @@ -11097,11 +11056,11 @@ public virtual void RefreshWorld() //Eden - Move to bind, and check if the loc is allowed public virtual bool MoveToBind() { - Region rgn = WorldMgr.GetRegion((ushort)BindRegion); - if (rgn == null || rgn.GetZone(BindXpos, BindYpos) == null) + Region rgn = WorldMgr.GetRegion(BindPosition.RegionID); + if (rgn == null || rgn.GetZone(BindPosition.Coordinate) == null) { if (log.IsErrorEnabled) - log.Error("Player: " + Name + " unknown bind point : (R/X/Y) " + BindRegion + "/" + BindXpos + "/" + BindYpos); + log.Error("Player: " + Name + " unknown bind point : (R/X/Y) " + BindPosition.RegionID + "/" + BindPosition.X + "/" + BindPosition.Y); //Kick the player, avoid server freeze Client.Out.SendPlayerQuit(true); SaveIntoDatabase(); @@ -11115,7 +11074,7 @@ public virtual bool MoveToBind() b.Account = Client.Account.Name; b.DateBan = DateTime.Now; b.Type = "B"; - b.Reason = "X/Y/Zone : " + Position.X + "/" + Position.Y + "/" + CurrentRegion.ID; + b.Reason = "X/Y/RegionID : " + Position.X + "/" + Position.Y + "/" + Position.RegionID; GameServer.Database.AddObject(b); GameServer.Database.SaveObject(b); string message = "Unknown bind point, your account is banned, contact a GM."; @@ -11126,7 +11085,7 @@ public virtual bool MoveToBind() } if (GameServer.ServerRules.IsAllowedToMoveToBind(this)) - return MoveTo((ushort)BindRegion, BindXpos, BindYpos, BindZpos, (ushort)BindHeading); + return MoveTo(BindPosition); return false; } @@ -11334,19 +11293,12 @@ public long AreaUpdateTick public uint LastNPCUpdateTick = 0; public uint LastNPCUpdateAllTick = 0; - public override Vector3 Position + public override Position Position { - get => IsMoving ? base.Position + MovementElapsedTicks * Velocity : base.Position; set { base.Position = value; - if (DBCharacter != null) - { - var p = base.Position; - DBCharacter.Xpos = (int)p.X; - DBCharacter.Ypos = (int)p.Y; - DBCharacter.Zpos = (int)p.Z; - } + if(DBCharacter != null) DBCharacter.SetPosition(value); } } @@ -11386,29 +11338,8 @@ public Zone LastPositionUpdateZone set { m_lastPositionUpdateZone = value; } } - - private uint m_lastPositionUpdateTick = 0; - - /// - /// The environment tick count when this players position was last updated - /// - public uint LastPositionUpdateTick - { - get { return m_lastPositionUpdateTick; } - set { m_lastPositionUpdateTick = value; } - } - - private Vector3 m_lastPositionUpdatePoint = new Vector3(0, 0, 0); - - /// - /// The last recorded position of this player - /// - public Vector3 LastPositionUpdatePoint - { - get { return m_lastPositionUpdatePoint; } - set { m_lastPositionUpdatePoint = value; } - } - + public Coordinate LastUpdateCoordinate => Motion.Start.Coordinate; + /// /// Gets or sets the players max Z for fall damage /// @@ -11427,15 +11358,12 @@ public override eRealm Realm } } - /// - /// Gets or sets the heading of this player - /// - public override ushort Heading + public override Angle Orientation { set { - base.Heading = value; - if (DBCharacter != null) DBCharacter.Direction = value; + base.Orientation = value; + if (DBCharacter != null) DBCharacter.Direction = value.InHeading; if (AttackState && ActiveWeaponSlot != eActiveWeaponSlot.Distance) { @@ -11779,6 +11707,21 @@ public override bool IsStrafing } get { return m_strafing; } } + + /// + /// Gets or sets the current speed of this player + /// + public override short CurrentSpeed + { + set + { + base.CurrentSpeed = value; + if (value != 0) + { + OnPlayerMove(); + } + } + } public virtual void OnPlayerMove() { @@ -11921,33 +11864,17 @@ public virtual void Sit(bool sit) UpdatePlayerStatus(); } - /// - /// Sets the Living's ground-target Coordinates inside the current Region - /// - public override Vector3? GroundTarget + public override Position GroundTargetPosition { set { - base.GroundTarget = value; - if (value.HasValue) - Out.SendMessage(String.Format("You ground-target {0}", value), eChatType.CT_System, eChatLoc.CL_SystemWindow); - if (SiegeWeapon != null) - SiegeWeapon.GroundTarget = value; + base.GroundTargetPosition = value; + Out.SendMessage(String.Format("You ground-target {0},{1},{2}", value.X, value.Y, value.Z), eChatType.CT_System, eChatLoc.CL_SystemWindow); + if (SiegeWeapon != null) SiegeWeapon.GroundTargetPosition = value; } } - /// - /// Holds unique locations array - /// - protected readonly GameLocation[] m_lastUniqueLocations; - - /// - /// Gets unique locations array - /// - public GameLocation[] LastUniqueLocations - { - get { return m_lastUniqueLocations; } - } + public Position[] LastUniquePositions { get; } = new Position[4]; /// /// Updates Health, Mana, Sitting, Endurance, Concentration and Alive status to client @@ -12704,11 +12631,7 @@ public virtual WorldInventoryItem CreateItemOnTheGround(InventoryItem item) else { gameItem = new WorldInventoryItem(item); - - var itemloc = GameMath.GetPointFromHeading(this.Position, this.Heading, 30); - gameItem.Position = new Vector3(itemloc, 0); - gameItem.Heading = Heading; - gameItem.CurrentRegionID = CurrentRegionID; + gameItem.Position = Position + Vector.Create(Orientation, length: 30); gameItem.AddOwner(this); gameItem.AddToWorld(); @@ -12745,8 +12668,8 @@ public virtual bool PickupObject(GameObject floorObject, bool checkRange) { log.DebugFormat("Pickup error: {0} object x{1}, y{2}, z{3}, r{4} - player x{5}, y{6}, z{7}, r{8}", Name, - floorObject.Position.X, floorObject.Position.Y, floorObject.Position.Z, floorObject.CurrentRegionID, - Position.X, Position.Y, Position.Z, CurrentRegionID); + floorObject.Position.X, floorObject.Position.Y, floorObject.Position.Z, floorObject.Position.RegionID, + Position.X, Position.Y, Position.Z, Position.RegionID); } catch { @@ -13467,23 +13390,21 @@ public override void LoadFromDatabase(DataObject obj) #endregion #region setting world-init-position (delegate to PlayerCharacter dont make sense) - Position = new Vector3(DBCharacter.Xpos, DBCharacter.Ypos, DBCharacter.Zpos); - m_Heading = (ushort)DBCharacter.Direction; + Position = DBCharacter.GetPosition(); //important, use CurrentRegion property //instead because it sets the Region too CurrentRegionID = (ushort)DBCharacter.Region; - if (CurrentRegion == null || CurrentRegion.GetZone(Position) == null) + if (CurrentRegion == null || CurrentRegion.GetZone(Coordinate) == null) { - log.WarnFormat("Invalid region/zone on char load ({0}): x={1:N0} y={2:N0} z={3:N0} reg={4}; moving to bind point.", DBCharacter.Name, Position.X, Position.Y, Position.Z, DBCharacter.Region); - Position = new Vector3(DBCharacter.BindXpos, DBCharacter.BindYpos, DBCharacter.BindZpos); - m_Heading = (ushort)DBCharacter.BindHeading; - CurrentRegionID = (ushort)DBCharacter.BindRegion; + log.WarnFormat("Invalid region/zone on char load ({0}): x={1} y={2} z={3} reg={4}; moving to bind point." + , DBCharacter.Name, Coordinate.X, Coordinate.Y, Coordinate.Z, DBCharacter.Region); + Position = DBCharacter.GetBindPosition(); } - for (int i = 0; i < m_lastUniqueLocations.Length; i++) + for (int i = 0; i < LastUniquePositions.Length; i++) { - m_lastUniqueLocations[i] = new GameLocation(null, CurrentRegionID, Position.X, Position.Y, Position.Z); + LastUniquePositions[i] = Position; } #endregion @@ -13620,14 +13541,9 @@ public override void SaveIntoDatabase() DBCharacter.ActiveWeaponSlot = (byte)((byte)ActiveWeaponSlot | (byte)ActiveQuiverSlot); if (m_stuckFlag) { - lock (m_lastUniqueLocations) + lock (LastUniquePositions) { - GameLocation loc = m_lastUniqueLocations[m_lastUniqueLocations.Length - 1]; - DBCharacter.Xpos = (int)loc.Position.X; - DBCharacter.Ypos = (int)loc.Position.Y; - DBCharacter.Zpos = (int)loc.Position.Z; - DBCharacter.Region = loc.RegionID; - DBCharacter.Direction = loc.Heading; + DBCharacter.SetPosition(LastUniquePositions[LastUniquePositions.Length - 1]); } } GameServer.Database.SaveObject(DBCharacter); @@ -14051,17 +13967,17 @@ protected override void OnTick() fieldOfListen += (npc.Level - player.Level) * 3; } - double angle = GameMath.GetAngle(npc, player); + var angle = npc.GetAngleTo(player.Coordinate); //player in front fieldOfView /= 2.0; - bool canSeePlayer = (angle >= 360 - fieldOfView || angle < fieldOfView); + bool canSeePlayer = (angle.InDegrees >= 360 - fieldOfView || angle.InDegrees < fieldOfView); //If npc can not see nor hear the player, continue the loop fieldOfListen /= 2.0; if (canSeePlayer == false && - !(angle >= (45 + 60) - fieldOfListen && angle < (45 + 60) + fieldOfListen) && - !(angle >= (360 - 45 - 60) - fieldOfListen && angle < (360 - 45 - 60) + fieldOfListen)) + !(angle.InDegrees >= (45 + 60) - fieldOfListen && angle.InDegrees < (45 + 60) + fieldOfListen) && + !(angle.InDegrees >= (360 - 45 - 60) - fieldOfListen && angle.InDegrees < (360 - 45 - 60) + fieldOfListen)) continue; double chanceMod = 1.0; @@ -16962,7 +16878,6 @@ public GamePlayer(GameClient client, DOLCharacters dbChar) m_debuffBonus = new PropertyIndexer((int)eProperty.MaxProperty); m_buff4Bonus = new PropertyIndexer((int)eProperty.MaxProperty); m_itemBonus = new PropertyIndexer((int)eProperty.MaxProperty); - m_lastUniqueLocations = new GameLocation[4]; m_canFly = false; m_wanted = false; m_reputation = 0; diff --git a/GameServer/gameobjects/GameSiegeWeapon.cs b/GameServer/gameobjects/GameSiegeWeapon.cs index 71bbb91b..610ef689 100644 --- a/GameServer/gameobjects/GameSiegeWeapon.cs +++ b/GameServer/gameobjects/GameSiegeWeapon.cs @@ -23,6 +23,7 @@ using DOL.AI.Brain; using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.Keeps; using System.Numerics; @@ -185,7 +186,20 @@ public string ItemId get { return m_itemId; } set { m_itemId = value; } } + + public Coordinate AimCoordinate + { + get + { + var targetPosition = Position.Zero; + if(TargetObject != null) targetPosition = TargetObject.Position; + else if(GroundTargetPosition != Position.Nowhere) targetPosition = GroundTargetPosition; + return targetPosition.Coordinate; + } + } + #endregion + #region public methode public void TakeControl(GamePlayer player) { @@ -236,10 +250,10 @@ public void Aim() if (Owner.TargetObject == null) return; if (!GameServer.ServerRules.IsAllowedToAttack(Owner, ((GameLiving)Owner.TargetObject), true)) return; CurrentState &= ~eState.Aimed; - GroundTarget = Owner.TargetObject.Position; + GroundTargetPosition = Owner.TargetObject.Position; TargetObject = Owner.TargetObject; SiegeWeaponTimer.CurrentAction = SiegeTimer.eAction.Aiming; - Heading = GetHeading(Owner.TargetObject.Position); + TurnTo(GroundTargetPosition.Coordinate); PreAction(); if (Owner != null) { @@ -263,9 +277,9 @@ public void Move() { if (!CanUse()) return; if (!m_enableToMove) return; - if (Owner == null || Owner.GroundTarget == null) return; - var groundTarget = Owner.GroundTarget.Value; - if (!this.IsWithinRadius(groundTarget, 1000)) + if (Owner == null || Owner.GroundTargetPosition == Position.Nowhere) return; + if (Owner == null || Owner.GroundTargetPosition == Position.Nowhere) return; + if (Coordinate.DistanceTo(Owner.GroundTargetPosition) > 1000) { Owner.Out.SendMessage("Ground target is too far away to move to!", eChatType.CT_System, eChatLoc.CL_SystemWindow); @@ -279,7 +293,7 @@ public void Move() } //let's check if we are trying to move too close to a door, if we are, don't move - foreach (IDoor door in Owner.CurrentRegion.GetDoorsInRadius(groundTarget.X, groundTarget.Y, groundTarget.Z, (ushort)(AttackRange - 50), false)) + foreach (IDoor door in Owner.CurrentRegion.GetDoorsInRadius(Owner.GroundTargetPosition.Coordinate, (ushort)(AttackRange - 50), false)) { if (door is GameKeepDoor) { @@ -290,7 +304,7 @@ public void Move() //unarmed siege weapon CurrentState &= ~eState.Armed; - PathTo(groundTarget, 100); + PathTo(Owner.GroundTargetPosition.Coordinate, 100); } public void StopMove() @@ -331,10 +345,8 @@ public void Fire() } return; } - if (TargetObject != null) - GroundTarget = TargetObject.Position; - if (GroundTarget == null) - return; + if (TargetObject != null) GroundTargetPosition = TargetObject.Position; + if (GroundTargetPosition == Position.Nowhere) return; new RegionTimer(this, new RegionTimerCallback(MakeDelayedDamage), GetActionDelay(SiegeTimer.eAction.Fire)); BroadcastFireAnimation(GetActionDelay(SiegeTimer.eAction.Fire)); if (Owner != null) diff --git a/GameServer/gameobjects/GameStaticItem.cs b/GameServer/gameobjects/GameStaticItem.cs index cab4bebd..4e8e2e76 100644 --- a/GameServer/gameobjects/GameStaticItem.cs +++ b/GameServer/gameobjects/GameStaticItem.cs @@ -20,11 +20,11 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Numerics; using DOL.Database; using DOL.Events; using DOL.GameEvents; using DOL.Language; +using DOL.GS.Geometry; namespace DOL.GS { @@ -67,7 +67,6 @@ public GameStaticItem Copy() item.EventID = EventID; item.Name = Name; item.ExamineArticle = ExamineArticle; - item.Heading = Heading; item.Level = Level; item.Realm = Realm; item.Position = Position; @@ -232,20 +231,19 @@ public override void LoadFromDatabase(DataObject obj) Model = item.Model; Emblem = item.Emblem; Realm = (eRealm)item.Realm; - Heading = item.Heading; - Position = new Vector3(item.X, item.Y, item.Z); + Position = Position.Create(item.Region, item.X, item.Y, item.Z, item.Heading); RespawnInterval = item.RespawnInterval; } /// /// Gets or sets the heading of this item /// - public override ushort Heading + public override Angle Orientation { - get { return base.Heading; } + get => base.Orientation; set { - base.Heading = value; + base.Orientation = value; if (ObjectState == eObjectState.Active) { foreach (GamePlayer player in GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE)) @@ -310,11 +308,11 @@ public override void SaveIntoDatabase() obj.Model = Model; obj.Emblem = Emblem; obj.Realm = (byte)Realm; - obj.Heading = Heading; - obj.Region = CurrentRegionID; - obj.X = (int)Position.X; - obj.Y = (int)Position.Y; - obj.Z = (int)Position.Z; + obj.Heading = Orientation.InHeading; + obj.Region = Position.RegionID; + obj.X = Position.X; + obj.Y = Position.Y; + obj.Z = Position.Z; obj.ClassType = this.GetType().ToString(); obj.RespawnInterval = RespawnInterval; diff --git a/GameServer/gameobjects/GameTeleporter.cs b/GameServer/gameobjects/GameTeleporter.cs index a575c2ee..3da91cac 100644 --- a/GameServer/gameobjects/GameTeleporter.cs +++ b/GameServer/gameobjects/GameTeleporter.cs @@ -24,6 +24,7 @@ using DOL.Language; using DOL.GS.PacketHandler; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Housing; using DOL.GS.Keeps; using DOL.GS.Spells; @@ -142,15 +143,15 @@ protected virtual bool GetTeleportLocation(GamePlayer player, string text) } else { - IGameLocation location = house.OutdoorJumpPoint; + var position = house.OutdoorJumpPosition; Teleport teleport = new Teleport(); teleport.TeleportID = "personal"; teleport.Realm = (int)DestinationRealm; - teleport.RegionID = location.RegionID; - teleport.X = (int)location.Position.X; - teleport.Y = (int)location.Position.Y; - teleport.Z = (int)location.Position.Z; - teleport.Heading = location.Heading; + teleport.RegionID = position.RegionID; + teleport.X = position.X; + teleport.Y = position.Y; + teleport.Z = position.Z; + teleport.Heading = position.Orientation.InHeading; OnDestinationPicked(player, teleport); return true; } @@ -161,16 +162,14 @@ protected virtual bool GetTeleportLocation(GamePlayer player, string text) if (text.ToLower() == "hearth") { // Check if player has set a house bind - if (!(player.BindHouseRegion > 0)) + if (!(player.BindHousePosition.RegionID > 0)) { SayTo(player, "Sorry, you haven't set any house bind point yet."); return false; } // Check if the house at the player's house bind location still exists - ArrayList houses = (ArrayList)HouseMgr.GetHousesCloseToSpot((ushort)player. - BindHouseRegion, player.BindHouseXpos, player. - BindHouseYpos, 700); + ArrayList houses = (ArrayList)HouseMgr.GetHousesCloseToSpot(player.BindHousePosition, radius: 700); if (houses.Count == 0) { SayTo(player, "I'm afraid I can't teleport you to your hearth since the house at your " + @@ -210,11 +209,11 @@ protected virtual bool GetTeleportLocation(GamePlayer player, string text) Teleport teleport = new Teleport(); teleport.TeleportID = "hearth"; teleport.Realm = (int)DestinationRealm; - teleport.RegionID = player.BindHouseRegion; - teleport.X = player.BindHouseXpos; - teleport.Y = player.BindHouseYpos; - teleport.Z = player.BindHouseZpos; - teleport.Heading = player.BindHouseHeading; + teleport.RegionID = player.BindHousePosition.RegionID; + teleport.X = player.BindHousePosition.X; + teleport.Y = player.BindHousePosition.Y; + teleport.Z = player.BindHousePosition.Z; + teleport.Heading = player.BindHousePosition.Orientation.InHeading; OnDestinationPicked(player, teleport); return true; } @@ -229,15 +228,15 @@ protected virtual bool GetTeleportLocation(GamePlayer player, string text) } else { - IGameLocation location = house.OutdoorJumpPoint; + var position = house.OutdoorJumpPosition; Teleport teleport = new Teleport(); teleport.TeleportID = "guild house"; teleport.Realm = (int)DestinationRealm; - teleport.RegionID = location.RegionID; - teleport.X = (int)location.Position.X; - teleport.Y = (int)location.Position.Y; - teleport.Z = (int)location.Position.Z; - teleport.Heading = location.Heading; + teleport.RegionID = position.RegionID; + teleport.X = position.X; + teleport.Y = position.Y; + teleport.Z = position.Z; + teleport.Heading = position.Orientation.InHeading; OnDestinationPicked(player, teleport); return true; } @@ -331,9 +330,8 @@ protected virtual void OnTeleport(GamePlayer player, Teleport destination) if (player.InCombat == false && GameRelic.IsPlayerCarryingRelic(player) == false) { player.LeaveHouse(); - GameLocation currentLocation = new GameLocation("TeleportStart", player.CurrentRegionID, player.Position, player.Heading); - player.MoveTo((ushort)destination.RegionID, destination.X, destination.Y, destination.Z, (ushort)destination.Heading); - GameServer.ServerRules.OnPlayerTeleport(player, currentLocation, destination); + player.MoveTo(destination.GetPosition()); + GameServer.ServerRules.OnPlayerTeleport(player, destination); } } } diff --git a/GameServer/gameobjects/GuildBannerItem.cs b/GameServer/gameobjects/GuildBannerItem.cs index 630973b5..00d4ba76 100644 --- a/GameServer/gameobjects/GuildBannerItem.cs +++ b/GameServer/gameobjects/GuildBannerItem.cs @@ -25,10 +25,10 @@ using DOL.Language; using DOL.GS.PacketHandler; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Spells; using log4net; using System.Linq; -using System.Numerics; namespace DOL.GS { @@ -233,8 +233,7 @@ public WorldInventoryItem CreateWorldItem() WorldInventoryItem item = new WorldInventoryItem(this); GamePlayer player = Banner.OwningPlayer; - var point = player.GetPointFromHeading(player.Heading, 30); - item.Position = new Vector3(point, player.Position.Z); + item.Position = player.Position + Vector.Create(player.Orientation, length: 30); item.Heading = player.Heading; item.CurrentRegionID = player.CurrentRegionID; return item; diff --git a/GameServer/gameobjects/InventoryItem/GameInventorySiegeBallista.cs b/GameServer/gameobjects/InventoryItem/GameInventorySiegeBallista.cs index 2f64dfc3..1398c004 100644 --- a/GameServer/gameobjects/InventoryItem/GameInventorySiegeBallista.cs +++ b/GameServer/gameobjects/InventoryItem/GameInventorySiegeBallista.cs @@ -72,8 +72,7 @@ public override bool Use(GamePlayer player) bal.Level = Convert.ToByte(Level); bal.Name = Name; bal.Model = (ushort)Model; - bal.Position = new System.Numerics.Vector3(player.Position.X, player.Position.Y, player.Position.Z); - bal.CurrentRegion = player.CurrentRegion; + bal.Position = player.Position; bal.Realm = player.Realm; bal.AddToWorld(); diff --git a/GameServer/gameobjects/InventoryItem/GameInventorySiegeCatapult.cs b/GameServer/gameobjects/InventoryItem/GameInventorySiegeCatapult.cs index 28c3ac3d..eea5c2e0 100644 --- a/GameServer/gameobjects/InventoryItem/GameInventorySiegeCatapult.cs +++ b/GameServer/gameobjects/InventoryItem/GameInventorySiegeCatapult.cs @@ -72,8 +72,7 @@ public override bool Use(GamePlayer player) cat.Level = Convert.ToByte(Level); cat.Name = Name; cat.Model = (ushort)Model; - cat.Position = new System.Numerics.Vector3(player.Position.X, player.Position.Y, player.Position.Z); - cat.CurrentRegion = player.CurrentRegion; + cat.Position = player.Position; cat.Realm = player.Realm; cat.AddToWorld(); diff --git a/GameServer/gameobjects/InventoryItem/GameInventorySiegeRam.cs b/GameServer/gameobjects/InventoryItem/GameInventorySiegeRam.cs index bbb024d0..7f1b9d72 100644 --- a/GameServer/gameobjects/InventoryItem/GameInventorySiegeRam.cs +++ b/GameServer/gameobjects/InventoryItem/GameInventorySiegeRam.cs @@ -72,8 +72,7 @@ public override bool Use(GamePlayer player) ram.Level = Convert.ToByte(Level); ram.Name = Name; ram.Model = (ushort)Model; - ram.Position = new System.Numerics.Vector3(player.Position.X, player.Position.Y, player.Position.Z); - ram.CurrentRegion = player.CurrentRegion; + ram.Position = player.Position; ram.Realm = player.Realm; ram.AddToWorld(); diff --git a/GameServer/gameobjects/InventoryItem/GameInventorySiegeTrebuchet.cs b/GameServer/gameobjects/InventoryItem/GameInventorySiegeTrebuchet.cs index fb761ee7..5248a178 100644 --- a/GameServer/gameobjects/InventoryItem/GameInventorySiegeTrebuchet.cs +++ b/GameServer/gameobjects/InventoryItem/GameInventorySiegeTrebuchet.cs @@ -72,8 +72,7 @@ public override bool Use(GamePlayer player) bal.Level = Convert.ToByte(Level); bal.Name = Name; bal.Model = (ushort)Model; - bal.Position = new System.Numerics.Vector3(player.Position.X, player.Position.Y, player.Position.Z); - bal.CurrentRegion = player.CurrentRegion; + bal.Position = player.Position; bal.Realm = player.Realm; bal.AddToWorld(); diff --git a/GameServer/gameobjects/SiegeWeapon/gamesiegecatapult.cs b/GameServer/gameobjects/SiegeWeapon/gamesiegecatapult.cs index 0d2eb0b5..e7080df6 100644 --- a/GameServer/gameobjects/SiegeWeapon/gamesiegecatapult.cs +++ b/GameServer/gameobjects/SiegeWeapon/gamesiegecatapult.cs @@ -18,6 +18,7 @@ */ using System; using System.Collections; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; namespace DOL.GS @@ -65,14 +66,14 @@ protected IList SelectTargets() { ArrayList list = new ArrayList(20); - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(this.CurrentRegionID, GroundTarget.Value, (ushort)150)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(GroundTargetPosition, (ushort)150)) { if (GameServer.ServerRules.IsAllowedToAttack(Owner, player, true)) { list.Add(player); } } - foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(this.CurrentRegionID, GroundTarget.Value, (ushort)150)) + foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(GroundTargetPosition, (ushort)150)) { if (GameServer.ServerRules.IsAllowedToAttack(Owner, npc, true)) { @@ -93,7 +94,7 @@ public override void DoDamage() //todo remove ammo + spell in db and uncomment //m_spellHandler.StartSpell(player); base.DoDamage();//anim mut be called after damage - if (GroundTarget == null) return; + if (GroundTargetPosition == Position.Nowhere) return; IList targets = SelectTargets(); foreach (GameLiving living in targets) diff --git a/GameServer/gameobjects/SiegeWeapon/gamesiegecauldron.cs b/GameServer/gameobjects/SiegeWeapon/gamesiegecauldron.cs index e0c26cc8..223928e4 100644 --- a/GameServer/gameobjects/SiegeWeapon/gamesiegecauldron.cs +++ b/GameServer/gameobjects/SiegeWeapon/gamesiegecauldron.cs @@ -19,10 +19,10 @@ using System.Collections; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.Spells; using DOL.GS.Keeps; -using System.Numerics; namespace DOL.GS { @@ -43,7 +43,7 @@ public GameSiegeCauldron() Effect = 0x8A1; Model = 0xA2F; CurrentState = eState.Aimed; - GroundTarget = Position - Vector3.UnitZ * 100; + GroundTargetPosition = Position - Vector.Create(z: 100); ActionDelay = new int[] { 0, //none @@ -56,7 +56,7 @@ public GameSiegeCauldron() public override bool AddToWorld() { - GroundTarget = new Vector3(Position.ToVector2(), Component.Keep.Z); + GroundTargetPosition = Position.With(z: Component.Keep.Z); return base.AddToWorld(); } diff --git a/GameServer/gameobjects/Spawner.cs b/GameServer/gameobjects/Spawner.cs index 647e1f72..5aa85f6d 100644 --- a/GameServer/gameobjects/Spawner.cs +++ b/GameServer/gameobjects/Spawner.cs @@ -1,6 +1,7 @@ using DOL.AI.Brain; using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.Styles; using DOL.MobGroups; using DOLDatabase.Tables; @@ -359,12 +360,8 @@ private void InstanciateMobs() private void SetCircularPosition(GameNPC npc, int index, int total, float distance) { double angle = (Math.PI * 2 * index) / total; - float xOffset = (float)Math.Cos(angle) * distance; - float yOffset = (float)Math.Sin(angle) * distance; - npc.Position = new System.Numerics.Vector3(Position.X + xOffset, Position.Y + yOffset, Position.Z); - npc.Heading = Heading; - npc.CurrentRegion = WorldMgr.GetRegion(CurrentRegionID); + npc.Position = Position + Vector.Create(Angle.Radians(angle), distance); npc.LoadedFromScript = true; npc.AddToWorld(); npc.OwnerID = InternalID; diff --git a/GameServer/gameutils/DoorMgr.cs b/GameServer/gameutils/DoorMgr.cs index 40808613..35343630 100644 --- a/GameServer/gameutils/DoorMgr.cs +++ b/GameServer/gameutils/DoorMgr.cs @@ -22,6 +22,7 @@ using System.Reflection; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Keeps; using log4net; @@ -67,7 +68,7 @@ public static bool LoadDoor(DBDoor door) if (currentZone == null) return false; //check if the door is a keep door - foreach (AbstractArea area in currentZone.GetAreasOfSpot(door.X, door.Y, door.Z)) + foreach (AbstractArea area in currentZone.GetAreasOfSpot(Coordinate.Create(door.X, door.Y, door.Z))) { if (area is KeepArea) { diff --git a/GameServer/gameutils/GameMath.cs b/GameServer/gameutils/GameMath.cs index fef6aea6..e714b055 100644 --- a/GameServer/gameutils/GameMath.cs +++ b/GameServer/gameutils/GameMath.cs @@ -1,13 +1,14 @@ using System; -using System.Numerics; using DOL.GS; +using DOL.GS.Geometry; +using System.Numerics; namespace DOL { public static class GameMath { public static Vector2 ToVector2(this Vector3 v) => new Vector2(v.X, v.Y); - + /// /// The factor to convert a heading value to radians /// @@ -48,19 +49,13 @@ public static class GameMath // The DOL Heading grid is 0 at the bottom of the Y-axis and increases clockwise. // General trigonometry and the System.Math library use the Cartesian grid. - public static ushort GetHeading(Vector2 origin, Vector3 target) - => GetHeading(origin, target.ToVector2()); - public static ushort GetHeading(Vector3 origin, Vector3 target) - => GetHeading(origin.ToVector2(), target.ToVector2()); - public static ushort GetHeading(Vector3 origin, Vector2 target) - => GetHeading(origin.ToVector2(), target); /// /// Get the heading to a point /// /// Source point /// Target point /// Heading to target point - public static ushort GetHeading(Vector2 origin, Vector2 target) + public static ushort GetHeading(Coordinate origin, Coordinate target) { float dx = target.X - origin.X; float dy = target.Y - origin.Y; @@ -74,8 +69,8 @@ public static ushort GetHeading(Vector2 origin, Vector2 target) } public static float GetAngle(GameObject origin, GameObject target) - => GetAngle(origin.Position.ToVector2(), origin.Heading, target.Position.ToVector2()); - public static float GetAngle(Vector2 origin, ushort originHeading, Vector2 target) + => GetAngle(origin.Coordinate, origin.Heading, target.Coordinate); + public static float GetAngle(Coordinate origin, ushort originHeading, Coordinate target) { float headingDifference = (GetHeading(origin, target) & 0xFFF) - (originHeading & 0xFFF); @@ -85,22 +80,15 @@ public static float GetAngle(Vector2 origin, ushort originHeading, Vector2 targe return (headingDifference * 360.0f / 4096.0f); } - public static Vector2 GetPointFromHeading(GameObject origin, float distance) - => GetPointFromHeading(origin.Position.ToVector2(), origin.Heading, distance); - public static Vector2 GetPointFromHeading(Vector3 origin, ushort heading, float distance) - => GetPointFromHeading(origin.ToVector2(), heading, distance); - public static Vector2 GetPointFromHeading(Vector2 origin, ushort heading, float distance) + public static Coordinate GetPointFromHeading(GameObject origin, float distance) + => GetPointFromHeading(origin.Coordinate, origin.Heading, distance); + public static Coordinate GetPointFromHeading(Coordinate origin, ushort heading, float distance) { float angle = heading * HEADING_TO_RADIAN; float targetX = origin.X - ((float)Math.Sin(angle) * distance); float targetY = origin.Y + ((float)Math.Cos(angle) * distance); - var point = new Vector2(); - if (targetX > 0) - point.X = targetX; - if (targetY > 0) - point.Y = targetY; - return point; + return Coordinate.Create(int.Max((int)targetX, 0), int.Max((int)targetY, 0)); } /// @@ -113,46 +101,75 @@ public static Vector2 GetPointFromHeading(Vector2 origin, ushort heading, float /// Source point /// Target point /// Distance to point - public static float GetDistance2D(Vector3 a, Vector3 b) - { - var vec = (b - a); - vec.Z = 0; // 2D - return vec.Length(); - } + public static float GetDistance2D(Coordinate a, Coordinate b) => (float)(b - a).Length2D; + public static float GetDistance2D(GameObject a, GameObject b) { if (a.CurrentRegion != b.CurrentRegion) return float.MaxValue; - return GetDistance2D(a.Position, b.Position); + return GetDistance2D(a.Coordinate, b.Coordinate); + } + + public static int GetDistance2DSquared(Coordinate a, Coordinate b) + { + int dX = b.X - a.X; + int dY = b.Y - a.Y; + return dX * dX + dY * dY; + } + + public static int GetDistance2DSquared(GameObject a, GameObject b) + { + if (a.CurrentRegion != b.CurrentRegion) + return int.MaxValue; + return GetDistance2DSquared(a.Coordinate, b.Coordinate); } + public static float GetDistance(Coordinate a, Coordinate b) => (float)(b - a).Length; + public static float GetDistance(GameObject a, GameObject b) { if (a.CurrentRegion != b.CurrentRegion) return float.MaxValue; - return Vector3.Distance(a.Position, b.Position); + return GetDistance(a.Coordinate, b.Coordinate); + } + public static int GetDistanceSquared(Coordinate a, Coordinate b) + { + int dX = b.X - a.X; + int dY = b.Y - a.Y; + int dZ = b.Z - a.Z; + return dX * dX + dY * dY + dZ * dZ; + } + public static int GetDistanceSquared(GameObject a, GameObject b) + { + if (a.CurrentRegion != b.CurrentRegion) + return int.MaxValue; + return GetDistanceSquared(a.Coordinate, b.Coordinate); } public static bool IsWithinRadius(GameObject source, GameObject target, float distance) { if (source.CurrentRegion != target.CurrentRegion) return false; - return Vector3.DistanceSquared(source.Position, target.Position) <= distance * distance; + return GetDistanceSquared(source.Coordinate, target.Coordinate) <= distance * distance; } - public static bool IsWithinRadius(GameObject source, Vector3 target, float distance) - => Vector3.DistanceSquared(source.Position, target) <= distance * distance; - public static bool IsWithinRadius(Vector3 source, Vector3 target, float distance) - => Vector3.DistanceSquared(source, target) <= distance * distance; + + public static bool IsWithinRadius(GameObject source, Coordinate target, float distance) + => GetDistanceSquared(source.Coordinate, target) <= distance * distance; + + public static bool IsWithinRadius(Coordinate source, Coordinate target, float distance) + => GetDistanceSquared(source, target) <= distance * distance; public static bool IsWithinRadius2D(GameObject source, GameObject target, float distance) { if (source.CurrentRegion != target.CurrentRegion) return false; - return Vector2.DistanceSquared(source.Position.ToVector2(), target.Position.ToVector2()) <= distance * distance; + return GetDistance2DSquared(source.Coordinate, target.Coordinate) <= distance * distance; } - public static bool IsWithinRadius2D(GameObject source, Vector3 target, float distance) - => Vector2.DistanceSquared(source.Position.ToVector2(), target.ToVector2()) <= distance * distance; - public static bool IsWithinRadius2D(Vector3 source, Vector3 target, float distance) - => Vector2.DistanceSquared(source.ToVector2(), target.ToVector2()) <= distance * distance; + + public static bool IsWithinRadius2D(GameObject source, Coordinate target, float distance) + => GetDistance2DSquared(source.Coordinate, target) <= distance * distance; + + public static bool IsWithinRadius2D(Coordinate source, Coordinate target, float distance) + => GetDistance2DSquared(source, target) <= distance * distance; } } \ No newline at end of file diff --git a/GameServer/gameutils/GamePlayerUtils.cs b/GameServer/gameutils/GamePlayerUtils.cs index 08893226..8fbca425 100644 --- a/GameServer/gameutils/GamePlayerUtils.cs +++ b/GameServer/gameutils/GamePlayerUtils.cs @@ -23,7 +23,7 @@ using DOL.Language; using DOL.Database; -using System.Numerics; +using DOL.GS.Geometry; using DOL.GS.ServerProperties; namespace DOL.GS @@ -34,17 +34,6 @@ namespace DOL.GS public static class GamePlayerUtils { #region Spot and Area Description / Translation - /// - /// Get Spot Description Checking Any Area with Description or Zone Description - /// - /// - /// - /// - public static string GetSpotDescription(this Region reg, Vector3 spot) - { - return reg.GetSpotDescription(spot.X, spot.Y, spot.Z); - } - /// /// Get Spot Description Checking Any Area with Description or Zone Description /// @@ -53,11 +42,12 @@ public static string GetSpotDescription(this Region reg, Vector3 spot) /// /// /// - public static string GetSpotDescription(this Region reg, float x, float y, float z) + public static string GetSpotDescription(this Region reg, int x, int y, int z) { + var coordinate = Coordinate.Create(x, y, z); if (reg != null) { - var area = reg.GetAreasOfSpot(x, y, z).OfType().FirstOrDefault(a => a.DisplayMessage && !string.IsNullOrEmpty(a.Description)); + var area = reg.GetAreasOfSpot(coordinate).OfType().FirstOrDefault(a => a.DisplayMessage && !string.IsNullOrEmpty(a.Description)); if (area != null) return area.Description; @@ -80,25 +70,11 @@ public static string GetSpotDescription(this Region reg, float x, float y, float /// /// /// - public static string GetTranslatedSpotDescription(this Region reg, GameClient client, Vector3 spot) - { - return reg.GetTranslatedSpotDescription(client, spot.X, spot.Y, spot.Z); - } - - /// - /// Get Spot Description Checking Any Area with Description or Zone Description and Try Translating it - /// - /// - /// - /// - /// - /// - /// - public static string GetTranslatedSpotDescription(this Region reg, GameClient client, float x, float y, float z) + public static string GetTranslatedSpotDescription(this Region reg, GameClient client, Coordinate coordinate) { if (reg != null) { - var area = reg.GetAreasOfSpot(x, y, z).OfType().FirstOrDefault(a => a.DisplayMessage); + var area = reg.GetAreasOfSpot(coordinate).OfType().FirstOrDefault(a => a.DisplayMessage); // Try Translate Area First if (area != null) @@ -111,7 +87,7 @@ public static string GetTranslatedSpotDescription(this Region reg, GameClient cl return area.Description; } - var zone = reg.GetZone(x, y); + var zone = reg.GetZone(coordinate); // Try Translate Zone if (zone != null) @@ -128,64 +104,6 @@ public static string GetTranslatedSpotDescription(this Region reg, GameClient cl return string.Empty; } - - /// - /// Get Player Spot Description Checking Any Area with Description or Zone Description and Try Translating it - /// - /// - /// - public static string GetTranslatedSpotDescription(this GamePlayer player) - { - return player.GetTranslatedSpotDescription(player.CurrentRegion, player.Position.X, player.Position.Y, player.Position.Z); - } - - /// - /// Get Player Spot Description Checking Any Area with Description or Zone Description and Try Translating it - /// - /// - /// - /// - /// - /// - /// - public static string GetTranslatedSpotDescription(this GamePlayer player, Region region, float x, float y, float z) - { - return player.Client.GetTranslatedSpotDescription(region, x, y, z); - } - - /// - /// Get Client Spot Description Checking Any Area with Description or Zone Description and Try Translating it - /// - /// - /// - /// - /// - /// - /// - public static string GetTranslatedSpotDescription(this GameClient client, Region region, float x, float y, float z) - { - return region.GetTranslatedSpotDescription(client, x, y, z); - } - - /// - /// Get Player Spot Description Checking Any Area with Description or Zone Description - /// - /// - /// - public static string GetSpotDescription(this GamePlayer player) - { - return player.GetTranslatedSpotDescription(); - } - - /// - /// Get Player's Bind Spot Description Checking Any Area with Description or Zone Description - /// - /// - /// - public static string GetBindSpotDescription(this GamePlayer player) - { - return player.GetTranslatedSpotDescription(WorldMgr.GetRegion((ushort)player.BindRegion), player.BindXpos, player.BindYpos, player.BindZpos); - } #endregion #region player skills / bonuses diff --git a/GameServer/gameutils/GameTimer.cs b/GameServer/gameutils/GameTimer.cs index 681708e6..62fc4638 100644 --- a/GameServer/gameutils/GameTimer.cs +++ b/GameServer/gameutils/GameTimer.cs @@ -598,10 +598,10 @@ public bool Stop() { while (!m_timeThread.Join(2000)) { - log.ErrorFormat("Timer Thread ({0}) can't stop after abort... maybe remaining threads going... trying again !"); - try { + log.ErrorFormat("Timer Thread ({0}) can't stop after abort... maybe remaining threads going... trying again !", m_name); + m_timeThread.Interrupt(); } catch diff --git a/GameServer/gameutils/GuildBanner.cs b/GameServer/gameutils/GuildBanner.cs index 5470071a..3b156c48 100644 --- a/GameServer/gameutils/GuildBanner.cs +++ b/GameServer/gameutils/GuildBanner.cs @@ -10,7 +10,6 @@ using DOL.GS.Effects; using DOL.GS.ServerProperties; using System.Linq; -using System.Numerics; namespace DOL.GS { diff --git a/GameServer/gameutils/IDoor.cs b/GameServer/gameutils/IDoor.cs index 48908871..13e93d15 100644 --- a/GameServer/gameutils/IDoor.cs +++ b/GameServer/gameutils/IDoor.cs @@ -19,6 +19,7 @@ using System.Numerics; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS { @@ -37,7 +38,9 @@ public interface IDoor { string Name { get; } uint Flag { get; } - Vector3 Position { get; } + Position Position { get; } + Coordinate Coordinate { get; } + Angle Orientation { get; } ushort Heading { get; } ushort ZoneID { get; } eRealm Realm { get; } diff --git a/GameServer/gameutils/InventoryLogging.cs b/GameServer/gameutils/InventoryLogging.cs index 48e092bb..704c43a6 100644 --- a/GameServer/gameutils/InventoryLogging.cs +++ b/GameServer/gameutils/InventoryLogging.cs @@ -53,7 +53,7 @@ public static class InventoryLogging }; public static Func GetGameObjectString = obj => - obj == null ? null : ($"({obj.Name};{obj.GetType()};{obj.Position.X:F0};{obj.Position.Y:F0};{obj.Position.Z:F0};{obj.CurrentRegionID})"); + obj == null ? "(null)" : ("(" + obj.Name + ";" + obj.GetType() + ";" + obj.Coordinate + ";" + obj.Position.RegionID + ")"); public static Func GetItemTemplateString = (item, count) => item == null ? null : ("(" + count + ";" + item.Name + ";" + item.Id_nb + ")"); diff --git a/GameServer/gameutils/MovementMgr.cs b/GameServer/gameutils/MovementMgr.cs index 99dacfe7..722b4e09 100644 --- a/GameServer/gameutils/MovementMgr.cs +++ b/GameServer/gameutils/MovementMgr.cs @@ -155,22 +155,21 @@ public static PathPoint LoadPath(string pathID) PathPoint prev = null; PathPoint first = null; - - foreach (DBPathPoint pp in pathPoints.Values) + + foreach (DBPathPoint dbPathPoint in pathPoints.Values) { - PathPoint p = new PathPoint(pp.X, pp.Y, pp.Z, pp.MaxSpeed, pathType); - p.WaitTime = pp.WaitTime; + var pathPoint = new PathPoint(dbPathPoint, pathType); if (first == null) { - first = p; + first = pathPoint; } - p.Prev = prev; + pathPoint.Prev = prev; if (prev != null) { - prev.Next = p; + prev.Next = pathPoint; } - prev = p; + prev = pathPoint; } return first; @@ -211,11 +210,11 @@ public static void SavePath(string pathID, PathPoint path) int i = 1; do { - DBPathPoint dbpp = new DBPathPoint((int)path.Position.X, (int)path.Position.Y, (int)path.Position.Z, path.MaxSpeed); - dbpp.Step = i++; - dbpp.PathID = pathID; - dbpp.WaitTime = path.WaitTime; - GameServer.Database.AddObject(dbpp); + var dbPathPoint = path.GenerateDbEntry(); + dbPathPoint.Step = i++; + dbPathPoint.PathID = pathID; + GameServer.Database.AddObject(dbPathPoint); + path = path.Next; } while (path != null && path != root); diff --git a/GameServer/gameutils/PathPoint.cs b/GameServer/gameutils/PathPoint.cs index d1b82e5f..b8e8f0d2 100644 --- a/GameServer/gameutils/PathPoint.cs +++ b/GameServer/gameutils/PathPoint.cs @@ -17,102 +17,53 @@ * */ using System; -using System.Numerics; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.Movement { - /// - /// represents a point in a way path - /// public class PathPoint { - protected int m_maxspeed; - protected PathPoint m_next = null; - protected PathPoint m_prev = null; - protected ePathType m_type; - protected bool m_flag; - protected int m_waitTime = 0; + public Coordinate Coordinate { get; set; } - public Vector3 Position { get; set; } + [Obsolete("Use .Coordinate instead!")] + public int X { get => Coordinate.X; set => Coordinate.With(x: value); } + [Obsolete("Use .Coordinate instead!")] + public int Y { get => Coordinate.Y; set => Coordinate.With(y: value); } + [Obsolete("Use .Coordinate instead!")] + public int Z { get => Coordinate.Z; set => Coordinate.With(z: value); } - public PathPoint(PathPoint pp) : this(pp.Position, pp.MaxSpeed, pp.Type) { } + [Obsolete("This is going to be removed.")] + public PathPoint(PathPoint pp) : this(pp.Coordinate, pp.MaxSpeed, pp.Type) { } - public PathPoint(Vector3 p, int maxspeed, ePathType type) : this(p.X, p.Y, p.Z, maxspeed, type) { } - - public PathPoint(float x, float y, float z, int maxspeed, ePathType type) - { - Position = new Vector3(x, y, z); - m_maxspeed = maxspeed; - m_type = type; - m_flag = false; - m_waitTime = 0; - } - - /// - /// Speed allowed after that waypoint in forward direction - /// - public int MaxSpeed - { - get { return m_maxspeed; } - set { m_maxspeed = value; } - } - - /// - /// next waypoint in path - /// - public PathPoint Next - { - get { return m_next; } - set { m_next = value; } - } - - /// - /// previous waypoint in path - /// - public PathPoint Prev - { - get { return m_prev; } - set { m_prev = value; } - } - - /// - /// flag toggle when go through pathpoint - /// - public bool FiredFlag + public PathPoint(Coordinate coordinate, int maxspeed, ePathType type) { - get { return m_flag; } - set { m_flag = value; } + Coordinate = coordinate; + MaxSpeed = maxspeed; + Type = type; } - /// - /// path type - /// - public ePathType Type - { - get { return m_type; } - set { m_type = value; } - } + public PathPoint(int x, int y, int z, int maxspeed, ePathType type) + : this(Coordinate.Create(x, y, z), maxspeed, type) { } - /// - /// path type - /// - public int WaitTime + public PathPoint(DBPathPoint dbEntry, ePathType type) { - get { return m_waitTime; } - set { m_waitTime = value; } + Coordinate = Coordinate.Create(dbEntry.X, dbEntry.Y, dbEntry.Z); + MaxSpeed = dbEntry.MaxSpeed; + WaitTime = dbEntry.WaitTime; + Type = type; } - - public PathPoint GetNearestNextPoint(Vector3 pos) + + public PathPoint GetNearestNextPoint(Coordinate pos) { var nearest = this; - var dist = Vector3.Distance(nearest.Position, pos); + var dist = GameMath.GetDistanceSquared(nearest.Coordinate, pos); var pp = this; while (pp.Next != null) { pp = pp.Next; - var d = Vector3.Distance(pp.Position, pos); + var d = GameMath.GetDistanceSquared(pp.Coordinate, pos); if (d < dist) { nearest = pp; @@ -122,5 +73,33 @@ public PathPoint GetNearestNextPoint(Vector3 pos) return nearest; } + + public Angle AngleToNextPathPoint + => Coordinate.GetOrientationTo(Next.Coordinate); + + public int MaxSpeed { get; set; } + + public PathPoint Prev { get; set; } + public PathPoint Next { get; set; } + + /// + /// flag toggle when go through pathpoint + /// + public bool FiredFlag { get; set; } = false; + + public ePathType Type { get; set; } + + public int WaitTime { get; set; } = 0; + + public DBPathPoint GenerateDbEntry() + { + var dbPathPoint = new DBPathPoint(); + dbPathPoint.X = Coordinate.X; + dbPathPoint.Y = Coordinate.Y; + dbPathPoint.Z = Coordinate.Z; + dbPathPoint.MaxSpeed = MaxSpeed; + dbPathPoint.WaitTime = WaitTime; + return dbPathPoint; + } } } diff --git a/GameServer/gameutils/RegionTimersResync.cs b/GameServer/gameutils/RegionTimersResync.cs index d50a1ee0..4728f0db 100644 --- a/GameServer/gameutils/RegionTimersResync.cs +++ b/GameServer/gameutils/RegionTimersResync.cs @@ -193,7 +193,7 @@ private static void Resynch(object nullValue) PathPoint path = MovementMgr.LoadPath(npc.PathID); if (path != null) { - var p = path.GetNearestNextPoint(npc.Position); + var p = path.GetNearestNextPoint(npc.Coordinate); npc.CurrentWayPoint = p; npc.MoveOnPath((short)p.MaxSpeed); } @@ -203,16 +203,18 @@ private static void Resynch(object nullValue) npc.SetOwnBrain(brain); npc.Brain.Start(); } - catch (Exception e) + catch(Exception e) { - log.Error("Can't restart Brain in RegionTimerResynch, NPC Name = " + npc.Name + " Position=" + npc.Position.ToString("F0") + "/R=" + npc.CurrentRegion.ID + " " + e); + log.Error("Can't restart Brain in RegionTimerResynch, NPC Name = "+npc.Name + +" X="+npc.Position.X+"/Y="+npc.Position.Y+"/Z="+npc.Position.Z+"/R="+npc.Position.RegionID+" "+e); try { npc.Die(null); } - catch (Exception ee) + catch(Exception ee) { - log.Error("Can't restart Brain and Kill NPC in RegionTimerResynch, NPC Name = " + npc.Name + " Position=" + npc.Position.ToString("F0") + "/R=" + npc.CurrentRegion.ID + " " + ee); + log.Error("Can't restart Brain and Kill NPC in RegionTimerResynch, NPC Name = "+npc.Name + +" X="+npc.Position.X+"/Y="+npc.Position.Y+"/Z="+npc.Position.Z+"/R="+npc.Position.RegionID+" "+ee); } } } diff --git a/GameServer/gameutils/TPPoint.cs b/GameServer/gameutils/TPPoint.cs index 44e51b1d..b86d41ad 100644 --- a/GameServer/gameutils/TPPoint.cs +++ b/GameServer/gameutils/TPPoint.cs @@ -20,15 +20,21 @@ using System.Linq; using System.Collections.Generic; using DOL.Database; -using DOL.Geometry; +using DOL.GS.Geometry; namespace DOL.GS { /// /// represents a point in a way path /// - public class TPPoint : Point3D + public class TPPoint { + public Position Position + { + get; + init; + } = Position.Nowhere; + protected TPPoint m_next = null; protected TPPoint m_prev = null; protected eTPPointType m_type; @@ -38,14 +44,13 @@ public class TPPoint : Point3D protected const ushort PLAYERS_RADIUS = 1500; - public TPPoint(TPPoint pp) : this(pp, pp.Type) { } - - public TPPoint(System.Numerics.Vector3 p, eTPPointType type) : this(0, (int)p.X, (int)p.Y, (int)p.Z, type, new DBTPPoint(0, (int)p.X, (int)p.Y, (int)p.Z)) { } + public TPPoint(TPPoint pp) : this(pp.Position, pp.Type) { } - public TPPoint(Point3D p, eTPPointType type) : this(0, (int)p.Position.X, (int)p.Position.Y, (int)p.Position.Z, type, new DBTPPoint(0, (int)p.Position.X, (int)p.Position.Y, (int)p.Position.Z)) { } + public TPPoint(Position p, eTPPointType type) : this(p.RegionID, (int)p.X, (int)p.Y, (int)p.Z, type, new DBTPPoint(p.RegionID, (int)p.X, (int)p.Y, (int)p.Z)) { } - public TPPoint(ushort region, int x, int y, int z, eTPPointType type, DBTPPoint bTPPoint) : base(x, y, z) + public TPPoint(ushort region, int x, int y, int z, eTPPointType type, DBTPPoint bTPPoint) { + Position = Position.Create(region, x, y, z); m_type = type; m_flag = false; dbTPPoint = bTPPoint; @@ -89,7 +94,7 @@ public eTPPointType Type } public DBTPPoint DbTPPoint { get => dbTPPoint; set => dbTPPoint = value; } - public ushort Region { get => region; set => region = value; } + public ushort Region { get => Position.RegionID; } public TPPoint GetNextTPPoint() { @@ -131,7 +136,7 @@ public TPPoint GetSmarttNextPoint() { if (pp != this) { - int newCount = WorldMgr.GetPlayersCloseToSpot(pp.Region, (float)pp.Position.X, (float)pp.Position.Y, (float)pp.Position.Z, PLAYERS_RADIUS).OfType().Count(); + int newCount = WorldMgr.GetPlayersCloseToSpot(pp.Region, pp.Position.X, pp.Position.Y, pp.Position.Z, PLAYERS_RADIUS).OfType().Count(); if (newCount > countPlayer) { nearest = pp; diff --git a/GameServer/gameutils/Util.cs b/GameServer/gameutils/Util.cs index 6dc3e5db..2993b227 100644 --- a/GameServer/gameutils/Util.cs +++ b/GameServer/gameutils/Util.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; using System.Collections.Generic; using System.Diagnostics; @@ -485,7 +486,7 @@ public static string FormatTime(long seconds) /// /// /// - public static bool IsNearValue(float valueToHave, float compareToCompare, ushort tolerance) + public static bool IsNearValue(int valueToHave, int compareToCompare, ushort tolerance) { return FastMath.Abs(valueToHave - compareToCompare) <= FastMath.Abs(tolerance); } @@ -501,11 +502,11 @@ public static bool IsNearValue(float valueToHave, float compareToCompare, ushort /// Z coord value to compare /// Tolerance distance between two coords /// - public static bool IsNearDistance(float xH, float yH, float zH, float xC, float yC, float zC, ushort tolerance) + public static bool IsNearDistance(int xH, int yH, int zH, int xC, int yC, int zC, ushort tolerance) { return IsNearValue(xH, xC, tolerance) && IsNearValue(yH, yC, tolerance) && IsNearValue(zH, zC, tolerance); } - public static bool IsNearDistance(Vector3 origin, Vector3 target, ushort tolerance) + public static bool IsNearDistance(Coordinate origin, Coordinate target, ushort tolerance) => IsNearDistance(origin.X, origin.Y, origin.Z, target.X, target.Y, target.Z, tolerance); #region Collection Utils diff --git a/GameServer/gameutils/WarMapMgr.cs b/GameServer/gameutils/WarMapMgr.cs index 68b456fc..d311ebc8 100644 --- a/GameServer/gameutils/WarMapMgr.cs +++ b/GameServer/gameutils/WarMapMgr.cs @@ -2,6 +2,7 @@ using System.Reflection; using System.Collections.Generic; using DOL.GS; +using DOL.GS.Geometry; using log4net; namespace DOL.GS @@ -56,8 +57,8 @@ public static bool AddFight(byte zoneid, int x, int y, byte realm1, byte realm2) long time = NFTime; Fight fight = new Fight(); fight.Zone = zoneid; - fight.X = (byte)((x - zone.XOffset) >> 14); - fight.Y = (byte)((y - zone.YOffset) >> 14); + fight.X = (byte)((x - zone.Offset.X) >> 14); + fight.Y = (byte)((y - zone.Offset.Y) >> 14); fight.Realm1 = realm1; fight.Realm2 = realm2; lock (m_fights) @@ -67,8 +68,16 @@ public static bool AddFight(byte zoneid, int x, int y, byte realm1, byte realm2) } return true; } - + + [Obsolete("Use .AddGroup(Position,string,byte) instead!")] public static bool AddGroup(byte zoneid, int x, int y, string name, byte realm) + { + var zone = WorldMgr.GetZone(zoneid); + if (zone == null) return false; + return AddGroup(Position.Create(zone.ZoneRegion.ID, x, y), name, realm); + } + + public static bool AddGroup(Position position, string name, byte realm) { if (!ServerProperties.Properties.ENABLE_WARMAPMGR) return false; @@ -77,13 +86,15 @@ public static bool AddGroup(byte zoneid, int x, int y, string name, byte realm) { if (m_groups.ContainsKey(name)) return false; m_groups.Add(name, new Dictionary()); - Zone zone = WorldMgr.GetZone(zoneid); + var region = WorldMgr.GetRegion(position.RegionID); + var zone = region.GetZone(position.Coordinate); if (zone == null) return false; long time = NFTime; Group group = new Group(); - group.Zone = zoneid; - group.X = (byte)((x - zone.XOffset) >> 14); - group.Y = (byte)((y - zone.YOffset) >> 14); + group.Zone = (byte)zone.ID; + var groupPosition = position - zone.Offset; + group.X = (byte)(groupPosition.X >> 14); + group.Y = (byte)((groupPosition.Y) >> 14); group.Realm = realm; while (m_groups[name].ContainsKey(time)) time++; m_groups[name].Add(time, group); diff --git a/GameServer/housing/House.cs b/GameServer/housing/House.cs index 42412fb6..1c5aaf4a 100644 --- a/GameServer/housing/House.cs +++ b/GameServer/housing/House.cs @@ -24,12 +24,14 @@ using System.Reflection; using DOL.Database; using DOL.GS.Finance; +using DOL.GS.Geometry; using DOL.Language; using log4net; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.GS.Housing { - public class House : IGameLocation + public class House { /// /// Defines a logger for this class. @@ -245,7 +247,7 @@ public bool IsOccupied { get { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(RegionID, Position.X, Position.Y, 25000, WorldMgr.VISIBILITY_DISTANCE)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Position.With(z: 25000), WorldMgr.VISIBILITY_DISTANCE)) { if (player.CurrentHouse == this && player.InHouse) { @@ -257,27 +259,57 @@ public bool IsOccupied } } - public Vector3 Position + public Position Position { - get => new Vector3(_databaseItem.X, _databaseItem.Y, _databaseItem.Z); + get => Position.Create(_databaseItem.RegionID, _databaseItem.X, _databaseItem.Y, _databaseItem.Z, (ushort)(_databaseItem.Heading/180.0*2048)); set { - _databaseItem.X = (int)value.X; - _databaseItem.Y = (int)value.Y; - _databaseItem.Z = (int)value.Z; + _databaseItem.X = value.X; + _databaseItem.Y = value.Y; + _databaseItem.Z = value.Z; + _databaseItem.Heading = value.Orientation.InDegrees; + _databaseItem.RegionID = value.RegionID; } } - public ushort RegionID + [Obsolete("Use .Position instead!")] + public int X { - get { return _databaseItem.RegionID; } - set { _databaseItem.RegionID = value; } + get => Position.X; + set => Position = Position.With(x: value); } + [Obsolete("Use .Position instead!")] + public int Y + { + get => Position.Y; + set => Position = Position.With(y: value); + } + + [Obsolete("Use .Position instead!")] + public int Z + { + get => Position.Z; + set => Position = Position.With(z: value); + } + + [Obsolete("Use either .Orientation (in degrees) or .Position.Heading instead!")] public ushort Heading { - get { return (ushort)_databaseItem.Heading; } - set { _databaseItem.Heading = value; } + get => (ushort)_databaseItem.Heading; + set => _databaseItem.Heading = value; + } + + ///House orientation in degrees. + public ushort Orientation + { + get => (ushort)_databaseItem.Heading; + } + + public ushort RegionID + { + get => Position.RegionID; + set => Position = Position.With(regionID: value); } public string Name @@ -302,29 +334,23 @@ public House(DBHouse house) { log.DebugFormat("House destructor called for House #{0} in region {1}", HouseNumber, RegionID); } - + + [Obsolete("Use OutdoorJumpPosition instead!")] + public GameLocation OutdoorJumpPoint + => new GameLocation(OutdoorJumpPosition); + /// /// The spot you are teleported to when you exit this house. /// - public GameLocation OutdoorJumpPoint - { - get - { - double angle = Heading * ((Math.PI * 2) / 360); // angle*2pi/360; - var x = (float)(Position.X + (0 * Math.Cos(angle) + 500 * Math.Sin(angle))); - var y = (float)(Position.Y - (500 * Math.Cos(angle) - 0 * Math.Sin(angle))); - var heading = (ushort)((Heading < 180 ? Heading + 180 : Heading - 180) / 0.08789); - - return new GameLocation("Housing", RegionID, x, y, Position.Z, heading); - } - } + public Position OutdoorJumpPosition + => (Position + Vector.Create(Position.Orientation + Angle.Degrees(180), length: 500)).TurnedAround(); /// /// Sends a update of the house and the garden to all players in range /// public void SendUpdate() { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(this, HousingConstants.HouseViewingDistance)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Position, HousingConstants.HouseViewingDistance)) { player.Out.SendHouse(this); player.Out.SendGarden(this); @@ -345,7 +371,7 @@ public void Enter(GamePlayer player) IList list = GetAllPlayersInHouse(); if (list.Count == 0) { - foreach (GamePlayer pl in WorldMgr.GetPlayersCloseToSpot(this, HousingConstants.HouseViewingDistance)) + foreach (GamePlayer pl in WorldMgr.GetPlayersCloseToSpot(Position, HousingConstants.HouseViewingDistance)) { pl.Out.SendHouseOccupied(this, true); } @@ -363,55 +389,55 @@ public void Enter(GamePlayer player) { //thx to sp4m default: - player.MoveTo(RegionID, Position.X, Position.Y, 25022, heading); + player.MoveTo(Position.With(z: 25022, heading: 0)); break; case 1: - player.MoveTo(RegionID, Position.X + 80, Position.Y + 100, ((25025)), heading); + player.MoveTo(Position.With(z: 25025, heading: 0) + Vector.Create(x: 80, y: 100)); break; case 2: - player.MoveTo(RegionID, Position.X - 260, Position.Y + 100, ((24910)), heading); + player.MoveTo(Position.With(z: 24910, heading: 0) + Vector.Create(x: -260, y: 100)); break; case 3: - player.MoveTo(RegionID, Position.X - 200, Position.Y + 100, ((24800)), heading); + player.MoveTo(Position.With(z: 24800, heading: 0) + Vector.Create(x: -200, y: 100)); break; case 4: - player.MoveTo(RegionID, Position.X - 350, Position.Y - 30, ((24660)), heading); + player.MoveTo(Position.With(z: 24660, heading: 0) + Vector.Create(x: -350, y: -30)); break; case 5: - player.MoveTo(RegionID, Position.X + 230, Position.Y - 480, ((25100)), heading); + player.MoveTo(Position.With(z: 25100, heading: 0) + Vector.Create(x: 230, y: -480)); break; case 6: - player.MoveTo(RegionID, Position.X - 80, Position.Y - 660, ((24700)), heading); + player.MoveTo(Position.With(z: 24700, heading: 0) + Vector.Create(x: -80, y: -660)); break; case 7: - player.MoveTo(RegionID, Position.X - 80, Position.Y - 660, ((24700)), heading); + player.MoveTo(Position.With(z: 24700, heading: 0) + Vector.Create(x: -80, y: -660)); break; case 8: - player.MoveTo(RegionID, Position.X - 90, Position.Y - 625, ((24670)), heading); + player.MoveTo(Position.With(z: 24670, heading: 0) + Vector.Create(x: -90, y: -625)); break; case 9: - player.MoveTo(RegionID, Position.X + 400, Position.Y - 160, ((25150)), heading); + player.MoveTo(Position.With(z: 25150, heading: 0) + Vector.Create(x: 400, y: -160)); break; case 10: - player.MoveTo(RegionID, Position.X + 400, Position.Y - 80, ((25060)), heading); + player.MoveTo(Position.With(z: 25060, heading: 0) + Vector.Create(x: 400, y: -80)); break; case 11: - player.MoveTo(RegionID, Position.X + 400, Position.Y - 60, ((24900)), heading); + player.MoveTo(Position.With(z: 24900, heading: 0) + Vector.Create(x: 400, y: -60)); break; case 12: - player.MoveTo(RegionID, Position.X, Position.Y - 620, ((24595)), heading); + player.MoveTo(Position.With(z: 24595, heading: 0) + Vector.Create(y: -620)); break; } @@ -425,7 +451,7 @@ public void Enter(GamePlayer player) /// text or not public void Exit(GamePlayer player, bool silent) { - player.MoveTo(OutdoorJumpPoint); + player.MoveTo(OutdoorJumpPosition); if (!silent) { @@ -437,7 +463,7 @@ public void Exit(GamePlayer player, bool silent) IList list = GetAllPlayersInHouse(); if (list.Count == 0) { - foreach (GamePlayer pl in WorldMgr.GetPlayersCloseToSpot(this, HousingConstants.HouseViewingDistance)) + foreach (GamePlayer pl in WorldMgr.GetPlayersCloseToSpot(Position, HousingConstants.HouseViewingDistance)) { pl.Out.SendHouseOccupied(this, false); } @@ -545,7 +571,7 @@ public int GetGuildEmblemFlags() public IList GetAllPlayersInHouse() { var ret = new List(); - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(RegionID, Position.X, Position.Y, 25000, WorldMgr.VISIBILITY_DISTANCE)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Position.With(z: 25000), WorldMgr.VISIBILITY_DISTANCE)) { if (player.CurrentHouse == this && player.InHouse) { @@ -614,21 +640,28 @@ public static void LoadHookpointOffsets() AddNewOffset(o); } } - + + [Obsolete("Use GetHookPointCoordinate(uint) instead!")] public Vector3? GetHookpointLocation(uint n) { - if (n > HousingConstants.MaxHookpointLocations) - return null; + var loc = GetHookPointCoordinate(n); + if(loc == Coordinate.Nowhere) return null; + else return loc.ToSysVector3(); + } - int[] hookpointsCoords = HousingConstants.RelativeHookpointsCoords[Model][n]; + public Coordinate GetHookPointCoordinate(uint number) + { + if (number > HousingConstants.MaxHookpointLocations) return Coordinate.Nowhere; - if (hookpointsCoords == null) - return null; + int[] hookpointsCoords = HousingConstants.RelativeHookpointsCoords[Model][number]; - return new Vector3(Position.X + hookpointsCoords[0], Position.Y + hookpointsCoords[1], 25000 + hookpointsCoords[2]); - } + if (hookpointsCoords == null) return Coordinate.Nowhere; - private int GetHookpointPosition(float objX, float objY, float _objZ) + var hookPointOffset = Vector.Create(x: hookpointsCoords[0], y: hookpointsCoords[1], z: hookpointsCoords[2]); + return Position.Coordinate.With(z: 25000) + hookPointOffset; + } + + private int GetHookpointPosition(Coordinate loc) { int position = -1; @@ -636,8 +669,8 @@ private int GetHookpointPosition(float objX, float objY, float _objZ) { if (HousingConstants.RelativeHookpointsCoords[Model][i] != null) { - if (HousingConstants.RelativeHookpointsCoords[Model][i][0] + Position.X == objX && - HousingConstants.RelativeHookpointsCoords[Model][i][1] + Position.Y == objY) + if (HousingConstants.RelativeHookpointsCoords[Model][i][0] + Position.X == loc.X && + HousingConstants.RelativeHookpointsCoords[Model][i][1] + Position.Y == loc.Y) { position = i; } @@ -657,7 +690,7 @@ private ushort GetHookpointHeading(uint n) if (hookpointsCoords == null) return 0; - return (ushort)(Heading + hookpointsCoords[3]); + return (ushort) (Orientation + hookpointsCoords[3]); } /// @@ -675,9 +708,8 @@ public bool FillHookpoint(uint position, string templateID, ushort heading, int return false; //get location from slot - var location = GetHookpointLocation(position); - if (location == null) - return false; + var coordinate = GetHookPointCoordinate(position); + if (coordinate == Coordinate.Nowhere) return false; GameObject hookpointObject = null; @@ -692,7 +724,7 @@ public bool FillHookpoint(uint position, string templateID, ushort heading, int } case eObjectType.HouseNPC: { - hookpointObject = GameServer.ServerRules.PlaceHousingNPC(this, item, location.Value, GetHookpointHeading(position)); + hookpointObject = GameServer.ServerRules.PlaceHousingNPC(this, item, coordinate, GetHookpointHeading(position)); break; } case eObjectType.HouseBindstone: @@ -700,9 +732,7 @@ public bool FillHookpoint(uint position, string templateID, ushort heading, int hookpointObject = new GameStaticItem(); hookpointObject.CurrentHouse = this; hookpointObject.OwnerID = templateID; - hookpointObject.Position = location.Value; - hookpointObject.Heading = heading; - hookpointObject.CurrentRegionID = RegionID; + hookpointObject.Position = Position.Create(RegionID, coordinate, heading); hookpointObject.Name = item.Name; hookpointObject.Model = (ushort)item.Model; hookpointObject.AddToWorld(); @@ -712,7 +742,7 @@ public bool FillHookpoint(uint position, string templateID, ushort heading, int } case eObjectType.HouseInteriorObject: { - hookpointObject = GameServer.ServerRules.PlaceHousingInteriorItem(this, item, location.Value, heading); + hookpointObject = GameServer.ServerRules.PlaceHousingInteriorItem(this, item, coordinate, heading); break; } } @@ -734,7 +764,7 @@ public void EmptyHookpoint(GamePlayer player, GameObject obj, bool addToInventor return; } - int position = GetHookpointPosition(obj.Position.X, obj.Position.Y, obj.Position.Z); + int position = GetHookpointPosition(obj.Coordinate); if (position < 0) { @@ -859,23 +889,18 @@ public bool AddConsignment(long startValue) float[] consignmentCoords = HousingConstants.ConsignmentPositioning[Model]; double multi = consignmentCoords[0]; - var range = consignmentCoords[1]; - var zaddition = consignmentCoords[2]; - var realm = consignmentCoords[3]; + var range = (int) consignmentCoords[1]; + var zaddition = (int) consignmentCoords[2]; + var realm = (int) consignmentCoords[3]; - double angle = Heading * ((Math.PI * 2) / 360); // angle*2pi/360; - var heading = (ushort)((Heading < 180 ? Heading + 180 : Heading - 180) / 0.08789); - var tX = (float)((Position.X + (500 * Math.Sin(angle))) - Math.Sin(angle - multi) * range); - var tY = (float)((Position.Y - (500 * Math.Cos(angle))) + Math.Cos(angle - multi) * range); + var merchantPosition = OutdoorJumpPosition + Vector.Create(Position.Orientation - Angle.Radians(multi), length: range, z: zaddition); GameConsignmentMerchant con = GameServer.ServerRules.CreateHousingConsignmentMerchant(this); - con.CurrentRegionID = RegionID; - con.Position = new Vector3(tX, tY, Position.Z - zaddition); + con.Position = merchantPosition; con.Level = 50; con.Realm = (eRealm)realm; con.HouseNumber = (ushort)HouseNumber; - con.Heading = heading; con.Model = 144; con.Flags |= GameNPC.eFlags.PEACE; diff --git a/GameServer/housing/HouseMgr.cs b/GameServer/housing/HouseMgr.cs index e50f5a09..10db3bb0 100644 --- a/GameServer/housing/HouseMgr.cs +++ b/GameServer/housing/HouseMgr.cs @@ -30,6 +30,7 @@ using DOL.Language; using log4net; +using DOL.GS.Geometry; namespace DOL.GS.Housing { @@ -447,7 +448,7 @@ public static void RemoveHouse(House house) } // remove the house for all nearby players - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(house, WorldMgr.OBJ_UPDATE_DISTANCE)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(house.Position, WorldMgr.OBJ_UPDATE_DISTANCE)) { player.Out.SendRemoveHouse(house); player.Out.SendGarden(house); @@ -835,20 +836,23 @@ public static void BuyHousingItem(GamePlayer player, ushort slot, byte count, eM GameServer.ServerRules.BuyHousingItem(player, slot, count, merchantType); } + [Obsolete("Use .GetHousesCloseToSpot(Position) instead!")] + public static IEnumerable GetHousesCloseToSpot(ushort regionid, int x, int y, int radius) + => GetHousesCloseToSpot(Position.Create(x: x, y: y, regionID: regionid), radius); /// /// This function gets the house close to spot /// /// array of house - public static IEnumerable GetHousesCloseToSpot(ushort regionid, int x, int y, int radius) + public static IEnumerable GetHousesCloseToSpot(Position position, int radius) { var myhouses = new ArrayList(); int radiussqrt = radius * radius; - foreach (House house in GetHouses(regionid).Values) + foreach (House house in GetHouses(position.RegionID).Values) { - float xdiff = house.Position.X - x; - float ydiff = house.Position.Y - y; - float range = xdiff * xdiff + ydiff * ydiff; + int xdiff = house.Position.X - position.X; + int ydiff = house.Position.Y - position.Y; + int range = xdiff * xdiff + ydiff * ydiff; if (range < 0) range *= -1; if (range > radiussqrt) @@ -858,4 +862,4 @@ public static IEnumerable GetHousesCloseToSpot(ushort regionid, int x, int y, in return myhouses; } } -} \ No newline at end of file +} diff --git a/GameServer/housing/LotMarker.cs b/GameServer/housing/LotMarker.cs index 9733ec4a..cc61b5d0 100644 --- a/GameServer/housing/LotMarker.cs +++ b/GameServer/housing/LotMarker.cs @@ -18,10 +18,10 @@ */ using System; using System.Collections; -using System.Numerics; using DOL.Database; using DOL.GS.Finance; using DOL.GS.PacketHandler; +using DOL.GS.Geometry; namespace DOL.GS.Housing { @@ -256,9 +256,7 @@ public static void SpawnLotMarker(DBHouse house) { var obj = new GameLotMarker { - Position = new Vector3(house.X, house.Y, house.Z), - CurrentRegionID = house.RegionID, - Heading = (ushort)house.Heading, + Position = Position.Create(house.RegionID, house.X, house.Y, house.Z, (ushort)house.Heading), Name = "Lot Marker", Model = 1308, DatabaseItem = house diff --git a/GameServer/keeps/AbstractGameKeep.cs b/GameServer/keeps/AbstractGameKeep.cs index e996c81e..aa4ad082 100644 --- a/GameServer/keeps/AbstractGameKeep.cs +++ b/GameServer/keeps/AbstractGameKeep.cs @@ -24,6 +24,7 @@ using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using log4net; @@ -195,7 +196,7 @@ public Zone CurrentZone { if (CurrentRegion != null) { - return CurrentRegion.GetZone(X, Y); + return CurrentRegion.GetZone(Position.Coordinate); } return null; } @@ -349,49 +350,47 @@ public virtual string Name set { DBKeep.Name = value; } } - /// - /// The Keep Region ID linked to the DBKeep - /// + public Position Position + { + get => DBKeep.GetPosition(); + set => DBKeep.SetPosition(value); + } + public ushort Region { - get { return DBKeep.Region; } - set { DBKeep.Region = value; } + get => Position.RegionID; + set => Position = Position.With(regionID: value); } - /// - /// The Keep X linked to the DBKeep - /// public int X { - get { return DBKeep.X; } - set { DBKeep.X = value; } + get => Position.X; + set => Position = Position.With(x: value); } - /// - /// The Keep Y linked to the DBKeep - /// public int Y { - get { return DBKeep.Y; } - set { DBKeep.Y = value; } + get => Position.Y; + set => Position = Position.With(y: value); } - /// - /// The Keep Z linked to the DBKeep - /// public int Z { - get { return DBKeep.Z; } - set { DBKeep.Z = value; } + get => Position.Z; + set => Position = Position.With(z: value); } - /// - /// The Keep Heading linked to the DBKeep - /// + [Obsolete("Use .Orientation instead!")] public ushort Heading { - get { return DBKeep.Heading; } - set { DBKeep.Heading = value; } + get => (ushort)Position.Orientation.InDegrees; + set => Position = Position.With(orientation: Angle.Degrees(value)); + } + + public Angle Orientation + { + get => Position.Orientation; + set => Position = Position.With(orientation: value); } /// @@ -467,7 +466,7 @@ public virtual void Load(DBKeep keep) GameEventMgr.AddHandler(CurrentRegion, RegionEvent.PlayerEnter, new DOLEventHandler(SendKeepInit)); KeepArea area = null; //see if any keep areas for this keep have already been added via DBArea - foreach (AbstractArea a in CurrentRegion.GetAreasOfSpot(keep.X, keep.Y, keep.Z)) + foreach (AbstractArea a in CurrentRegion.GetAreasOfSpot(keep.GetPosition().Coordinate)) { if (a is KeepArea && a.Description == keep.Name) { @@ -514,9 +513,7 @@ public virtual void Remove(KeepArea area) { door.Delete(); GameDoor d = new GameDoor(); - d.CurrentRegionID = door.CurrentRegionID; d.DoorID = door.DoorID; - d.Heading = door.Heading; d.Level = door.Level; d.Model = door.Model; d.Name = "door"; @@ -668,7 +665,7 @@ public virtual bool CheckForClaim(GamePlayer player) int count = 0; foreach (GamePlayer p in player.Group.GetPlayersInTheGroup()) { - if (GameServer.KeepManager.GetKeepCloseToSpot(p.CurrentRegionID, p.Position, WorldMgr.VISIBILITY_DISTANCE) == this) + if (GameServer.KeepManager.GetKeepCloseToSpot(p.Position, WorldMgr.VISIBILITY_DISTANCE) == this) count++; } @@ -1191,16 +1188,15 @@ protected void ResetPlayersOfKeep() DBKeepHookPoint hp = DOLDB.SelectObject(DB.Column(nameof(DBKeepHookPoint.HookPointID)).IsEqualTo(97).And(DB.Column(nameof(DBKeepHookPoint.Height)).IsEqualTo(Height))); if (hp == null) return; - float z = component.Position.Z + hp.Z; + int z = component.Position.Z + hp.Z; foreach (GamePlayer player in component.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE)) { - var d = player.GetDistanceTo(hookpoint.Position); + int d = (int)hookpoint.Position.Coordinate.DistanceTo(player.Coordinate, ignoreZ: true); if (d > distance) continue; - if (player.Position.Z > z) - player.MoveTo(player.CurrentRegionID, player.Position.X, player.Position.Y, z, player.Heading); + if (player.Position.Z > z) player.MoveTo(player.Position.With(z: z)); } } diff --git a/GameServer/keeps/GameKeepComponent.cs b/GameServer/keeps/GameKeepComponent.cs index ec963273..c05bc52c 100644 --- a/GameServer/keeps/GameKeepComponent.cs +++ b/GameServer/keeps/GameKeepComponent.cs @@ -23,10 +23,12 @@ using System.Text; using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.ServerProperties; using log4net; using System.Numerics; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.GS.Keeps { @@ -115,6 +117,12 @@ public bool Climbing /// relative heading to keep ( 0, 1, 2, 3) /// public int ComponentHeading { get; set; } + + public Angle RelativeOrientationToKeep + { + get => Angle.Degrees(ComponentHeading * 90); + set => ComponentHeading = value.InDegrees / 90; + } protected int m_oldMaxHealth; @@ -151,7 +159,7 @@ public override IList GetExamineMessages(GamePlayer player) if (player.Client.Account.PrivLevel > 1) { - list.Add(Name + " with a Z of " + Position.Z.ToString("F0")); + list.Add($"{Name} with a Z of {Position.Z}"); } return list; @@ -205,20 +213,17 @@ public virtual void LoadFromDatabase(DBKeepComponent component, AbstractGameKeep //this.DBKeepComponent = component; base.LoadFromDatabase(component); //this x and y is for get object in radius - double angle = keep.Heading * ((Math.PI * 2) / 360); // angle*2pi/360; - Position = new Vector3( - keep.X + (float)((sbyte)component.X * 148 * Math.Cos(angle) + (sbyte)component.Y * 148 * Math.Sin(angle)), - keep.Y - (float)((sbyte)component.Y * 148 * Math.Cos(angle) - (sbyte)component.X * 148 * Math.Sin(angle)), - keep.Z - ); + var angle = keep.Orientation; + var offset = Vector.Create(148 * (sbyte)component.X, -148 * (sbyte)component.Y, 0) + .RotatedClockwise(angle); + + //need check to be sure for heading + angle += Angle.Degrees(component.Heading * 90); + Position = keep.Position.With(angle) + offset; // and this one for packet sent ComponentX = component.X; ComponentY = component.Y; ComponentHeading = (ushort)component.Heading; - //need check to be sure for heading - angle = (component.Heading * 90 + keep.Heading); - if (angle > 360) angle -= 360; - Heading = (ushort)(angle / 0.08789); Name = keep.Name; Model = INVISIBLE_MODEL; Skin = component.Skin; @@ -558,8 +563,8 @@ public override void Die(GameObject killer) foreach (var guard in Keep.Guards.Values) { - guard.MoveTo(guard.CurrentRegionID, guard.Position.X, guard.Position.Y, Keep.Z, guard.Heading); - guard.SpawnPoint += Vector3.UnitZ * Keep.Z; + guard.MoveTo(guard.Position); + guard.SpawnPosition = guard.SpawnPosition.With(z: Keep.Z); } } } @@ -716,8 +721,8 @@ public override string ToString() .Append(" ComponentID=").Append(ID) .Append(" Skin=").Append(Skin) .Append(" Height=").Append(Height) - .Append(" Heading=").Append(Heading) - .Append(" nComponentX=").Append((sbyte)ComponentX) + .Append(" Heading=").Append(Orientation.InHeading) + .Append(" ComponentX=").Append((sbyte)ComponentX) .Append(" ComponentY=").Append((sbyte)ComponentY) .Append(" ComponentHeading=").Append(ComponentHeading) .ToString(); diff --git a/GameServer/keeps/Gameobjects/FrontiersPortalStone.cs b/GameServer/keeps/Gameobjects/FrontiersPortalStone.cs index 84b5241c..cc123590 100644 --- a/GameServer/keeps/Gameobjects/FrontiersPortalStone.cs +++ b/GameServer/keeps/Gameobjects/FrontiersPortalStone.cs @@ -19,7 +19,9 @@ using System.Collections; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; +using System; namespace DOL.GS.Keeps { @@ -64,7 +66,7 @@ public override eRealm Realm { if (m_component != null) return m_component.Keep.Realm; - if (m_CurrentRegion.ID == 163) + if (CurrentRegion.ID == 163) return CurrentZone.Realm; return base.Realm; } @@ -125,15 +127,13 @@ public override bool Interact(GamePlayer player) return true; } + [Obsolete("This is going to be removed.")] public void GetTeleportLocation(out int x, out int y) { - ushort originalHeading = m_Heading; - m_Heading = (ushort)Util.Random((m_Heading - 500), (m_Heading + 500)); - int distance = Util.Random(50, 150); - var portloc = GameMath.GetPointFromHeading(Position, Heading, distance); - x = (int)portloc.X; - y = (int)portloc.Y; - m_Heading = originalHeading; + var angle = Orientation + Angle.Heading(Util.Random(- 500, 500)); + var portPosition = Position + Vector.Create(angle, length: Util.Random(50, 150)); + x = portPosition.X; + y = portPosition.Y; } public class TeleporterEffect : GameNPC @@ -157,9 +157,7 @@ public override bool AddToWorld() { if (!base.AddToWorld()) return false; TeleporterEffect mob = new TeleporterEffect(); - mob.CurrentRegion = this.CurrentRegion; mob.Position = this.Position; - mob.Heading = this.Heading; mob.Health = mob.MaxHealth; mob.MaxSpeedBase = 0; if (mob.AddToWorld()) diff --git a/GameServer/keeps/Gameobjects/GameKeepBanner.cs b/GameServer/keeps/Gameobjects/GameKeepBanner.cs index 3b9ce87a..3d573c99 100644 --- a/GameServer/keeps/Gameobjects/GameKeepBanner.cs +++ b/GameServer/keeps/Gameobjects/GameKeepBanner.cs @@ -17,8 +17,8 @@ * */ using System; -using System.Numerics; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; namespace DOL.GS.Keeps @@ -167,14 +167,14 @@ public virtual void LoadFromPosition(DBKeepPosition pos, GameKeepComponent compo if (component.Keep.Guild != null) { ChangeGuild(); - Position += Vector3.UnitZ * 1500; + Position += Vector.Create(z: 1500); this.AddToWorld(); } } else { ChangeRealm(); - Position += Vector3.UnitZ * 1000; // this works around an issue where all banners are at keep level instead of on top + Position += Vector.Create(z: 1500); // this works around an issue where all banners are at keep level instead of on top // with a z value > height of the keep the banners show correctly - tolakram this.AddToWorld(); } @@ -183,14 +183,14 @@ public virtual void LoadFromPosition(DBKeepPosition pos, GameKeepComponent compo log.Warn($"LoadFromPosition(): There is already a Banner with TemplateID {this.TemplateID} on KeepID {component.Keep.KeepID}, not adding Banner for KeepPosition_ID {pos.ObjectId} on KeepComponent_ID {component.InternalID}"); } + [Obsolete("This is going to be removed!")] public void MoveToPosition(DBKeepPosition position) { PositionMgr.LoadKeepItemPosition(position, this); int zAdd = 1000; - if (BannerType == eBannerType.Guild) - zAdd = 1500; + if (BannerType == eBannerType.Guild) zAdd = 1500; - this.MoveTo(this.CurrentRegionID, Position + Vector3.UnitZ * zAdd, this.Heading); + this.MoveTo(Position + Vector.Create(z: zAdd)); } public void ChangeRealm() diff --git a/GameServer/keeps/Gameobjects/GameKeepDoor.cs b/GameServer/keeps/Gameobjects/GameKeepDoor.cs index 3fef54a5..967c659c 100644 --- a/GameServer/keeps/Gameobjects/GameKeepDoor.cs +++ b/GameServer/keeps/Gameobjects/GameKeepDoor.cs @@ -23,10 +23,12 @@ using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.ServerProperties; using log4net; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.GS.Keeps @@ -406,7 +408,7 @@ public override bool Interact(GamePlayer player) if (!GameServer.KeepManager.IsEnemy(this, player) || player.Client.Account.PrivLevel != 1) { - float keepz = Position.Z, distance = 0; + int keepz = Position.Z, distance = 0; //calculate distance //normal door @@ -449,14 +451,14 @@ public override bool Interact(GamePlayer player) { if ((GameKeepComponent.eComponentSkin)c.Skin == GameKeepComponent.eComponentSkin.Keep) { - keepdistance = Vector3.Distance(Position, c.Position); + keepdistance = (float)Coordinate.DistanceTo(c.Position); } if ((GameKeepComponent.eComponentSkin)c.Skin == GameKeepComponent.eComponentSkin.Gate) { - gatedistance = Vector3.Distance(Position, c.Position); + gatedistance = (float)Coordinate.DistanceTo(c.Position); } //when these are filled we can stop the search - if (keepdistance != int.MaxValue && gatedistance != int.MaxValue) + if (keepdistance != float.MaxValue && gatedistance != float.MaxValue) break; } if (DoorIndex == 1 && keepdistance < gatedistance) @@ -464,15 +466,13 @@ public override bool Interact(GamePlayer player) } } - Vector2 keepPoint; + Position keepPoint; //calculate x y - if (IsObjectInFront(player, 180, false)) - keepPoint = GameMath.GetPointFromHeading(Position, Heading, -distance); - else - keepPoint = GameMath.GetPointFromHeading(Position, Heading, distance); + if (IsObjectInFront(player, 180, false)) keepPoint = Position + Vector.Create(Orientation, -distance); + else keepPoint = Position + Vector.Create(Orientation, distance); //move player - player.MoveTo(CurrentRegionID, keepPoint.X, keepPoint.Y, keepz, player.Heading); + player.MoveTo(keepPoint.With(z: keepz).With(player.Orientation)); } return base.Interact(player); } @@ -616,8 +616,7 @@ public override void LoadFromDatabase(DataObject obj) if (curZone == null) return; this.CurrentRegion = curZone.ZoneRegion; m_name = door.Name; - m_Heading = (ushort)door.Heading; - Position = new Vector3(door.X, door.Y, door.Z); + Position = Position.Create(regionID: CurrentRegion.ID, x: door.X, y: door.Y, z: door.Z, heading: (ushort)door.Heading); m_level = 0; m_model = 0xFFFF; m_doorID = door.InternalID; diff --git a/GameServer/keeps/Gameobjects/GameRelicDoor.cs b/GameServer/keeps/Gameobjects/GameRelicDoor.cs index f17274d3..adae8993 100644 --- a/GameServer/keeps/Gameobjects/GameRelicDoor.cs +++ b/GameServer/keeps/Gameobjects/GameRelicDoor.cs @@ -16,17 +16,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ -using System; using System.Collections; -using System.Numerics; -using System.Reflection; using DOL.Database; -using DOL.Events; using DOL.GS.PacketHandler; - -using log4net; - +using DOL.GS.Geometry; namespace DOL.GS.Keeps { @@ -154,15 +148,13 @@ public override bool Interact(GamePlayer player) if (GameServer.ServerRules.IsSameRealm(player, this, true) || player.Client.Account.PrivLevel != 1) { - Vector2 point; + Position position; //calculate x y - if (IsObjectInFront(player, 180, false)) - point = this.GetPointFromHeading(this.Heading, -500); - else - point = this.GetPointFromHeading(this.Heading, 500); + if ( IsObjectInFront( player, 180, false ) ) position = Position + Vector.Create(Position.Orientation, length: -500); + else position = Position + Vector.Create(Position.Orientation, length: 500); //move player - player.MoveTo(CurrentRegionID, new Vector3(point, player.Position.Z), player.Heading); + player.MoveTo(position); } return base.Interact(player); } @@ -245,8 +237,7 @@ public override void LoadFromDatabase(DataObject obj) if (curZone == null) return; this.CurrentRegion = curZone.ZoneRegion; m_name = door.Name; - m_Heading = (ushort)door.Heading; - Position = new Vector3(door.X, door.Y, door.Z); + Position = Position.Create(regionID: CurrentRegion.ID, x: door.X, y: door.Y, z: door.Z, heading: (ushort)door.Heading); m_level = 0; m_model = 0xFFFF; m_doorID = door.InternalID; diff --git a/GameServer/keeps/Gameobjects/Guards/GameKeepGuard.cs b/GameServer/keeps/Gameobjects/Guards/GameKeepGuard.cs index 41e43c51..e8461864 100644 --- a/GameServer/keeps/Gameobjects/Guards/GameKeepGuard.cs +++ b/GameServer/keeps/Gameobjects/Guards/GameKeepGuard.cs @@ -21,6 +21,7 @@ using DOL.AI.Brain; using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.Language; using DOL.GS.ServerProperties; @@ -28,7 +29,6 @@ using DOL.GS.Realm; using DOL.GS.PlayerClass; using System.Threading.Tasks; -using System.Numerics; namespace DOL.GS.Keeps { @@ -734,7 +734,8 @@ public override bool AddToWorld() { CurrentWayPoint = guard.CurrentWayPoint; m_changingPositions = true; - MoveTo(guard.CurrentRegionID, guard.Position - new Vector3(Util.Random(200, 350), Util.Random(200, 350), 0), guard.Heading); + var offset = Vector.Create(x: Util.Random(200, 350), y: Util.Random(200, 350)); + MoveTo(guard.Position - offset); m_changingPositions = false; foundGuard = true; break; @@ -968,8 +969,7 @@ public void LoadFromPosition(DBKeepPosition pos, GameKeepComponent component) public void MoveToPosition(DBKeepPosition position) { PositionMgr.LoadGuardPosition(position, this); - if (!InCombat) - MoveTo(CurrentRegionID, Position, Heading); + if (!InCombat) MoveTo(Position); } #endregion @@ -1015,13 +1015,15 @@ public void ChangeGuild() /// /// Adding special handling for walking to a point for patrol guards to be in a formation /// - public override void WalkTo(Vector3 target, short speed) + public override void WalkTo(Coordinate destination, short speed) { - int offX = 0; - int offY = 0; + int offX = 0; int offY = 0; if (IsMovingOnPath && PatrolGroup != null) + { PatrolGroup.GetMovementOffset(this, out offX, out offY); - base.WalkTo(target - new Vector3(offX, offY, 0), speed); + } + var offset = Vector.Create(x: offX, y: offY ); + base.WalkTo(destination - offset, speed); } public override void WalkToSpawn(short speed) diff --git a/GameServer/keeps/Gameobjects/Guards/Patrol.cs b/GameServer/keeps/Gameobjects/Guards/Patrol.cs index 06344bec..f1f82870 100644 --- a/GameServer/keeps/Gameobjects/Guards/Patrol.cs +++ b/GameServer/keeps/Gameobjects/Guards/Patrol.cs @@ -7,6 +7,7 @@ using DOL.GS.Movement; using DOL.Events; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.Keeps { @@ -175,38 +176,23 @@ public void ChangePatrolLevel() CreatePatrolGuard(PatrolGuards.Count); } - float x = 0; - float y = 0; - - List guardsToKeep = new List(); - + var position = Position.Zero; + var guardsToKeep = new List(); for (int i = 0; i < PatrolGuards.Count; i++) { - GameKeepGuard guard = PatrolGuards[i] as GameKeepGuard; - - // Console.WriteLine(PatrolID + " loading guard " + guard.Name); + var guard = PatrolGuards[i] as GameKeepGuard; if (i < guardsToPatrol) { // we need to reposition the patrol at their spawn point plus variation - if (x == 0) - { - x = guard.SpawnPoint.X; - y = guard.SpawnPoint.Y; - } - else - { - x += Util.Random(250, 350); - y += Util.Random(250, 350); - } + if (position == Position.Zero) position = guard.SpawnPosition; + else position += Vector.Create(x: Util.Random(250, 350), y: Util.Random(250, 350)); if (guard.IsAlive) { + if (guard.IsMovingOnPath) guard.StopMovingOnPath(); - if (guard.IsMovingOnPath) - guard.StopMovingOnPath(); - - guard.MoveTo(guard.CurrentRegionID, x, y, guard.SpawnPoint.Z, guard.SpawnHeading); + guard.MoveTo(position); } guardsToKeep.Add(guard); diff --git a/GameServer/keeps/Gameobjects/IKeepItem.cs b/GameServer/keeps/Gameobjects/IKeepItem.cs index e352e318..710ed1b7 100644 --- a/GameServer/keeps/Gameobjects/IKeepItem.cs +++ b/GameServer/keeps/Gameobjects/IKeepItem.cs @@ -18,16 +18,16 @@ */ using System; using System.Collections; -using System.Numerics; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.Keeps { public interface IKeepItem { + Position Position { get; set; } ushort CurrentRegionID { get; set; } - Vector3 Position { get; set; } ushort Heading { get; set; } string TemplateID { get; } GameKeepComponent Component { get; set; } diff --git a/GameServer/keeps/HookPointInventory.cs b/GameServer/keeps/HookPointInventory.cs index 581494df..d9b1f3e5 100644 --- a/GameServer/keeps/HookPointInventory.cs +++ b/GameServer/keeps/HookPointInventory.cs @@ -278,7 +278,6 @@ public void Invoke(GamePlayer player, int payType, GameKeepHookPoint hookpoint, if (hookPointObj is GameSiegeWeapon) ((GameSiegeWeapon)hookPointObj).EnableToMove = false; hookPointObj.Position = hookpoint.Position; - hookPointObj.Heading = hookpoint.Heading; if (hookPointObj is GameSiegeWeapon) (hookPointObj as GameSiegeWeapon).HookPoint = hookpoint; @@ -325,7 +324,6 @@ public static void Invoke(GameKeepHookPoint hookpoint, string objectType) ((GameSiegeWeapon)hookPointObj).EnableToMove = false; hookPointObj.Position = hookpoint.Position; - hookPointObj.Heading = hookpoint.Heading; if (hookPointObj is GameSiegeWeapon) (hookPointObj as GameSiegeWeapon).HookPoint = hookpoint; diff --git a/GameServer/keeps/IGameKeep.cs b/GameServer/keeps/IGameKeep.cs index e416dadc..f092566b 100644 --- a/GameServer/keeps/IGameKeep.cs +++ b/GameServer/keeps/IGameKeep.cs @@ -20,6 +20,7 @@ using System.Collections; using System.Collections.Generic; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.Keeps @@ -36,11 +37,12 @@ public interface IGameKeep ushort KeepID { get; } - + Position Position { get; } int X { get; } int Y { get; } int Z { get; } ushort Heading { get; } + Angle Orientation { get; } Region CurrentRegion { get; } Guild Guild { get; } diff --git a/GameServer/keeps/IKeepManager.cs b/GameServer/keeps/IKeepManager.cs index 92c4e379..4c2f174e 100644 --- a/GameServer/keeps/IKeepManager.cs +++ b/GameServer/keeps/IKeepManager.cs @@ -20,11 +20,12 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Numerics; using System.Reflection; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using log4net; +using Vector3 = System.Numerics.Vector3; namespace DOL.GS.Keeps { @@ -55,15 +56,17 @@ public interface IKeepManager bool Load(); bool IsNewKeepComponent(int skin); void RegisterKeep(int keepID, AbstractGameKeep keep); - AbstractGameKeep GetKeepByID(int id); - ICollection GetKeepsCloseToSpot(ushort regionid, Vector3 point3d, int radius); + AbstractGameKeep GetKeepByID(int id); [Obsolete("This is going to be removed.")] + IEnumerable GetKeepsCloseToSpot(ushort regionid, Vector3 point3d, int radius); + [Obsolete("This is going to be removed.")] AbstractGameKeep GetKeepCloseToSpot(ushort regionid, Vector3 point3d, int radius); + [Obsolete("Use .GetKeepCloseToSpot(Position, int) instead!")] + AbstractGameKeep GetKeepCloseToSpot(ushort regionid, int x, int y, int z, int radius); + AbstractGameKeep GetKeepCloseToSpot(Position position, int radius); ICollection GetKeepsByRealmMap(int map); AbstractGameKeep GetBGPK(GamePlayer player); ICollection GetFrontierKeeps(); ICollection GetKeepsOfRegion(ushort region); - ICollection GetKeepsCloseToSpot(ushort regionid, float x, float y, float z, int radius); - AbstractGameKeep GetKeepCloseToSpot(ushort regionid, float x, float y, float z, int radius); int GetTowerCountByRealm(eRealm realm); Dictionary GetTowerCountAllRealm(); Dictionary GetTowerCountFromZones(List zones); @@ -76,6 +79,8 @@ public interface IKeepManager bool IsEnemy(GameKeepDoor checker, GamePlayer target); bool IsEnemy(GameKeepComponent checker, GamePlayer target); byte GetHeightFromLevel(byte level); + Position GetBorderKeepPosition(int keepid); + [Obsolete("Use GetBorderKeepPosition(int) instead!")] void GetBorderKeepLocation(int keepid, out int x, out int y, out int z, out ushort heading); int GetRealmKeepBonusLevel(eRealm realm); int GetRealmTowerBonusLevel(eRealm realm); diff --git a/GameServer/keeps/KeepArea.cs b/GameServer/keeps/KeepArea.cs index 409fdedb..3213332d 100644 --- a/GameServer/keeps/KeepArea.cs +++ b/GameServer/keeps/KeepArea.cs @@ -1,6 +1,7 @@ using DOL.GS; using DOL.GS.PacketHandler; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.Keeps { @@ -69,9 +70,9 @@ public void ChangeRadius(int newRadius) DbArea.Radius = this.Radius; DbArea.Region = (ushort)this.Keep.Region; DbArea.Sound = this.Sound; - DbArea.X = (int)Position.X; - DbArea.Y = (int)Position.Y; - DbArea.Z = (int)Position.Z; + DbArea.X = (int)Coordinate.X; + DbArea.Y = (int)Coordinate.Y; + DbArea.Z = (int)Coordinate.Z; GameServer.Database.AddObject(DbArea); } @@ -82,7 +83,7 @@ public override void LoadFromDatabase(DBArea area) { base.LoadFromDatabase(area); GameServer.KeepManager.Log.Debug("KeepArea " + area.Description + " LoadFromDatabase called"); - GameServer.KeepManager.Log.Debug("X: " + area.X + "(" + Position.X + ") Y: " + area.Y + "(" + Position.Y + ") Region:" + area.Region + " Radius: " + m_Radius); + GameServer.KeepManager.Log.Debug("X: " + area.X + "(" + Coordinate.X + ") Y: " + area.Y + "(" + Coordinate.Y + ") Region:" + area.Region + " Radius: " + m_Radius); } } } diff --git a/GameServer/keeps/KeepHookPoint.cs b/GameServer/keeps/KeepHookPoint.cs index 5f7a48d8..a4a71aaf 100644 --- a/GameServer/keeps/KeepHookPoint.cs +++ b/GameServer/keeps/KeepHookPoint.cs @@ -21,6 +21,8 @@ using System.Numerics; using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.GS.Keeps { @@ -29,44 +31,22 @@ namespace DOL.GS.Keeps /// public class GameKeepHookPoint { - public Vector3 Position { get; set; } public GameKeepHookPoint(int id, GameKeepComponent component) { m_index = id; m_component = component; m_hookpointTimer = new HookpointTimer(this, this.Component); this.Position = component.Position; - this.Heading = component.Heading; } public GameKeepHookPoint(DBKeepHookPoint dbhookPoint, GameKeepComponent component) { - double angle = component.Keep.Heading * ((Math.PI * 2) / 360); // angle*2pi/360; - Vector3 p = component.Position; - switch (component.ComponentHeading) - { - case 0: - p.X += (int)(Math.Cos(angle) * dbhookPoint.X + Math.Sin(angle) * dbhookPoint.Y); - p.Y -= (int)(Math.Cos(angle) * dbhookPoint.Y + Math.Sin(angle) * dbhookPoint.X); - break; - case 1: - p.X += (int)(Math.Cos(angle) * dbhookPoint.Y - Math.Sin(angle) * dbhookPoint.X); - p.Y += (int)(Math.Cos(angle) * dbhookPoint.X + Math.Sin(angle) * dbhookPoint.Y); - break; - case 2: - p.X -= (int)(Math.Cos(angle) * dbhookPoint.X - Math.Sin(angle) * dbhookPoint.Y); - p.Y += (int)(Math.Cos(angle) * dbhookPoint.Y - Math.Sin(angle) * dbhookPoint.X); - break; - case 3: - p.X -= (int)(Math.Cos(angle) * dbhookPoint.Y + Math.Sin(angle) * dbhookPoint.X); - p.Y -= (int)(Math.Cos(angle) * dbhookPoint.X - Math.Sin(angle) * dbhookPoint.Y); - break; - } - p.Z += dbhookPoint.Z; - this.Position = p; - this.Heading = (ushort)(component.Heading + dbhookPoint.Heading); - this.m_index = dbhookPoint.HookPointID; - this.Component = component; + var angle = component.Keep.Orientation + component.RelativeOrientationToKeep; + var offset = Vector.Create(dbhookPoint.X, -dbhookPoint.Y, dbhookPoint.Z).RotatedClockwise(angle); + Position = component.Position + offset; + Position = Position.With(component.Orientation + Angle.Heading(dbhookPoint.Heading)); + m_index = dbhookPoint.HookPointID; + Component = component; m_hookpointTimer = new HookpointTimer(this, this.Component); } @@ -92,12 +72,6 @@ public bool IsFree get { return (m_object == null); } } - private ushort m_heading; - public ushort Heading - { - get { return m_heading; } - set { m_heading = value; } - } private GameLiving m_object; public GameLiving Object @@ -113,6 +87,7 @@ public GameLiving Object } } } + public Position Position { get; } #endregion diff --git a/GameServer/keeps/KeepManager.cs b/GameServer/keeps/KeepManager.cs index 4e3060c0..dd5431ab 100644 --- a/GameServer/keeps/KeepManager.cs +++ b/GameServer/keeps/KeepManager.cs @@ -23,6 +23,7 @@ using System.Numerics; using System.Reflection; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using log4net; @@ -290,29 +291,13 @@ public AbstractGameKeep GetKeepByID(int id) return m_keepList[id] as AbstractGameKeep; } - /// - /// get list of keep close to spot - /// - /// - /// - /// - /// - public ICollection GetKeepsCloseToSpot(ushort regionid, Vector3 point3d, int radius) - { - return GetKeepsCloseToSpot(regionid, point3d.X, point3d.Y, point3d.Z, radius); - } + [Obsolete("Use .GetKeepCloseToSpot(Position, int) instead!")] + public virtual IEnumerable GetKeepsCloseToSpot(ushort regionid, System.Numerics.Vector3 point3d, int radius) + => GetKeepsCloseToSpot(regionid, point3d.X, point3d.Y, point3d.Z, radius); - /// - /// get the keep with minimum distance close to spot - /// - /// - /// - /// - /// - public AbstractGameKeep GetKeepCloseToSpot(ushort regionid, Vector3 point3d, int radius) - { - return GetKeepCloseToSpot(regionid, point3d.X, point3d.Y, point3d.Z, radius); - } + [Obsolete("Use .GetKeepCloseToSpot(Position, int) instead!")] + public virtual AbstractGameKeep GetKeepCloseToSpot(ushort regionid, System.Numerics.Vector3 point3d, int radius) + => GetKeepCloseToSpot(Position.Create(regionid, Coordinate.Create((int)point3d.X, (int)point3d.Y, (int)point3d.Y)), radius); /// /// Gets all keeps by a realm map /rw @@ -439,6 +424,9 @@ public virtual ICollection GetKeepsCloseToSpot(ushort regionid return closeKeeps; } + + public virtual AbstractGameKeep GetKeepCloseToSpot(ushort regionid, int x, int y, int z, int radius) + => GetKeepCloseToSpot(Position.Create(regionid,x,y), radius); /// /// get the keep with minimum distance close to spot @@ -449,7 +437,7 @@ public virtual ICollection GetKeepsCloseToSpot(ushort regionid /// /// /// - public virtual AbstractGameKeep GetKeepCloseToSpot(ushort regionid, float x, float y, float z, int radius) + public virtual AbstractGameKeep GetKeepCloseToSpot(Position position, int radius) { AbstractGameKeep closestKeep = null; @@ -460,11 +448,12 @@ public virtual AbstractGameKeep GetKeepCloseToSpot(ushort regionid, float x, flo foreach (AbstractGameKeep keep in m_keepList.Values) { - if (keep == null || keep.DBKeep == null || keep.DBKeep.Region != regionid) + if (keep == null || keep.DBKeep == null || keep.DBKeep.Region != position.RegionID) continue; - var diff = new Vector2(keep.DBKeep.X, keep.DBKeep.Y) - new Vector2(x, y); - var range = diff.LengthSquared(); + long xdiff = keep.DBKeep.X - position.X; + long ydiff = keep.DBKeep.Y - position.Y; + long range = xdiff * xdiff + ydiff * ydiff; if (range > radiussqrt) continue; @@ -694,69 +683,34 @@ public virtual byte GetHeightFromLevel(byte level) return 0; } - + public virtual void GetBorderKeepLocation(int keepid, out int x, out int y, out int z, out ushort heading) { - x = 0; - y = 0; - z = 0; - heading = 0; + var result = GetBorderKeepPosition(keepid); + x = result.X; + y = result.Y; + z = result.Z; + heading = result.Orientation.InHeading; + } + + public virtual Position GetBorderKeepPosition(int keepid) + { + var newFrontierRegionID = (ushort)163; switch (keepid) { //sauvage - case 1: - { - x = 653811; - y = 616998; - z = 9560; - heading = 2040; - break; - } + case 1: return Position.Create(newFrontierRegionID, x: 653811, y: 616998, z: 9560, heading: 2040); //snowdonia - case 2: - { - x = 616149; - y = 679042; - z = 9560; - heading = 1611; - break; - } + case 2: return Position.Create(newFrontierRegionID, x: 616149, y: 679042, z: 9560, heading: 1611); //svas - case 3: - { - x = 651460; - y = 313758; - z = 9432; - heading = 1004; - break; - } + case 3: return Position.Create(newFrontierRegionID, x: 651460, y: 313758, z: 9432, heading: 1004); //vind - case 4: - { - x = 715179; - y = 365101; - z = 9432; - heading = 314; - break; - } + case 4: return Position.Create(newFrontierRegionID, x: 715179, y: 365101, z: 9432, heading: 314); //ligen - case 5: - { - x = 396519; - y = 618017; - z = 9838; - heading = 2159; - break; - } + case 5: return Position.Create(newFrontierRegionID, x: 396519, y: 618017, z: 9838, heading: 2159); //cain - case 6: - { - x = 432841; - y = 680032; - z = 9747; - heading = 2585; - break; - } + case 6: return Position.Create(newFrontierRegionID, x: 432841, y: 680032, z: 9747, heading: 2585); + default: return Position.Zero; } } @@ -835,9 +789,8 @@ public virtual void ExitBattleground(GamePlayer player) if (location != "") { - Teleport t = DOLDB.SelectObject(DB.Column(nameof(Teleport.TeleportID)).IsEqualTo(location)); - if (t != null) - player.MoveTo((ushort)t.RegionID, t.X, t.Y, t.Z, (ushort)t.Heading); + var t = DOLDB.SelectObject(DB.Column(nameof(Teleport.TeleportID)).IsEqualTo(location)); + if (t != null) player.MoveTo(t.GetPosition()); } } } diff --git a/GameServer/keeps/Managers/Position Manager.cs b/GameServer/keeps/Managers/Position Manager.cs index c6dace5f..e549cc63 100644 --- a/GameServer/keeps/Managers/Position Manager.cs +++ b/GameServer/keeps/Managers/Position Manager.cs @@ -23,10 +23,10 @@ using DOL.Database; using DOL.GS; +using DOL.GS.Geometry; using DOL.GS.Movement; using DOL.GS.PacketHandler; using System.Collections.Generic; -using System.Numerics; namespace DOL.GS.Keeps { @@ -83,118 +83,22 @@ public static void LoadGuardPosition(DBKeepPosition pos, GameKeepGuard guard) { LoadKeepItemPosition(pos, guard); - guard.SpawnPoint = guard.Position; - guard.SpawnHeading = guard.Heading; + guard.SpawnPosition = guard.Position; } - + public static void LoadKeepItemPosition(DBKeepPosition pos, IKeepItem item) { - item.CurrentRegionID = item.Component.CurrentRegionID; - int x, y; - LoadXY(item.Component, pos.XOff, pos.YOff, out x, out y); - item.Position = new Vector3(x, y, item.Component.Keep.Z + pos.ZOff); - - item.Heading = (ushort)(item.Component.Heading + pos.HOff); - + var keepPositionOffset = Vector.Create(pos.XOff, -pos.YOff, pos.ZOff).RotatedClockwise(item.Component.Orientation); + var orientation = item.Component.Orientation + Angle.Heading(pos.HOff); + item.Position = (item.Component.Position + keepPositionOffset).With(orientation); item.DBPosition = pos; } - /// - /// Calculates X and Y based on component rotation and offset - /// - /// The assigned component object - /// The argument X - /// The argument Y - /// The result X - /// The result Y - public static void LoadXY(GameKeepComponent component, int inX, int inY, out int outX, out int outY) + public static Vector SaveXY(GameKeepComponent component, Coordinate keepPointCoordinate) { - double angle = component.Keep.Heading * ((Math.PI * 2) / 360); // angle*2pi/360; - double C = Math.Cos(angle); - double S = Math.Sin(angle); - switch (component.ComponentHeading) - { - case 0: - { - outX = (int)(component.Position.X + C * inX + S * inY); - outY = (int)(component.Position.Y - C * inY + S * inX); - break; - } - case 1: - { - outX = (int)(component.Position.X + C * inY - S * inX); - outY = (int)(component.Position.Y + C * inX + S * inY); - break; - } - case 2: - { - outX = (int)(component.Position.X - C * inX - S * inY); - outY = (int)(component.Position.Y + C * inY - S * inX); - break; - } - case 3: - { - outX = (int)(component.Position.X - C * inY + S * inX); - outY = (int)(component.Position.Y - C * inX - S * inY); - break; - } - default: - { - outX = 0; - outY = 0; - break; - } - } - } - - /// - /// Saves X and Y offsets - /// - /// The assigned component object - /// The argument X - /// The argument Y - /// The result X - /// The result Y - public static void SaveXY(GameKeepComponent component, int inX, int inY, out int outX, out int outY) - { - double angle = component.Keep.Heading * ((Math.PI * 2) / 360); // angle*2pi/360; - int gx = (int)(inX - component.Position.X); - int gy = (int)(inY - component.Position.Y); - double C = Math.Cos(angle); - double S = Math.Sin(angle); - switch (component.ComponentHeading) - { - case 0: - { - outX = (int)(gx * C + gy * S); - outY = (int)(gx * S - gy * C); - break; - } - case 1: - { - outX = (int)(gy * C - gx * S); - outY = (int)(gx * C + gy * S); - break; - } - case 2: - { - outX = (int)((gx * C + gy * S) / (-C * C - S * S)); - outY = (int)(gy * C - gx * S); - break; - } - case 3: - { - outX = (int)(gx * S - gy * C); - outY = (int)((gx * C + gy * S) / (-C * C - S * S)); - break; - } - default: - { - outX = 0; - outY = 0; - break; - } - } + var angle = component.Keep.Orientation + component.RelativeOrientationToKeep; + var vector = keepPointCoordinate - component.Coordinate; + return vector.RotatedClockwise(angle - Angle.Degrees(90)); } /// @@ -245,15 +149,13 @@ public static DBKeepPosition CreatePosition(string templateID, GameKeepComponent pos.ComponentSkin = component.Skin; pos.ComponentRotation = component.ComponentHeading; pos.TemplateID = templateID; - int x, y; - - SaveXY(component, (int)player.Position.X, (int)player.Position.Y, out x, out y); - pos.XOff = x; - pos.YOff = y; - - pos.ZOff = (int)(player.Position.Z - component.Position.Z); + + var keepPositionOffset = SaveXY(component, player.Coordinate); + pos.XOff = keepPositionOffset.X; + pos.YOff = keepPositionOffset.Y; + pos.ZOff = keepPositionOffset.Z; - pos.HOff = player.Heading - component.Heading; + pos.HOff = (player.Orientation - component.Orientation).InHeading; return pos; } @@ -339,25 +241,22 @@ public static PathPoint LoadPatrolPath(string pathID, GameKeepComponent componen PathPoint first = null; for (int i = 0; i < sorted.Count; i++) { - DBPathPoint pp = (DBPathPoint)sorted.GetByIndex(i); - PathPoint p = new PathPoint(pp.X, pp.Y, pp.Z, pp.MaxSpeed, pathType); - - int x, y; - LoadXY(component, pp.X, pp.Y, out x, out y); - p.Position = new Vector3(x, y, component.Keep.Z + p.Position.Z); - - p.WaitTime = pp.WaitTime; + var dbPathPoint = (DBPathPoint)sorted.GetByIndex(i); + var pathPoint = new PathPoint(dbPathPoint, pathType); + var relativeOffset = Vector.Create(pathPoint.Coordinate.X, -pathPoint.Coordinate.Y, pathPoint.Coordinate.Z) + .RotatedClockwise(component.Orientation); + pathPoint.Coordinate = component.Coordinate + relativeOffset; if (first == null) { - first = p; + first = pathPoint; } - p.Prev = prev; + pathPoint.Prev = prev; if (prev != null) { - prev.Next = p; + prev.Next = pathPoint; } - prev = p; + prev = pathPoint; } return first; } @@ -385,17 +284,15 @@ public static void SavePatrolPath(string pathID, PathPoint path, GameKeepCompone int i = 1; do { - DBPathPoint dbpp = new DBPathPoint((int)path.Position.X, (int)path.Position.Y, (int)path.Position.Z, path.MaxSpeed); - int x, y; - SaveXY(component, dbpp.X, dbpp.Y, out x, out y); - dbpp.X = x; - dbpp.Y = y; - dbpp.Z = (int)(dbpp.Z - component.Position.Z); - - dbpp.Step = i++; - dbpp.PathID = pathID; - dbpp.WaitTime = path.WaitTime; - GameServer.Database.AddObject(dbpp); + var dbPathPoint = path.GenerateDbEntry(); + var offset = SaveXY(component, Coordinate.Create(dbPathPoint.X, dbPathPoint.Y)); + dbPathPoint.X = offset.X; + dbPathPoint.Y = offset.Y; + dbPathPoint.Z = offset.Z; + dbPathPoint.Step = i++; + dbPathPoint.PathID = pathID; + + GameServer.Database.AddObject(dbPathPoint); path = path.Next; } while (path != null && path != root); } @@ -434,15 +331,13 @@ public static void CreateDoor(int doorID, GamePlayer player) pos.ComponentSkin = component.Skin; pos.ComponentRotation = component.ComponentHeading; pos.TemplateID = Guid.NewGuid().ToString(); - int x, y; - - SaveXY(component, (int)player.Position.X, (int)player.Position.Y, out x, out y); - pos.XOff = x; - pos.YOff = y; - - pos.ZOff = (int)(player.Position.Z - component.Position.Z); + + var keepPositionOffset = SaveXY(component, player.Coordinate); + pos.XOff = keepPositionOffset.X; + pos.YOff = keepPositionOffset.Y; + pos.ZOff = keepPositionOffset.Z; - pos.HOff = player.Heading - component.Heading; + pos.HOff = (player.Orientation - component.Orientation).InHeading; GameServer.Database.AddObject(pos); diff --git a/GameServer/keeps/Relics/GameRelic.cs b/GameServer/keeps/Relics/GameRelic.cs index 258e9579..49ede91b 100644 --- a/GameServer/keeps/Relics/GameRelic.cs +++ b/GameServer/keeps/Relics/GameRelic.cs @@ -7,7 +7,7 @@ using DOL.GS.PacketHandler; using DOL.Database; using log4net; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { @@ -193,9 +193,8 @@ protected virtual void Update() { if (m_item == null || m_currentCarrier == null) return; - CurrentRegionID = m_currentCarrier.CurrentRegionID; + Position = m_currentCarrier.Position; - Heading = m_currentCarrier.Heading; } @@ -224,7 +223,7 @@ protected virtual void PlayerTakesRelic(GamePlayer player) if (IsMounted) { - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(m_currentRelicPad.CurrentRegionID, m_currentRelicPad.Position, WorldMgr.VISIBILITY_DISTANCE); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(m_currentRelicPad.Position, WorldMgr.VISIBILITY_DISTANCE); log.DebugFormat("keep {0}", keep); @@ -490,9 +489,7 @@ public override void LoadFromDatabase(DataObject obj) { InternalID = obj.ObjectId; m_dbRelic = obj as DBRelic; - CurrentRegionID = (ushort)m_dbRelic.Region; - Position = new Vector3(m_dbRelic.X, m_dbRelic.Y, m_dbRelic.Z); - Heading = (ushort)m_dbRelic.Heading; + Position = Position.Create((ushort)m_dbRelic.Region, m_dbRelic.X, m_dbRelic.Y, m_dbRelic.Z, (ushort)m_dbRelic.Heading); m_relicType = (eRelicType)m_dbRelic.relicType; Realm = (eRealm)m_dbRelic.Realm; m_originalRealm = (eRealm)m_dbRelic.OriginalRealm; @@ -536,12 +533,12 @@ public override void SaveIntoDatabase() m_dbRelic.Realm = (int)Realm; m_dbRelic.OriginalRealm = (int)OriginalRealm; m_dbRelic.LastRealm = (int)m_lastRealm; - m_dbRelic.Heading = (int)Heading; - m_dbRelic.Region = (int)CurrentRegionID; + m_dbRelic.Heading = Orientation.InHeading; + m_dbRelic.Region = Position.RegionID; m_dbRelic.relicType = (int)RelicType; - m_dbRelic.X = (int)Position.X; - m_dbRelic.Y = (int)Position.Y; - m_dbRelic.Z = (int)Position.Z; + m_dbRelic.X = Position.X; + m_dbRelic.Y = Position.Y; + m_dbRelic.Z = Position.Z; if (InternalID == null) { diff --git a/GameServer/keeps/Relics/GameRelicPad.cs b/GameServer/keeps/Relics/GameRelicPad.cs index aabf8800..0e8f4165 100644 --- a/GameServer/keeps/Relics/GameRelicPad.cs +++ b/GameServer/keeps/Relics/GameRelicPad.cs @@ -224,7 +224,7 @@ public class PadArea : Area.Circle GameRelicPad m_parent; public PadArea(GameRelicPad parentPad) - : base("", parentPad.Position, PAD_AREA_RADIUS) + : base("", parentPad.Coordinate, PAD_AREA_RADIUS) { m_parent = parentPad; } diff --git a/GameServer/language/LanguageMgr.cs b/GameServer/language/LanguageMgr.cs index 12e82141..b8259bee 100644 --- a/GameServer/language/LanguageMgr.cs +++ b/GameServer/language/LanguageMgr.cs @@ -32,6 +32,7 @@ using System.Numerics; using System.Linq; using DOL.GS.Finance; +using DOL.GS.Geometry; namespace DOL.Language { @@ -576,6 +577,23 @@ public static string GetDamageTypeNoun(string language, eDamageType resist) } return translation; } + + public static string GetCardinalDirection(string languageID, Angle direction) + { + var clockwiseDirectionIndexBeginningFromSouth = ((direction.InHeading + 256) % 4096) / 512; + switch (clockwiseDirectionIndexBeginningFromSouth) + { + case 0: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.South"); + case 1: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.SouthWest"); + case 2: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.West"); + case 3: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.NorthWest"); + case 4: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.North"); + case 5: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.NorthEast"); + case 6: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.East"); + case 7: return LanguageMgr.GetTranslation(languageID, "Language.CardinalDirection.SouthEast"); + } + return "(unknown)"; + } public static string GetResistNoun(string language, eResist resist) { diff --git a/GameServer/managers/worldmanager/RegionWeather.cs b/GameServer/managers/worldmanager/RegionWeather.cs index b3e8cbf8..e6562a9a 100644 --- a/GameServer/managers/worldmanager/RegionWeather.cs +++ b/GameServer/managers/worldmanager/RegionWeather.cs @@ -89,8 +89,8 @@ public sealed class RegionWeather public RegionWeather(Region Region) { this.Region = Region; - WeatherMinPosition = (uint)Math.Max(0, Region.Zones.Any() ? Region.Zones.Min(z => z.XOffset) : 0); - WeatherMaxPosition = (uint)Math.Max(0, Region.Zones.Any() ? Region.Zones.Max(z => z.XOffset + z.Width) : 0); + WeatherMinPosition = (uint)Math.Max(0, Region.Zones.Min(z => z.Offset.X)); + WeatherMaxPosition = (uint)Math.Max(0, Region.Zones.Max(z => z.Offset.X + z.Width)); } /// diff --git a/GameServer/minotaurrelics/MinotaurRelic.cs b/GameServer/minotaurrelics/MinotaurRelic.cs index 76c373c1..9a56d2cb 100644 --- a/GameServer/minotaurrelics/MinotaurRelic.cs +++ b/GameServer/minotaurrelics/MinotaurRelic.cs @@ -25,6 +25,7 @@ using DOL.Database; using DOL.Events; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.Spells; @@ -48,11 +49,6 @@ public MinotaurRelic(DBMinotaurRelic obj) DBMinotaurRelic m_dbRelic; Timer timer = null; public RegionTimer respawntimer = null; - protected int m_spawny; - protected int m_spawnx; - protected int m_spawnz; - protected int m_spawnheading; - protected int m_spawnregion; protected int m_relicSpellID; protected Spell m_relicSpell; protected string m_relicTarget; @@ -127,35 +123,7 @@ public string RelicTarget set { m_relicTarget = value; } } - public int SpawnX - { - get { return m_spawnx; } - set { m_spawnx = value; } - } - - public int SpawnY - { - get { return m_spawny; } - set { m_spawny = value; } - } - - public int SpawnZ - { - get { return m_spawnz; } - set { m_spawnz = value; } - } - - public int SpawnHeading - { - get { return m_spawnheading; } - set { m_spawnheading = value; } - } - - public int SpawnRegion - { - get { return m_spawnregion; } - set { m_spawnregion = value; } - } + public Position SpawnPosition { get; set; } public int Effect { @@ -175,16 +143,10 @@ public override void LoadFromDatabase(DataObject obj) m_dbRelic = obj as DBMinotaurRelic; RelicID = m_dbRelic.RelicID; - Heading = (ushort)m_dbRelic.SpawnHeading; - CurrentRegionID = (ushort)m_dbRelic.SpawnRegion; - Position = new Vector3(m_dbRelic.SpawnX, m_dbRelic.SpawnY, m_dbRelic.SpawnZ); + SpawnPosition = Position.Create((ushort)m_dbRelic.SpawnRegion, m_dbRelic.SpawnX, m_dbRelic.SpawnY, m_dbRelic.SpawnZ, (ushort)m_dbRelic.SpawnHeading); + Position = SpawnPosition; - SpawnHeading = m_dbRelic.SpawnHeading; - SpawnRegion = m_dbRelic.SpawnRegion; Effect = m_dbRelic.Effect; - SpawnX = m_dbRelic.SpawnX; - SpawnY = m_dbRelic.SpawnY; - SpawnZ = m_dbRelic.SpawnZ; RelicSpellID = m_dbRelic.relicSpell; RelicSpell = SkillBase.GetSpellByID(m_dbRelic.relicSpell); @@ -208,11 +170,11 @@ public override void LoadFromDatabase(DataObject obj) /// public override void SaveIntoDatabase() { - m_dbRelic.SpawnHeading = Heading; - m_dbRelic.SpawnRegion = CurrentRegionID; - m_dbRelic.SpawnX = (int)Position.X; - m_dbRelic.SpawnY = (int)Position.Y; - m_dbRelic.SpawnZ = (int)Position.Z; + m_dbRelic.SpawnHeading = Orientation.InHeading; + m_dbRelic.SpawnRegion = Position.RegionID; + m_dbRelic.SpawnX = Position.X; + m_dbRelic.SpawnY = Position.Y; + m_dbRelic.SpawnZ = Position.Z; m_dbRelic.Effect = Effect; @@ -511,9 +473,8 @@ protected override int RespawnTimerCallback(RegionTimer respawnTimer) } if (ObjectState == eObjectState.Active) return 0; - Position = new Vector3(SpawnX, SpawnY, SpawnZ); - Heading = (ushort)SpawnHeading; - CurrentRegionID = (ushort)SpawnRegion; + + Position = SpawnPosition; XP = MinotaurRelicManager.MAX_RELIC_EXP; AddToWorld(); return 0; @@ -526,10 +487,10 @@ public virtual void ManualRespawn() respawntimer.Stop(); respawntimer = null; } + if (ObjectState == eObjectState.Active) return; - Position = new Vector3(SpawnX, SpawnY, SpawnZ); - Heading = (ushort)SpawnHeading; - CurrentRegionID = (ushort)SpawnRegion; + + Position = SpawnPosition; XP = MinotaurRelicManager.MAX_RELIC_EXP; AddToWorld(); } @@ -541,14 +502,12 @@ public virtual void ManualRespawn() protected virtual void Update(GameLiving living) { if (living == null) return; - CurrentRegionID = living.CurrentRegionID; Position = living.Position; - Heading = living.Heading; foreach (GameClient clt in WorldMgr.GetClientsOfRegion(CurrentRegionID)) { if (clt == null || clt.Player == null) continue; if (XP > 0) - clt.Player.Out.SendMinotaurRelicMapUpdate((byte)RelicID, CurrentRegionID, (int)Position.X, (int)Position.Y, (int)Position.Z); + clt.Player.Out.SendMinotaurRelicMapUpdate((byte)RelicID, Position); else clt.Player.Out.SendMinotaurRelicMapRemove((byte)RelicID); } @@ -628,7 +587,7 @@ public override bool AddToWorld() { if (SpawnLocked) { - if ((int)Position.X == SpawnX && (int)Position.Y == SpawnY) + if (Position.Coordinate == SpawnPosition.Coordinate) { if (ProtectorClassType != string.Empty) { diff --git a/GameServer/minotaurrelics/MinotaurRelicManager.cs b/GameServer/minotaurrelics/MinotaurRelicManager.cs index b990e003..bbbd9efb 100644 --- a/GameServer/minotaurrelics/MinotaurRelicManager.cs +++ b/GameServer/minotaurrelics/MinotaurRelicManager.cs @@ -140,7 +140,7 @@ private static void MapUpdate(object nullValue) { foreach (MinotaurRelic relic in relics[clt.Player.CurrentRegionID]) { - clt.Player.Out.SendMinotaurRelicMapUpdate((byte)relic.RelicID, relic.CurrentRegionID, (int)relic.Position.X, (int)relic.Position.Y, (int)relic.Position.Z); + clt.Player.Out.SendMinotaurRelicMapUpdate((byte)relic.RelicID, relic.Position); } } } diff --git a/GameServer/minotaurrelics/Protectors/ArrektosProtector.cs b/GameServer/minotaurrelics/Protectors/ArrektosProtector.cs index 8b84acdf..24e93e1f 100644 --- a/GameServer/minotaurrelics/Protectors/ArrektosProtector.cs +++ b/GameServer/minotaurrelics/Protectors/ArrektosProtector.cs @@ -41,6 +41,7 @@ using System.Numerics; using System.Text; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.Spells; @@ -56,9 +57,7 @@ public override bool AddToWorld() //foreman fogo doesn't leave the room. TetherRange = 1000; - Position = new Vector3(49293, 42208, 27562); - Heading = 2057; - CurrentRegionID = 245; + Position = Position.Create(regionID: 245, x: 49293, y: 42208, z: 27562,heading: 2057); Flags = 0; diff --git a/GameServer/minotaurrelics/Protectors/BaseProtector.cs b/GameServer/minotaurrelics/Protectors/BaseProtector.cs index 33393c7a..d9942a27 100644 --- a/GameServer/minotaurrelics/Protectors/BaseProtector.cs +++ b/GameServer/minotaurrelics/Protectors/BaseProtector.cs @@ -70,8 +70,6 @@ public static bool LockRelic() LockedEffect.Model = 1583; LockedEffect.Name = "LOCKED_RELIC"; LockedEffect.Position = Relic.Position; - LockedEffect.Heading = Relic.Heading; - LockedEffect.CurrentRegionID = Relic.CurrentRegionID; LockedEffect.Flags = GameNPC.eFlags.CANTTARGET; LockedEffect.AddToWorld(); diff --git a/GameServer/packets/Client/168/DialogResponseHandler.cs b/GameServer/packets/Client/168/DialogResponseHandler.cs index 0a7f0da1..433b2aed 100644 --- a/GameServer/packets/Client/168/DialogResponseHandler.cs +++ b/GameServer/packets/Client/168/DialogResponseHandler.cs @@ -257,7 +257,7 @@ protected override void OnTick() return; } - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(player.CurrentRegionID, player.Position, WorldMgr.VISIBILITY_DISTANCE); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(player.Position, WorldMgr.VISIBILITY_DISTANCE); if (keep == null) { player.Out.SendMessage("You have to be near the keep to claim it.", eChatType.CT_System, diff --git a/GameServer/packets/Client/168/DoorRequestHandler.cs b/GameServer/packets/Client/168/DoorRequestHandler.cs index 4e205bcb..8c363c63 100644 --- a/GameServer/packets/Client/168/DoorRequestHandler.cs +++ b/GameServer/packets/Client/168/DoorRequestHandler.cs @@ -188,10 +188,10 @@ public void AddingDoor(GamePlayer player, byte response) door.MaxHealth = 2545; door.Health = 2545; door.Locked = 0; - door.X = (int)player.Position.X; - door.Y = (int)player.Position.Y; - door.Z = (int)player.Position.Z; - door.Heading = player.Heading; + door.X = player.Position.X; + door.Y = player.Position.Y; + door.Z = player.Position.Z; + door.Heading = player.Orientation.InHeading; GameServer.Database.AddObject(door); @@ -295,9 +295,8 @@ protected override void OnTick() //else basic quick hack var door = new GameDoor(); door.DoorID = m_doorId; - door.Position = player.Position; + door.Position = player.Position.With(door.Orientation); door.Realm = eRealm.Door; - door.CurrentRegion = player.CurrentRegion; door.Open(player); } } diff --git a/GameServer/packets/Client/168/HousingPlaceItemHandler.cs b/GameServer/packets/Client/168/HousingPlaceItemHandler.cs index 2700bf38..19acfc34 100644 --- a/GameServer/packets/Client/168/HousingPlaceItemHandler.cs +++ b/GameServer/packets/Client/168/HousingPlaceItemHandler.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.Reflection; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Housing; using DOL.GS.ServerProperties; using DOL.GS.Utils; @@ -329,7 +330,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) ChatUtil.SendSystemMessage(client, "Scripts.Player.Housing.GardenItemPlacedName", orgitem.Name); // update all nearby players - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(house.RegionID, house.Position, WorldMgr.OBJ_UPDATE_DISTANCE)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(house.Position, WorldMgr.OBJ_UPDATE_DISTANCE)) { player.Out.SendGarden(house); } @@ -393,7 +394,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) }; // figure out proper rotation for item - int properRotation = client.Player.Heading / 10; + int properRotation = client.Player.Orientation.InHeading / 10; properRotation = properRotation.Clamp(0, 360); if (method == 2 && IsSuitableForWall(orgitem)) @@ -553,7 +554,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) } // if the hookpoint doesn't exist, prompt player to Log it in the database for us - if (house.GetHookpointLocation((uint)_position) == null) + if (house.GetHookPointCoordinate((uint)_position) == Coordinate.Nowhere) { client.Out.SendInventorySlotsUpdate(new[] { slot }); @@ -573,7 +574,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) } } } - else if (house.GetHookpointLocation((uint)_position) != null) + else if (house.GetHookPointCoordinate((uint)_position) != Coordinate.Nowhere) { var point = new DBHouseHookpointItem { @@ -596,7 +597,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) if (house.HousepointItems.ContainsKey(point.HookpointID) == false) { house.HousepointItems.Add(point.HookpointID, point); - house.FillHookpoint((uint)_position, orgitem.Id_nb, client.Player.Heading, 0); + house.FillHookpoint((uint)_position, orgitem.Id_nb, client.Player.Orientation.InHeading, 0); } else { @@ -696,7 +697,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) } // if hookpoint doesn't exist, prompt player to Log it in the database for us - if (house.GetHookpointLocation((uint)_position) == null) + if (house.GetHookPointCoordinate((uint)_position) == Coordinate.Nowhere) { client.Out.SendInventorySlotsUpdate(new[] { slot }); @@ -743,7 +744,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) // create the new vault and attach it to the house var houseVault = new GameHouseVault(orgitem.Template, vaultIndex); - houseVault.Attach(house, (uint)_position, (ushort)((client.Player.Heading + 2048) % 4096)); + houseVault.Attach(house, (uint)_position, (client.Player.Orientation + Angle.Degrees(180)).InHeading); // remove the original item from the player's inventory client.Player.Inventory.RemoveItem(orgitem); @@ -881,15 +882,16 @@ private void LogLocation(GamePlayer player, byte response) if (player.CurrentHouse == null) return; - + + var offset = player.Coordinate - player.CurrentHouse.Position.Coordinate; var a = new HouseHookpointOffset { HouseModel = player.CurrentHouse.Model, HookpointID = _position, - X = (int)(player.Position.X - player.CurrentHouse.Position.X), - Y = (int)(player.Position.Y - player.CurrentHouse.Position.Y), - Z = (int)(player.Position.Z - 25000), - Heading = player.Heading - player.CurrentHouse.Heading + X = offset.X, + Y = offset.Y, + Z = player.Position.Z - 25000, + Heading = player.Orientation.InHeading - player.CurrentHouse.Position.Orientation.InHeading }; if (GameServer.Database.AddObject(a) && House.AddNewOffset(a)) diff --git a/GameServer/packets/Client/168/PlayerGroundTargetHandler.cs b/GameServer/packets/Client/168/PlayerGroundTargetHandler.cs index 243ba2bc..eccedf54 100644 --- a/GameServer/packets/Client/168/PlayerGroundTargetHandler.cs +++ b/GameServer/packets/Client/168/PlayerGroundTargetHandler.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System.Numerics; namespace DOL.GS.PacketHandler.Client.v168 @@ -79,7 +80,7 @@ protected override void OnTick() { var player = (GamePlayer)m_actionSource; player.GroundTargetInView = ((m_flag & 0x100) != 0); - player.GroundTarget = new Vector3(m_x, m_y, m_z); + player.GroundTargetPosition = Position.Create(player.Position.RegionID, m_x, m_y, m_z); if (!player.GroundTargetInView) player.Out.SendMessage("Your ground target is not visible!", eChatType.CT_System, eChatLoc.CL_SystemWindow); @@ -98,7 +99,7 @@ protected override void OnTick() if (player.Steed.OwnerID == player.InternalID) { player.Out.SendMessage("You usher your boat forward.", eChatType.CT_System, eChatLoc.CL_SystemWindow); - player.Steed.PathTo(player.GroundTarget.Value, player.Steed.MaxSpeed); + player.Steed.PathTo(player.GroundTargetPosition.Coordinate, player.Steed.MaxSpeed); return; } } @@ -109,7 +110,7 @@ protected override void OnTick() eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } - player.Steed.PathTo(player.GroundTarget.Value, player.Steed.MaxSpeed); + player.Steed.PathTo(player.GroundTargetPosition.Coordinate, player.Steed.MaxSpeed); return; } } diff --git a/GameServer/packets/Client/168/PlayerHeadingUpdateHandler.cs b/GameServer/packets/Client/168/PlayerHeadingUpdateHandler.cs index fddf0a2d..96b11b42 100644 --- a/GameServer/packets/Client/168/PlayerHeadingUpdateHandler.cs +++ b/GameServer/packets/Client/168/PlayerHeadingUpdateHandler.cs @@ -20,6 +20,7 @@ using System.Collections; using System.Reflection; using DOL.GS; +using DOL.GS.Geometry; using log4net; namespace DOL.GS.PacketHandler.Client.v168 @@ -55,7 +56,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) var steedSlot = (byte)packet.ReadByte(); var ridingFlag = (byte)packet.ReadByte(); - client.Player.Heading = (ushort)(head & 0xFFF); + client.Player.Orientation = Angle.Heading(head); // client.Player.PetInView = ((flags & 0x04) != 0); // TODO client.Player.GroundTargetInView = ((flags & 0x08) != 0); client.Player.TargetInView = ((flags & 0x10) != 0); @@ -65,7 +66,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) state = 5; // set dead state else if (client.Player.Steed != null && client.Player.Steed.ObjectState == GameObject.eObjectState.Active) { - client.Player.Heading = client.Player.Steed.Heading; + client.Player.Orientation = client.Player.Steed.Orientation; state = 6; // Set ride state steedSlot = (byte)client.Player.Steed.RiderSlot(client.Player); // there rider slot this player head = (ushort)client.Player.Steed.ObjectID; // heading = steed ID diff --git a/GameServer/packets/Client/168/PlayerInitRequestHandler.cs b/GameServer/packets/Client/168/PlayerInitRequestHandler.cs index cfd3bfdb..68436d8c 100644 --- a/GameServer/packets/Client/168/PlayerInitRequestHandler.cs +++ b/GameServer/packets/Client/168/PlayerInitRequestHandler.cs @@ -213,9 +213,7 @@ private static void CheckBGLevelCapForPlayerAndMoveIfNecessary(GamePlayer player { player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "PlayerInitRequestHandler.LevelCap"), eChatType.CT_YouWereHit, eChatLoc.CL_SystemWindow); - player.MoveTo((ushort)player.BindRegion, player.BindXpos, - player.BindYpos, player.BindZpos, - (ushort)player.BindHeading); + player.MoveTo(player.BindPosition); break; } } @@ -235,7 +233,7 @@ private static void CheckIfPlayerLogsNearEnemyKeepAndMoveIfNecessary(GamePlayer int gracePeriodInMinutes = 0; Int32.TryParse(Properties.RVR_LINK_DEATH_RELOG_GRACE_PERIOD, out gracePeriodInMinutes); - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(player.CurrentRegionID, player.Position, WorldMgr.VISIBILITY_DISTANCE); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(player.Position, WorldMgr.VISIBILITY_DISTANCE); if (keep != null && player.Client.Account.PrivLevel == 1 && GameServer.KeepManager.IsEnemy(keep, player)) { if (WorldMgr.RvRLinkDeadPlayers.ContainsKey(player.InternalID)) @@ -266,9 +264,7 @@ private static void SendMessageAndMoveToSafeLocation(GamePlayer player) { player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "PlayerInitRequestHandler.SaferLocation"), eChatType.CT_System, eChatLoc.CL_SystemWindow); - player.MoveTo((ushort)player.BindRegion, player.BindXpos, - player.BindYpos, player.BindZpos, - (ushort)player.BindHeading); + player.MoveTo(player.BindPosition); } private static void SendHouseRentRemindersToPlayer(GamePlayer player) diff --git a/GameServer/packets/Client/168/PlayerPositionUpdateHandler.cs b/GameServer/packets/Client/168/PlayerPositionUpdateHandler.cs index 29e86ca3..613370ed 100644 --- a/GameServer/packets/Client/168/PlayerPositionUpdateHandler.cs +++ b/GameServer/packets/Client/168/PlayerPositionUpdateHandler.cs @@ -29,7 +29,7 @@ using DOL.GS; using DOL.GS.PacketHandler; using log4net; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS.PacketHandler.Client.v168 { @@ -92,6 +92,10 @@ public void HandlePacket(GameClient client, GSPacketIn packet) ushort xOffsetInZone = packet.ReadShort(); ushort yOffsetInZone = packet.ReadShort(); ushort currentZoneID = packet.ReadShort(); + + var headingflag = packet.ReadShort(); + var flyingflag = packet.ReadShort(); + var flags = (byte)packet.ReadByte(); //Dinberg - Instance considerations. @@ -129,17 +133,14 @@ public void HandlePacket(GameClient client, GSPacketIn packet) // move to bind if player fell through the floor if (realZ == 0) { - client.Player.MoveTo( - (ushort)client.Player.BindRegion, - client.Player.BindXpos, - client.Player.BindYpos, - (ushort)client.Player.BindZpos, - (ushort)client.Player.BindHeading - ); + client.Player.MoveTo(client.Player.BindPosition); return; } - var realPos = new Vector3(newZone.XOffset + xOffsetInZone, newZone.YOffset + yOffsetInZone, realZ); + var newCoordinate = Coordinate.Create( + x: newZone.Offset.X + xOffsetInZone, + y: newZone.Offset.Y + yOffsetInZone, + z: realZ); bool zoneChange = newZone != client.Player.LastPositionUpdateZone; if (zoneChange) @@ -176,17 +177,17 @@ public void HandlePacket(GameClient client, GSPacketIn packet) float coordsPerSec = 0; float jumpDetect = 0; - var timediff = GameTimer.GetTickCount() - client.Player.LastPositionUpdateTick; + int timediff = Environment.TickCount - client.Player.MovementStartTick; float distance = 0; if (timediff > 0) { - distance = Vector3.Distance(client.Player.LastPositionUpdatePoint, realPos); + distance = (int)client.Player.LastUpdateCoordinate.DistanceTo(newCoordinate); coordsPerSec = distance * 1000 / timediff; - if (distance < 100 && client.Player.LastPositionUpdatePoint.Z > 0) + if (distance < 100 && client.Player.LastUpdateCoordinate.Z > 0) { - jumpDetect = realZ - client.Player.LastPositionUpdatePoint.Z; + jumpDetect = realZ - client.Player.LastUpdateCoordinate.Z; } } @@ -203,9 +204,6 @@ public void HandlePacket(GameClient client, GSPacketIn packet) #endif #endregion DEBUG - client.Player.LastPositionUpdateTick = GameTimer.GetTickCount(); - client.Player.LastPositionUpdatePoint = realPos; - int tolerance = ServerProperties.Properties.CPS_TOLERANCE; if (client.Player.Steed != null && client.Player.Steed.MaxSpeed > 0) @@ -306,23 +304,16 @@ public void HandlePacket(GameClient client, GSPacketIn packet) client.Player.TempProperties.setProperty(LASTCPSTICK, environmentTick); } - var headingflag = packet.ReadShort(); - var flyingflag = packet.ReadShort(); - var flags = (byte)packet.ReadByte(); - - client.Player.Heading = (ushort)(headingflag & 0xFFF); - if (Vector3.DistanceSquared(client.Player.Position, realPos) > 0.1f) + if (client.Player.Coordinate.X != newCoordinate.X || client.Player.Coordinate.Y != newCoordinate.Y) + { client.Player.TempProperties.setProperty(LASTMOVEMENTTICK, client.Player.CurrentRegion.Time); - client.Player.Position = realPos; + } + client.Player.Position = Position.Create(client.Player.Position.RegionID, coordinate: newCoordinate, heading: (ushort)(headingflag & 0xFFF)); // update client zone information for waterlevel and diving if (zoneChange) client.Out.SendPlayerPositionAndObjectID(); - // used to predict current position, should be before - // any calculation (like fall damage) - client.Player.MovementStartTick = GameTimer.GetTickCount(); - // Begin ---------- New Area System ----------- if (client.Player.CurrentRegion.Time > client.Player.AreaUpdateTick) // check if update is needed { @@ -331,7 +322,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) // Because we may be in an instance we need to do the area check from the current region // rather than relying on the zone which is in the skinned region. - Tolakram - var newAreas = client.Player.CurrentRegion.GetAreasOfZone(newZone, client.Player.Position, true); + var newAreas = client.Player.CurrentRegion.GetAreasOfZone(newZone, client.Player.Coordinate, true); // Check for left areas if (oldAreas != null) @@ -512,18 +503,16 @@ public void HandlePacket(GameClient client, GSPacketIn packet) client.Player.TempProperties.setProperty(SHLASTFLY, SHlastFly); client.Player.TempProperties.setProperty(SHLASTSTATUS, SHlastStatus); client.Player.TempProperties.setProperty(SHSPEEDCOUNTER, SHcount); - lock (client.Player.LastUniqueLocations) + lock (client.Player.LastUniquePositions) { - GameLocation[] locations = client.Player.LastUniqueLocations; - GameLocation loc = locations[0]; - if (loc.Position != realPos || loc.RegionID != client.Player.CurrentRegionID) + var positions = client.Player.LastUniquePositions; + var pos = positions[0]; + var newPosition = client.Player.Position.With(coordinate: newCoordinate); + if (pos.Coordinate != newPosition.Coordinate) { - loc = locations[locations.Length - 1]; - Array.Copy(locations, 0, locations, 1, locations.Length - 1); - locations[0] = loc; - loc.Position = realPos; - loc.Heading = client.Player.Heading; - loc.RegionID = client.Player.CurrentRegionID; + pos = positions[positions.Length - 1]; + Array.Copy(positions, 0, positions, 1, positions.Length - 1); + positions[0] = newPosition; } } @@ -572,7 +561,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) //Riding is set here! if (client.Player.Steed != null && client.Player.Steed.ObjectState == GameObject.eObjectState.Active) - client.Player.Heading = client.Player.Steed.Heading; + client.Player.Orientation = client.Player.Steed.Orientation; if (zoneChange) // Update water level and diving flag for the new zone @@ -608,9 +597,10 @@ public void HandlePacket(GameClient client, GSPacketIn packet) } outpak.WriteShort(content); } - outpak.WriteShort((ushort)client.Player.Position.Z); - outpak.WriteShort((ushort)(client.Player.Position.X - client.Player.CurrentZone.XOffset)); - outpak.WriteShort((ushort)(client.Player.Position.Y - client.Player.CurrentZone.YOffset)); + var zoneCoord = client.Player.Coordinate - client.Player.CurrentZone.Offset; + outpak.WriteShort((ushort)zoneCoord.Z); + outpak.WriteShort((ushort)zoneCoord.X); + outpak.WriteShort((ushort)zoneCoord.Y); // Write Zone outpak.WriteShort(client.Player.CurrentZone.ZoneSkinID); @@ -623,7 +613,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) else { // Set Player always on ground, this is an "anti lag" packet - ushort contenthead = (ushort)(client.Player.Heading + (true ? 0x1000 : 0)); + ushort contenthead = (ushort)(client.Player.Orientation.InHeading + (true ? 0x1000 : 0)); outpak.WriteShort(contenthead); outpak.WriteShort(0); // No Fall Speed. } @@ -683,7 +673,7 @@ public void HandlePacket(GameClient client, GSPacketIn packet) outpak1124.WriteShort(currentZoneID); outpak1124.WriteShort(playerState); outpak1124.WriteShort((ushort)(client.Player.Steed?.RiderSlot(client.Player) ?? 0)); // fall damage flag coming in, steed seat position going out - outpak1124.WriteShort(client.Player.Heading); + outpak1124.WriteShort(client.Player.Orientation.InHeading); outpak1124.WriteByte(playerAction); outpak1124.WriteByte((byte)(client.Player.RPFlag ? 1 : 0)); outpak1124.WriteByte(0); @@ -852,26 +842,30 @@ private void _HandlePacket1124(GameClient client, GSPacketIn packet) client.Player.LastPositionUpdateZone = newZone; } - float coordsPerSec = 0; - float jumpDetect = 0; - uint timediff = GameTimer.GetTickCount() - client.Player.LastPositionUpdateTick; - float distance = 0; + var newPosition = Position.Create( + regionID: newZone.ZoneRegion.ID, + x: (int)newPlayerX, + y: (int)newPlayerY, + z: (int)newPlayerZ, + heading: (ushort)(newHeading & 0xFFF) + ); + + int coordsPerSec = 0; + int jumpDetect = 0; + int timediff = Environment.TickCount - client.Player.MovementStartTick; + int distance = 0; if (timediff > 0) { - distance = Vector3.Distance(client.Player.LastPositionUpdatePoint, new Vector3(newPlayerX, newPlayerY, newPlayerZ)); + distance = (int)client.Player.LastUpdateCoordinate.DistanceTo(newPosition.Coordinate); coordsPerSec = distance * 1000 / timediff; - if (distance < 100 && client.Player.LastPositionUpdatePoint.Z > 0) + if (distance < 100 && client.Player.LastUpdateCoordinate.Z > 0) { - jumpDetect = newPlayerZ - client.Player.LastPositionUpdatePoint.Z; + jumpDetect = (int)newPlayerZ - client.Player.LastUpdateCoordinate.Z; } } - client.Player.LastPositionUpdateTick = GameTimer.GetTickCount(); - client.Player.LastPositionUpdatePoint = new Vector3(newPlayerX, newPlayerY, newPlayerZ); - client.Player.Position = client.Player.LastPositionUpdatePoint; - int tolerance = ServerProperties.Properties.CPS_TOLERANCE; if (client.Player.Steed != null && client.Player.Steed.MaxSpeed > 0) @@ -977,18 +971,12 @@ private void _HandlePacket1124(GameClient client, GSPacketIn packet) } //client.Player.Heading = (ushort)(newHeading & 0xFFF); //patch 0024 expermental - if (Vector3.DistanceSquared(client.Player.Position, new Vector3(newPlayerX, newPlayerY, newPlayerZ)) > 0.1f) + if (client.Player.Position.X != newPosition.X || client.Player.Position.Y != newPosition.Y) { client.Player.TempProperties.setProperty(LASTMOVEMENTTICK, client.Player.CurrentRegion.Time); - client.Player.OnPlayerMove(); } - client.Player.Position = new Vector3(newPlayerX, newPlayerY, newPlayerZ); - client.Player.Heading = (ushort)(newHeading & 0xFFF); - - // used to predict current position, should be before - // any calculation (like fall damage) - client.Player.MovementStartTick = GameTimer.GetTickCount(); // experimental 0024 + client.Player.Position = newPosition; // Begin ---------- New Area System ----------- if (client.Player.CurrentRegion.Time > client.Player.AreaUpdateTick) // check if update is needed @@ -998,7 +986,7 @@ private void _HandlePacket1124(GameClient client, GSPacketIn packet) // Because we may be in an instance we need to do the area check from the current region // rather than relying on the zone which is in the skinned region. - Tolakram - var newAreas = client.Player.CurrentRegion.GetAreasOfZone(newZone, client.Player.Position, true); + var newAreas = client.Player.CurrentRegion.GetAreasOfZone(newZone, client.Player.Coordinate); // Check for left areas if (oldAreas != null) @@ -1078,18 +1066,16 @@ private void _HandlePacket1124(GameClient client, GSPacketIn packet) return; } } - lock (client.Player.LastUniqueLocations) + + lock (client.Player.LastUniquePositions) { - GameLocation[] locations = client.Player.LastUniqueLocations; - GameLocation loc = locations[0]; - if (loc.Position.X != newPlayerX || loc.Position.Y != newPlayerY || loc.Position.Z != newPlayerZ || loc.RegionID != client.Player.CurrentRegionID) + var positions = client.Player.LastUniquePositions; + var pos = positions[0]; + if (pos.Coordinate != newPosition.Coordinate) { - loc = locations[locations.Length - 1]; - Array.Copy(locations, 0, locations, 1, locations.Length - 1); - locations[0] = loc; - loc.Position = new Vector3(newPlayerX, newPlayerY, newPlayerZ); - loc.Heading = client.Player.Heading; - loc.RegionID = client.Player.CurrentRegionID; + pos = positions[positions.Length - 1]; + Array.Copy(positions, 0, positions, 1, positions.Length - 1); + positions[0] = newPosition; } } @@ -1132,7 +1118,7 @@ private void _HandlePacket1124(GameClient client, GSPacketIn packet) if (client.Player.Steed != null && client.Player.Steed.ObjectState == GameObject.eObjectState.Active) { - client.Player.Heading = client.Player.Steed.Heading; + client.Player.Orientation = client.Player.Steed.Orientation; newHeading = (ushort)client.Player.Steed.ObjectID; } else if ((playerState >> 10) == 4) // patch 0062 fix bug on release preventing players from receiving res sickness @@ -1194,9 +1180,9 @@ private void _HandlePacket1124(GameClient client, GSPacketIn packet) outpak190.WriteShort((ushort)client.SessionID); outpak190.WriteShort((ushort)(client.Player.CurrentSpeed & 0x1FF)); outpak190.WriteShort((ushort)newPlayerZ); - var xoff = (ushort)(newPlayerX - (client.Player.CurrentZone?.XOffset ?? 0)); + var xoff = (ushort)(newPlayerX - (client.Player.CurrentZone?.Offset.X ?? 0)); outpak190.WriteShort(xoff); - var yoff = (ushort)(newPlayerY - (client.Player.CurrentZone?.YOffset ?? 0)); + var yoff = (ushort)(newPlayerY - (client.Player.CurrentZone?.Offset.Y ?? 0)); outpak190.WriteShort(yoff); outpak190.WriteShort(currentZoneID); outpak190.WriteShort(newHeading); diff --git a/GameServer/packets/Client/168/RegionChangeRequestHandler.cs b/GameServer/packets/Client/168/RegionChangeRequestHandler.cs index 5566dcfe..e853dd21 100644 --- a/GameServer/packets/Client/168/RegionChangeRequestHandler.cs +++ b/GameServer/packets/Client/168/RegionChangeRequestHandler.cs @@ -26,6 +26,7 @@ using DOL.GS.ServerRules; using log4net; +using DOL.GS.Geometry; namespace DOL.GS.PacketHandler.Client.v168 { @@ -73,8 +74,8 @@ public void HandlePacket(GameClient client, GSPacketIn packet) ChatUtil.SendDebugMessage(client, $"Invalid Jump (ZonePoint table): [{jumpSpotId}]{((zonePoint == null) ? ". Entry missing!" : ". TargetRegion is 0!")}"); zonePoint = new ZonePoint(); zonePoint.Id = jumpSpotId; - string zonePointLocation = $"Region {player.CurrentRegionID} and coordinates ({player.Position})"; - Log.Error($"ZonePoint {jumpSpotId} at {zonePointLocation} on client {client.Version} missing. Either ZonePoint missing or RegionChangeRequestHandler needs to be updated."); + string zonePointToText = $"Region {player.CurrentRegionID} and coordinates ({player.Coordinate})"; + Log.Error($"ZonePoint {jumpSpotId} at {zonePointToText} on client {client.Version} missing. Either ZonePoint missing or RegionChangeRequestHandler needs to be updated."); } if (client.Account.PrivLevel > 1) @@ -240,7 +241,7 @@ protected override void OnTick() } //move the player - player.MoveTo(m_zonePoint.TargetRegion, m_zonePoint.TargetX, m_zonePoint.TargetY, m_zonePoint.TargetZ, m_zonePoint.TargetHeading); + player.MoveTo(m_zonePoint.GetTargetPosition()); } } } diff --git a/GameServer/packets/Client/168/UseSkillHandler.cs b/GameServer/packets/Client/168/UseSkillHandler.cs index 853f87e8..4b7cde2e 100644 --- a/GameServer/packets/Client/168/UseSkillHandler.cs +++ b/GameServer/packets/Client/168/UseSkillHandler.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; using System.Collections; using System.Collections.Generic; @@ -36,23 +37,21 @@ public class UseSkillHandler : IPacketHandler public void HandlePacket(GameClient client, GSPacketIn packet) { + var player = client.Player; if (client.Version >= GameClient.eClientVersion.Version1124) { - var x = packet.ReadFloatLowEndian(); - var y = packet.ReadFloatLowEndian(); - var z = packet.ReadFloatLowEndian(); - var speed = packet.ReadFloatLowEndian(); + var x = (int)packet.ReadFloatLowEndian(); + var y = (int)packet.ReadFloatLowEndian(); + var z = (int)packet.ReadFloatLowEndian(); + player.CurrentSpeed = (short)packet.ReadFloatLowEndian(); var heading = packet.ReadShort(); - - client.Player.Position = new Vector3(x, y, z); - client.Player.SetCurrentSpeed((short)speed); - client.Player.Heading = heading; + player.Position = Position.Create(player.Position.RegionID, x, y, z, heading); } int flagSpeedData = packet.ReadShort(); int index = packet.ReadByte(); int type = packet.ReadByte(); - new UseSkillAction(client.Player, flagSpeedData, index, type).Start(1); + new UseSkillAction(player, flagSpeedData, index, type).Start(1); } /// diff --git a/GameServer/packets/Client/168/UseSlotHandler.cs b/GameServer/packets/Client/168/UseSlotHandler.cs index b564af27..2350b47f 100644 --- a/GameServer/packets/Client/168/UseSlotHandler.cs +++ b/GameServer/packets/Client/168/UseSlotHandler.cs @@ -17,7 +17,7 @@ * */ -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS.PacketHandler.Client.v168 { @@ -29,23 +29,21 @@ public class UseSlotHandler : IPacketHandler { public void HandlePacket(GameClient client, GSPacketIn packet) { + var player = client.Player; if (client.Version >= GameClient.eClientVersion.Version1124) { - var x = packet.ReadFloatLowEndian(); - var y = packet.ReadFloatLowEndian(); - var z = packet.ReadFloatLowEndian(); - var speed = packet.ReadFloatLowEndian(); + var x = (int)packet.ReadFloatLowEndian(); + var y = (int)packet.ReadFloatLowEndian(); + var z = (int)packet.ReadFloatLowEndian(); + player.CurrentSpeed = (short)packet.ReadFloatLowEndian(); var heading = packet.ReadShort(); - - client.Player.Position = new Vector3(x, y, z); - client.Player.SetCurrentSpeed((short)speed); - client.Player.Heading = heading; + player.Position = Position.Create(player.Position.RegionID, x, y, z, heading); } int flagSpeedData = packet.ReadShort(); int slot = packet.ReadByte(); int type = packet.ReadByte(); - new UseSlotAction(client.Player, flagSpeedData, slot, type).Start(1); + new UseSlotAction(player, flagSpeedData, slot, type).Start(1); } /// diff --git a/GameServer/packets/Client/168/UseSpellHandler.cs b/GameServer/packets/Client/168/UseSpellHandler.cs index 4473c737..7702b44f 100644 --- a/GameServer/packets/Client/168/UseSpellHandler.cs +++ b/GameServer/packets/Client/168/UseSpellHandler.cs @@ -16,10 +16,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; using System.Collections; using System.Collections.Generic; -using System.Numerics; using System.Reflection; using log4net; @@ -43,15 +43,13 @@ public void HandlePacket(GameClient client, GSPacketIn packet) int spellLineIndex; if (client.Version >= GameClient.eClientVersion.Version1124) { - var x = packet.ReadFloatLowEndian(); - var y = packet.ReadFloatLowEndian(); - var z = packet.ReadFloatLowEndian(); - var speed = packet.ReadFloatLowEndian(); + var x = (int)packet.ReadFloatLowEndian(); + var y = (int)packet.ReadFloatLowEndian(); + var z = (int)packet.ReadFloatLowEndian(); + var speed = (short)packet.ReadFloatLowEndian(); var heading = packet.ReadShort(); - - client.Player.Position = new Vector3(x, y, z); - client.Player.SetCurrentSpeed((short)speed); - client.Player.Heading = heading; + client.Player.Position = Position.Create(client.Player.CurrentRegionID, x, y, z, heading); + client.Player.CurrentSpeed = speed; flagSpeedData = packet.ReadShort(); // target visible ? 0xA000 : 0x0000 spellLevel = packet.ReadByte(); spellLineIndex = packet.ReadByte(); @@ -76,15 +74,20 @@ public void HandlePacket(GameClient client, GSPacketIn packet) } else { - client.Player.Position = new Vector3(newZone.XOffset + xOffsetInZone, newZone.YOffset + yOffsetInZone, realZ); - client.Player.MovementStartTick = GameTimer.GetTickCount(); + client.Player.Position = Position.Create( + client.Player.CurrentRegionID, + newZone.Offset.X + xOffsetInZone, + newZone.Offset.Y + yOffsetInZone, + realZ, + client.Player.Orientation + ); } } spellLevel = packet.ReadByte(); spellLineIndex = packet.ReadByte(); - client.Player.Heading = (ushort)(heading & 0xfff); + client.Player.Orientation = Angle.Heading(heading); } new UseSpellAction(client.Player, flagSpeedData, spellLevel, spellLineIndex).Start(1); diff --git a/GameServer/packets/Client/168/warmapshowrequesthandler.cs b/GameServer/packets/Client/168/warmapshowrequesthandler.cs index 7d46644b..ecd3ea7e 100644 --- a/GameServer/packets/Client/168/warmapshowrequesthandler.cs +++ b/GameServer/packets/Client/168/warmapshowrequesthandler.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; using System.Collections; @@ -128,54 +129,43 @@ public void HandlePacket(GameClient client, GSPacketIn packet) } } - int x = 0; - int y = 0; - int z = 0; - ushort heading = 0; + var portPosition = Position.Zero; switch (keepId) { - //sauvage - case 1: - //snowdonia - case 2: - //svas - case 3: - //vind - case 4: - //ligen - case 5: - //cain - case 6: + + case 1: //sauvage + case 2: //snowdonia + case 3: //svas + case 4: //vind + case 5: //ligen + case 6: //cain { - GameServer.KeepManager.GetBorderKeepLocation(keepId, out x, out y, out z, out heading); + portPosition = GameServer.KeepManager.GetBorderKeepPosition(keepId); break; } default: { if (keep != null && keep is GameKeep) { - FrontiersPortalStone stone = keep.TeleportStone; - if (stone != null) + var stone = keep.TeleportStone; + if (stone != null) { - heading = stone.Heading; - z = (int)stone.Position.Z; - stone.GetTeleportLocation(out x, out y); + var distance = Util.Random(50, 150); + var direction = stone.Orientation + Angle.Heading(Util.Random(- 500, 500)); + portPosition = stone.Position + Vector.Create(direction, distance); } else { - x = keep.X; - y = keep.Y; - z = keep.Z + 150; - heading = keep.Heading; + portPosition = Position.Create(regionID: 163, keep.X, keep.Y, keep.Z+150, keep.Orientation); } } break; } } - if (x != 0) + if (portPosition != Position.Zero) { - client.Player.MoveTo(163, x, y, z, heading); + client.Player.MoveTo(portPosition); } break; diff --git a/GameServer/packets/Server/IPacketLib.cs b/GameServer/packets/Server/IPacketLib.cs index d3c1743a..6cf58d18 100644 --- a/GameServer/packets/Server/IPacketLib.cs +++ b/GameServer/packets/Server/IPacketLib.cs @@ -22,6 +22,7 @@ using System.Numerics; using DOL.AI.Brain; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Housing; using DOL.GS.Keeps; using DOL.GS.Quests; @@ -749,7 +750,9 @@ void SendDialogBox(eDialogCode code, ushort data1, ushort data2, ushort data3, u void SendConcentrationList(); void SendUpdateCraftingSkills(); void SendChangeTarget(GameObject newTarget); + [Obsolete("Use .SendChangeGroundTarget(Coordinate) instead!")] void SendChangeGroundTarget(Vector3 newTarget); + void SendChangeGroundTarget(Coordinate groundTarget); void SendPetWindow(GameLiving pet, ePetWindowAction windowAction, eAggressionState aggroState, eWalkState walkState); void SendPlaySound(eSoundType soundType, ushort soundID); void SendNPCsQuestEffect(GameNPC npc, eQuestIndicator indicator); @@ -761,6 +764,8 @@ void SendDialogBox(eDialogCode code, ushort data1, ushort data2, ushort data3, u void SendSiegeWeaponCloseInterface(); void SendSiegeWeaponInterface(GameSiegeWeapon siegeWeapon, int time); void SendLivingDataUpdate(GameLiving living, bool updateStrings); + void SendSoundEffect(ushort soundId, Position position, ushort radius); + [Obsolete("Use .SendSoundEffect(ushort,Position,ushort) instead!")] void SendSoundEffect(ushort soundId, ushort zoneId, ushort x, ushort y, ushort z, ushort radius); //keep void SendKeepInfo(IGameKeep keep); @@ -811,7 +816,9 @@ void SendDialogBox(eDialogCode code, ushort data1, ushort data2, ushort data3, u void SendVampireEffect(GameLiving living, bool show); void SendXFireInfo(byte flag); void SendMinotaurRelicMapRemove(byte id); + [Obsolete("Use .SendMinotaurRelicMapUpdate(byte, Position) instead!")] void SendMinotaurRelicMapUpdate(byte id, ushort region, int x, int y, int z); + void SendMinotaurRelicMapUpdate(byte id, Position position); void SendMinotaurRelicWindow(GamePlayer player, int spell, bool flag); void SendMinotaurRelicBarUpdate(GamePlayer player, int xp); diff --git a/GameServer/packets/Server/PacketLib1104.cs b/GameServer/packets/Server/PacketLib1104.cs index 3b14eca4..f69e8d65 100644 --- a/GameServer/packets/Server/PacketLib1104.cs +++ b/GameServer/packets/Server/PacketLib1104.cs @@ -22,7 +22,7 @@ using System.Reflection; using DOL.Database; - +using DOL.GS.Geometry; using log4net; @@ -145,7 +145,7 @@ public override void SendCharacterOverview(eRealm realm) Region region = WorldMgr.GetRegion((ushort)c.Region); if (region != null) { - locationDescription = m_gameClient.GetTranslatedSpotDescription(region, c.Xpos, c.Ypos, c.Zpos); + locationDescription = GamePlayerUtils.GetTranslatedSpotDescription(region, m_gameClient, c.GetPosition().Coordinate); } pak.FillString(locationDescription, 24); diff --git a/GameServer/packets/Server/PacketLib1110.cs b/GameServer/packets/Server/PacketLib1110.cs index 725003d6..b9f50c3c 100644 --- a/GameServer/packets/Server/PacketLib1110.cs +++ b/GameServer/packets/Server/PacketLib1110.cs @@ -28,6 +28,7 @@ using System.Numerics; using DOL.GS.Spells; using DOL.GS.Delve; +using DOL.GS.Geometry; namespace DOL.GS.PacketHandler { @@ -164,10 +165,10 @@ public override void SendSiegeWeaponAnimation(GameSiegeWeapon siegeWeapon) using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.SiegeWeaponAnimation))) { pak.WriteInt((uint)siegeWeapon.ObjectID); - var pos = siegeWeapon.GroundTarget ?? siegeWeapon.TargetObject?.Position ?? Vector3.Zero; - pak.WriteInt((uint)pos.X); - pak.WriteInt((uint)pos.Y); - pak.WriteInt((uint)pos.Z); + var aimCoordinate = siegeWeapon.AimCoordinate; + pak.WriteInt((uint)aimCoordinate.X); + pak.WriteInt((uint)aimCoordinate.Y); + pak.WriteInt((uint)aimCoordinate.Z); pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.ObjectID)); pak.WriteShort(siegeWeapon.Effect); pak.WriteShort((ushort)(siegeWeapon.SiegeWeaponTimer.TimeUntilElapsed)); // timer is no longer ( value / 100 ) @@ -188,12 +189,12 @@ public override void SendSiegeWeaponFireAnimation(GameSiegeWeapon siegeWeapon, i return; using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.SiegeWeaponAnimation))) { - pak.WriteInt((uint)siegeWeapon.ObjectID); - var pos = siegeWeapon.GroundTarget ?? siegeWeapon.TargetObject?.Position ?? Vector3.Zero; - pos.Z += 50; - pak.WriteInt((uint)pos.X); - pak.WriteInt((uint)pos.Y); - pak.WriteInt((uint)pos.Z); + var targetPosition = siegeWeapon.TargetObject.Position; + if(targetPosition == Position.Nowhere) targetPosition = siegeWeapon.GroundTargetPosition; + pak.WriteInt((uint) siegeWeapon.ObjectID); + pak.WriteInt((uint) (targetPosition.X)); + pak.WriteInt((uint) (targetPosition.Y)); + pak.WriteInt((uint) (targetPosition.Z + 50)); pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.ObjectID)); pak.WriteShort(siegeWeapon.Effect); pak.WriteShort((ushort)(timer)); // timer is no longer ( value / 100 ) diff --git a/GameServer/packets/Server/PacketLib1112.cs b/GameServer/packets/Server/PacketLib1112.cs index ebd52514..0461adee 100644 --- a/GameServer/packets/Server/PacketLib1112.cs +++ b/GameServer/packets/Server/PacketLib1112.cs @@ -566,7 +566,7 @@ public override void SendPlayerForgedPosition(GamePlayer player) // Write Speed if (player.Steed != null && player.Steed.ObjectState == GameObject.eObjectState.Active) { - player.Heading = player.Steed.Heading; + player.Orientation = player.Steed.Orientation; pak.WriteShort(0x1800); } else @@ -610,13 +610,10 @@ public override void SendPlayerForgedPosition(GamePlayer player) pak.WriteShort(content); } - // Get Off Corrd - var offX = player.Position.X - player.CurrentZone.XOffset; - var offY = player.Position.Y - player.CurrentZone.YOffset; - - pak.WriteShort((ushort)player.Position.Z); - pak.WriteShort((ushort)offX); - pak.WriteShort((ushort)offY); + var zoneCoordinate = player.Coordinate - player.CurrentZone.Offset; + pak.WriteShort((ushort)zoneCoordinate.Z); + pak.WriteShort((ushort)zoneCoordinate.X); + pak.WriteShort((ushort)zoneCoordinate.Y); // Write Zone pak.WriteShort(player.CurrentZone.ZoneSkinID); @@ -630,7 +627,7 @@ public override void SendPlayerForgedPosition(GamePlayer player) else { // Set Player always on ground, this is an "anti lag" packet - ushort contenthead = (ushort)(player.Heading + (true ? 0x1000 : 0)); + ushort contenthead = (ushort)(player.Orientation.InHeading + (true ? 0x1000 : 0)); pak.WriteShort(contenthead); // No Fall Speed. pak.WriteShort(0); diff --git a/GameServer/packets/Server/PacketLib1115.cs b/GameServer/packets/Server/PacketLib1115.cs index cc18c189..02dec9f3 100644 --- a/GameServer/packets/Server/PacketLib1115.cs +++ b/GameServer/packets/Server/PacketLib1115.cs @@ -135,11 +135,11 @@ public override void SendKeepInfo(IGameKeep keep) using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.KeepInfo))) { - pak.WriteShort((ushort)keep.KeepID); + pak.WriteShort(keep.KeepID); pak.WriteShort(0); pak.WriteInt((uint)keep.X); pak.WriteInt((uint)keep.Y); - pak.WriteShort((ushort)keep.Heading); + pak.WriteShort((ushort)keep.Orientation.InDegrees); pak.WriteByte((byte)keep.Realm); pak.WriteByte((byte)keep.Level);//level pak.WriteShort(0);//unk diff --git a/GameServer/packets/Server/PacketLib1124.cs b/GameServer/packets/Server/PacketLib1124.cs index fb83aa7f..0f28da39 100644 --- a/GameServer/packets/Server/PacketLib1124.cs +++ b/GameServer/packets/Server/PacketLib1124.cs @@ -65,16 +65,14 @@ public override void SendKeepInfo(IGameKeep keep) using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.KeepInfo))) { - pak.WriteShort((ushort)keep.KeepID); + pak.WriteShort(keep.KeepID); pak.WriteShort(0); pak.WriteInt((uint)keep.X); pak.WriteInt((uint)keep.Y); - pak.WriteShort((ushort)keep.Heading); + pak.WriteShort((ushort)keep.Orientation.InDegrees); pak.WriteByte((byte)keep.Realm); pak.WriteByte((byte)keep.Level);//level pak.WriteShort(0);//unk - pak.WriteByte(0);//model // patch 0072 - pak.WriteByte(0);//unk SendTCP(pak); } @@ -151,6 +149,8 @@ public override void SendLoginGranted(byte color) public override void SendNPCCreate(GameNPC npc) { + if (npc == null) + return; if (m_gameClient.Player == null || npc.IsVisibleTo(m_gameClient.Player) == false) return; @@ -187,16 +187,14 @@ public override void SendNPCCreate(GameNPC npc) else npcFlags = npc.Flags; - if (npc == null) - return; - if (!npc.IsAtTargetPosition) + if (!npc.IsAtTargetLocation) { speed = npc.CurrentSpeed; - speedZ = (ushort)npc.Velocity.Z; + speedZ = (ushort)npc.ZSpeedFactor; } pak.WriteShort((ushort)npc.ObjectID); pak.WriteShort((ushort)(speed)); - pak.WriteShort(npc.Heading); + pak.WriteShort(npc.Orientation.InHeading); pak.WriteShort((ushort)npc.Position.Z); pak.WriteInt((uint)npc.Position.X); pak.WriteInt((uint)npc.Position.Y); @@ -354,7 +352,7 @@ public override void SendPlayerCreate(GamePlayer playerToCreate) pak.WriteFloatLowEndian(playerToCreate.Position.Z); pak.WriteShort((ushort)playerToCreate.Client.SessionID); pak.WriteShort((ushort)playerToCreate.ObjectID); - pak.WriteShort(playerToCreate.Heading); + pak.WriteShort(playerToCreate.Orientation.InHeading); pak.WriteShort(playerToCreate.Model); pak.WriteByte(playerToCreate.GetDisplayLevel(m_gameClient.Player)); @@ -437,7 +435,7 @@ public override void SendPlayerPositionAndObjectID() pak.WriteFloatLowEndian(m_gameClient.Player.Position.Y); pak.WriteFloatLowEndian(m_gameClient.Player.Position.Z); pak.WriteShort((ushort)m_gameClient.Player.ObjectID); //This is the player's objectid not Sessionid!!! - pak.WriteShort(m_gameClient.Player.Heading); + pak.WriteShort(m_gameClient.Player.Orientation.InHeading); int flags = 0; Zone zone = m_gameClient.Player.CurrentZone; @@ -448,8 +446,8 @@ public override void SendPlayerPositionAndObjectID() if (zone.IsDungeon) { - pak.WriteShort((ushort)(zone.XOffset / 0x2000)); - pak.WriteShort((ushort)(zone.YOffset / 0x2000)); + pak.WriteShort((ushort)(zone.Offset.X / 0x2000)); + pak.WriteShort((ushort)(zone.Offset.Y / 0x2000)); } else { @@ -701,10 +699,10 @@ public override void SendSiegeWeaponAnimation(GameSiegeWeapon siegeWeapon) using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.SiegeWeaponAnimation))) { pak.WriteInt((uint)siegeWeapon.ObjectID); - var pos = siegeWeapon.GroundTarget ?? siegeWeapon.TargetObject?.Position ?? Vector3.Zero; - pak.WriteInt((uint)pos.X); - pak.WriteInt((uint)pos.Y); - pak.WriteInt((uint)pos.Z); + var aimCoordinate = siegeWeapon.AimCoordinate; + pak.WriteInt((uint)aimCoordinate.X); + pak.WriteInt((uint)aimCoordinate.Y); + pak.WriteInt((uint)aimCoordinate.Z); pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.ObjectID)); pak.WriteShort(siegeWeapon.Effect); pak.WriteShort((ushort)(siegeWeapon.SiegeWeaponTimer.TimeUntilElapsed)); @@ -891,13 +889,14 @@ protected override void WriteGroupMemberMapUpdate(GSTCPPacketOut pak, GameLiving if (living.CurrentSpeed != 0) { Zone zone = living.CurrentZone; + var zoneCoordinate = living.Coordinate - zone.Offset; if (zone == null) return; pak.WriteByte((byte)(0x40 | living.GroupIndex)); //Dinberg - ZoneSkinID for group members aswell. pak.WriteShort(zone.ZoneSkinID); - pak.WriteShort((ushort)(living.Position.X - zone.XOffset)); - pak.WriteShort((ushort)(living.Position.Y - zone.YOffset)); + pak.WriteShort((ushort)(zoneCoordinate.X)); + pak.WriteShort((ushort)(zoneCoordinate.Y)); } } diff --git a/GameServer/packets/Server/PacketLib1125.cs b/GameServer/packets/Server/PacketLib1125.cs index a2280455..2090eb9b 100644 --- a/GameServer/packets/Server/PacketLib1125.cs +++ b/GameServer/packets/Server/PacketLib1125.cs @@ -19,6 +19,7 @@ using DOL.Database; using DOL.GS.Effects; using DOL.GS.Finance; +using DOL.GS.Geometry; using DOL.GS.Housing; using DOL.GS.Profession; using DOL.GS.Spells; @@ -205,7 +206,7 @@ public override void SendCharacterOverview(eRealm realm) Region region = WorldMgr.GetRegion((ushort)c.Region); if (region != null) { - locationDescription = region.GetTranslatedSpotDescription(m_gameClient, c.Xpos, c.Ypos, c.Zpos); + locationDescription = region.GetTranslatedSpotDescription(m_gameClient, c.GetPosition().Coordinate); } if (locationDescription.Length > 23) // location name over 23 chars has to be truncated eg. "The Great Pyramid of Stygia" { diff --git a/GameServer/packets/Server/PacketLib1126.cs b/GameServer/packets/Server/PacketLib1126.cs index bc4dff06..11904090 100644 --- a/GameServer/packets/Server/PacketLib1126.cs +++ b/GameServer/packets/Server/PacketLib1126.cs @@ -17,6 +17,7 @@ * */ using DOL.Database; +using DOL.GS.Geometry; using log4net; using System; using System.Collections.Generic; @@ -182,7 +183,7 @@ public override void SendCharacterOverview(eRealm realm) string locationDescription = string.Empty; Region region = WorldMgr.GetRegion((ushort) c.Region); if (region != null) - locationDescription = m_gameClient.GetTranslatedSpotDescription(region, c.Xpos, c.Ypos, c.Zpos); + locationDescription = GamePlayerUtils.GetTranslatedSpotDescription(region, m_gameClient, c.GetPosition().Coordinate); string classname = ""; if (c.Class != 0) classname = ((eCharacterClass) c.Class).ToString(); diff --git a/GameServer/packets/Server/PacketLib168.cs b/GameServer/packets/Server/PacketLib168.cs index 1a975559..659c016e 100644 --- a/GameServer/packets/Server/PacketLib168.cs +++ b/GameServer/packets/Server/PacketLib168.cs @@ -36,6 +36,7 @@ using DOL.GS.Spells; using DOL.GS.Styles; using DOL.GS.Finance; +using DOL.GS.Geometry; using DOL.GS.Profession; using log4net; @@ -234,7 +235,8 @@ public virtual void SendCharacterOverview(eRealm realm) Region reg = WorldMgr.GetRegion((ushort)characters[j].Region); if (reg != null) { - var description = m_gameClient.GetTranslatedSpotDescription(reg, characters[j].Xpos, characters[j].Ypos, characters[j].Zpos); + var coordinate = characters[j].GetPosition().Coordinate; + var description = GamePlayerUtils.GetTranslatedSpotDescription(reg, m_gameClient, coordinate); pak.FillString(description, 24); } else @@ -534,11 +536,11 @@ public virtual void SendPlayerPositionAndObjectID() using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.PositionAndObjectID))) { - pak.WriteShort((ushort)m_gameClient.Player.ObjectID); //This is the player's objectid not Sessionid!!! - pak.WriteShort((ushort)m_gameClient.Player.Position.Z); - pak.WriteInt((uint)m_gameClient.Player.Position.X); - pak.WriteInt((uint)m_gameClient.Player.Position.Y); - pak.WriteShort(m_gameClient.Player.Heading); + pak.WriteShort((ushort) m_gameClient.Player.ObjectID); //This is the player's objectid not Sessionid!!! + pak.WriteShort((ushort) m_gameClient.Player.Position.Z); + pak.WriteInt((uint) m_gameClient.Player.Position.X); + pak.WriteInt((uint) m_gameClient.Player.Position.Y); + pak.WriteShort(m_gameClient.Player.Orientation.InHeading); int flags = 0; if (m_gameClient.Player.CurrentZone.IsDivingEnabled) @@ -557,11 +559,11 @@ public virtual void SendPlayerJump(bool headingOnly) using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.CharacterJump))) { - pak.WriteInt((uint)(headingOnly ? 0 : m_gameClient.Player.Position.X)); - pak.WriteInt((uint)(headingOnly ? 0 : m_gameClient.Player.Position.Y)); - pak.WriteShort((ushort)m_gameClient.Player.ObjectID); - pak.WriteShort((ushort)(headingOnly ? 0 : m_gameClient.Player.Position.Z)); - pak.WriteShort(m_gameClient.Player.Heading); + pak.WriteInt((uint) (headingOnly ? 0 : m_gameClient.Player.Position.X)); + pak.WriteInt((uint) (headingOnly ? 0 : m_gameClient.Player.Position.Y)); + pak.WriteShort((ushort) m_gameClient.Player.ObjectID); + pak.WriteShort((ushort) (headingOnly ? 0 : m_gameClient.Player.Position.Z)); + pak.WriteShort(m_gameClient.Player.Orientation.InHeading); if (m_gameClient.Player.InHouse == false || m_gameClient.Player.CurrentHouse == null) { pak.WriteShort(0); @@ -658,7 +660,12 @@ public virtual void SendMessage(string msg, eChatType type, eChatLoc loc) SendTCP(pak); } } + + protected ushort GetXOffsetInZone(GamePlayer player) + => (ushort)(player.Coordinate.X - player.CurrentZone.Offset.X); + protected ushort GetYOffsetInZone(GamePlayer player) + => (ushort)(player.Coordinate.Y - player.CurrentZone.Offset.Y); public virtual void SendPlayerCreate(GamePlayer playerToCreate) { if (playerToCreate == null) @@ -687,20 +694,20 @@ public virtual void SendPlayerCreate(GamePlayer playerToCreate) using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.PlayerCreate))) { pak.WriteShort((ushort)playerToCreate.Client.SessionID); - pak.WriteShort((ushort)playerToCreate.ObjectID); + pak.WriteShort((ushort) playerToCreate.ObjectID); //pak.WriteInt(playerToCreate.X); //pak.WriteInt(playerToCreate.Y); - pak.WriteShort((ushort)playerRegion.GetXOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort((ushort)playerRegion.GetYOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); + pak.WriteShort(GetXOffsetInZone(playerToCreate)); + pak.WriteShort(GetYOffsetInZone(playerToCreate)); //Dinberg:Instances - changing to ZoneSkinID for instance zones. - pak.WriteByte((byte)playerZone.ZoneSkinID); + pak.WriteByte((byte) playerZone.ZoneSkinID); pak.WriteByte(0); - pak.WriteShort((ushort)playerToCreate.Position.Z); - pak.WriteShort(playerToCreate.Heading); + pak.WriteShort((ushort) playerToCreate.Position.Z); + pak.WriteShort(playerToCreate.Orientation.InHeading); pak.WriteShort(playerToCreate.Model); //DOLConsole.WriteLine("send created player "+target.Player.Name+" to "+client.Player.Name+" alive="+target.Player.Alive); - pak.WriteByte((byte)(playerToCreate.IsAlive ? 0x1 : 0x0)); + pak.WriteByte((byte) (playerToCreate.IsAlive ? 0x1 : 0x0)); pak.WriteByte(0x00); pak.WriteByte(GameServer.ServerRules.GetLivingRealm(m_gameClient.Player, playerToCreate)); pak.WriteByte(playerToCreate.GetDisplayLevel(m_gameClient.Player)); @@ -760,11 +767,8 @@ public virtual void SendObjectUpdate(GameObject obj) return; } - var xOffsetInZone = (ushort)(obj.Position.X - z.XOffset); - var yOffsetInZone = (ushort)(obj.Position.Y - z.YOffset); - ushort xOffsetInTargetZone = 0; - ushort yOffsetInTargetZone = 0; - ushort zOffsetInTargetZone = 0; + var currentZoneCoord = obj.Coordinate - z.Offset; + var targetZoneCoord = Coordinate.Zero; int speed = 0; ushort targetZone = 0; @@ -809,17 +813,19 @@ public virtual void SendObjectUpdate(GameObject obj) flags |= 0x20; } - if (npc.IsMoving && !npc.IsAtTargetPosition) + if (npc.IsMoving && !npc.IsAtTargetLocation) { speed = npc.CurrentSpeed; - if (npc.TargetPosition != Vector3.Zero) + if (npc.Destination != Coordinate.Nowhere && npc.Destination != npc.Coordinate) { - Zone tz = npc.CurrentRegion.GetZone(npc.TargetPosition); + Zone tz = npc.CurrentRegion.GetZone(npc.Destination); if (tz != null) { - xOffsetInTargetZone = (ushort)(npc.TargetPosition.X - tz.XOffset); - yOffsetInTargetZone = (ushort)(npc.TargetPosition.Y - tz.YOffset); - zOffsetInTargetZone = (ushort)(npc.TargetPosition.Z); + targetZoneCoord = npc.Destination - tz.Offset; + + var overshootVector = targetZoneCoord - currentZoneCoord; + overshootVector = overshootVector * (100/overshootVector.Length); + targetZoneCoord += overshootVector; //Dinberg:Instances - zoneSkinID for object positioning clientside. targetZone = tz.ZoneSkinID; } @@ -844,20 +850,13 @@ public virtual void SendObjectUpdate(GameObject obj) { pak.WriteShort((ushort)speed); - if (obj is GameNPC) - { - pak.WriteShort((ushort)(obj.Heading & 0xFFF)); - } - else - { - pak.WriteShort(obj.Heading); - } - pak.WriteShort(xOffsetInZone); - pak.WriteShort(xOffsetInTargetZone); - pak.WriteShort(yOffsetInZone); - pak.WriteShort(yOffsetInTargetZone); - pak.WriteShort((ushort)obj.Position.Z); - pak.WriteShort(zOffsetInTargetZone); + pak.WriteShort(obj.Orientation.InHeading); + pak.WriteShort((ushort)currentZoneCoord.X); + pak.WriteShort((ushort)targetZoneCoord.X); + pak.WriteShort((ushort)currentZoneCoord.Y); + pak.WriteShort((ushort)targetZoneCoord.Y); + pak.WriteShort((ushort)currentZoneCoord.Z); + pak.WriteShort((ushort)targetZoneCoord.Z); pak.WriteShort((ushort)obj.ObjectID); pak.WriteShort((ushort)targetOID); //health @@ -936,12 +935,12 @@ public virtual void SendObjectCreate(GameObject obj) { pak.WriteShort((ushort)obj.ObjectID); if (obj is GameStaticItem) - pak.WriteShort((ushort)(obj as GameStaticItem).Emblem); + pak.WriteShort((ushort) (obj as GameStaticItem).Emblem); else pak.WriteShort(0); - pak.WriteShort(obj.Heading); - pak.WriteShort((ushort)obj.Position.Z); - pak.WriteInt((uint)obj.Position.X); - pak.WriteInt((uint)obj.Position.Y); + pak.WriteShort(obj.Orientation.InHeading); + pak.WriteShort((ushort) obj.Position.Z); + pak.WriteInt((uint) obj.Position.X); + pak.WriteInt((uint) obj.Position.Y); int flag = ((byte)obj.Realm & 3) << 4; ushort model = obj.Model; if (obj.IsUnderwater) @@ -1080,17 +1079,17 @@ public virtual void SendNPCCreate(GameNPC npc) { int speed = 0; ushort speedZ = 0; - if (npc.IsMoving && !npc.IsAtTargetPosition) + if (npc.IsMoving && !npc.IsAtTargetLocation) { speed = npc.CurrentSpeed; - speedZ = (ushort)npc.Velocity.Z; + speedZ = (ushort)npc.ZSpeedFactor; } - pak.WriteShort((ushort)npc.ObjectID); - pak.WriteShort((ushort)speed); - pak.WriteShort(npc.Heading); - pak.WriteShort((ushort)npc.Position.Z); - pak.WriteInt((uint)npc.Position.X); - pak.WriteInt((uint)npc.Position.Y); + pak.WriteShort((ushort) npc.ObjectID); + pak.WriteShort((ushort) speed); + pak.WriteShort(npc.Orientation.InHeading); + pak.WriteShort((ushort) npc.Position.Z); + pak.WriteInt((uint) npc.Position.X); + pak.WriteInt((uint) npc.Position.Y); pak.WriteShort(speedZ); var model = npc.Model; @@ -2111,7 +2110,7 @@ public virtual void SendPlayerForgedPosition(GamePlayer player) // Write Speed if (player.Steed != null && player.Steed.ObjectState == GameObject.eObjectState.Active) { - player.Heading = player.Steed.Heading; + player.Orientation = player.Steed.Orientation; pak.WriteShort(0x1800); } else @@ -2156,12 +2155,11 @@ public virtual void SendPlayerForgedPosition(GamePlayer player) } // Get Off Corrd - float offX = player.Position.X - player.CurrentZone.XOffset; - float offY = player.Position.Y - player.CurrentZone.YOffset; + var zoneCoord = player.Coordinate - player.CurrentZone.Offset; - pak.WriteShort((ushort)player.Position.Z); - pak.WriteShort((ushort)offX); - pak.WriteShort((ushort)offY); + pak.WriteShort((ushort)zoneCoord.Z); + pak.WriteShort((ushort)zoneCoord.X); + pak.WriteShort((ushort)zoneCoord.Y); // Write Zone pak.WriteByte((byte)player.CurrentZone.ZoneSkinID); @@ -2176,7 +2174,7 @@ public virtual void SendPlayerForgedPosition(GamePlayer player) else { // Set Player always on ground, this is an "anti lag" packet - ushort contenthead = (ushort)(player.Heading + (true ? 0x1000 : 0)); + ushort contenthead = (ushort)(player.Orientation.InHeading + (true ? 0x1000 : 0)); pak.WriteShort(contenthead); // No Fall Speed. pak.WriteShort(0); @@ -3135,13 +3133,18 @@ public void SendChangeTarget(GameObject newTarget) } } - public void SendChangeGroundTarget(Vector3 newTarget) + [Obsolete("Use .SendChangeGroundTarget(Coordinate) instead!")] + public void SendChangeGroundTarget(System.Numerics.Vector3 newTarget) + => SendChangeGroundTarget(Coordinate.Create((int)newTarget.X, (int)newTarget.Y, (int)newTarget.Z)); + + public void SendChangeGroundTarget(Coordinate newTarget) { using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.ChangeGroundTarget))) { - pak.WriteInt((uint)newTarget.X); - pak.WriteInt((uint)newTarget.Y); - pak.WriteInt((uint)newTarget.Z); + var gtLoc = newTarget == Coordinate.Nowhere ? Coordinate.Zero : newTarget; + pak.WriteInt((uint)(gtLoc.X)); + pak.WriteInt((uint)(gtLoc.Y)); + pak.WriteInt((uint)(gtLoc.Z)); SendTCP(pak); } } @@ -3266,7 +3269,7 @@ public virtual void SendHouse(House house) pak.WriteShort((ushort)house.Position.Z); pak.WriteInt((uint)house.Position.X); pak.WriteInt((uint)house.Position.Y); - pak.WriteShort((ushort)house.Heading); + pak.WriteShort((ushort)house.Orientation); pak.WriteShort((ushort)house.PorchRoofColor); pak.WriteShort((ushort)house.GetPorchAndGuildEmblemFlags()); pak.WriteShort((ushort)house.Emblem); @@ -3298,10 +3301,10 @@ public virtual void SendRemoveHouse(House house) using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.HouseCreate))) { - pak.WriteShort((ushort)house.HouseNumber); - pak.WriteShort((ushort)house.Position.Z); - pak.WriteInt((uint)house.Position.X); - pak.WriteInt((uint)house.Position.Y); + pak.WriteShort((ushort) house.HouseNumber); + pak.WriteShort((ushort) house.Position.Z); + pak.WriteInt((uint) house.Position.X); + pak.WriteInt((uint) house.Position.Y); pak.Fill(0x00, 15); pak.WriteByte(0x03); pak.WritePascalString(""); @@ -3390,9 +3393,9 @@ public virtual void SendEnterHouse(House house) { pak.WriteShort((ushort)house.HouseNumber); pak.WriteShort(25000); //constant! - pak.WriteInt((uint)house.Position.X); - pak.WriteInt((uint)house.Position.Y); - pak.WriteShort((ushort)house.Heading); //useless/ignored by client. + pak.WriteInt((uint) house.Position.X); + pak.WriteInt((uint) house.Position.Y); + pak.WriteShort((ushort) house.Orientation); //useless/ignored by client. pak.WriteByte(0x00); pak.WriteByte((byte)house.GetGuildEmblemFlags()); //emblem style pak.WriteShort((ushort)house.Emblem); //emblem @@ -3560,10 +3563,10 @@ public virtual void SendMovingObjectCreate(GameMovingObject obj) { pak.WriteShort((ushort)obj.ObjectID); pak.WriteShort(0); - pak.WriteShort(obj.Heading); - pak.WriteShort((ushort)obj.Position.Z); - pak.WriteInt((uint)obj.Position.X); - pak.WriteInt((uint)obj.Position.Y); + pak.WriteShort(obj.Orientation.InHeading); + pak.WriteShort((ushort) obj.Position.Z); + pak.WriteInt((uint) obj.Position.X); + pak.WriteInt((uint) obj.Position.Y); pak.WriteShort(obj.Model); int flag = (obj.Type() | ((byte)obj.Realm == 3 ? 0x40 : (byte)obj.Realm << 4) | obj.GetDisplayLevel(m_gameClient.Player) << 9); pak.WriteShort((ushort)flag); //(0x0002-for Ship,0x7D42-for catapult,0x9602,0x9612,0x9622-for ballista) @@ -3662,10 +3665,10 @@ public virtual void SendSiegeWeaponAnimation(GameSiegeWeapon siegeWeapon) using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.SiegeWeaponAnimation))) { pak.WriteInt((uint)siegeWeapon.ObjectID); - var pos = siegeWeapon.GroundTarget ?? siegeWeapon.TargetObject?.Position ?? Vector3.Zero; - pak.WriteInt((uint)pos.X); - pak.WriteInt((uint)pos.Y); - pak.WriteInt((uint)pos.Z); + var aimCoordinate = siegeWeapon.AimCoordinate; + pak.WriteInt((uint)aimCoordinate.X); + pak.WriteInt((uint)aimCoordinate.Y); + pak.WriteInt((uint)aimCoordinate.Z); pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.ObjectID)); pak.WriteShort(siegeWeapon.Effect); pak.WriteShort((ushort)(siegeWeapon.SiegeWeaponTimer.TimeUntilElapsed / 100)); @@ -3681,11 +3684,11 @@ public virtual void SendSiegeWeaponFireAnimation(GameSiegeWeapon siegeWeapon, in return; using (var pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.SiegeWeaponAnimation))) { - pak.WriteInt((uint)siegeWeapon.ObjectID); - pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.Position.X)); - pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.Position.Y)); - pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.Position.Z + 50)); - pak.WriteInt((uint)(siegeWeapon.TargetObject == null ? 0 : siegeWeapon.TargetObject.ObjectID)); + pak.WriteInt((uint) siegeWeapon.ObjectID); + pak.WriteInt((uint) (siegeWeapon.TargetObject?.Position.X ?? 0)); + pak.WriteInt((uint) (siegeWeapon.TargetObject?.Position.Y ?? 0)); + pak.WriteInt((uint) (siegeWeapon.TargetObject?.Position.Z + 50 ?? 0)); + pak.WriteInt((uint) (siegeWeapon.TargetObject?.ObjectID ?? 0)); pak.WriteShort(siegeWeapon.Effect); pak.WriteShort((ushort)(timer / 100)); pak.WriteByte((byte)SiegeTimer.eAction.Fire); @@ -3722,6 +3725,18 @@ public virtual void SendLivingDataUpdate(GameLiving living, bool updateStrings) SendLivingEquipmentUpdate(living as GameNPC); } } + + public virtual void SendSoundEffect(ushort soundId, Position pos, ushort radius) + { + var region = WorldMgr.GetRegion(pos.RegionID); + if(region == null) return; + + var zone = region.GetZone(pos.Coordinate); + if(zone == null) return; + + var zoneCoord = pos - zone.Offset; + SendSoundEffect(soundId, zone.ID, (ushort)zoneCoord.X, (ushort)zoneCoord.Y, (ushort)zoneCoord.Z, radius); + } public virtual void SendSoundEffect(ushort soundId, ushort zoneId, ushort x, ushort y, ushort z, ushort radius) { @@ -3949,8 +3964,11 @@ public virtual void SendConsignmentMerchantMoney(long money) public virtual void SendMinotaurRelicMapRemove(byte id) { } + + public void SendMinotaurRelicMapUpdate(byte id, ushort region, int x, int y, int z) + => SendMinotaurRelicMapUpdate(id, Position.Create(region, x, y, z)); - public virtual void SendMinotaurRelicMapUpdate(byte id, ushort region, int x, int y, int z) + public virtual void SendMinotaurRelicMapUpdate(byte id, Position position) { } diff --git a/GameServer/packets/Server/PacketLib170.cs b/GameServer/packets/Server/PacketLib170.cs index 4d55577c..2620e37b 100644 --- a/GameServer/packets/Server/PacketLib170.cs +++ b/GameServer/packets/Server/PacketLib170.cs @@ -52,12 +52,11 @@ public override void SendKeepInfo(IGameKeep keep) { using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.KeepInfo))) { - - pak.WriteShort((ushort)keep.KeepID); + pak.WriteShort(keep.KeepID); pak.WriteShort(0);//zone id not sure pak.WriteInt((uint)keep.X); pak.WriteInt((uint)keep.Y); - pak.WriteShort((ushort)keep.Heading); + pak.WriteShort((ushort)keep.Orientation.InDegrees); pak.WriteByte((byte)keep.Realm); pak.WriteByte((byte)keep.Level);//level(not sure) pak.WriteShort(0);//unk diff --git a/GameServer/packets/Server/PacketLib171.cs b/GameServer/packets/Server/PacketLib171.cs index 78a01a1d..434c7dfc 100644 --- a/GameServer/packets/Server/PacketLib171.cs +++ b/GameServer/packets/Server/PacketLib171.cs @@ -58,7 +58,7 @@ public override void SendPlayerPositionAndObjectID() pak.WriteShort((ushort)m_gameClient.Player.Position.Z); pak.WriteInt((uint)m_gameClient.Player.Position.X); pak.WriteInt((uint)m_gameClient.Player.Position.Y); - pak.WriteShort(m_gameClient.Player.Heading); + pak.WriteShort(m_gameClient.Player.Orientation.InHeading); int flags = 0; if (m_gameClient.Player.CurrentZone.IsDivingEnabled) @@ -68,8 +68,8 @@ public override void SendPlayerPositionAndObjectID() pak.WriteByte(0x00); //TODO Unknown Zone zone = m_gameClient.Player.CurrentZone; if (zone == null) return; - pak.WriteShort((ushort)(zone.XOffset / 0x2000)); - pak.WriteShort((ushort)(zone.YOffset / 0x2000)); + pak.WriteShort((ushort)(zone.Offset.X / 0x2000)); + pak.WriteShort((ushort)(zone.Offset.Y / 0x2000)); //Dinberg - Changing to allow instances... pak.WriteShort(m_gameClient.Player.CurrentRegion.Skin); pak.WriteShort(0x00); //TODO: unknown, new in 1.71 @@ -91,7 +91,7 @@ public override void SendObjectCreate(GameObject obj) if (obj is GameStaticItem) pak.WriteShort((ushort)(obj as GameStaticItem).Emblem); else pak.WriteShort(0); - pak.WriteShort(obj.Heading); + pak.WriteShort(obj.Orientation.InHeading); pak.WriteShort((ushort)obj.Position.Z); pak.WriteInt((uint)obj.Position.X); pak.WriteInt((uint)obj.Position.Y); @@ -186,15 +186,15 @@ public override void SendNPCCreate(GameNPC npc) } else npcFlags = npc.Flags; - - if (!npc.IsAtTargetPosition) + + if (!npc.IsAtTargetLocation) { speed = npc.CurrentSpeed; - speedZ = (ushort)npc.Velocity.Z; + speedZ = (ushort)npc.ZSpeedFactor; } pak.WriteShort((ushort)npc.ObjectID); pak.WriteShort((ushort)(speed)); - pak.WriteShort(npc.Heading); + pak.WriteShort(npc.Orientation.InHeading); pak.WriteShort((ushort)npc.Position.Z); pak.WriteInt((uint)npc.Position.X); pak.WriteInt((uint)npc.Position.Y); diff --git a/GameServer/packets/Server/PacketLib172.cs b/GameServer/packets/Server/PacketLib172.cs index d6c731ef..6e14dd0d 100644 --- a/GameServer/packets/Server/PacketLib172.cs +++ b/GameServer/packets/Server/PacketLib172.cs @@ -72,9 +72,9 @@ public override void SendPlayerCreate(GamePlayer playerToCreate) pak.WriteShort((ushort)playerToCreate.Position.Z); //Dinberg:Instances - Zoneskin ID for clientside positioning 'bluff'. pak.WriteShort(playerZone.ZoneSkinID); - pak.WriteShort((ushort)playerRegion.GetXOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort((ushort)playerRegion.GetYOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort(playerToCreate.Heading); + pak.WriteShort(GetXOffsetInZone(playerToCreate)); + pak.WriteShort(GetYOffsetInZone(playerToCreate)); + pak.WriteShort(playerToCreate.Orientation.InHeading); pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.EyeSize)); //1-4 = Eye Size / 5-8 = Nose Size pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.LipSize)); //1-4 = Ear size / 5-8 = Kin size @@ -124,7 +124,7 @@ public override void SendPlayerForgedPosition(GamePlayer player) // Write Speed if (player.Steed != null && player.Steed.ObjectState == GameObject.eObjectState.Active) { - player.Heading = player.Steed.Heading; + player.Orientation = player.Steed.Orientation; pak.WriteShort(0x1800); } else @@ -169,12 +169,10 @@ public override void SendPlayerForgedPosition(GamePlayer player) } // Get Off Corrd - var offX = player.Position.X - player.CurrentZone.XOffset; - var offY = player.Position.Y - player.CurrentZone.YOffset; - - pak.WriteShort((ushort)player.Position.Z); - pak.WriteShort((ushort)offX); - pak.WriteShort((ushort)offY); + var zoneCoord = player.Coordinate - player.CurrentZone.Offset; + pak.WriteShort((ushort)zoneCoord.Z); + pak.WriteShort((ushort)zoneCoord.X); + pak.WriteShort((ushort)zoneCoord.Y); // Write Zone pak.WriteShort(player.CurrentZone.ZoneSkinID); @@ -188,7 +186,7 @@ public override void SendPlayerForgedPosition(GamePlayer player) else { // Set Player always on ground, this is an "anti lag" packet - ushort contenthead = (ushort)(player.Heading + (true ? 0x1000 : 0)); + ushort contenthead = (ushort)(player.Orientation.InHeading + (true ? 0x1000 : 0)); pak.WriteShort(contenthead); // No Fall Speed. pak.WriteShort(0); diff --git a/GameServer/packets/Server/PacketLib173.cs b/GameServer/packets/Server/PacketLib173.cs index ddc94d6c..75f2531a 100644 --- a/GameServer/packets/Server/PacketLib173.cs +++ b/GameServer/packets/Server/PacketLib173.cs @@ -26,6 +26,7 @@ using DOL.Language; using DOL.Database; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.Keeps; using DOL.GS.Quests; using DOL.GS.Spells; @@ -300,7 +301,8 @@ public override void SendCharacterOverview(eRealm realm) Region reg = WorldMgr.GetRegion((ushort)characters[j].Region); if (reg != null) { - var description = m_gameClient.GetTranslatedSpotDescription(reg, characters[j].Xpos, characters[j].Ypos, characters[j].Zpos); + var coordinate = characters[j].GetPosition().Coordinate; + var description = GamePlayerUtils.GetTranslatedSpotDescription(reg, m_gameClient, coordinate); pak.FillString(description, 24); } else @@ -446,14 +448,13 @@ public override void SendKeepInfo(IGameKeep keep) return; using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.KeepInfo))) { - - pak.WriteShort((ushort)keep.KeepID); + pak.WriteShort(keep.KeepID); pak.WriteShort(0); pak.WriteInt((uint)keep.X); pak.WriteInt((uint)keep.Y); - pak.WriteShort((ushort)keep.Heading); + pak.WriteShort((ushort)keep.Orientation.InDegrees); pak.WriteByte((byte)keep.Realm); - pak.WriteByte((byte)keep.Level);//level + pak.WriteByte(keep.Level);//level pak.WriteShort(0);//unk pak.WriteByte(0x52);//model pak.WriteByte(0);//unk diff --git a/GameServer/packets/Server/PacketLib174.cs b/GameServer/packets/Server/PacketLib174.cs index 16554253..ef0ba171 100644 --- a/GameServer/packets/Server/PacketLib174.cs +++ b/GameServer/packets/Server/PacketLib174.cs @@ -24,6 +24,7 @@ using DOL.Language; using DOL.Database; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.Keeps; using DOL.GS.PlayerTitles; using DOL.GS.Spells; @@ -117,7 +118,8 @@ public override void SendCharacterOverview(eRealm realm) Region reg = WorldMgr.GetRegion((ushort)characters[j].Region); if (reg != null) { - var description = m_gameClient.GetTranslatedSpotDescription(reg, characters[j].Xpos, characters[j].Ypos, characters[j].Zpos); + var coordinate = characters[j].GetPosition().Coordinate; + var description = GamePlayerUtils.GetTranslatedSpotDescription(reg, m_gameClient, coordinate); pak.FillString(description, 24); } else @@ -286,9 +288,9 @@ public override void SendPlayerCreate(GamePlayer playerToCreate) pak.WriteShort((ushort)playerToCreate.Position.Z); //Dinberg:Instances - zoneSkinID for object positioning clientside (as zones are hardcoded). pak.WriteShort(playerZone.ZoneSkinID); - pak.WriteShort((ushort)playerRegion.GetXOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort((ushort)playerRegion.GetYOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort(playerToCreate.Heading); + pak.WriteShort(GetXOffsetInZone(playerToCreate)); + pak.WriteShort(GetYOffsetInZone(playerToCreate)); + pak.WriteShort(playerToCreate.Orientation.InHeading); pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.EyeSize)); //1-4 = Eye Size / 5-8 = Nose Size pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.LipSize)); //1-4 = Ear size / 5-8 = Kin size @@ -332,7 +334,7 @@ public override void SendPlayerPositionAndObjectID() pak.WriteShort((ushort)m_gameClient.Player.Position.Z); pak.WriteInt((uint)m_gameClient.Player.Position.X); pak.WriteInt((uint)m_gameClient.Player.Position.Y); - pak.WriteShort(m_gameClient.Player.Heading); + pak.WriteShort(m_gameClient.Player.Orientation.InHeading); int flags = 0; Zone zone = m_gameClient.Player.CurrentZone; @@ -347,8 +349,8 @@ public override void SendPlayerPositionAndObjectID() if (zone.IsDungeon) { - pak.WriteShort((ushort)(zone.XOffset / 0x2000)); - pak.WriteShort((ushort)(zone.YOffset / 0x2000)); + pak.WriteShort((ushort)(zone.Offset.X / 0x2000)); + pak.WriteShort((ushort)(zone.Offset.Y / 0x2000)); } else { @@ -380,8 +382,9 @@ protected virtual void WriteGroupMemberMapUpdate(GSTCPPacketOut pak, GameLiving pak.WriteByte((byte)(0x40 | living.GroupIndex)); //Dinberg - ZoneSkinID for group members aswell. pak.WriteShort(zone.ZoneSkinID); - pak.WriteShort((ushort)(living.Position.X - zone.XOffset)); - pak.WriteShort((ushort)(living.Position.Y - zone.YOffset)); + var zoneCoord = living.Coordinate - zone.Offset; + pak.WriteShort((ushort)(zoneCoord.X)); + pak.WriteShort((ushort)(zoneCoord.Y)); } } diff --git a/GameServer/packets/Server/PacketLib175.cs b/GameServer/packets/Server/PacketLib175.cs index 9b12398e..481ed715 100644 --- a/GameServer/packets/Server/PacketLib175.cs +++ b/GameServer/packets/Server/PacketLib175.cs @@ -476,9 +476,9 @@ public override void SendPlayerCreate(GamePlayer playerToCreate) pak.WriteShort((ushort)playerToCreate.Position.Z); //Dinberg:Instances - as with all objects, we need to use a zoneSkinID for clientside positioning. pak.WriteShort(playerZone.ZoneSkinID); - pak.WriteShort((ushort)playerRegion.GetXOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort((ushort)playerRegion.GetYOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort(playerToCreate.Heading); + pak.WriteShort(GetXOffsetInZone(playerToCreate)); + pak.WriteShort(GetYOffsetInZone(playerToCreate)); + pak.WriteShort(playerToCreate.Orientation.InHeading); pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.EyeSize)); //1-4 = Eye Size / 5-8 = Nose Size pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.LipSize)); //1-4 = Ear size / 5-8 = Kin size diff --git a/GameServer/packets/Server/PacketLib176.cs b/GameServer/packets/Server/PacketLib176.cs index 281b1651..9c238735 100644 --- a/GameServer/packets/Server/PacketLib176.cs +++ b/GameServer/packets/Server/PacketLib176.cs @@ -109,7 +109,7 @@ public override void SendObjectCreate(GameObject obj) else pak.WriteShort(0); - pak.WriteShort(obj.Heading); + pak.WriteShort(obj.Orientation.InHeading); pak.WriteShort((ushort)obj.Position.Z); pak.WriteInt((uint)obj.Position.X); pak.WriteInt((uint)obj.Position.Y); @@ -373,7 +373,7 @@ public override void SendHouse(House house) pak.WriteShort((ushort)house.Position.Z); pak.WriteInt((uint)house.Position.X); pak.WriteInt((uint)house.Position.Y); - pak.WriteShort((ushort)house.Heading); + pak.WriteShort((ushort)house.Orientation); pak.WriteShort((ushort)house.PorchRoofColor); pak.WriteShort((ushort)(house.GetPorchAndGuildEmblemFlags() | (house.Emblem & 0x010000) >> 13));//new Guild Emblem pak.WriteShort((ushort)house.Emblem); @@ -403,7 +403,7 @@ public override void SendEnterHouse(House house) pak.WriteShort((ushort)25000); //constant! pak.WriteInt((uint)house.Position.X); pak.WriteInt((uint)house.Position.Y); - pak.WriteShort((ushort)house.Heading); //useless/ignored by client. + pak.WriteShort((ushort)house.Orientation); //useless/ignored by client. pak.WriteByte(0x00); pak.WriteByte((byte)(house.GetGuildEmblemFlags() | (house.Emblem & 0x010000) >> 14));//new Guild Emblem pak.WriteShort((ushort)house.Emblem); //emblem diff --git a/GameServer/packets/Server/PacketLib180.cs b/GameServer/packets/Server/PacketLib180.cs index 8dec3203..4311f6a9 100644 --- a/GameServer/packets/Server/PacketLib180.cs +++ b/GameServer/packets/Server/PacketLib180.cs @@ -160,9 +160,9 @@ public override void SendPlayerCreate(GamePlayer playerToCreate) pak.WriteShort((ushort)playerToCreate.Position.Z); //Dinberg:Instances - send out the 'fake' zone ID to the client for positioning purposes. pak.WriteShort(playerZone.ZoneSkinID); - pak.WriteShort((ushort)playerRegion.GetXOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort((ushort)playerRegion.GetYOffInZone(playerToCreate.Position.X, playerToCreate.Position.Y)); - pak.WriteShort(playerToCreate.Heading); + pak.WriteShort(GetXOffsetInZone(playerToCreate)); + pak.WriteShort(GetYOffsetInZone(playerToCreate)); + pak.WriteShort(playerToCreate.Orientation.InHeading); pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.EyeSize)); //1-4 = Eye Size / 5-8 = Nose Size pak.WriteByte(playerToCreate.GetFaceAttribute(eCharFacePart.LipSize)); //1-4 = Ear size / 5-8 = Kin size diff --git a/GameServer/packets/Server/PacketLib186.cs b/GameServer/packets/Server/PacketLib186.cs index 94b50b49..1056654f 100644 --- a/GameServer/packets/Server/PacketLib186.cs +++ b/GameServer/packets/Server/PacketLib186.cs @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ +using DOL.GS.Geometry; using System; using log4net; using DOL.GS.Quests; @@ -113,16 +114,16 @@ public override void SendMinotaurRelicMapRemove(byte id) } } - public override void SendMinotaurRelicMapUpdate(byte id, ushort region, int x, int y, int z) + public override void SendMinotaurRelicMapUpdate(byte id, Position position) { using (GSTCPPacketOut pak = new GSTCPPacketOut(GetPacketCode(eServerPackets.MinotaurRelicMapUpdate))) { pak.WriteIntLowEndian((uint)id); - pak.WriteIntLowEndian((uint)region); - pak.WriteIntLowEndian((uint)x); - pak.WriteIntLowEndian((uint)y); - pak.WriteIntLowEndian((uint)z); + pak.WriteIntLowEndian((uint)position.RegionID); + pak.WriteIntLowEndian((uint)position.X); + pak.WriteIntLowEndian((uint)position.Y); + pak.WriteIntLowEndian((uint)position.Z); SendTCP(pak); } diff --git a/GameServer/packets/Server/PacketLib189.cs b/GameServer/packets/Server/PacketLib189.cs index 39cbd5d6..cb189f4d 100644 --- a/GameServer/packets/Server/PacketLib189.cs +++ b/GameServer/packets/Server/PacketLib189.cs @@ -421,7 +421,7 @@ public override void SendHouse(House house) pak.WriteShort((ushort)house.Position.Z); pak.WriteInt((uint)house.Position.X); pak.WriteInt((uint)house.Position.Y); - pak.WriteShort((ushort)house.Heading); + pak.WriteShort((ushort)house.Orientation); pak.WriteShort((ushort)house.PorchRoofColor); int flagPorchAndGuildEmblem = (house.Emblem & 0x010000) >> 13;//new Guild Emblem if (house.Porch) @@ -521,7 +521,7 @@ public override void SendEnterHouse(House house) pak.WriteShort((ushort)25000); //constant! pak.WriteInt((uint)house.Position.X); pak.WriteInt((uint)house.Position.Y); - pak.WriteShort((ushort)house.Heading); //useless/ignored by client. + pak.WriteShort((ushort)house.Orientation); //useless/ignored by client. pak.WriteByte(0x00); pak.WriteByte((byte)(house.GetGuildEmblemFlags() | (house.Emblem & 0x010000) >> 14));//new Guild Emblem pak.WriteShort((ushort)house.Emblem); //emblem diff --git a/GameServer/packets/Server/PacketLib190.cs b/GameServer/packets/Server/PacketLib190.cs index fa932004..8d66e27c 100644 --- a/GameServer/packets/Server/PacketLib190.cs +++ b/GameServer/packets/Server/PacketLib190.cs @@ -246,7 +246,7 @@ public override void SendPlayerForgedPosition(GamePlayer player) // Write Speed if (player.Steed != null && player.Steed.ObjectState == GameObject.eObjectState.Active) { - player.Heading = player.Steed.Heading; + player.Orientation = player.Steed.Orientation; pak.WriteShort(0x1800); } else @@ -291,12 +291,10 @@ public override void SendPlayerForgedPosition(GamePlayer player) } // Get Off Corrd - var offX = player.Position.X - player.CurrentZone.XOffset; - var offY = player.Position.Y - player.CurrentZone.YOffset; - - pak.WriteShort((ushort)player.Position.Z); - pak.WriteShort((ushort)offX); - pak.WriteShort((ushort)offY); + var zoneCoord = player.Coordinate - player.CurrentZone.Offset; + pak.WriteShort((ushort)zoneCoord.Z); + pak.WriteShort((ushort)zoneCoord.X); + pak.WriteShort((ushort)zoneCoord.Y); // Write Zone pak.WriteShort(player.CurrentZone.ZoneSkinID); @@ -310,7 +308,7 @@ public override void SendPlayerForgedPosition(GamePlayer player) else { // Set Player always on ground, this is an "anti lag" packet - ushort contenthead = (ushort)(player.Heading + (true ? 0x1000 : 0)); + ushort contenthead = (ushort)(player.Orientation.InHeading + (true ? 0x1000 : 0)); pak.WriteShort(contenthead); // No Fall Speed. pak.WriteShort(0); diff --git a/GameServer/packets/Server/PacketLib199.cs b/GameServer/packets/Server/PacketLib199.cs index ff1dd3f0..2a4092e4 100644 --- a/GameServer/packets/Server/PacketLib199.cs +++ b/GameServer/packets/Server/PacketLib199.cs @@ -22,6 +22,7 @@ using System.Reflection; using DOL.Database; +using DOL.GS.Geometry; using DOL.Language; using log4net; @@ -116,7 +117,8 @@ public override void SendCharacterOverview(eRealm realm) Region reg = WorldMgr.GetRegion((ushort)characters[j].Region); if (reg != null) { - var description = m_gameClient.GetTranslatedSpotDescription(reg, characters[j].Xpos, characters[j].Ypos, characters[j].Zpos); + var coordinate = characters[j].GetPosition().Coordinate; + var description = GamePlayerUtils.GetTranslatedSpotDescription(reg, m_gameClient, coordinate); pak.FillString(description, 24); } else diff --git a/GameServer/quests/JsonQuests/Goals/BringAFriendGoal.cs b/GameServer/quests/JsonQuests/Goals/BringAFriendGoal.cs index 789f7d5f..c835b993 100644 --- a/GameServer/quests/JsonQuests/Goals/BringAFriendGoal.cs +++ b/GameServer/quests/JsonQuests/Goals/BringAFriendGoal.cs @@ -2,6 +2,7 @@ using DOL.Events; using DOL.MobGroups; using DOL.GS.Behaviour; +using DOL.GS.Geometry; using System; using System.Collections.Generic; using System.Linq; @@ -36,13 +37,13 @@ public BringAFriendGoal(DataQuestJson quest, int goalId, dynamic db) : base(ques } if (db.AreaRadius != null && db.AreaRadius != "" && db.AreaRegion != null && db.AreaRegion != "" && db.AreaCenter != null) { - m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", new Vector3((float)db.AreaCenter.X, (float)db.AreaCenter.Y, (float)db.AreaCenter.Z), (int)db.AreaRadius); + m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", Coordinate.Create((int)((float)db.AreaCenter.X), (int)((float)db.AreaCenter.Y), (int)((float)db.AreaCenter.Z)), (int)db.AreaRadius); m_area.DisplayMessage = false; m_areaRegion = db.AreaRegion; var reg = WorldMgr.GetRegion(m_areaRegion); reg.AddArea(m_area); - PointA = new QuestZonePoint(reg.GetZone(m_area.Position), m_area.Position); + PointA = new QuestZonePoint(reg.GetZone(m_area.Coordinate), m_area.Coordinate); } } @@ -50,7 +51,7 @@ public override Dictionary GetDatabaseJsonObject() { var dict = base.GetDatabaseJsonObject(); dict.Add("TargetName", m_target); - dict.Add("AreaCenter", m_area.Position); + dict.Add("AreaCenter", m_area.Coordinate); dict.Add("AreaRadius", m_area.Radius); dict.Add("AreaRegion", m_areaRegion); return dict; @@ -59,9 +60,7 @@ public override Dictionary GetDatabaseJsonObject() public override void AbortGoal(PlayerQuest questData) { if (lastFriend != null) - if (hasMobGroup) - lastFriend.ResetFriendMobs(); - else lastFriend.ResetFriendMob(); + lastFriend.ResetFollow(); base.AbortGoal(questData); } diff --git a/GameServer/quests/JsonQuests/Goals/EnterAreaGoal.cs b/GameServer/quests/JsonQuests/Goals/EnterAreaGoal.cs index 2ab1ea0e..062b6e6f 100644 --- a/GameServer/quests/JsonQuests/Goals/EnterAreaGoal.cs +++ b/GameServer/quests/JsonQuests/Goals/EnterAreaGoal.cs @@ -1,5 +1,6 @@ using DOL.Events; using DOL.GS.Behaviour; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using System; using System.Collections.Generic; @@ -20,19 +21,19 @@ public class EnterAreaGoal : DataQuestJsonGoal public EnterAreaGoal(DataQuestJson quest, int goalId, dynamic db) : base(quest, goalId, (object)db) { m_text = db.Text; - m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", new Vector3((float)db.AreaCenter.X, (float)db.AreaCenter.Y, (float)db.AreaCenter.Z), (int)db.AreaRadius); + m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", Coordinate.Create((int)((float)db.AreaCenter.X), (int)((float)db.AreaCenter.Y), (int)((float)db.AreaCenter.Z)), (int)db.AreaRadius); m_area.DisplayMessage = false; m_areaRegion = db.AreaRegion; var reg = WorldMgr.GetRegion(m_areaRegion); reg.AddArea(m_area); - PointA = new QuestZonePoint(reg.GetZone(m_area.Position), m_area.Position); + PointA = new QuestZonePoint(reg.GetZone(m_area.Coordinate), m_area.Coordinate); } public override Dictionary GetDatabaseJsonObject() { var dict = base.GetDatabaseJsonObject(); - dict.Add("AreaCenter", m_area.Position); + dict.Add("AreaCenter", m_area.Coordinate); dict.Add("AreaRadius", m_area.Radius); dict.Add("AreaRegion", m_areaRegion); dict.Add("Text", m_text); diff --git a/GameServer/quests/JsonQuests/Goals/KillGoal.cs b/GameServer/quests/JsonQuests/Goals/KillGoal.cs index cbbb78ca..2e90f8c1 100644 --- a/GameServer/quests/JsonQuests/Goals/KillGoal.cs +++ b/GameServer/quests/JsonQuests/Goals/KillGoal.cs @@ -1,4 +1,5 @@ using DOL.Events; +using DOL.GS.Geometry; using System; using System.Collections.Generic; using System.Linq; @@ -28,13 +29,13 @@ public KillGoal(DataQuestJson quest, int goalId, dynamic db) : base(quest, goalI if (db.AreaRadius != null && db.AreaRadius != "" && db.AreaRegion != null && db.AreaRegion != "" && db.AreaCenter != null) { hasArea = true; - m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", new Vector3((float)db.AreaCenter.X, (float)db.AreaCenter.Y, (float)db.AreaCenter.Z), (int)db.AreaRadius); + m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", Coordinate.Create((int)((float)db.AreaCenter.X), (int)((float)db.AreaCenter.Y), (int)((float)db.AreaCenter.Z)), (int)db.AreaRadius); m_area.DisplayMessage = false; m_areaRegion = db.AreaRegion; var reg = WorldMgr.GetRegion(m_areaRegion); reg.AddArea(m_area); - PointA = new QuestZonePoint(reg.GetZone(m_area.Position), m_area.Position); + PointA = new QuestZonePoint(reg.GetZone(m_area.Coordinate), m_area.Coordinate); } else { @@ -48,7 +49,7 @@ public override Dictionary GetDatabaseJsonObject() dict.Add("TargetName", m_target.Name); dict.Add("TargetRegion", m_target.CurrentRegionID); dict.Add("KillCount", m_killCount); - dict.Add("AreaCenter", m_area.Position); + dict.Add("AreaCenter", m_area.Coordinate); dict.Add("AreaRadius", m_area.Radius); dict.Add("AreaRegion", m_areaRegion); return dict; @@ -64,7 +65,7 @@ public override void NotifyActive(PlayerQuest quest, PlayerGoalState goal, DOLEv { var killed = killedArgs.Target; if (killed == null || m_target.Name != killed.Name || m_target.CurrentRegion != killed.CurrentRegion - || (hasArea && !m_area.IsContaining(killed.Position, false))) + || (hasArea && !m_area.IsContaining(killed.Coordinate, false))) return; AdvanceGoal(quest, goal); } diff --git a/GameServer/quests/JsonQuests/Goals/KillGroupMobGoal.cs b/GameServer/quests/JsonQuests/Goals/KillGroupMobGoal.cs index 3188b354..92b209cb 100644 --- a/GameServer/quests/JsonQuests/Goals/KillGroupMobGoal.cs +++ b/GameServer/quests/JsonQuests/Goals/KillGroupMobGoal.cs @@ -1,5 +1,6 @@ using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using DOL.MobGroups; using DOLDatabase.Tables; using System; @@ -32,17 +33,17 @@ public KillGroupMobGoal(DataQuestJson quest, int goalId, dynamic db) : base(ques if (db.AreaRadius != null && db.AreaRadius != "" && db.AreaRegion != null && db.AreaRegion != "" && db.AreaCenter != null) { hasArea = true; - m_area = new Area.Circle($"{quest.Name} KillGroupMobGoal {goalId}", new Vector3((float)db.AreaCenter.X, (float)db.AreaCenter.Y, (float)db.AreaCenter.Z), (int)db.AreaRadius); + m_area = new Area.Circle($"{quest.Name} KillGroupMobGoal {goalId}", Coordinate.Create((int)((float)db.AreaCenter.X), (int)((float)db.AreaCenter.Y), (int)((float)db.AreaCenter.Z)), (int)db.AreaRadius); m_area.DisplayMessage = !false; m_areaRegion = db.AreaRegion; var reg = WorldMgr.GetRegion(m_areaRegion); reg.AddArea(m_area); - PointA = new QuestZonePoint(reg.GetZone(m_area.Position), m_area.Position); + PointA = new QuestZonePoint(reg.GetZone(m_area.Coordinate), m_area.Coordinate); } else if (m_region != null && db.AreaCenter != null) { - var pos = new Vector3((float)db.AreaCenter.X, (float)db.AreaCenter.Y, (float)db.AreaCenter.Z); + var pos = Coordinate.Create((int)((float)db.AreaCenter.X), (int)((float)db.AreaCenter.Y), (int)((float)db.AreaCenter.Z)); PointA = new QuestZonePoint(m_region.GetZone(pos), pos); } } @@ -52,7 +53,7 @@ public override Dictionary GetDatabaseJsonObject() var dict = base.GetDatabaseJsonObject(); dict.Add("TargetName", m_targetName); dict.Add("TargetRegion", m_regionId); - dict.Add("AreaCenter", m_area.Position); + dict.Add("AreaCenter", m_area.Coordinate); dict.Add("AreaRadius", m_area.Radius); dict.Add("AreaRegion", m_areaRegion); return dict; @@ -72,7 +73,7 @@ public override void NotifyActive(PlayerQuest quest, PlayerGoalState goal, DOLEv if (killed == null || m_region != killed.CurrentRegion - || (hasArea && !m_area.IsContaining(killed.Position, false))) + || (hasArea && !m_area.IsContaining(killed.Coordinate, false))) return; if (killed is GameNPC killedNpc && MobGroupManager.Instance.Groups.TryGetValue(m_targetName, out MobGroup targetGroup) && !targetGroup.IsAllDead(killedNpc)) diff --git a/GameServer/quests/JsonQuests/Goals/KillPlayerGoal.cs b/GameServer/quests/JsonQuests/Goals/KillPlayerGoal.cs index 6eaee6b6..ea795c3f 100644 --- a/GameServer/quests/JsonQuests/Goals/KillPlayerGoal.cs +++ b/GameServer/quests/JsonQuests/Goals/KillPlayerGoal.cs @@ -1,4 +1,5 @@ using DOL.Events; +using DOL.GS.Geometry; using System; using System.Collections.Generic; using System.Linq; @@ -28,13 +29,13 @@ public KillPlayerGoal(DataQuestJson quest, int goalId, dynamic db) : base(quest, if (db.AreaRadius != null && db.AreaRadius != "" && db.AreaRegion != null && db.AreaRegion != "" && db.AreaCenter != null) { hasArea = true; - m_area = new Area.Circle($"{quest.Name} KillPlayerGoal {goalId}", new Vector3((float)db.AreaCenter.X, (float)db.AreaCenter.Y, (float)db.AreaCenter.Z), (int)db.AreaRadius); + m_area = new Area.Circle($"{quest.Name} KillPlayerGoal {goalId}", Coordinate.Create((int)((float)db.AreaCenter.X), (int)((float)db.AreaCenter.Y), (int)((float)db.AreaCenter.Z)), (int)db.AreaRadius); m_area.DisplayMessage = false; m_areaRegion = db.AreaRegion; var reg = WorldMgr.GetRegion(m_areaRegion); reg.AddArea(m_area); - PointA = new QuestZonePoint(reg.GetZone(m_area.Position), m_area.Position); + PointA = new QuestZonePoint(reg.GetZone(m_area.Coordinate), m_area.Coordinate); } } @@ -43,7 +44,7 @@ public override Dictionary GetDatabaseJsonObject() var dict = base.GetDatabaseJsonObject(); dict.Add("TargetRegion", m_regionId); dict.Add("KillCount", m_killCount); - dict.Add("AreaCenter", m_area.Position); + dict.Add("AreaCenter", m_area.Coordinate); dict.Add("AreaRadius", m_area.Radius); dict.Add("AreaRegion", m_areaRegion); return dict; @@ -60,7 +61,7 @@ public override void NotifyActive(PlayerQuest quest, PlayerGoalState goal, DOLEv var killed = killedArgs.Target; if (killed == null || (m_region != null && m_region != killed.CurrentRegion) || !(killed is GamePlayer) - || (hasArea && !m_area.IsContaining(killed.Position, false))) + || (hasArea && !m_area.IsContaining(killed.Coordinate, false))) return; AdvanceGoal(quest, goal); } diff --git a/GameServer/quests/JsonQuests/Goals/UseItemGoal.cs b/GameServer/quests/JsonQuests/Goals/UseItemGoal.cs index 5dccea35..36ee9ebf 100644 --- a/GameServer/quests/JsonQuests/Goals/UseItemGoal.cs +++ b/GameServer/quests/JsonQuests/Goals/UseItemGoal.cs @@ -1,6 +1,7 @@ using DOL.Database; using DOL.Events; using DOL.GS.Behaviour; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using System; using System.Collections.Generic; @@ -34,13 +35,13 @@ public UseItemGoal(DataQuestJson quest, int goalId, dynamic db) : base(quest, go if (db.AreaRadius != null && db.AreaRadius != "" && db.AreaRegion != null && db.AreaRegion != "" && db.AreaCenter != null) { hasArea = true; - m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", new Vector3((float)db.AreaCenter.X, (float)db.AreaCenter.Y, (float)db.AreaCenter.Z), (int)db.AreaRadius); + m_area = new Area.Circle($"{quest.Name} EnterAreaGoal {goalId}", Coordinate.Create((int)((float)db.AreaCenter.X), (int)((float)db.AreaCenter.Y), (int)((float)db.AreaCenter.Z)), (int)db.AreaRadius); m_area.DisplayMessage = false; m_areaRegion = db.AreaRegion; var reg = WorldMgr.GetRegion(m_areaRegion); reg.AddArea(m_area); - PointA = new QuestZonePoint(reg.GetZone(m_area.Position), m_area.Position); + PointA = new QuestZonePoint(reg.GetZone(m_area.Coordinate), m_area.Coordinate); } if (db.TargetName != null && db.TargetName != "" && db.TargetRegion != null && db.TargetRegion != "") { @@ -61,7 +62,7 @@ public override Dictionary GetDatabaseJsonObject() dict.Add("TargetName", m_target.Name); dict.Add("DestroyItem", destroyItem); dict.Add("TargetRegion", m_target.CurrentRegionID); - dict.Add("AreaCenter", m_area.Position); + dict.Add("AreaCenter", m_area.Coordinate); dict.Add("AreaRadius", m_area.Radius); dict.Add("AreaRegion", m_areaRegion); dict.Add("Text", m_text); @@ -71,7 +72,7 @@ public override Dictionary GetDatabaseJsonObject() public override void NotifyActive(PlayerQuest quest, PlayerGoalState goal, DOLEvent e, object sender, EventArgs args) { var player = quest.Owner; - if ((!hasArea || (hasArea && m_area.IsContaining(player.Position, false))) && e == GamePlayerEvent.UseSlot && args is UseSlotEventArgs useSlot) + if ((!hasArea || (hasArea && m_area.IsContaining(player.Coordinate, false))) && e == GamePlayerEvent.UseSlot && args is UseSlotEventArgs useSlot) { var usedItem = player.Inventory.GetItem((eInventorySlot)useSlot.Slot); if (usedItem.Id_nb == QuestItem.Id_nb && (m_target == null || player.TargetObject == m_target)) diff --git a/GameServer/quests/JsonQuests/IQuest.cs b/GameServer/quests/JsonQuests/IQuest.cs index c06d408f..26ac9e69 100644 --- a/GameServer/quests/JsonQuests/IQuest.cs +++ b/GameServer/quests/JsonQuests/IQuest.cs @@ -1,5 +1,6 @@ using System; using DOL.Database; +using DOL.GS.Geometry; using System.Collections.Generic; using System.Numerics; @@ -81,15 +82,15 @@ public QuestZonePoint(ushort zoneId, ushort x, ushort y) public QuestZonePoint(GameObject obj) { ZoneId = obj.CurrentZone.ZoneSkinID; - X = (ushort)(obj.Position.X - obj.CurrentZone.XOffset); - Y = (ushort)(obj.Position.Y - obj.CurrentZone.YOffset); + X = (ushort)(obj.Position.X - obj.CurrentZone.Offset.X); + Y = (ushort)(obj.Position.Y - obj.CurrentZone.Offset.Y); } - public QuestZonePoint(Zone zone, Vector3 globalPos) + public QuestZonePoint(Zone zone, Coordinate globalPos) { ZoneId = zone.ZoneSkinID; - X = (ushort)(globalPos.X - zone.XOffset); - Y = (ushort)(globalPos.Y - zone.YOffset); + X = (ushort)(globalPos.X - zone.Offset.X); + Y = (ushort)(globalPos.Y - zone.Offset.Y); } public static QuestZonePoint None => new QuestZonePoint { ZoneId = 0, X = 0, Y = 0 }; diff --git a/GameServer/quests/Tasks/KillTask.cs b/GameServer/quests/Tasks/KillTask.cs index 2c9d19a1..987b391d 100644 --- a/GameServer/quests/Tasks/KillTask.cs +++ b/GameServer/quests/Tasks/KillTask.cs @@ -22,6 +22,7 @@ using DOL.Database; using DOL.Events; using DOL.GS.PacketHandler; +using DOL.Language; namespace DOL.GS.Quests { @@ -245,7 +246,6 @@ public override void Notify(DOLEvent e, object sender, EventArgs args) droppeditem.Name = itemdrop.Name; droppeditem.Level = 1; droppeditem.Position = target.Position; - droppeditem.CurrentRegion = target.CurrentRegion; droppeditem.AddToWorld(); if (dropMessages.Count > 0) { @@ -320,33 +320,11 @@ public static bool BuildTask(GamePlayer player, GameLiving source) ((KillTask)player.Task).ItemIndex = Util.Random(0, TaskObjects.Length - 1); ((KillTask)player.Task).MobName = Mob.Name; player.Task.RecieverName = source.Name; - player.Out.SendMessage(source.Name + " says, *Very well " + player.Name + ", it's good to see adventurers willing to help out the realm in such times. Search to the " + GetDirectionFromHeading(Mob.Heading) + " and kill a " + Mob.Name + " and return to me for your reward. Good luck!*", eChatType.CT_System, eChatLoc.CL_SystemWindow); + player.Out.SendMessage(source.Name + " says, *Very well " + player.Name + ", it's good to see adventurers willing to help out the realm in such times. Search to the " + LanguageMgr.GetCardinalDirection(player.Client.Account.Language, Mob.Orientation) + " and kill a " + Mob.Name + " and return to me for your reward. Good luck!*", eChatType.CT_System, eChatLoc.CL_SystemWindow); player.Out.SendDialogBox(eDialogCode.SimpleWarning, 1, 1, 1, 1, eDialogType.Ok, false, "You have been given a task!"); return true; } } - public static string GetDirectionFromHeading(ushort heading) - { - if (heading < 0) - heading += 4096; - if (heading >= 3840 || heading <= 256) - return "South"; - else if (heading > 256 && heading < 768) - return "South West"; - else if (heading >= 768 && heading <= 1280) - return "West"; - else if (heading > 1280 && heading < 1792) - return "North West"; - else if (heading >= 1792 && heading <= 2304) - return "North"; - else if (heading > 2304 && heading < 2816) - return "North East"; - else if (heading >= 2816 && heading <= 3328) - return "East"; - else if (heading > 3328 && heading < 3840) - return "South East"; - return ""; - } /// /// Find a Random Mob in Radius Distance diff --git a/GameServer/realmabilities/Statics/GenericBase.cs b/GameServer/realmabilities/Statics/GenericBase.cs index 4349719b..306d58bd 100644 --- a/GameServer/realmabilities/Statics/GenericBase.cs +++ b/GameServer/realmabilities/Statics/GenericBase.cs @@ -3,6 +3,7 @@ using DOL.GS; using DOL.GS.Spells; using DOL.Events; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using System.Numerics; @@ -19,26 +20,26 @@ public abstract class GenericBase : GameStaticItem protected uint m_pulseFrequency; int currentTick = 0; int currentPulse = 0; - protected int getCurrentPulse() - { return currentPulse; } + protected int getCurrentPulse () + {return currentPulse;} - public void CreateStatic(GamePlayer caster, Vector3 gt, uint lifeTime, uint pulseFrequency, ushort radius) + public void CreateStatic(GamePlayer caster, Coordinate gt, uint lifeTime, uint pulseFrequency, ushort radius) { - m_lifeTime = lifeTime; - m_caster = caster; - m_radius = radius; - m_pulseFrequency = pulseFrequency; - this.Name = GetStaticName(); - this.Model = GetStaticModel(); - this.Position = gt; - this.CurrentRegionID = m_caster.CurrentRegionID; - this.Level = caster.Level; + m_lifeTime = lifeTime; + m_caster = caster; + m_radius = radius; + m_pulseFrequency = pulseFrequency; + this.Name = GetStaticName(); + this.Model = GetStaticModel(); + Position = caster.Position.With(coordinate: gt); + this.Level = caster.Level; this.Realm = caster.Realm; this.AddToWorld(); - } - public override bool AddToWorld() + } + + public override bool AddToWorld() { - new RegionTimer(this, new RegionTimerCallback(PulseTimer), 1000); + new RegionTimer(this, new RegionTimerCallback(PulseTimer),1000); GameEventMgr.AddHandler(m_caster, GamePlayerEvent.RemoveFromWorld, new DOLEventHandler(PlayerLeftWorld)); return base.AddToWorld(); } diff --git a/GameServer/realmabilities/effects/rr5/BoilingCauldronEffect.cs b/GameServer/realmabilities/effects/rr5/BoilingCauldronEffect.cs index 27ecb7d4..d2086935 100644 --- a/GameServer/realmabilities/effects/rr5/BoilingCauldronEffect.cs +++ b/GameServer/realmabilities/effects/rr5/BoilingCauldronEffect.cs @@ -70,13 +70,11 @@ public override void Stop() private void SummonCauldron() { Cauldron = new GameStaticItem(); - Cauldron.CurrentRegion = EffectOwner.CurrentRegion; - Cauldron.Heading = (ushort)((EffectOwner.Heading + 2048) % 4096); Cauldron.Level = cauldronLevel; Cauldron.Realm = EffectOwner.Realm; Cauldron.Name = cauldronName; Cauldron.Model = cauldronModel; - Cauldron.Position = EffectOwner.Position; + Cauldron.Position = EffectOwner.Position.TurnedAround(); Cauldron.AddToWorld(); new RegionTimer(EffectOwner, new RegionTimerCallback(CauldronCallBack), RealmAbilities.BoilingCauldronAbility.DURATION - 1000); diff --git a/GameServer/realmabilities/effects/rr5/MinionRescueEffect.cs b/GameServer/realmabilities/effects/rr5/MinionRescueEffect.cs index fbefd19b..28250459 100644 --- a/GameServer/realmabilities/effects/rr5/MinionRescueEffect.cs +++ b/GameServer/realmabilities/effects/rr5/MinionRescueEffect.cs @@ -23,10 +23,10 @@ using DOL.AI.Brain; using DOL.Events; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.RealmAbilities; using DOL.GS.Spells; -using System.Numerics; namespace DOL.GS.Effects { @@ -117,8 +117,6 @@ public override void Stop() private void SummonSpirit(int spiritId, GamePlayer targetPlayer) { spirits[spiritId] = new GameNPC(); - spirits[spiritId].CurrentRegion = EffectOwner.CurrentRegion; - spirits[spiritId].Heading = (ushort)((EffectOwner.Heading + 2048) % 4096); spirits[spiritId].Level = spiritLevel; spirits[spiritId].Realm = EffectOwner.Realm; spirits[spiritId].Name = spiritName; @@ -126,8 +124,8 @@ private void SummonSpirit(int spiritId, GamePlayer targetPlayer) spirits[spiritId].MaxSpeedBase = spiritSpeed; spirits[spiritId].GuildName = ""; spirits[spiritId].Size = 50; - var rand = new Vector3(Util.Random(20, 40) - Util.Random(20, 40), Util.Random(20, 40) - Util.Random(20, 40), 0); - spirits[spiritId].Position = EffectOwner.Position + rand; + spirits[spiritId].Position = EffectOwner.Position.TurnedAround() + + Vector.Create(x: Util.Random(-20, 20), y: Util.Random(-20, 20)); spirits[spiritId].Flags |= GameNPC.eFlags.DONTSHOWNAME; spirits[spiritId].SetOwnBrain(new StandardMobBrain()); spirits[spiritId].AddToWorld(); diff --git a/GameServer/realmabilities/handlers/DecimationTrap.cs b/GameServer/realmabilities/handlers/DecimationTrap.cs index 2501c6f1..221942ea 100644 --- a/GameServer/realmabilities/handlers/DecimationTrap.cs +++ b/GameServer/realmabilities/handlers/DecimationTrap.cs @@ -4,6 +4,7 @@ using DOL.GS.Effects; using DOL.GS.PacketHandler; using DOL.Events; +using DOL.GS.Geometry; using System.Numerics; namespace DOL.GS.RealmAbilities @@ -59,12 +60,11 @@ public override void Execute(GameLiving living) } } - if (living.GroundTarget == null) + if (living.GroundTargetPosition == Position.Nowhere) return; - if (!living.IsWithinRadius(living.GroundTarget.Value, 1500)) + if (living.Coordinate.DistanceTo(living.GroundTargetPosition) > 1500 ) return; - GamePlayer player = living as GamePlayer; - if (player == null) + if (living is not GamePlayer player) return; if (player.RealmAbilityCastTimer != null) @@ -92,7 +92,7 @@ private int startSpell(RegionTimer timer) if (!owner.IsAlive) return 0; - traparea = new Area.Circle("decimation trap", owner.Position, 50); + traparea = new Area.Circle("decimation trap", owner.Coordinate, 50); owner.CurrentRegion.AddArea(traparea); region = owner.CurrentRegionID; @@ -136,14 +136,14 @@ private void removeHandlers() private void getTargets() { - foreach (GamePlayer target in WorldMgr.GetPlayersCloseToSpot(region, traparea.Position, 350)) + foreach (GamePlayer target in WorldMgr.GetPlayersCloseToSpot(Position.Create(region, traparea.Coordinate), 350)) { if (GameServer.ServerRules.IsAllowedToAttack(owner, target, true)) { DamageTarget(target); } } - foreach (GameNPC target in WorldMgr.GetNPCsCloseToSpot(region, traparea.Position, 350)) + foreach (GameNPC target in WorldMgr.GetNPCsCloseToSpot(Position.Create(region, traparea.Coordinate), 350)) { if (GameServer.ServerRules.IsAllowedToAttack(owner, target, true)) { @@ -163,7 +163,7 @@ private void DamageTarget(GameLiving target) ticktimer.Stop(); removeHandlers(); } - var dist = Vector3.Distance(target.Position, traparea.Position); + var dist = (int)target.Coordinate.DistanceTo(traparea.Coordinate); double mod = 1; if (dist > 0) mod = 1 - ((double)dist / 350); diff --git a/GameServer/realmabilities/handlers/NegativeMaelstromAbility.cs b/GameServer/realmabilities/handlers/NegativeMaelstromAbility.cs index 97d33dc4..6e1611ce 100644 --- a/GameServer/realmabilities/handlers/NegativeMaelstromAbility.cs +++ b/GameServer/realmabilities/handlers/NegativeMaelstromAbility.cs @@ -6,6 +6,7 @@ using DOL.GS.Effects; using DOL.Events; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.RealmAbilities { @@ -28,7 +29,7 @@ public override void Execute(GameLiving living) return; } - if (caster.GroundTarget == null || !caster.IsWithinRadius(caster.GroundTarget.Value, 1500)) + if (caster.GroundTargetPosition == Position.Nowhere || !caster.IsWithinRadius(caster.GroundTargetPosition, 1500)) { caster.Out.SendMessage("You groundtarget is too far away to use this ability!", eChatType.CT_System, eChatLoc.CL_SystemWindow); return; @@ -104,7 +105,7 @@ protected virtual int EndCast(RegionTimer timer) if (!castWasSuccess) return 0; Statics.NegativeMaelstromBase nm = new Statics.NegativeMaelstromBase(dmgValue); - nm.CreateStatic(player, player.GroundTarget.Value, duration, 5, 350); + nm.CreateStatic(player, player.GroundTargetPosition.Coordinate, duration, 5, 350); DisableSkill(player); timer.Stop(); timer = null; diff --git a/GameServer/realmabilities/handlers/PerfectRecoveryAbility.cs b/GameServer/realmabilities/handlers/PerfectRecoveryAbility.cs index 70b4b65a..5bba1e81 100644 --- a/GameServer/realmabilities/handlers/PerfectRecoveryAbility.cs +++ b/GameServer/realmabilities/handlers/PerfectRecoveryAbility.cs @@ -183,7 +183,7 @@ public void ResurrectLiving(GamePlayer resurrectedPlayer, GameLiving rezzer) resurrectedPlayer.Health = (int)(resurrectedPlayer.MaxHealth * m_resurrectValue / 100); resurrectedPlayer.Mana = (int)(resurrectedPlayer.MaxMana * m_resurrectValue / 100); resurrectedPlayer.Endurance = (int)(resurrectedPlayer.MaxEndurance * m_resurrectValue / 100); //no endurance after any rez - resurrectedPlayer.MoveTo(rezzer.CurrentRegionID, rezzer.Position, rezzer.Heading); + resurrectedPlayer.MoveTo(rezzer.Position); GameLiving living = resurrectedPlayer as GameLiving; GameTimer resurrectExpiredTimer = null; diff --git a/GameServer/realmabilities/handlers/StaticTempestAbility.cs b/GameServer/realmabilities/handlers/StaticTempestAbility.cs index 0c64be1c..b4bfa8da 100644 --- a/GameServer/realmabilities/handlers/StaticTempestAbility.cs +++ b/GameServer/realmabilities/handlers/StaticTempestAbility.cs @@ -78,7 +78,7 @@ public override void Execute(GameLiving living) } } Statics.StaticTempestBase st = new Statics.StaticTempestBase(m_stunDuration); - st.CreateStatic(caster, caster.TargetObject.Position, m_duration, 5, 360); + st.CreateStatic(caster, caster.TargetObject.Coordinate, m_duration, 5, 360); DisableSkill(living); } public override int GetReUseDelay(int level) diff --git a/GameServer/realmabilities/handlers/ThornweedFieldAbility.cs b/GameServer/realmabilities/handlers/ThornweedFieldAbility.cs index cd565ba9..65032a0e 100644 --- a/GameServer/realmabilities/handlers/ThornweedFieldAbility.cs +++ b/GameServer/realmabilities/handlers/ThornweedFieldAbility.cs @@ -6,6 +6,7 @@ using DOL.GS.Effects; using DOL.Events; using DOL.Database; +using DOL.GS.Geometry; namespace DOL.GS.RealmAbilities { @@ -30,12 +31,12 @@ public override void Execute(GameLiving living) return; } - if (caster.GroundTarget == null) + if (caster.GroundTargetPosition == Position.Nowhere) { caster.Out.SendMessage("You must set a ground target to use this ability!", eChatType.CT_System, eChatLoc.CL_SystemWindow); return; } - else if (!caster.IsWithinRadius(caster.GroundTarget.Value, 1500)) + else if (!caster.IsWithinRadius(caster.GroundTargetPosition, 1500)) { caster.Out.SendMessage("Your ground target is too far away to use this ability!", eChatType.CT_System, eChatLoc.CL_SystemWindow); return; @@ -102,7 +103,7 @@ protected virtual int EndCast(RegionTimer timer) if (m_player.IsMezzed || m_player.IsStunned || m_player.IsSitting) return 0; Statics.ThornweedFieldBase twf = new Statics.ThornweedFieldBase(m_dmgValue); - twf.CreateStatic(m_player, m_player.GroundTarget.Value, m_duration, 3, 500); + twf.CreateStatic(m_player, m_player.GroundTargetPosition.Coordinate, m_duration, 3, 500); DisableSkill(m_player); timer.Stop(); timer = null; diff --git a/GameServer/realmabilities/handlers/rr5/WallOfFlameAbility.cs b/GameServer/realmabilities/handlers/rr5/WallOfFlameAbility.cs index 94f4fdf3..704c789c 100644 --- a/GameServer/realmabilities/handlers/rr5/WallOfFlameAbility.cs +++ b/GameServer/realmabilities/handlers/rr5/WallOfFlameAbility.cs @@ -47,7 +47,7 @@ public override void Execute(GameLiving living) } Statics.WallOfFlameBase wof = new Statics.WallOfFlameBase(dmgValue); - wof.CreateStatic(caster, caster.Position, duration, 3, 150); + wof.CreateStatic(caster, caster.Coordinate, duration, 3, 150); DisableSkill(living); caster.StopCurrentSpellcast(); diff --git a/GameServer/relics/RelicPad.cs b/GameServer/relics/RelicPad.cs index 5737d120..936c0731 100644 --- a/GameServer/relics/RelicPad.cs +++ b/GameServer/relics/RelicPad.cs @@ -95,7 +95,7 @@ public class Surface : Area.Circle private RelicPad m_relicPad; public Surface(RelicPad relicPad) - : base("", relicPad.Position, RelicPad.Radius) + : base("", relicPad.Coordinate, RelicPad.Radius) { m_relicPad = relicPad; } diff --git a/GameServer/serverrules/AbstractServerRules.cs b/GameServer/serverrules/AbstractServerRules.cs index f8576914..bb34bd71 100644 --- a/GameServer/serverrules/AbstractServerRules.cs +++ b/GameServer/serverrules/AbstractServerRules.cs @@ -28,6 +28,7 @@ using DOL.Events; using DOL.gameobjects.CustomNPC; using DOL.GS.Finance; +using DOL.GS.Geometry; using DOL.GS.Housing; using DOL.GS.Keeps; using DOL.GS.PacketHandler; @@ -252,16 +253,22 @@ public virtual void OnReleased(DOLEvent e, object sender, EventArgs args) GamePlayer player = (GamePlayer)sender; StartImmunityTimer(player, ServerProperties.Properties.TIMER_KILLED_BY_MOB * 1000);//When Killed by a Mob } - + /// /// Should be called whenever a player teleports to a new location /// /// /// /// + public virtual void OnPlayerTeleport(GamePlayer player, Teleport destination) + { + } + + [Obsolete("Use .OnPlayerTeleport(GamePlayer,Teleport) instead!")] + public virtual void OnPlayerTeleport(GamePlayer player, GameLocation source, Teleport destination) { - // override this in order to do something, like set immunity, when a player teleports + OnPlayerTeleport(player, destination); } /// @@ -1443,7 +1450,7 @@ and it will also let higher level players (the 35-50s who tend to hit this clamp if (player != null) { AbstractGameKeep keep = - GameServer.KeepManager.GetKeepCloseToSpot(living.CurrentRegionID, living.Position, 16000); + GameServer.KeepManager.GetKeepCloseToSpot(living.Position, 16000); if (keep != null) { byte bonus = 0; @@ -1801,7 +1808,7 @@ public virtual void OnPlayerKilled(GamePlayer killedPlayer, GameObject killer) if (!BG && living is GamePlayer) { - AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(living.CurrentRegionID, living.Position, 16000); + AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(living.Position, 16000); if (keep != null) { byte bonus = 0; @@ -2368,16 +2375,15 @@ public virtual void BuyHousingItem(GamePlayer player, ushort slot, byte count, D GameMerchant.OnPlayerBuy(player, slot, count, items); } + [Obsolete("Use .PlaceHousingNPC(House, ItemTemplate, Coordinate, ushort) instead!")] + public virtual GameNPC PlaceHousingNPC(DOL.GS.Housing.House house, ItemTemplate item, Vector3 location, ushort heading) + => PlaceHousingNPC(house, item, Coordinate.Create((int)location.X, (int)location.Y, (int)location.Z), heading); /// /// Get a housing hookpoint NPC /// - /// - /// - /// - /// /// - public virtual GameNPC PlaceHousingNPC(DOL.GS.Housing.House house, ItemTemplate item, Vector3 location, ushort heading) + public virtual GameNPC PlaceHousingNPC(DOL.GS.Housing.House house, ItemTemplate item, Coordinate coordinate, ushort heading) { NpcTemplate npcTemplate = NpcTemplateMgr.GetTemplate(item.Bonus); @@ -2446,9 +2452,7 @@ public virtual GameNPC PlaceHousingNPC(DOL.GS.Housing.House house, ItemTemplate npc.Name = item.Name; npc.CurrentHouse = house; npc.OwnerID = item.Id_nb; - npc.Position = location; - npc.Heading = heading; - npc.CurrentRegionID = house.RegionID; + npc.Position = Position.Create(house.RegionID, coordinate, heading); if (!npc.IsPeaceful) { npc.Flags ^= GameNPC.eFlags.PEACE; @@ -2464,15 +2468,16 @@ public virtual GameNPC PlaceHousingNPC(DOL.GS.Housing.House house, ItemTemplate return null; } - + [Obsolete("Use .PlaceHousingInteriorItem(House, ItemTemplate, Coordinate, ushort) instead!")] public virtual GameStaticItem PlaceHousingInteriorItem(DOL.GS.Housing.House house, ItemTemplate item, Vector3 location, ushort heading) + => PlaceHousingInteriorItem(house, item, Coordinate.Create((int)location.X, (int)location.Y, (int)location.Z), heading); + + public virtual GameStaticItem PlaceHousingInteriorItem(DOL.GS.Housing.House house, ItemTemplate item, Coordinate coordinate, ushort heading) { GameStaticItem hookpointObject = new GameStaticItem(); hookpointObject.CurrentHouse = house; hookpointObject.OwnerID = item.Id_nb; - hookpointObject.Position = location; - hookpointObject.Heading = heading; - hookpointObject.CurrentRegionID = house.RegionID; + hookpointObject.Position = Position.Create(house.RegionID, coordinate, heading); hookpointObject.Name = item.Name; hookpointObject.Model = (ushort)item.Model; hookpointObject.AddToWorld(); diff --git a/GameServer/serverrules/AdventureWingJumpPoint.cs b/GameServer/serverrules/AdventureWingJumpPoint.cs index 4ec21a03..c9bb64d5 100644 --- a/GameServer/serverrules/AdventureWingJumpPoint.cs +++ b/GameServer/serverrules/AdventureWingJumpPoint.cs @@ -18,6 +18,7 @@ */ using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using System.Collections; using System.Collections.Generic; @@ -46,7 +47,7 @@ public bool IsAllowedToJump(ZonePoint targetPoint, GamePlayer player) { //Handles zoning INTO an instance. - GameLocation loc = null; + Position position = Position.Nowhere; AdventureWingInstance previousInstance = null; // Do we have a group ? @@ -116,11 +117,6 @@ public bool IsAllowedToJump(ZonePoint targetPoint, GamePlayer player) { // I have no instance to go to, create one ! previousInstance = (AdventureWingInstance)WorldMgr.CreateInstance(targetPoint.TargetRegion, typeof(AdventureWingInstance)); - if (targetPoint.SourceRegion != 0 && targetPoint.SourceRegion == player.CurrentRegionID) - { - //source loc seems legit... - previousInstance.SourceEntrance = new GameLocation("source", targetPoint.SourceRegion, targetPoint.SourceX, targetPoint.SourceY, targetPoint.SourceZ); - } if (player.Group != null) { @@ -192,18 +188,12 @@ public bool IsAllowedToJump(ZonePoint targetPoint, GamePlayer player) } - //get loc of instance - if (previousInstance != null) - { - loc = new GameLocation(previousInstance.Description + " (instance)", previousInstance.ID, targetPoint.TargetX, targetPoint.TargetY, targetPoint.TargetZ, targetPoint.TargetHeading); - } - - - if (loc != null) + position = targetPoint.GetTargetPosition().With(regionID: previousInstance.ID); + if (position != Position.Nowhere) { // Move Player, changing target destination is failing !! - player.MoveTo(loc); + player.MoveTo(position); return false; } diff --git a/GameServer/serverrules/IServerRules.cs b/GameServer/serverrules/IServerRules.cs index 13127a6a..251010a1 100644 --- a/GameServer/serverrules/IServerRules.cs +++ b/GameServer/serverrules/IServerRules.cs @@ -24,6 +24,7 @@ using DOL.GS.Keeps; using System.Numerics; using AmteScripts.Managers; +using DOL.GS.Geometry; using System.Linq; namespace DOL.GS.ServerRules @@ -292,9 +293,9 @@ public interface IServerRules /// /// Invoked when a player teleports somewhere /// - /// - /// - /// + void OnPlayerTeleport(GamePlayer player, Teleport destination); + + [Obsolete("Use .OnPlayerTeleport(GamePlayer,Teleport) instead!")] void OnPlayerTeleport(GamePlayer player, GameLocation source, Teleport destination); /// @@ -494,21 +495,18 @@ public interface IServerRules /// /// Get a housing hookpoint NPC /// - /// - /// - /// - /// /// + GameNPC PlaceHousingNPC(DOL.GS.Housing.House house, ItemTemplate item, Coordinate coordinate, ushort heading); + + [Obsolete("Use .PlayerHousingNPC(House,ItemTemplate,Coordinate,ushort) instead!")] GameNPC PlaceHousingNPC(DOL.GS.Housing.House house, ItemTemplate item, Vector3 location, ushort heading); /// /// Get a static interior object for a house hookpoint /// - /// - /// - /// - /// /// + GameStaticItem PlaceHousingInteriorItem(DOL.GS.Housing.House house, ItemTemplate item, Coordinate coordinate, ushort heading); + [Obsolete("Use .PlaceHousingInteriorItem(House,ItemTemplate,Coordinate,ushort) instead!")] GameStaticItem PlaceHousingInteriorItem(DOL.GS.Housing.House house, ItemTemplate item, Vector3 location, ushort heading); /// diff --git a/GameServer/serverrules/PvPServerRules.cs b/GameServer/serverrules/PvPServerRules.cs index 29a9d1d3..cbc10685 100644 --- a/GameServer/serverrules/PvPServerRules.cs +++ b/GameServer/serverrules/PvPServerRules.cs @@ -109,11 +109,11 @@ public override void OnReleased(DOLEvent e, object sender, EventArgs args) /// /// /// - public override void OnPlayerTeleport(GamePlayer player, GameLocation source, Teleport destination) + public override void OnPlayerTeleport(GamePlayer player, Teleport destination) { // Since region change already starts an immunity timer we only want to do this if a player // is teleporting within the same region - if (source.RegionID == destination.RegionID) + if (player.CurrentRegionID == destination.RegionID) { StartImmunityTimer(player, ServerProperties.Properties.TIMER_PVP_TELEPORT * 1000); } @@ -135,7 +135,7 @@ public override void OnPlayerTeleport(GamePlayer player, GameLocation source, Te //No PVP Dungeons: http://support.darkageofcamelot.com/cgi-bin/support.cfg/php/enduser/std_adp.php?p_sid=frxnPUjg&p_lva=&p_refno=020709-000000&p_created=1026248996&p_sp=cF9ncmlkc29ydD0mcF9yb3dfY250PTE0JnBfc2VhcmNoX3RleHQ9JnBfc2VhcmNoX3R5cGU9MyZwX2NhdF9sdmwxPTI2JnBfY2F0X2x2bDI9fmFueX4mcF9zb3J0X2J5PWRmbHQmcF9wYWdlPTE*&p_li 21, //Tomb of Mithra - 129, //Nisse�s Lair (Nisee's Lair in regions.ini) + 129, //Nisse's Lair (Nisse's Lair in regions.ini) 221, //Muire Tomb (Undead in regions.ini) }; diff --git a/GameServer/serverrules/TaskDungeonJumpPoint.cs b/GameServer/serverrules/TaskDungeonJumpPoint.cs index f00bd376..3beabf9d 100644 --- a/GameServer/serverrules/TaskDungeonJumpPoint.cs +++ b/GameServer/serverrules/TaskDungeonJumpPoint.cs @@ -18,6 +18,7 @@ */ using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.Quests; @@ -39,7 +40,7 @@ public class TaskDungeonJumpPoint : IJumpPointHandler public bool IsAllowedToJump(ZonePoint targetPoint, GamePlayer player) { //Handles zoning INTO an instance. - GameLocation loc = null; + var loc = Position.Nowhere; //First, we try the groups mission. if (player.Group != null) @@ -49,23 +50,23 @@ public bool IsAllowedToJump(ZonePoint targetPoint, GamePlayer player) { //Attempt to get the instance entrance location... TaskDungeonMission task = (TaskDungeonMission)grp.Mission; - loc = task.TaskRegion.InstanceEntranceLocation; + loc = task.TaskRegion.EntrancePosition; } } else if (player.Mission != null && player.Mission is TaskDungeonMission) { //Then, try personal missions... TaskDungeonMission task = (TaskDungeonMission)player.Mission; - loc = task.TaskRegion.InstanceEntranceLocation; + loc = task.TaskRegion.EntrancePosition; } - if (loc != null) + if (loc != Position.Nowhere) { - targetPoint.TargetX = (int)loc.Position.X; - targetPoint.TargetY = (int)loc.Position.Y; - targetPoint.TargetZ = (int)loc.Position.Z; + targetPoint.TargetX = loc.X; + targetPoint.TargetY = loc.Y; + targetPoint.TargetZ = loc.Z; targetPoint.TargetRegion = loc.RegionID; - targetPoint.TargetHeading = loc.Heading; + targetPoint.TargetHeading = loc.Orientation.InHeading; return true; } diff --git a/GameServer/spells/Animist/SummonAnimistFnF.cs b/GameServer/spells/Animist/SummonAnimistFnF.cs index d924e877..c5adaa0f 100644 --- a/GameServer/spells/Animist/SummonAnimistFnF.cs +++ b/GameServer/spells/Animist/SummonAnimistFnF.cs @@ -37,14 +37,14 @@ public override bool CheckBeginCast(GameLiving selectedTarget) Region rgn = WorldMgr.GetRegion(Caster.CurrentRegion.ID); - if (rgn == null || rgn.GetZone(Caster.GroundTarget.Value) == null) + if (rgn == null || rgn.GetZone(Caster.GroundTargetPosition.Coordinate) == null) { if (Caster is GamePlayer) MessageToCaster(LanguageMgr.GetTranslation((Caster as GamePlayer).Client, "SummonAnimistFnF.CheckBeginCast.NoGroundTarget"), eChatType.CT_SpellResisted); return false; } - foreach (GameNPC npc in Caster.CurrentRegion.GetNPCsInRadius(Caster.GroundTarget.Value, (ushort)Properties.TURRET_AREA_CAP_RADIUS, false, true)) + foreach (GameNPC npc in Caster.CurrentRegion.GetNPCsInRadius(Caster.GroundTargetPosition.Coordinate, (ushort)Properties.TURRET_AREA_CAP_RADIUS, false, true)) if (npc.Brain is TurretFNFBrain) nCount++; diff --git a/GameServer/spells/Animist/SummonAnimistPet.cs b/GameServer/spells/Animist/SummonAnimistPet.cs index 8203e333..1c859bce 100644 --- a/GameServer/spells/Animist/SummonAnimistPet.cs +++ b/GameServer/spells/Animist/SummonAnimistPet.cs @@ -17,6 +17,7 @@ * */ using DOL.AI.Brain; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.Language; using System.Numerics; @@ -30,7 +31,7 @@ protected SummonAnimistPet(GameLiving caster, Spell spell, SpellLine line) public override bool CheckBeginCast(GameLiving selectedTarget) { - if (Caster.GroundTarget == null) + if (Caster.GroundTargetPosition == Position.Nowhere) { if (Caster is GamePlayer) MessageToCaster(LanguageMgr.GetTranslation((Caster as GamePlayer).Client, "SummonAnimistPet.CheckBeginCast.GroundTargetNull"), eChatType.CT_SpellResisted); @@ -44,7 +45,7 @@ public override bool CheckBeginCast(GameLiving selectedTarget) return false; } - if (!Caster.IsWithinRadius(Caster.GroundTarget.Value, CalculateSpellRange())) + if (!Caster.IsWithinRadius(Caster.GroundTargetPosition, CalculateSpellRange())) { if (Caster is GamePlayer) MessageToCaster(LanguageMgr.GetTranslation((Caster as GamePlayer).Client, "SummonAnimistPet.CheckBeginCast.GroundTargetNotInSpellRange"), eChatType.CT_SpellResisted); @@ -55,7 +56,7 @@ public override bool CheckBeginCast(GameLiving selectedTarget) } public override void FinishSpellCast(GameLiving target) { - if (Caster.GroundTarget == null) + if (Caster.GroundTargetPosition == Position.Nowhere) { if (Caster is GamePlayer) MessageToCaster(LanguageMgr.GetTranslation((Caster as GamePlayer).Client, "SummonAnimistPet.CheckBeginCast.GroundTargetNull"), eChatType.CT_SpellResisted); @@ -76,7 +77,7 @@ public override void FinishSpellCast(GameLiving target) return; } - if (!Caster.IsWithinRadius(Caster.GroundTarget.Value, CalculateSpellRange())) + if (!Caster.IsWithinRadius(Caster.GroundTargetPosition, CalculateSpellRange())) { if (Caster is GamePlayer) MessageToCaster(LanguageMgr.GetTranslation((Caster as GamePlayer).Client, "SummonAnimistPet.CheckBeginCast.GroundTargetNotInSpellRange"), eChatType.CT_SpellResisted); @@ -112,12 +113,8 @@ protected override IControlledBrain GetPetBrain(GameLiving owner) return new TurretBrain(owner); } - protected override void GetPetLocation(out Vector3 pos, out ushort heading, out Region region) - { - pos = Caster.GroundTarget.Value; - heading = Caster.Heading; - region = Caster.CurrentRegion; - } + protected override Position GetSummonPosition() + => Caster.GroundTargetPosition; /// /// Do not trigger SubSpells diff --git a/GameServer/spells/Animist/TurretSpellHandler.cs b/GameServer/spells/Animist/TurretSpellHandler.cs index 753dc543..4507b427 100644 --- a/GameServer/spells/Animist/TurretSpellHandler.cs +++ b/GameServer/spells/Animist/TurretSpellHandler.cs @@ -74,7 +74,7 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness { if (target != null && target.CurrentRegion != null) { - foreach (GameNPC npc in target.CurrentRegion.GetNPCsInRadius(target.Position, (ushort)Spell.Radius, false, true)) + foreach (GameNPC npc in target.CurrentRegion.GetNPCsInRadius(target.Coordinate, (ushort)Spell.Radius, false, true)) { if (npc == null || !npc.IsAlive) { diff --git a/GameServer/spells/Archery/Archery.cs b/GameServer/spells/Archery/Archery.cs index 727d0a50..25b02684 100644 --- a/GameServer/spells/Archery/Archery.cs +++ b/GameServer/spells/Archery/Archery.cs @@ -107,7 +107,7 @@ public override bool CheckBeginCast(GameLiving selectedTarget) String targetType = m_spell.Target.ToLower(); if (targetType == "area") { - if (!m_caster.IsWithinRadius(m_caster.GroundTarget.Value, CalculateSpellRange())) + if (!m_caster.IsWithinRadius(m_caster.GroundTargetPosition, CalculateSpellRange())) { MessageToCaster("Your area target is out of range. Select a closer target.", eChatType.CT_SpellResisted); return false; @@ -309,7 +309,7 @@ public override void FinishSpellCast(GameLiving target) Caster.LastAttackTickPvE = Caster.CurrentRegion.Time; Caster.LastAttackTickPvP = Caster.CurrentRegion.Time; - foreach (GameLiving npc in WorldMgr.GetNPCsCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GameLiving npc in WorldMgr.GetNPCsCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (npc.Realm == 0 || Caster.Realm == 0) { diff --git a/GameServer/spells/Artifacts/bracerofzo.cs b/GameServer/spells/Artifacts/bracerofzo.cs index d307080c..dc357586 100644 --- a/GameServer/spells/Artifacts/bracerofzo.cs +++ b/GameServer/spells/Artifacts/bracerofzo.cs @@ -21,7 +21,7 @@ using DOL.GS.PacketHandler; using DOL.GS.Effects; using DOL.AI.Brain; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS.Spells { @@ -53,16 +53,13 @@ public override void OnEffectStart(GameSpellEffect effect) return; } - Vector2 spawnPoint = Caster.GetPointFromHeading(Caster.Heading, 64); + var spawnPoint = Caster.Position.TurnedAround() + Vector.Create(Caster.Orientation, length: 64); int i = 0; - for (i = 0; i < 3; i++) - { + for(i=0;i<3;i++) + { deamons[i] = new ZoarkatPet(template); deamons[i].SetOwnBrain(new ProcPetBrain(player)); - var offset = new Vector2(Util.Random(20, 40) - Util.Random(20, 40), Util.Random(20, 40) - Util.Random(20, 40)); - deamons[i].Position = new Vector3(spawnPoint + offset, Caster.Position.Z); - deamons[i].CurrentRegion = Caster.CurrentRegion; - deamons[i].Heading = (ushort)((Caster.Heading + 2048) % 4096); + deamons[i].Position = spawnPoint + Vector.Create(x: Util.Random(-20,20), y: Util.Random(-20,20)); deamons[i].Realm = Caster.Realm; deamons[i].Level = 36; deamons[i].Flags |= GameNPC.eFlags.FLYING; diff --git a/GameServer/spells/AstralPetSummon.cs b/GameServer/spells/AstralPetSummon.cs index 5e885066..ccd58f22 100644 --- a/GameServer/spells/AstralPetSummon.cs +++ b/GameServer/spells/AstralPetSummon.cs @@ -27,8 +27,8 @@ using DOL.GS.PacketHandler; using DOL.Language; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.Styles; -using System.Numerics; namespace DOL.GS.Spells { @@ -76,11 +76,8 @@ protected override void OnNpcReleaseCommand(DOLEvent e, object sender, EventArgs effect.Cancel(false); } - protected override void GetPetLocation(out Vector3 pos, out ushort heading, out Region region) - { - base.GetPetLocation(out pos, out heading, out region); - heading = Caster.Heading; - } + protected override Position GetSummonPosition() + => Caster.Position + Vector.Create(Caster.Orientation, length: 64); public AstralPetSummon(GameLiving caster, Spell spell, SpellLine line) : base(caster, spell, line) { } diff --git a/GameServer/spells/CommonAstralSpells.cs b/GameServer/spells/CommonAstralSpells.cs index 9596ab11..2034cfc5 100644 --- a/GameServer/spells/CommonAstralSpells.cs +++ b/GameServer/spells/CommonAstralSpells.cs @@ -19,7 +19,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Numerics; using System.Reflection; using DOL.AI.Brain; @@ -27,6 +26,7 @@ using DOL.Events; using DOL.GS; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.Spells; using DOL.Language; @@ -123,15 +123,13 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness } beffect = CreateSpellEffect(target, effectiveness); - var summonloc = GameMath.GetPointFromHeading(target, 64); + var summonPosition = target.Position.TurnedAround() + Vector.Create(target.Orientation, length: 64); BrittleBrain controlledBrain = new BrittleBrain(player); controlledBrain.IsMainPet = false; summoned = new GameNPC(template); summoned.SetOwnBrain(controlledBrain); - summoned.Position = new Vector3(summonloc, target.Position.Z); - summoned.CurrentRegion = target.CurrentRegion; - summoned.Heading = (ushort)((target.Heading + 2048) % 4096); + summoned.Position = summonPosition; summoned.Realm = target.Realm; summoned.Level = Caster.Level; summoned.Size = 50; diff --git a/GameServer/spells/EarthquakeSpellHandler.cs b/GameServer/spells/EarthquakeSpellHandler.cs index 4e3734f1..6b67dfe1 100644 --- a/GameServer/spells/EarthquakeSpellHandler.cs +++ b/GameServer/spells/EarthquakeSpellHandler.cs @@ -1,5 +1,5 @@ -using DOL.Geometry; -using DOL.GS.Effects; +using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.GS.PlayerClass; using System; @@ -11,7 +11,11 @@ public class EarthquakeSpellHandler : SpellHandler { uint unk1 = 0; float radius, intensity, duration, delay = 0; - int x, y, z = 0; + private Coordinate Coordinate + { + get; + set; + } public EarthquakeSpellHandler(GameLiving caster, Spell spell, SpellLine spellLine) : base(caster, spell, spellLine) { @@ -27,16 +31,13 @@ public override bool StartSpell(GameLiving targetObject) MessageToCaster("Your spell was cancelled.", eChatType.CT_SpellExpires); return false; } - if (Caster.GroundTarget == null) + if (Caster.GroundTargetPosition == Position.Nowhere) { - x = (int)Caster.Position.X; - y = (int)Caster.Position.Y; + Coordinate = Caster.Coordinate; } else { - x = (int)Caster.Position.X; - y = (int)Caster.Position.Y; - z = (int)Caster.Position.Z; + Coordinate = Caster.GroundTargetPosition.Coordinate; } /*if (args.Length > 1) { @@ -81,13 +82,13 @@ public override bool StartSpell(GameLiving targetObject) if (Caster is GamePlayer player) { - int distance = (int)System.Numerics.Vector3.Distance(player.Position, new System.Numerics.Vector3(x, y, player.Position.Z)); + int distance = (int)player.Coordinate.DistanceTo(Coordinate, true); float newIntensity = intensity * (1 - distance / radius); GSTCPPacketOut pak = new GSTCPPacketOut(0x47); pak.WriteIntLowEndian(unk1); - pak.WriteIntLowEndian((uint)x); - pak.WriteIntLowEndian((uint)y); - pak.WriteIntLowEndian((uint)z); + pak.WriteIntLowEndian((uint)Coordinate.X); + pak.WriteIntLowEndian((uint)Coordinate.Y); + pak.WriteIntLowEndian((uint)Coordinate.Z); pak.Write(BitConverter.GetBytes(radius), 0, sizeof(float)); pak.Write(BitConverter.GetBytes(newIntensity), 0, sizeof(float)); pak.Write(BitConverter.GetBytes(duration), 0, sizeof(float)); @@ -130,13 +131,13 @@ public override void OnSpellPulse(PulsingSpellEffect effect) if (Caster is GamePlayer player) { - int distance = (int)System.Numerics.Vector3.Distance(player.Position, new System.Numerics.Vector3(x, y, player.Position.Z)); + int distance = (int)player.Coordinate.DistanceTo(Coordinate, true); float newIntensity = intensity * (1 - distance / radius); GSTCPPacketOut pak = new GSTCPPacketOut(0x47); pak.WriteIntLowEndian(unk1); - pak.WriteIntLowEndian((uint)x); - pak.WriteIntLowEndian((uint)y); - pak.WriteIntLowEndian((uint)z); + pak.WriteIntLowEndian((uint)Coordinate.X); + pak.WriteIntLowEndian((uint)Coordinate.Y); + pak.WriteIntLowEndian((uint)Coordinate.Z); pak.Write(BitConverter.GetBytes(radius), 0, sizeof(float)); pak.Write(BitConverter.GetBytes(newIntensity), 0, sizeof(float)); pak.Write(BitConverter.GetBytes(duration), 0, sizeof(float)); @@ -158,7 +159,7 @@ public override void OnSpellPulse(PulsingSpellEffect effect) public override void ApplyEffectOnTarget(GameLiving target, double effectiveness) { - int distance = (int)System.Numerics.Vector3.Distance(target.Position, new System.Numerics.Vector3(x, y, target.Position.Z)); + int distance = (int)target.Coordinate.DistanceTo(Coordinate, true); if (distance > radius) { CancelPulsingSpell(target, Spell.SpellType); @@ -173,9 +174,9 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness return; GSTCPPacketOut pakBis = new GSTCPPacketOut(0x47); pakBis.WriteIntLowEndian(unk1); - pakBis.WriteIntLowEndian((uint)x); - pakBis.WriteIntLowEndian((uint)y); - pakBis.WriteIntLowEndian((uint)z); + pakBis.WriteIntLowEndian((uint)Coordinate.X); + pakBis.WriteIntLowEndian((uint)Coordinate.Y); + pakBis.WriteIntLowEndian((uint)Coordinate.Z); pakBis.Write(BitConverter.GetBytes(radius), 0, sizeof(float)); pakBis.Write(BitConverter.GetBytes(newIntensity), 0, sizeof(float)); pakBis.Write(BitConverter.GetBytes(duration), 0, sizeof(float)); diff --git a/GameServer/spells/Masterlevel/Convoker.cs b/GameServer/spells/Masterlevel/Convoker.cs index bb8bcba2..8b9932f2 100644 --- a/GameServer/spells/Masterlevel/Convoker.cs +++ b/GameServer/spells/Masterlevel/Convoker.cs @@ -12,6 +12,8 @@ using DOL.GS.RealmAbilities; using System.Numerics; using DOL; +using DOL.GS.Geometry; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.GS.Spells { @@ -62,8 +64,6 @@ public PrescienceNodeSpellHandler(GameLiving caster, Spell spell, SpellLine line font.Name = spell.Name; font.Realm = caster.Realm; font.Position = caster.Position; - font.CurrentRegionID = caster.CurrentRegionID; - font.Heading = caster.Heading; font.Owner = (GamePlayer)caster; // Construct the font spell @@ -138,8 +138,6 @@ public PowerTrapSpellHandler(GameLiving caster, Spell spell, SpellLine line) mine.Name = spell.Name; mine.Realm = caster.Realm; mine.Position = caster.Position; - mine.CurrentRegionID = caster.CurrentRegionID; - mine.Heading = caster.Heading; mine.Owner = (GamePlayer)caster; // Construct the mine spell @@ -190,8 +188,6 @@ public SpeedWrapWardSpellHandler(GameLiving caster, Spell spell, SpellLine line) font.Name = spell.Name; font.Realm = caster.Realm; font.Position = caster.Position; - font.CurrentRegionID = caster.CurrentRegionID; - font.Heading = caster.Heading; font.Owner = (GamePlayer)caster; // Construct the mine spell @@ -314,13 +310,13 @@ public override void OnEffectStart(GameSpellEffect effect) if ((effect.Owner is GamePlayer)) { GamePlayer casterPlayer = effect.Owner as GamePlayer; - if (casterPlayer.GroundTarget != null && casterPlayer.GroundTargetInView) + if (casterPlayer.GroundTargetPosition != Position.Nowhere && casterPlayer.GroundTargetInView) { GameEventMgr.AddHandler(casterPlayer, GamePlayerEvent.Moving, new DOLEventHandler(PlayerMoves)); GameEventMgr.AddHandler(warder, GameLivingEvent.Dying, new DOLEventHandler(BattleWarderDie)); GameEventMgr.AddHandler(casterPlayer, GamePlayerEvent.CastStarting, new DOLEventHandler(PlayerMoves)); GameEventMgr.AddHandler(casterPlayer, GamePlayerEvent.AttackFinished, new DOLEventHandler(PlayerMoves)); - warder.Position = casterPlayer.GroundTarget.Value; + warder.Position = casterPlayer.GroundTargetPosition; warder.AddBrain(new MLBrain()); warder.AddToWorld(); } @@ -379,7 +375,7 @@ private void BattleWarderDie(DOLEvent e, object sender, EventArgs args) public override bool CheckBeginCast(GameLiving selectedTarget) { if (!base.CheckBeginCast(selectedTarget)) return false; - if (!(m_caster.GroundTarget != null && m_caster.GroundTargetInView)) + if (!(m_caster.GroundTargetPosition != Position.Nowhere && m_caster.GroundTargetInView)) { MessageToCaster("Your area target is out of range. Set a closer ground position.", eChatType.CT_SpellResisted); return false; @@ -393,7 +389,7 @@ public BattlewarderSpellHandler(GameLiving caster, Spell spell, SpellLine line) warder = new GameNPC(); //Fill the object variables warder.CurrentRegion = caster.CurrentRegion; - warder.Heading = (ushort)((caster.Heading + 2048) % 4096); + warder.Orientation = caster.Orientation + Angle.Degrees(180); warder.Level = 70; warder.Realm = caster.Realm; warder.Name = "Battle Warder"; @@ -423,8 +419,6 @@ public DissonanceTrapSpellHandler(GameLiving caster, Spell spell, SpellLine line mine.Name = spell.Name; mine.Realm = caster.Realm; mine.Position = caster.Position; - mine.CurrentRegionID = caster.CurrentRegionID; - mine.Heading = caster.Heading; mine.Owner = (GamePlayer)caster; // Construct the mine spell @@ -511,9 +505,7 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness controlledBrain.IsMainPet = false; summoned = new GameNPC(template); summoned.SetOwnBrain(controlledBrain); - summoned.Position = new Vector3(summonloc, target.Position.Z); - summoned.CurrentRegion = target.CurrentRegion; - summoned.Heading = (ushort)((target.Heading + 2048) % 4096); + summoned.Position = summoned.Position.TurnedAround() + Vector.Create(target.Orientation, length: 64); summoned.Realm = target.Realm; summoned.Level = 1; summoned.Size = 10; @@ -626,7 +618,7 @@ public class Convoker10SpellHandler : MasterlevelHandling { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - private float x, y, z; + private Position position = Position.Nowhere; GameNPC summoned = null; RegionTimer m_growTimer; private const int C_GROWTIMER = 2000; @@ -635,7 +627,7 @@ public Convoker10SpellHandler(GameLiving caster, Spell spell, SpellLine line) : public override bool CheckBeginCast(GameLiving selectedTarget) { - if (!CheckCastLocation()) + if (!CheckCastCoordinate()) return false; return base.CheckBeginCast(selectedTarget); } @@ -678,11 +670,9 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness summoned.SetOwnBrain(controlledBrain); //Suncheck: // Is needed, else it can cause error (i.e. /cast-command) - if (x == 0 || y == 0) - CheckCastLocation(); - summoned.Position = new Vector3(x, y, z); - summoned.CurrentRegion = player.CurrentRegion; - summoned.Heading = (ushort)((player.Heading + 2048) % 4096); + if (position == Position.Nowhere) CheckCastCoordinate(); + + summoned.Position = position.With(orientation: Caster.Orientation + Angle.Degrees(180)); summoned.Realm = player.Realm; summoned.Size = 10; summoned.Level = 100; @@ -710,22 +700,18 @@ private int TitanGrows(RegionTimer timer) return 0; } - private bool CheckCastLocation() + private bool CheckCastCoordinate() { - x = Caster.Position.X; - y = Caster.Position.Y; - z = Caster.Position.Z; + position = Caster.Position; if (Spell.Target.ToLower() == "area") { - if (Caster.GroundTargetInView && Caster.GroundTarget != null) + if (Caster.GroundTargetInView && Caster.GroundTargetPosition != Position.Nowhere) { - x = Caster.GroundTarget.Value.X; - y = Caster.GroundTarget.Value.Y; - z = Caster.GroundTarget.Value.Z; + position = Caster.GroundTargetPosition; } else { - if (Caster.GroundTarget == null) + if (Caster.GroundTargetPosition == Position.Nowhere) { MessageToCaster("You must set a groundtarget!", eChatType.CT_SpellResisted); return false; @@ -739,6 +725,7 @@ private bool CheckCastLocation() } return true; } + /// /// When an applied effect expires. /// Duration spells only. diff --git a/GameServer/spells/Masterlevel/MasterLevelBase.cs b/GameServer/spells/Masterlevel/MasterLevelBase.cs index 09d483bb..3a2e7f3a 100644 --- a/GameServer/spells/Masterlevel/MasterLevelBase.cs +++ b/GameServer/spells/Masterlevel/MasterLevelBase.cs @@ -77,7 +77,7 @@ public override IList SelectTargets(GameObject castTarget) case "area": if (Spell.Radius > 0) { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, player, true)) { @@ -280,14 +280,14 @@ public override IList SelectTargets(GameObject castTarget) case "area": if (Spell.Radius > 0) { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, player, true)) { list.Add(player); } } - foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, npc, true)) { @@ -469,14 +469,14 @@ public override IList SelectTargets(GameObject castTarget) case "area": if (Spell.Radius > 0) { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, player, true)) { list.Add(player); } } - foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, npc, true)) { @@ -658,14 +658,14 @@ public override IList SelectTargets(GameObject castTarget) case "area": if (Spell.Radius > 0) { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, player, true)) { list.Add(player); } } - foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, npc, true)) { @@ -875,14 +875,14 @@ public override IList SelectTargets(GameObject castTarget) case "area": if (Spell.Radius > 0) { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, player, true)) { list.Add(player); } } - foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, (ushort)Spell.Radius)) + foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.GroundTargetPosition, (ushort)Spell.Radius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, npc, true)) { @@ -1186,7 +1186,7 @@ public override void OnEffectPulse(GameSpellEffect effect) { return; } - var ranged = storm.GetDistanceTo(effect.Owner.Position); + var ranged = (int)storm.Coordinate.DistanceTo(effect.Owner.Coordinate); if (ranged > 3000) return; if (s.Name == "Dazzling Array") diff --git a/GameServer/spells/Masterlevel/Perfecter.cs b/GameServer/spells/Masterlevel/Perfecter.cs index 19049430..d3c4fe40 100644 --- a/GameServer/spells/Masterlevel/Perfecter.cs +++ b/GameServer/spells/Masterlevel/Perfecter.cs @@ -50,8 +50,6 @@ public FOHSpellHandler(GameLiving caster, Spell spell, SpellLine line) font.Name = spell.Name; font.Realm = caster.Realm; font.Position = caster.Position; - font.CurrentRegionID = caster.CurrentRegionID; - font.Heading = caster.Heading; font.Owner = (GamePlayer)caster; // Construct the font spell @@ -104,8 +102,6 @@ public FOPSpellHandler(GameLiving caster, Spell spell, SpellLine line) font.Name = spell.Name; font.Realm = caster.Realm; font.Position = caster.Position; - font.CurrentRegionID = caster.CurrentRegionID; - font.Heading = caster.Heading; font.Owner = (GamePlayer)caster; // Construct the font spell @@ -157,8 +153,6 @@ public FORSpellHandler(GameLiving caster, Spell spell, SpellLine line) font.Name = spell.Name; font.Realm = caster.Realm; font.Position = caster.Position; - font.CurrentRegionID = caster.CurrentRegionID; - font.Heading = caster.Heading; font.Owner = (GamePlayer)caster; // Construct the font spell @@ -227,8 +221,6 @@ public FODSpellHandler(GameLiving caster, Spell spell, SpellLine line) font.Name = spell.Name; font.Realm = caster.Realm; font.Position = caster.Position; - font.CurrentRegionID = caster.CurrentRegionID; - font.Heading = caster.Heading; font.Owner = (GamePlayer)caster; // Construct the font spell diff --git a/GameServer/spells/Masterlevel/Sojourner.cs b/GameServer/spells/Masterlevel/Sojourner.cs index 6c78513d..8570b49b 100644 --- a/GameServer/spells/Masterlevel/Sojourner.cs +++ b/GameServer/spells/Masterlevel/Sojourner.cs @@ -7,8 +7,8 @@ using DOL.AI.Brain; using DOL.GS; using DOL.Events; +using DOL.GS.Geometry; using System.Collections.Specialized; -using System.Numerics; using DOL.GS.Profession; namespace DOL.GS.Spells @@ -101,9 +101,8 @@ public AncientTransmuterSpellHandler(GameLiving caster, Spell spell, SpellLine l GamePlayer casterPlayer = caster as GamePlayer; merchant = new GameMerchant(); //Fill the object variables - merchant.Position = casterPlayer.Position + new Vector3(Util.Random(20, 40) - Util.Random(20, 40), Util.Random(20, 40) - Util.Random(20, 40), 0); - merchant.CurrentRegion = casterPlayer.CurrentRegion; - merchant.Heading = (ushort)((casterPlayer.Heading + 2048) % 4096); + merchant.Position = casterPlayer.Position.TurnedAround() + + Vector.Create(Util.Random(-20, 20), Util.Random(-20, 20)); merchant.Level = 1; merchant.Realm = casterPlayer.Realm; merchant.Name = "Ancient Transmuter"; @@ -175,7 +174,7 @@ public class FZSpellHandler : MasterlevelHandling protected RegionTimer m_expireTimer; protected GameNPC m_npc; protected GamePlayer m_target; - protected Vector3 m_loc; + protected Coordinate m_loc; public override void OnDirectEffect(GameLiving target, double effectiveness) { @@ -314,19 +313,18 @@ private void ArriveAtTarget(DOLEvent e, object obj, EventArgs args) if (Caster is GamePlayer) { //Calculate random target - m_loc = GetTargetLoc(); + m_loc = m_npc.Coordinate + Vector.Create(x: Util.Random(-1500, 1500), y: Util.Random(-1500, 1500));; (Caster as GamePlayer).Out.SendCheckLOS((Caster as GamePlayer), m_npc, new CheckLOSResponse(ZephyrCheckLOS)); } } public void ZephyrCheckLOS(GamePlayer player, ushort response, ushort targetOID) { - if ((response & 0x100) == 0x100) - m_npc.PathTo(m_loc.X, m_loc.Y, m_loc.Z, 100); + if ((response & 0x100) == 0x100) m_npc.WalkTo(m_loc, 100); } - public virtual Vector3 GetTargetLoc() + public virtual Coordinate GetTargetLoc() { - return m_npc.Position + new Vector3(Util.Random(-1500, 1500), Util.Random(-1500, 1500), 0); + return m_npc.Coordinate + Vector.Create(Util.Random(-1500, 1500), Util.Random(-1500, 1500), 0); } public override int CalculateSpellResistChance(GameLiving target) diff --git a/GameServer/spells/Masterlevel/Spymaster.cs b/GameServer/spells/Masterlevel/Spymaster.cs index 7adec030..f881f4f7 100644 --- a/GameServer/spells/Masterlevel/Spymaster.cs +++ b/GameServer/spells/Masterlevel/Spymaster.cs @@ -96,8 +96,7 @@ public DecoySpellHandler(GameLiving caster, Spell spell, SpellLine line) decoy = new GameDecoy(); //Fill the object variables decoy.CurrentRegion = caster.CurrentRegion; - decoy.Heading = (ushort)((caster.Heading + 2048) % 4096); - decoy.Level = 50; + decoy.Position = caster.Position.TurnedAround(); decoy.Realm = caster.Realm; decoy.Position = caster.Position; string TemplateId = ""; @@ -177,8 +176,6 @@ public TangleSnareSpellHandler(GameLiving caster, Spell spell, SpellLine line) mine.Name = spell.Name; mine.Realm = caster.Realm; mine.Position = caster.Position; - mine.CurrentRegionID = caster.CurrentRegionID; - mine.Heading = caster.Heading; mine.Owner = (GamePlayer)caster; // Construct the mine spell @@ -228,8 +225,6 @@ public PoisonSpikeSpellHandler(GameLiving caster, Spell spell, SpellLine line) mine.Name = spell.Name; mine.Realm = caster.Realm; mine.Position = caster.Position; - mine.CurrentRegionID = caster.CurrentRegionID; - mine.Heading = caster.Heading; mine.Owner = (GamePlayer)caster; // Construct the mine spell @@ -372,8 +367,6 @@ public SiegeWreckerSpellHandler(GameLiving caster, Spell spell, SpellLine line) mine.Realm = caster.Realm; mine.Position = caster.Position; mine.MaxSpeedBase = 0; - mine.CurrentRegionID = caster.CurrentRegionID; - mine.Heading = caster.Heading; mine.Owner = (GamePlayer)caster; // Construct the mine spell diff --git a/GameServer/spells/Masterlevel/Stormlord.cs b/GameServer/spells/Masterlevel/Stormlord.cs index 2adc2472..2cfeac27 100644 --- a/GameServer/spells/Masterlevel/Stormlord.cs +++ b/GameServer/spells/Masterlevel/Stormlord.cs @@ -23,9 +23,9 @@ using DOL.GS.Effects; using DOL.Database; using DOL.Events; +using DOL.GS.Geometry; using System.Collections; using System.Collections.Generic; -using System.Numerics; namespace DOL.GS.Spells { @@ -43,8 +43,6 @@ public DazzlingArraySpellHandler(GameLiving caster, Spell spell, SpellLine line) storm = new GameStorm(); storm.Realm = caster.Realm; storm.Position = caster.Position; - storm.CurrentRegionID = caster.CurrentRegionID; - storm.Heading = caster.Heading; storm.Owner = (GamePlayer)caster; storm.Movable = true; @@ -155,8 +153,8 @@ public override void OnDirectEffect(GameLiving target, double effectiveness) GameNPC targetNPC = targetStorm as GameNPC; int range = Util.Random(0, 750); double angle = Util.RandomDouble() * 2 * Math.PI; - var rand = new Vector3(range * (float)Math.Cos(angle), range * (float)Math.Sin(angle), 0); - targetNPC.PathTo(targetNPC.Position + rand, targetNPC.MaxSpeed); + var offset = Vector.Create(x: (int)(range * Math.Cos(angle)), y: (int)(range * Math.Sin(angle)) ); + targetNPC.WalkTo(targetNPC.Coordinate + offset, targetNPC.MaxSpeed); } } } @@ -181,8 +179,6 @@ public EnervatingGasSpellHandler(GameLiving caster, Spell spell, SpellLine line) storm = new GameStorm(); storm.Realm = caster.Realm; storm.Position = caster.Position; - storm.CurrentRegionID = caster.CurrentRegionID; - storm.Heading = caster.Heading; storm.Owner = (GamePlayer)caster; storm.Movable = true; @@ -266,8 +262,6 @@ public InebriatingFumesSpellHandler(GameLiving caster, Spell spell, SpellLine li storm = new GameStorm(); storm.Realm = caster.Realm; storm.Position = caster.Position; - storm.CurrentRegionID = caster.CurrentRegionID; - storm.Heading = caster.Heading; storm.Owner = (GamePlayer)caster; storm.Movable = true; @@ -347,8 +341,6 @@ public MentalSiphonSpellHandler(GameLiving caster, Spell spell, SpellLine line) storm = new GameStorm(); storm.Realm = caster.Realm; storm.Position = caster.Position; - storm.CurrentRegionID = caster.CurrentRegionID; - storm.Heading = caster.Heading; storm.Owner = (GamePlayer)caster; storm.Movable = true; @@ -505,8 +497,6 @@ public ChokingVaporsSpellHandler(GameLiving caster, Spell spell, SpellLine line) storm = new GameStorm(); storm.Realm = caster.Realm; storm.Position = caster.Position; - storm.CurrentRegionID = caster.CurrentRegionID; - storm.Heading = caster.Heading; storm.Owner = (GamePlayer)caster; storm.Movable = true; @@ -586,8 +576,6 @@ public SenseDullingCloudSpellHandler(GameLiving caster, Spell spell, SpellLine l storm = new GameStorm(); storm.Realm = caster.Realm; storm.Position = caster.Position; - storm.CurrentRegionID = caster.CurrentRegionID; - storm.Heading = caster.Heading; storm.Owner = (GamePlayer)caster; storm.Movable = true; @@ -666,8 +654,6 @@ public EnergyTempestSpellHandler(GameLiving caster, Spell spell, SpellLine line) storm = new GameStorm(); storm.Realm = caster.Realm; storm.Position = caster.Position; - storm.CurrentRegionID = caster.CurrentRegionID; - storm.Heading = caster.Heading; storm.Owner = (GamePlayer)caster; storm.Movable = true; diff --git a/GameServer/spells/PlayerPortal.cs b/GameServer/spells/PlayerPortal.cs index b605011e..d78cddf8 100644 --- a/GameServer/spells/PlayerPortal.cs +++ b/GameServer/spells/PlayerPortal.cs @@ -92,12 +92,8 @@ public override void OnEffectStart(GameSpellEffect effect) secondPortalNPC = CreatePortalNPC(secondPortalNPC, player); // set to player bind location - secondPortal.CurrentRegion = WorldMgr.GetRegion((ushort)player.BindRegion); - secondPortal.Position = new Vector3(player.BindXpos, player.BindYpos, player.BindZpos); - secondPortal.Heading = (ushort)player.BindHeading; - secondPortalNPC.CurrentRegion = WorldMgr.GetRegion((ushort)player.BindRegion); - secondPortalNPC.Position = new Vector3(player.BindXpos, player.BindYpos, player.BindZpos); - secondPortalNPC.Heading = (ushort)player.BindHeading; + secondPortal.Position = player.BindPosition; + secondPortalNPC.Position = player.BindPosition; if (player == null) return; diff --git a/GameServer/spells/ResurrectSpellHandler.cs b/GameServer/spells/ResurrectSpellHandler.cs index 39d60a31..f4684ee4 100644 --- a/GameServer/spells/ResurrectSpellHandler.cs +++ b/GameServer/spells/ResurrectSpellHandler.cs @@ -170,7 +170,7 @@ protected virtual void ResurrectLiving(GameLiving living) else living.Endurance = 0; - living.MoveTo(m_caster.CurrentRegionID, m_caster.Position, m_caster.Heading); + living.MoveTo(m_caster.Position); GameTimer resurrectExpiredTimer = null; lock (m_resTimersByLiving.SyncRoot) diff --git a/GameServer/spells/SpellHandler.cs b/GameServer/spells/SpellHandler.cs index 9bd124fe..f45288b0 100644 --- a/GameServer/spells/SpellHandler.cs +++ b/GameServer/spells/SpellHandler.cs @@ -773,7 +773,7 @@ public virtual bool CheckBeginCast(GameLiving selectedTarget, bool quiet) } if (targetType == "area") { - if (!m_caster.IsWithinRadius(m_caster.GroundTarget.Value, CalculateSpellRange())) + if (!m_caster.IsWithinRadius(m_caster.GroundTargetPosition, CalculateSpellRange())) { if (!quiet) MessageToCaster("Your area target is out of range. Select a closer target.", eChatType.CT_SpellResisted); return false; @@ -1045,7 +1045,7 @@ public virtual bool CheckEndCast(GameLiving target) if (m_spell.Target.ToLower() == "area") { - if (!m_caster.IsWithinRadius(m_caster.GroundTarget.Value, CalculateSpellRange())) + if (!m_caster.IsWithinRadius(m_caster.GroundTargetPosition, CalculateSpellRange())) { MessageToCaster("Your area target is out of range. Select a closer target.", eChatType.CT_SpellResisted); return false; @@ -1221,7 +1221,7 @@ public virtual bool CheckDuringCast(GameLiving target, bool quiet) if (m_spell.Target.ToLower() == "area") { - if (!m_caster.IsWithinRadius(m_caster.GroundTarget.Value, CalculateSpellRange())) + if (!m_caster.IsWithinRadius(m_caster.GroundTargetPosition, CalculateSpellRange())) { if (!quiet) MessageToCaster("Your area target is out of range. Select a closer target.", eChatType.CT_SpellResisted); return false; @@ -1432,7 +1432,7 @@ public virtual bool CheckAfterCast(GameLiving target, bool quiet) if (m_spell.Target.ToLower() == "area") { - if (!m_caster.IsWithinRadius(m_caster.GroundTarget.Value, CalculateSpellRange())) + if (!m_caster.IsWithinRadius(m_caster.GroundTargetPosition, CalculateSpellRange())) { if (!quiet) MessageToCaster("Your area target is out of range. Select a closer target.", eChatType.CT_SpellResisted); return false; @@ -2105,7 +2105,7 @@ public virtual IList SelectTargets(GameObject castTarget, bool force else if (modifiedRadius > 0) { - foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, modifiedRadius)) + foreach (GamePlayer player in WorldMgr.GetPlayersCloseToSpot(Caster.GroundTargetPosition, modifiedRadius)) { if (GameServer.ServerRules.IsAllowedToAttack(Caster, player, true) || force) { @@ -2123,7 +2123,7 @@ public virtual IList SelectTargets(GameObject castTarget, bool force else list.Add(player); } } - foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.CurrentRegionID, Caster.GroundTarget.Value, modifiedRadius)) + foreach (GameNPC npc in WorldMgr.GetNPCsCloseToSpot(Caster.GroundTargetPosition, modifiedRadius)) { if (npc is GameStorm) list.Add(npc); @@ -2597,20 +2597,20 @@ public virtual bool StartSpell(GameLiving target, bool force = false) } else if (Spell.Target.ToLower() == "area") { - var dist = Vector3.Distance(t.Position, Caster.GroundTarget.Value); + int dist = (int)t.Coordinate.DistanceTo(Caster.GroundTargetPosition); if (dist >= 0) ApplyEffectOnTarget(t, (effectiveness - CalculateAreaVariance(t, dist, Spell.Radius))); } else if (Spell.Target.ToLower() == "cone") { - var dist = Vector3.Distance(t.Position, Caster.Position); + var dist = (int)t.Coordinate.DistanceTo(Caster.Position); //Cone spells use the range for their variance! if (dist >= 0) ApplyEffectOnTarget(t, (effectiveness - CalculateAreaVariance(t, dist, Spell.Range))); } else { - var dist = Vector3.Distance(t.Position, target.Position); + var dist = (int)t.Coordinate.DistanceTo(target.Position); if (dist >= 0) ApplyEffectOnTarget(t, (effectiveness - CalculateAreaVariance(t, dist, Spell.Radius))); } diff --git a/GameServer/spells/SummonIllusionBlade.cs b/GameServer/spells/SummonIllusionBlade.cs index ef4533a4..a8c3d067 100644 --- a/GameServer/spells/SummonIllusionBlade.cs +++ b/GameServer/spells/SummonIllusionBlade.cs @@ -47,15 +47,7 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness IControlledBrain brain = GetPetBrain(Caster); m_pet = GetGamePet(template); m_pet.SetOwnBrain(brain as AI.ABrain); - Vector3 pos; - ushort heading; - Region region; - - GetPetLocation(out pos, out heading, out region); - - m_pet.Position = pos; - m_pet.Heading = heading; - m_pet.CurrentRegion = region; + m_pet.Position = GetSummonPosition(); // m_pet.CurrentSpeed = 0; m_pet.Realm = Caster.Realm; m_pet.Race = 0; diff --git a/GameServer/spells/SummonSpellHandler.cs b/GameServer/spells/SummonSpellHandler.cs index a6d13757..36af8d40 100644 --- a/GameServer/spells/SummonSpellHandler.cs +++ b/GameServer/spells/SummonSpellHandler.cs @@ -20,11 +20,11 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Numerics; using System.Reflection; using DOL.AI.Brain; using DOL.Events; using DOL.GS.Effects; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; using DOL.Language; @@ -87,13 +87,19 @@ public override void FinishSpellCast(GameLiving target) #region ApplyEffectOnTarget Gets - protected virtual void GetPetLocation(out Vector3 position, out ushort heading, out Region region) + [Obsolete("Use GetSummonPosition() instead!")] + protected virtual void GetPetLocation(out int x, out int y, out int z, out ushort heading, out Region region) { - Vector2 point = Caster.GetPointFromHeading(Caster.Heading, 64); - position = new Vector3(point, Caster.Position.Z); - heading = (ushort)((Caster.Heading + 2048) % 4096); - region = Caster.CurrentRegion; + var position = GetSummonPosition(); + x = position.X; + y = position.Y; + z = position.Z; + heading = position.Orientation.InHeading; + region = WorldMgr.GetRegion(position.RegionID); } + + protected virtual Position GetSummonPosition() + => Caster.Position.TurnedAround() + Vector.Create(Caster.Orientation, length: 64); protected virtual GamePet GetGamePet(INpcTemplate template) { @@ -153,16 +159,7 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness m_pet.SummonSpellDamage = Spell.Damage; m_pet.SummonSpellValue = Spell.Value; - - Vector3 pos; - ushort heading; - Region region; - - GetPetLocation(out pos, out heading, out region); - - m_pet.Position = pos; - m_pet.Heading = heading; - m_pet.CurrentRegion = region; + m_pet.Position = GetSummonPosition(); m_pet.Realm = Caster.Realm; diff --git a/GameServer/spells/Teleport/GatewayPersonalBind.cs b/GameServer/spells/Teleport/GatewayPersonalBind.cs index 4ca778ae..bef6ad6e 100644 --- a/GameServer/spells/Teleport/GatewayPersonalBind.cs +++ b/GameServer/spells/Teleport/GatewayPersonalBind.cs @@ -106,7 +106,7 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness UniPortalEffect effect = new UniPortalEffect(this, 1000); effect.Start(player); - player.MoveTo((ushort)player.BindRegion, player.BindXpos, player.BindYpos, player.BindZpos, (ushort)player.BindHeading); + player.MoveTo(player.BindPosition); } diff --git a/GameServer/spells/TeleportSpellHandler.cs b/GameServer/spells/TeleportSpellHandler.cs index b1b15196..bc89e9ae 100644 --- a/GameServer/spells/TeleportSpellHandler.cs +++ b/GameServer/spells/TeleportSpellHandler.cs @@ -10,7 +10,7 @@ public class TeleportSpellHandler : SpellHandler public TeleportSpellHandler(GameLiving caster, Spell spell, SpellLine spellLine) : base(caster, spell, spellLine) { TPPoint tPPoint = TeleportMgr.LoadTP((ushort)Spell.LifeDrainReturn); - zoneName = WorldMgr.GetRegion(tPPoint.Region).GetZone((float)tPPoint.Position.X, (float)tPPoint.Position.Y).Description; + zoneName = WorldMgr.GetRegion(tPPoint.Region).GetZone(tPPoint.Position.Coordinate).Description; } public override void ApplyEffectOnTarget(GameLiving target, double effectiveness) @@ -37,7 +37,7 @@ public override void ApplyEffectOnTarget(GameLiving target, double effectiveness } } target.TPPoint = tPPoint; - target.MoveTo(tPPoint.Region, (float)tPPoint.Position.X, (float)tPPoint.Position.Y, (float)tPPoint.Position.Z, target.GetHeading(target)); + target.MoveTo(tPPoint.Position.With(target.Orientation)); } } public override string ShortDescription diff --git a/GameServer/spells/Theurgist/SummonTheurgistPet.cs b/GameServer/spells/Theurgist/SummonTheurgistPet.cs index 9a0579c4..c99bece6 100644 --- a/GameServer/spells/Theurgist/SummonTheurgistPet.cs +++ b/GameServer/spells/Theurgist/SummonTheurgistPet.cs @@ -19,7 +19,7 @@ using DOL.GS.PacketHandler; using DOL.AI.Brain; using DOL.GS.Effects; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS.Spells { @@ -75,10 +75,7 @@ protected override IControlledBrain GetPetBrain(GameLiving owner) protected override void SetBrainToOwner(IControlledBrain brain) { } - protected override void GetPetLocation(out Vector3 pos, out ushort heading, out Region region) - { - base.GetPetLocation(out pos, out heading, out region); - heading = Caster.Heading; - } + protected override Position GetSummonPosition() + => Caster.Position + Vector.Create(Caster.Orientation, length: 64); } } diff --git a/GameServer/spells/negative/FearBrain.cs b/GameServer/spells/negative/FearBrain.cs index 731d28b9..b4bc60fc 100644 --- a/GameServer/spells/negative/FearBrain.cs +++ b/GameServer/spells/negative/FearBrain.cs @@ -17,8 +17,8 @@ * */ using System; -using System.Numerics; using DOL.GS; +using DOL.GS.Geometry; namespace DOL.AI.Brain { @@ -53,13 +53,12 @@ public override void Think() ///The target to flee. protected virtual void CalculateFleeTarget(GameLiving target) { - ushort TargetAngle = (ushort)((Body.GetHeading(target) + 2048) % 4096); + var targetAngle = Body.Coordinate.GetOrientationTo(target.Coordinate) + Angle.Degrees(180); - var fleePoint = Body.GetPointFromHeading(TargetAngle, 300); - var point = PathingMgr.Instance.GetClosestPoint(Body.CurrentZone, new Vector3(fleePoint, Body.Position.Z), 128, 128, 256); Body.StopFollowing(); Body.StopAttack(); - Body.PathTo(point.HasValue ? point.Value : new Vector3(fleePoint, Body.Position.Z), Body.MaxSpeed); + var destination = Body.Position + Vector.Create(targetAngle, length: 300); + Body.PathTo(destination.Coordinate, Body.MaxSpeed); } /// diff --git a/GameServer/spells/negative/SuperFearBrain.cs b/GameServer/spells/negative/SuperFearBrain.cs index 77202af9..8c39be3d 100644 --- a/GameServer/spells/negative/SuperFearBrain.cs +++ b/GameServer/spells/negative/SuperFearBrain.cs @@ -17,8 +17,8 @@ * */ using System; -using System.Numerics; using DOL.GS; +using DOL.GS.Geometry; namespace DOL.AI.Brain { @@ -29,15 +29,15 @@ public class SuperFearBrain : FearBrain /// Calculate flee target. /// ///The target to flee. - protected virtual void CalculateFleeTarget(GameLiving target) + protected override void CalculateFleeTarget(GameLiving target) { - ushort TargetAngle = (ushort)((Body.GetHeading(target) + 2048) % 4096); + var TargetAngle = Body.GetAngleTo(target.Coordinate); - var fleePoint = Body.GetPointFromHeading(TargetAngle, 450); - var point = PathingMgr.Instance.GetClosestPoint(Body.CurrentZone, new Vector3(fleePoint, Body.Position.Z), 128, 128, 256); + var fleePoint = Body.Coordinate + Vector.Create(TargetAngle, 300); + var point = PathingMgr.Instance.GetClosestPointAsync(Body.CurrentZone, fleePoint, 128, 128, 256); Body.StopFollowing(); Body.StopAttack(); - Body.PathTo(point.HasValue ? point.Value : new Vector3(fleePoint, Body.Position.Z), Body.MaxSpeed); + Body.PathTo(point.HasValue ? Coordinate.Create(point.Value) : fleePoint, Body.MaxSpeed); //set speed to 130% m_maxSpeedBuff = (short)(Body.MaxSpeedBase * 0.3); Body.MaxSpeedBase = (short)(Body.MaxSpeedBase * 1.3); diff --git a/GameServer/styles/StyleProcessor.cs b/GameServer/styles/StyleProcessor.cs index 02b42bd5..26b99c35 100644 --- a/GameServer/styles/StyleProcessor.cs +++ b/GameServer/styles/StyleProcessor.cs @@ -143,7 +143,7 @@ public static bool CanUseStyle(GameLiving living, Style style, InventoryItem wea return false; // get players angle on target - float angle = GameMath.GetAngle(target, living); + var angle = target.GetAngleTo(living.Coordinate); //player.Out.SendDebugMessage("Positional check: "+style.OpeningRequirementValue+" angle "+angle+" target heading="+target.Heading); switch ((Style.eOpeningPosition)style.OpeningRequirementValue) @@ -151,17 +151,17 @@ public static bool CanUseStyle(GameLiving living, Style style, InventoryItem wea //Back Styles //60 degree since 1.62 patch case Style.eOpeningPosition.Back: - if (!(angle >= 150 && angle < 210)) return false; + if (angle.InDegrees is < 150 or >= 210) return false; break; // Side Styles //105 degree since 1.62 patch case Style.eOpeningPosition.Side: - if (!(angle >= 45 && angle < 150) && !(angle >= 210 && angle < 315)) return false; + if (angle.InDegrees is (< 45 or >= 150) and (< 210 or >= 315)) return false; break; // Front Styles // 90 degree case Style.eOpeningPosition.Front: - if (!(angle >= 315 || angle < 45)) return false; + if (angle.InDegrees is < 315 and >= 45) return false; break; } //DOLConsole.WriteLine("Positional check success: "+style.OpeningRequirementValue); diff --git a/GameServer/world/AbstractArea.cs b/GameServer/world/AbstractArea.cs index 88831e41..25ca22e1 100644 --- a/GameServer/world/AbstractArea.cs +++ b/GameServer/world/AbstractArea.cs @@ -22,8 +22,8 @@ using DOL.Events; using DOL.Language; using DOL.GS.PacketHandler; -using System.Numerics; using DOL.GameEvents; +using DOL.GS.Geometry; using System.Linq; using System.Threading.Tasks; @@ -231,20 +231,15 @@ public void RegisterPlayerLeave(DOLEventHandler callback) /// /// /// - public abstract bool IsContaining(Vector3 spot, bool checkZ); + public abstract bool IsContaining(Coordinate spot, bool checkZ); - public bool IsContaining(Vector3 spot) - { - return IsContaining(spot, true); - } - public bool IsContaining(float x, float y, float z, bool checkZ) - { - return IsContaining(new Vector3(x, y, z), checkZ); - } - public bool IsContaining(float x, float y, float z) - { - return IsContaining(new Vector3(x, y, z), true); - } + public bool IsContaining(Coordinate spot) => IsContaining(spot, true); + + [Obsolete("Use .IsContaining(Coordinate[,bool]) instead!")] + public bool IsContaining(int x, int y, int z, bool checkZ) => IsContaining(Coordinate.Create(x, y, z), checkZ); + + [Obsolete("Use .IsContaining(Coordinate[,bool]) instead!")] + public bool IsContaining(int x, int y, int z) => IsContaining(Coordinate.Create(x, y, z), true); /// /// Get the distance to the closest edge of this area from a point @@ -252,7 +247,7 @@ public bool IsContaining(float x, float y, float z) /// Position to calculate the distance from /// Whether to take Z into account /// - public abstract float DistanceSquared(Vector3 position, bool checkZ); + public abstract float DistanceSquared(Coordinate position, bool checkZ); public bool CanVol { get; protected set; } diff --git a/GameServer/world/Area.cs b/GameServer/world/Area.cs index c9692644..5ecd61b7 100644 --- a/GameServer/world/Area.cs +++ b/GameServer/world/Area.cs @@ -21,9 +21,12 @@ using DOL.Events; using DOL.GS.PacketHandler; using DOL.Database; +using DOL.GS.Geometry; using DOL.Language; using System.Numerics; using static DOL.GS.WarMapMgr; +using System.Drawing; +using Vector = DOL.GS.Geometry.Vector; namespace DOL.GS { @@ -39,25 +42,25 @@ public class Square : AbstractArea /// /// The center coordinate of this Area /// - public Vector3 Position { get; private set; } + public Coordinate Coordinate { get; private set; } /// /// The width of this Area /// - protected float m_Width; + protected int m_Width; /// /// The height of this Area /// - protected float m_Height; + protected int m_Height; public Square() : base() { } - public Square(string desc, float x, float y, float z, float width, float height, bool isPvp) : base(desc) + public Square(string desc, int x, int y, int z, int width, int height, bool isPvp) : base(desc) { - Position = new Vector3(x, y, z); + Coordinate = Coordinate.Create(x, y, z); m_Height = height; m_Width = width; IsPvP = isPvp; @@ -66,7 +69,7 @@ public Square(string desc, float x, float y, float z, float width, float height, /// /// Returns the Width of this Area /// - public float Width + public int Width { get { return m_Width; } } @@ -74,7 +77,7 @@ public float Width /// /// Returns the Height of this Area /// - public float Height + public int Height { get { return m_Height; } } @@ -86,13 +89,13 @@ public float Height /// public override bool IsIntersectingZone(Zone zone) { - if (Position.X + Width < zone.XOffset) + if (Coordinate.X + Width < zone.Offset.X) return false; - if (Position.X - Width >= zone.XOffset + 65536) + if (Coordinate.X - Width >= zone.Offset.X + 65536) return false; - if (Position.Y + Height < zone.YOffset) + if (Coordinate.Y + Height < zone.Offset.Y) return false; - if (Position.Y - Height >= zone.YOffset + 65536) + if (Coordinate.Y - Height >= zone.Offset.Y + 65536) return false; return true; @@ -103,13 +106,13 @@ public override bool IsIntersectingZone(Zone zone) /// /// /// - public override bool IsContaining(Vector3 p, bool checkZ) + public override bool IsContaining(Coordinate p, bool checkZ) { - var m_xdiff = p.X - Position.X; + var m_xdiff = p.X - Coordinate.X; if (m_xdiff < 0 || m_xdiff > Width) return false; - var m_ydiff = p.Y - Position.Y; + var m_ydiff = p.Y - Coordinate.Y; if (m_ydiff < 0 || m_ydiff > Height) return false; @@ -127,34 +130,36 @@ public override bool IsContaining(Vector3 p, bool checkZ) } /// - public override float DistanceSquared(Vector3 position, bool checkZ) + public override float DistanceSquared(Coordinate position, bool checkZ) { - Vector3 direction = position - Position; - Vector3 intersection = new Vector3(); + int dirX = position.X - Coordinate.X; + int dirY = position.X - Coordinate.X; + int interX; + int interY; - if (Math.Abs(direction.X) < Width && Math.Abs(direction.Y) < Height) // Inside + if (Math.Abs(dirX) < Width && Math.Abs(dirY) < Height) // Inside { return 0.0f; } - if (direction.X > 0) + if (dirX > 0) { - intersection.X = position.X + Math.Min(Width, direction.X); + interX = Coordinate.X + Math.Min(Width, dirX); } else { - intersection.X = position.X - Math.Max(-Width, direction.X); + interX = Coordinate.X - Math.Max(-Width, dirX); } - if (direction.Y > 0) + if (dirY > 0) { - intersection.Y = position.Y + Math.Min(Height, direction.Y); + interY = Coordinate.Y + Math.Min(Height, dirY); } else { - intersection.Y = position.Y - Math.Max(-Height, direction.Y); + interY = Coordinate.Y - Math.Max(-Height, dirY); } - float dx = position.X - intersection.X; - float dy = position.Y - intersection.Y; + float dx = Coordinate.X - interX; + float dy = Coordinate.Y - interY; return dx * dx + dy * dy; } @@ -163,7 +168,7 @@ public override void LoadFromDatabase(DBArea area) DbArea = area; m_translationId = area.TranslationId; m_Description = area.Description; - Position = new Vector3(area.X, area.Y, area.Z); + Coordinate = Coordinate.Create(area.X, area.Y, area.Z); m_Width = area.Radius; m_Height = area.Radius; this.CanVol = area.AllowVol; @@ -186,19 +191,19 @@ public Circle() { } - public Circle(string desc, Vector3 center, int radius) : base(desc) + public Circle(string desc, Coordinate center, int radius) : base(desc) { m_Description = desc; - Position = center; + Coordinate = center; m_Radius = radius; m_RadiusRadius = radius * radius; } - public Circle(string desc, float x, float y, float z, int radius) : this(desc, new Vector3(x, y, z), radius) + public Circle(string desc, int x, int y, int z, int radius) : this(desc, Coordinate.Create(x, y, z), radius) { } - public Vector3 Position { get; private set; } + public Coordinate Coordinate { get; private set; } /// /// Returns the Height of this Area @@ -222,28 +227,28 @@ public int Radius /// public override bool IsIntersectingZone(Zone zone) { - if (Position.X + Radius < zone.XOffset) + if (Coordinate.X + Radius < zone.Offset.X) return false; - if (Position.X - Radius >= zone.XOffset + 65536) + if (Coordinate.X - Radius >= zone.Offset.X + 65536) return false; - if (Position.Y + Radius < zone.YOffset) + if (Coordinate.Y + Radius < zone.Offset.Y) return false; - if (Position.Y - Radius >= zone.YOffset + 65536) + if (Coordinate.Y - Radius >= zone.Offset.Y + 65536) return false; return true; } - public override bool IsContaining(Vector3 point, bool checkZ) + public override bool IsContaining(Coordinate point, bool checkZ) { // spot is not in square around circle no need to check for circle... - var diff = point - Position; + var diff = point - Coordinate; // check if spot is in circle - var m_distSq = diff.ToVector2().LengthSquared(); - if (Position.Z != 0 && point.Z != 0 && checkZ) + double m_distSq = (double)diff.X * diff.X + (double)diff.Y * diff.Y; + if (Coordinate.Z != 0 && point.Z != 0 && checkZ) { - float m_zdiff = point.Z - Position.Z; + double m_zdiff = point.Z - Coordinate.Z; m_distSq += m_zdiff * m_zdiff; } @@ -251,17 +256,22 @@ public override bool IsContaining(Vector3 point, bool checkZ) } /// - public override float DistanceSquared(Vector3 position, bool checkZ) + public override float DistanceSquared(Coordinate position, bool checkZ) { - Vector3 direction = position - Position; - float radiusSquared = Radius * Radius; - float distanceToCenterSquared = direction.LengthSquared(); + var diff = position - Coordinate; + double radiusSquared = Radius * Radius; + double m_distSq = (double)diff.X * diff.X + (double)diff.Y * diff.Y; + if (Coordinate.Z != 0 && position.Z != 0 && checkZ) + { + double m_zdiff = position.Z - Coordinate.Z; + m_distSq += m_zdiff * m_zdiff; + } - if (direction.LengthSquared() < radiusSquared) // Inside + if (m_distSq < radiusSquared) // Inside { return 0.0f; } - return distanceToCenterSquared - radiusSquared; + return (float)(m_distSq - radiusSquared); } public override void LoadFromDatabase(DBArea area) @@ -269,7 +279,7 @@ public override void LoadFromDatabase(DBArea area) DbArea = area; m_translationId = area.TranslationId; m_Description = area.Description; - Position = new Vector3(area.X, area.Y, area.Z); + Coordinate = Coordinate.Create(area.X, area.Y, area.Z); m_Radius = area.Radius; m_RadiusRadius = area.Radius * area.Radius; this.CanVol = area.AllowVol; @@ -283,7 +293,7 @@ public class Polygon : AbstractArea /// /// The center coordinate of this Area /// - public Vector3 Position { get; private set; } + public Coordinate Coordinate { get; private set; } /// /// Returns the Height of this Area @@ -306,18 +316,18 @@ public int Radius /// /// The Points list /// - protected IList m_points; + protected IList m_points; public Polygon() : base() { } - public Polygon(string desc, float x, float y, float z, int radius, string points) + public Polygon(string desc, int x, int y, int z, int radius, string points) : base(desc) { m_Description = desc; - Position = new Vector3(x, y, z); + Coordinate = Coordinate.Create(x, y, z); m_Radius = radius; StringPoints = points; } @@ -334,7 +344,7 @@ public string StringPoints set { m_stringpoints = value; - m_points = new List(); + m_points = new List(); if (m_stringpoints.Length < 1) return; string[] points = m_stringpoints.Split('|'); foreach (string point in points) @@ -343,7 +353,7 @@ public string StringPoints if (pts.Length != 2) continue; int x = Convert.ToInt32(pts[0]); int y = Convert.ToInt32(pts[1]); - Vector2 p = new Vector2(x, y); + Vector p = Vector.Create(x, y); if (!m_points.Contains(p)) m_points.Add(p); } } @@ -357,29 +367,29 @@ public string StringPoints public override bool IsIntersectingZone(Zone zone) { // TODO if needed - if (Position.X + Radius < zone.XOffset) + if (Coordinate.X + Radius < zone.Offset.X) return false; - if (Position.X - Radius >= zone.XOffset + 65536) + if (Coordinate.X - Radius >= zone.Offset.X + 65536) return false; - if (Position.Y + Radius < zone.YOffset) + if (Coordinate.Y + Radius < zone.Offset.Y) return false; - if (Position.Y - Radius >= zone.YOffset + 65536) + if (Coordinate.Y - Radius >= zone.Offset.Y + 65536) return false; return true; } - public override bool IsContaining(Vector3 obj, bool _checkZ) + public override bool IsContaining(Coordinate obj, bool _checkZ) { if (m_points.Count < 3) return false; - Vector2 p1, p2; + Vector p1, p2; bool inside = false; - Vector2 oldpt = new Vector2(m_points[m_points.Count - 1].X, m_points[m_points.Count - 1].Y); + Vector oldpt = Vector.Create(m_points[m_points.Count - 1].X, m_points[m_points.Count - 1].Y); - foreach (Vector2 pt in m_points) + foreach (var pt in m_points) { - Vector2 newpt = new Vector2(pt.X, pt.Y); + Vector newpt = Vector.Create(pt.X, pt.Y); if (newpt.X > oldpt.X) { p1 = oldpt; p2 = newpt; } else { p1 = newpt; p2 = oldpt; } @@ -394,17 +404,13 @@ public override bool IsContaining(Vector3 obj, bool _checkZ) } /// - public override float DistanceSquared(Vector3 position, bool checkZ) + public override float DistanceSquared(Coordinate position, bool checkZ) { - Vector3 direction = position - Position; + var direction = position - Coordinate; float radiusSquared = Radius * Radius; - if (!checkZ) - { - direction.Z = 0; - } - float distanceToCenterSquared = direction.LengthSquared(); + var distanceToCenterSquared = (float)(checkZ ? direction.Length : direction.Length2D); - if (direction.LengthSquared() < radiusSquared) // Inside + if (distanceToCenterSquared < radiusSquared) // Inside { return 0.0f; } @@ -416,7 +422,7 @@ public override void LoadFromDatabase(DBArea area) DbArea = area; m_translationId = area.TranslationId; m_Description = area.Description; - Position = new Vector3(area.X, area.Y, area.Z); + Coordinate = Coordinate.Create(area.X, area.Y, area.Z); m_Radius = area.Radius; StringPoints = area.Points; this.CanVol = area.AllowVol; @@ -482,7 +488,7 @@ public CombatZone() { } - public CombatZone(Guild owningGuild, Vector3 position) + public CombatZone(Guild owningGuild, Coordinate position) : base("", position, ServerProperties.Properties.GUILD_COMBAT_ZONE_RADIUS) { CanVol = true; diff --git a/GameServer/world/GameLocation.cs b/GameServer/world/GameLocation.cs index 19f03565..92dae7a0 100644 --- a/GameServer/world/GameLocation.cs +++ b/GameServer/world/GameLocation.cs @@ -17,121 +17,105 @@ * */ using System; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { - /// - /// - /// + [Obsolete("Use DOL.GS.Geometry.Position instead!")] public class GameLocation : IGameLocation { - protected ushort m_regionId; - protected ushort m_heading; - protected string m_name; + public GameLocation(String name, ushort regionId, ushort zoneId, int x, int y, int z, ushort heading) + : this(name, Position.Create(regionId, Coordinate.Create(x,y,z)+WorldMgr.GetZone(zoneId).Offset, heading)) { } - public GameLocation(string name, GameObject obj) : this(name, obj.CurrentRegionID, obj.Position, obj.Heading) - { - } - public GameLocation(string name, ushort regionId, float x, float y, float z, ushort heading) - : this(name, regionId, new Vector3(x, y, z), heading) - { - } - public GameLocation(string name, ushort regionId, ushort zoneId, float x, float y, float z, ushort heading) - : this(name, regionId, ConvertLocalXToGlobalX(x, zoneId), ConvertLocalYToGlobalY(y, zoneId), z, heading) - { - } + public GameLocation(String name, ushort regionId, int x, int y, int z) + : this(name, Position.Create(regionId, x, y, z, heading: 0)) { } + + public GameLocation(String name, ushort regionId, int x, int y, int z, ushort heading) + : this(name, Position.Create(regionId, x, y, z, heading)) { } - public GameLocation(string name, ushort regionId, float x, float y, float z) : this(name, regionId, x, y, z, 0) + public GameLocation(String name, Position position) { + Position = position; + Name = name; } - public GameLocation(string name, ushort regionId, Vector3 position, ushort heading) + public GameLocation(Position position) { - m_regionId = regionId; - m_name = name; - m_heading = heading; Position = position; } - public Vector3 Position { get; set; } + public Position Position { get; set; } = Position.Zero; - /// - /// heading of this point - /// - public ushort Heading + public int X { - get { return m_heading; } - set { m_heading = value; } + get => Position.X; + set => Position.With(x: value); } - /// - /// RegionID of this point - /// - public ushort RegionID + public int Y { - get { return m_regionId; } - set { m_regionId = value; } + get => Position.Y; + set => Position.With(y: value); } - /// - /// Name of this point - /// - public string Name + public int Z { - get { return m_name; } - set { m_name = value; } + get => Position.Z; + set => Position.With(z: value); } - /// - /// calculates distance between 2 points - /// - /// - /// - /// - public float GetDistance(IGameLocation location) + public ushort Heading { - if (this.RegionID == location.RegionID) - { - return Vector3.Distance(Position, location.Position); - } - else - { - return -1; - } + get => Position.Orientation.InHeading; + set => Position.With(heading: value); } - public static float ConvertLocalXToGlobalX(float localX, ushort zoneId) + public ushort RegionID { - Zone z = WorldMgr.GetZone(zoneId); - return z.XOffset + localX; + get => Position.RegionID; + set => Position.With(regionID: value); } - public static float ConvertLocalYToGlobalY(float localY, ushort zoneId) - { - Zone z = WorldMgr.GetZone(zoneId); - return z.YOffset + localY; - } + public String Name { get; set; } = null; - public static float ConvertGlobalXToLocalX(float globalX, ushort zoneId) + public int GetDistance(IGameLocation location) { - Zone z = WorldMgr.GetZone(zoneId); - return globalX - z.XOffset; - } + if (this.RegionID != location.RegionID) return -1; - public static float ConvertGlobalYToLocalY(float globalY, ushort zoneId) - { - Zone z = WorldMgr.GetZone(zoneId); - return globalY - z.YOffset; + return (int)Position.Coordinate.DistanceTo(location.Position.Coordinate); } - [Obsolete("Use instance method GetDistance( IGameLocation location )")] - public static float GetDistance(ushort r1, float x1, float y1, float z1, ushort r2, float x2, float y2, float z2) + public static int ConvertLocalXToGlobalX(int localX, ushort zoneId) + { + Zone z = WorldMgr.GetZone(zoneId); + return z.Offset.X + localX; + } + + public static int ConvertLocalYToGlobalY(int localY, ushort zoneId) + { + Zone z = WorldMgr.GetZone(zoneId); + return z.Offset.Y + localY; + } + + public static int ConvertGlobalXToLocalX(int globalX, ushort zoneId) + { + Zone z = WorldMgr.GetZone(zoneId); + return globalX - z.Offset.X; + } + + public static int ConvertGlobalYToLocalY(int globalY, ushort zoneId) + { + Zone z = WorldMgr.GetZone(zoneId); + return globalY - z.Offset.Y; + } + + public static int GetDistance( int r1, int x1, int y1, int z1, int r2, int x2, int y2, int z2 ) { - GameLocation loc1 = new GameLocation("loc1", r1, x1, y1, z1); - GameLocation loc2 = new GameLocation("loc2", r2, x2, y2, z2); + if (r1 != r2) return -1; + var loc1 = Coordinate.Create(x1,y1,z1); + var loc2 = Coordinate.Create(x2,y2,z2); - return loc1.GetDistance(loc2); + return (int)loc1.DistanceTo(loc2); } - } + } } diff --git a/GameServer/world/IArea.cs b/GameServer/world/IArea.cs index cfd2d538..d634bcdc 100644 --- a/GameServer/world/IArea.cs +++ b/GameServer/world/IArea.cs @@ -20,6 +20,7 @@ using System; using System.Numerics; using DOL.Events; +using DOL.GS.Geometry; using DOL.Language; namespace DOL.GS @@ -61,15 +62,15 @@ public interface IArea : ITranslatableObject /// /// /// - bool IsContaining(Vector3 spot); + bool IsContaining(Coordinate spot, bool ignoreZ = false); + + [Obsolete("Use .IsContaining(Coordinate[,bool]) instead!")] + bool IsContaining(int x, int y, int z); + + [Obsolete("Use .IsContaining(Coordinate[,bool]) instead!")] + bool IsContaining(int x, int y, int z, bool checkZ); - bool IsContaining(Vector3 spot, bool checkZ); - - bool IsContaining(float x, float y, float z); - - bool IsContaining(float x, float y, float z, bool checkZ); - - float DistanceSquared(Vector3 position, bool checkZ); + float DistanceSquared(Coordinate position, bool checkZ); /// /// Called whenever a player leaves the given area diff --git a/GameServer/world/IGameLocation.cs b/GameServer/world/IGameLocation.cs index 59c339f1..99b7a0b5 100644 --- a/GameServer/world/IGameLocation.cs +++ b/GameServer/world/IGameLocation.cs @@ -1,33 +1,33 @@ /* * DAWN OF LIGHT - The first free open source DAoC server emulator - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { - /// - /// interface for classes that represent a point in 3d space - /// public interface IGameLocation { + int X { get; } + int Y { get; } + int Z { get; } + Position Position { get; } ushort RegionID { get; } - Vector3 Position { get; } ushort Heading { get; } string Name { get; } } -} \ No newline at end of file +} diff --git a/GameServer/world/Instance/BaseInstance.cs b/GameServer/world/Instance/BaseInstance.cs index 1d08808a..48780f59 100644 --- a/GameServer/world/Instance/BaseInstance.cs +++ b/GameServer/world/Instance/BaseInstance.cs @@ -30,7 +30,7 @@ using DOL.GS; using DOL.Database; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { @@ -420,7 +420,7 @@ protected override void OnTick() /// /// /// - public override IList GetAreasOfZone(Zone zone, Vector3 p, bool checkZ) + public override IList GetAreasOfZone(Zone zone, Coordinate loc, bool checkZ) { Zone checkZone = zone; var areas = new List(); @@ -447,7 +447,7 @@ public override IList GetAreasOfZone(Zone zone, Vector3 p, bool checkZ) for (int i = 0; i < m_ZoneAreasCount[zoneIndex]; i++) { IArea area = (IArea)Areas[m_ZoneAreas[zoneIndex][i]]; - if (area.IsContaining(p, checkZ)) + if (area.IsContaining(loc, checkZ)) { areas.Add(area); } @@ -470,7 +470,7 @@ public override IList GetAreasOfZone(Zone zone, Vector3 p, bool checkZ) /// /// /// - public override IList GetAreasOfZone(Zone zone, int x, int y, int z) + public override IList GetAreasOfZone(Zone zone, Coordinate loc) { Zone checkZone = zone; var areas = new List(); @@ -497,7 +497,7 @@ public override IList GetAreasOfZone(Zone zone, int x, int y, int z) for (int i = 0; i < m_ZoneAreasCount[zoneIndex]; i++) { IArea area = (IArea)Areas[m_ZoneAreas[zoneIndex][i]]; - if (area.IsContaining(x, y, z)) + if (area.IsContaining(loc)) areas.Add(area); } } diff --git a/GameServer/world/Instance/Instance.cs b/GameServer/world/Instance/Instance.cs index a9806834..d575e6cc 100644 --- a/GameServer/world/Instance/Instance.cs +++ b/GameServer/world/Instance/Instance.cs @@ -27,7 +27,7 @@ using DOL.Database; using DOL.GS.Utils; using log4net; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { @@ -54,13 +54,13 @@ public Instance(ushort ID, GameTimer.TimeManager time, RegionData data) : base(I #region Entrance - protected GameLocation m_entranceLocation = null; + [Obsolete("Use .InstanceEntranceName or .EntrancePosition instead!")] + public GameLocation InstanceEntranceLocation => new GameLocation(EntrancePosition); - /// - /// Returns the entrance location into this instance. - /// - public GameLocation InstanceEntranceLocation - { get { return m_entranceLocation; } } + [Obsolete("This is going to be removed.")] + public string InstanceEntranceName { get; set; } = null; + + public Position EntrancePosition { get; set; } = Position.Nowhere; #endregion @@ -95,7 +95,7 @@ public virtual void LoadFromDatabase(string instanceName) case "entrance": { //create the entrance, then move to the next. - m_entranceLocation = new GameLocation(instanceName + "entranceRegion" + ID, ID, entry.X, entry.Y, entry.Z, entry.Heading); + EntrancePosition = Position.Create(regionID: ID, entry.X, entry.Y, entry.Z, entry.Heading); //move to the next entry, nothing more to do here... continue; } @@ -119,7 +119,7 @@ public virtual void LoadFromDatabase(string instanceName) //We now have an object that isnt null. Lets place it at the location, in this region. - obj.Position = new Vector3(entry.X, entry.Y, entry.Z); + obj.Position = Position.Create(regionID: ID, entry.X, entry.Y, entry.Z, entry.Heading); obj.Heading = entry.Heading; obj.CurrentRegionID = ID; diff --git a/GameServer/world/Instance/RegionInstance.cs b/GameServer/world/Instance/RegionInstance.cs index e52f7b2d..63b34433 100644 --- a/GameServer/world/Instance/RegionInstance.cs +++ b/GameServer/world/Instance/RegionInstance.cs @@ -46,11 +46,6 @@ public class RegionInstance : BaseInstance /// private List m_players_in; - /// - /// Entrance location of Instance, needed to force exit players. - /// - protected GameLocation m_sourceentrance; - /// /// List Containing players in instance /// @@ -59,15 +54,6 @@ protected List PlayersInside get { return m_players_in; } } - /// - /// Entrance location of Instance, needed to force exit players. - /// - public GameLocation SourceEntrance - { - get { return m_sourceentrance; } - set { m_sourceentrance = value; } - } - /// /// On Player Enter override to add him to container /// diff --git a/GameServer/world/Region.cs b/GameServer/world/Region.cs index 4cd76747..3c1f6700 100644 --- a/GameServer/world/Region.cs +++ b/GameServer/world/Region.cs @@ -31,8 +31,8 @@ using DOL.GS.Utils; using DOL.GS.ServerProperties; using log4net; -using System.Numerics; using DOL.GameEvents; +using DOL.GS.Geometry; namespace DOL.GS { @@ -405,8 +405,8 @@ public virtual bool IsDungeon return false; //Dungeons only have 1 zone! var zone = Zones[0]; - - if (zone.XOffset == dungeonOffset && zone.YOffset == dungeonOffset) + + if (zone.Offset.X == dungeonOffset && zone.Offset.Y == dungeonOffset) return true; //Only dungeons got this offset return false; @@ -633,9 +633,9 @@ public virtual GameKeepComponent CreateGameKeepComponent() return new GameKeepComponent(); } - public virtual void CreateCombatZone(Guild owningGuild, Vector3 position) + public virtual void CreateCombatZone(Guild owningGuild, Position position) { - Area.CombatZone zone = new(owningGuild, position); + Area.CombatZone zone = new(owningGuild, position.Coordinate); AddArea(zone); CombatZoneBanner banner = CombatZoneBanner.Create(owningGuild, zone); @@ -1026,7 +1026,7 @@ public virtual void LoadFromDatabase(Mob[] mobObjs, ref long mobCount, ref long internal bool AddObject(GameObject obj) { //Thread.Sleep(10000); - Zone zone = GetZone(obj.Position); + Zone zone = GetZone(obj.Coordinate); if (zone == null) { if (log.IsWarnEnabled) @@ -1277,9 +1277,18 @@ public GameObject GetObject(ushort id) /// /// point for the zone you're retrieving /// The zone you're retrieving or null if it couldn't be found - public Zone GetZone(Vector3 point) + public Zone GetZone(Coordinate coordinate) { - return this.GetZone((int)point.X, (int)point.Y); + foreach (var zone in m_zones) + { + var isInZone = zone.Offset.X <= coordinate.X && zone.Offset.Y <= coordinate.Y + && (zone.Offset.X + zone.Width) > coordinate.X && (zone.Offset.Y + zone.Height) > coordinate.Y; + if (isInZone) + { + return zone; + } + } + return null; } /// @@ -1288,14 +1297,9 @@ public Zone GetZone(Vector3 point) /// X value for the zone you're retrieving /// Y value for the zone you're retrieving /// The zone you're retrieving or null if it couldn't be found - public Zone GetZone(float x, float y) + public Zone GetZone(int x, int y) { - foreach (Zone zone in m_zones) - { - if (zone.XOffset <= x && zone.YOffset <= y && (zone.XOffset + zone.Width) > x && (zone.YOffset + zone.Height) > y) - return zone; - } - return null; + return GetZone(Coordinate.Create(x, y)); } /// @@ -1304,12 +1308,12 @@ public Zone GetZone(float x, float y) /// X value for the zone's offset you're retrieving /// Y value for the zone's offset you're retrieving /// The X offset of the zone you specified or 0 if it couldn't be found - public float GetXOffInZone(float x, float y) + public int GetXOffInZone(int x, int y) { - Zone z = GetZone(x, y); + Zone? z = GetZone(Coordinate.Create(x, y)); if (z == null) return 0; - return x - z.XOffset; + return x - z.Offset.X; } /// @@ -1318,12 +1322,12 @@ public float GetXOffInZone(float x, float y) /// X value for the zone's offset you're retrieving /// Y value for the zone's offset you're retrieving /// The Y offset of the zone you specified or 0 if it couldn't be found - public float GetYOffInZone(float x, float y) + public int GetYOffInZone(int x, int y) { - Zone z = GetZone(x, y); + Zone? z = GetZone(Coordinate.Create(x, y)); if (z == null) return 0; - return y - z.YOffset; + return y - z.Offset.Y; } /// @@ -1446,38 +1450,17 @@ public virtual void RemoveArea(IArea area) } } } - + /// /// Gets the areas for given location, /// less performant than getAreasOfZone so use other on if possible /// /// /// - public IList GetAreasOfSpot(Vector3 point) - { - Zone zone = GetZone(point.X, point.Y); - return GetAreasOfZone(zone, point, true); - } - - /// - /// Gets the areas for a certain spot, - /// less performant than getAreasOfZone so use other on if possible - /// - /// - /// - /// - /// - public IList GetAreasOfSpot(float x, float y, float z) - { - Zone zone = GetZone(x, y); - var p = new Vector3(x, y, z); - return GetAreasOfZone(zone, p, true); - } - - public virtual IList GetAreasOfZone(Zone zone, Vector3 vector3, Vector3 p) - { - return GetAreasOfZone(zone, p, true); - } + public IList GetAreasOfSpot(Coordinate coordinate) => GetAreasOfZone(GetZone(coordinate), coordinate); + + public virtual IList GetAreasOfZone(Zone zone, Coordinate spot) + => GetAreasOfZone(zone, spot, true); /// /// Gets the areas for a certain spot @@ -1486,7 +1469,7 @@ public virtual IList GetAreasOfZone(Zone zone, Vector3 vector3, Vector3 p /// /// /// - public virtual IList GetAreasOfZone(Zone zone, Vector3 p, bool checkZ) + public virtual IList GetAreasOfZone(Zone zone, Coordinate spot, bool checkZ) { lock (m_lockAreas) { @@ -1499,8 +1482,8 @@ public virtual IList GetAreasOfZone(Zone zone, Vector3 p, bool checkZ) { for (int i = 0; i < m_ZoneAreasCount[zoneIndex]; i++) { - IArea area = (IArea)m_Areas[m_ZoneAreas[zoneIndex][i]]; - if (area.IsContaining(p, checkZ)) + var area = m_Areas[m_ZoneAreas[zoneIndex][i]]; + if (area.IsContaining(spot, checkZ)) { areas.Add(area); } @@ -1524,7 +1507,7 @@ public virtual IList GetAreasOfZone(Zone zone, Vector3 p, bool checkZ) /// /// /// - public virtual IList GetAreasInRadius(Vector3 p, float radius, bool checkZ) + public virtual IList GetAreasInRadius(Coordinate center, float radius, bool checkZ) { lock (m_lockAreas) { @@ -1532,7 +1515,7 @@ public virtual IList GetAreasInRadius(Vector3 p, float radius, bool check var areas = new List(); foreach (Zone zone in m_zones) { - if (zone.XOffset <= p.X + radius && (zone.XOffset + zone.Width) > p.X - radius && zone.YOffset <= p.Y + radius && (zone.YOffset + zone.Height) > p.Y - radius) + if (zone.Offset.X <= center.X + radius && (zone.Offset.X + zone.Width) > center.X - radius && zone.Offset.Y <= center.Y + radius && (zone.Offset.Y + zone.Height) > center.Y - radius) { float radiusSquared = radius * radius; @@ -1543,7 +1526,7 @@ public virtual IList GetAreasInRadius(Vector3 p, float radius, bool check for (int i = 0; i < m_ZoneAreasCount[zoneIndex]; i++) { IArea area = (IArea)m_Areas[m_ZoneAreas[zoneIndex][i]]; - if (area.DistanceSquared(p, checkZ) <= radiusSquared) + if (area.DistanceSquared(center, checkZ) <= radiusSquared) { areas.Add(area); } @@ -1569,14 +1552,14 @@ public virtual IList GetAreasInRadius(Vector3 p, float radius, bool check /// /// /// - public virtual IArea FindAnyAreaInRadius(Vector3 p, float radius, bool checkZ) + public virtual IArea FindAnyAreaInRadius(Coordinate center, float radius, bool checkZ) { lock (m_lockAreas) { int zoneIndex = 0; foreach (Zone zone in m_zones) { - if (zone.XOffset <= p.X + radius && (zone.XOffset + zone.Width) > p.X - radius && zone.YOffset <= p.Y + radius && (zone.YOffset + zone.Height) > p.Y - radius) + if (zone.Offset.X <= center.X + radius && (zone.Offset.X + zone.Width) > center.X - radius && zone.Offset.Y <= center.Y + radius && (zone.Offset.Y + zone.Height) > center.Y - radius) { float radiusSquared = radius * radius; @@ -1586,8 +1569,8 @@ public virtual IArea FindAnyAreaInRadius(Vector3 p, float radius, bool checkZ) { for (int i = 0; i < m_ZoneAreasCount[zoneIndex]; i++) { - IArea area = (IArea)m_Areas[m_ZoneAreas[zoneIndex][i]]; - if (area.DistanceSquared(p, checkZ) <= radiusSquared) + IArea area = m_Areas[m_ZoneAreas[zoneIndex][i]]; + if (area.DistanceSquared(center, checkZ) <= radiusSquared) { return area; } @@ -1607,7 +1590,7 @@ public virtual IArea FindAnyAreaInRadius(Vector3 p, float radius, bool checkZ) public virtual IList GetAreasOfZone(Zone zone, int x, int y, int z) { - return GetAreasOfZone(zone, area => area.IsContaining(x, y, z)); + return GetAreasOfZone(zone, Coordinate.Create(x, y, z)); } public virtual IList GetAreasOfZone(Zone zone) @@ -1702,14 +1685,14 @@ public virtual void Notify(DOLEvent e, EventArgs args) /// radius around origin /// Get an ObjectDistance enumerator /// IEnumerable to be used with foreach - protected IEnumerable GetInRadius(Zone.eGameObjectType type, float x, float y, float z, ushort radius, bool withDistance, bool ignoreZ) + protected IEnumerable GetInRadius(Zone.eGameObjectType type, Coordinate center, ushort radius, bool withDistance, bool ignoreZ) { // check if we are around borders of a zone - Zone startingZone = GetZone(x, y); + Zone startingZone = GetZone(center); if (startingZone != null) { - ArrayList res = startingZone.GetObjectsInRadius(type, x, y, z, radius, new ArrayList(), ignoreZ); + ArrayList res = startingZone.GetObjectsInRadius(type, center, radius, new ArrayList(), ignoreZ); uint sqRadius = (uint)radius * radius; @@ -1717,9 +1700,9 @@ protected IEnumerable GetInRadius(Zone.eGameObjectType type, float x, float y, f { if ((currentZone != startingZone) && (currentZone.TotalNumberOfObjects > 0) - && CheckShortestDistance(currentZone, x, y, sqRadius)) + && CheckShortestDistance(currentZone, center, sqRadius)) { - res = currentZone.GetObjectsInRadius(type, x, y, z, radius, res, ignoreZ); + res = currentZone.GetObjectsInRadius(type, center, radius, res, ignoreZ); } } @@ -1730,16 +1713,16 @@ protected IEnumerable GetInRadius(Zone.eGameObjectType type, float x, float y, f switch (type) { case Zone.eGameObjectType.ITEM: - tmp = new ItemDistanceEnumerator(x, y, z, res); + tmp = new ItemDistanceEnumerator(center, res); break; case Zone.eGameObjectType.NPC: - tmp = new NPCDistanceEnumerator(x, y, z, res); + tmp = new NPCDistanceEnumerator(center, res); break; case Zone.eGameObjectType.PLAYER: - tmp = new PlayerDistanceEnumerator(x, y, z, res); + tmp = new PlayerDistanceEnumerator(center, res); break; case Zone.eGameObjectType.DOOR: - tmp = new DoorDistanceEnumerator(x, y, z, res); + tmp = new DoorDistanceEnumerator(center, res); break; default: tmp = new EmptyEnumerator(); @@ -1756,7 +1739,7 @@ protected IEnumerable GetInRadius(Zone.eGameObjectType type, float x, float y, f { if (log.IsDebugEnabled) { - log.Error("GetInRadius starting zone is null for (" + type + ", " + x + ", " + y + ", " + z + ", " + radius + ") in Region ID=" + ID); + log.Error("GetInRadius starting zone is null for (" + type + ", " + center + ", " + radius + ") in Region ID=" + ID); } return new EmptyEnumerator(); } @@ -1771,32 +1754,32 @@ protected IEnumerable GetInRadius(Zone.eGameObjectType type, float x, float y, f /// Y value of the point /// The square radius to compare the distance with /// True if the distance is shorter false either - private static bool CheckShortestDistance(Zone zone, float x, float y, uint squareRadius) + private static bool CheckShortestDistance(Zone zone, Coordinate coordinate, uint squareRadius) { // coordinates of zone borders - int xLeft = zone.XOffset; - int xRight = zone.XOffset + zone.Width; - int yTop = zone.YOffset; - int yBottom = zone.YOffset + zone.Height; + int xLeft = zone.Offset.X; + int xRight = zone.Offset.X + zone.Width; + int yTop = zone.Offset.Y; + int yBottom = zone.Offset.Y + zone.Height; long distance = 0; - if ((y >= yTop) && (y <= yBottom)) + if ((coordinate.Y >= yTop) && (coordinate.Y <= yBottom)) { - var xdiff = Math.Min(FastMath.Abs(x - xLeft), FastMath.Abs(x - xRight)); - distance = (long)(xdiff * xdiff); + int xdiff = Math.Min(FastMath.Abs(coordinate.X - xLeft), FastMath.Abs(coordinate.X - xRight)); + distance = (long)xdiff * xdiff; } else { - if ((x >= xLeft) && (x <= xRight)) + if ((coordinate.X >= xLeft) && (coordinate.X <= xRight)) { - var ydiff = Math.Min(FastMath.Abs(y - yTop), FastMath.Abs(y - yBottom)); - distance = (long)(ydiff * ydiff); + int ydiff = Math.Min(FastMath.Abs(coordinate.Y - yTop), FastMath.Abs(coordinate.Y - yBottom)); + distance = (long)ydiff * ydiff; } else { - var xdiff = Math.Min(FastMath.Abs(x - xLeft), FastMath.Abs(x - xRight)); - var ydiff = Math.Min(FastMath.Abs(y - yTop), FastMath.Abs(y - yBottom)); - distance = (long)(xdiff * xdiff) + (long)(ydiff * ydiff); + int xdiff = Math.Min(FastMath.Abs(coordinate.X - xLeft), FastMath.Abs(coordinate.X - xRight)); + int ydiff = Math.Min(FastMath.Abs(coordinate.Y - yTop), FastMath.Abs(coordinate.Y - yBottom)); + distance = (long)xdiff * xdiff + (long)ydiff * ydiff; } } @@ -1812,12 +1795,12 @@ private static bool CheckShortestDistance(Zone zone, float x, float y, uint squa /// radius around origin /// Get an ObjectDistance enumerator /// IEnumerable to be used with foreach - public IEnumerable GetItemsInRadius(float x, float y, float z, ushort radius, bool withDistance) - { - return GetInRadius(Zone.eGameObjectType.ITEM, x, y, z, radius, withDistance, false); - } - public IEnumerable GetItemsInRadius(Vector3 center, ushort radius, bool withDistance) - => GetInRadius(Zone.eGameObjectType.ITEM, center.X, center.Y, center.Z, radius, withDistance, false); + public IEnumerable GetItemsInRadius(Coordinate center, ushort radius, bool withDistance) + => GetInRadius(Zone.eGameObjectType.ITEM, center, radius, withDistance, false); + + [Obsolete("Use .GetItemsInRadius(Coordinate,ushort,bool) instead!")] + public IEnumerable GetItemsInRadius(int x, int y, int z, ushort radius, bool withDistance) + => GetItemsInRadius(Coordinate.Create(x,y,z), radius, withDistance); /// /// Gets NPCs in a radius around a spot @@ -1828,12 +1811,12 @@ public IEnumerable GetItemsInRadius(Vector3 center, ushort radius, bool withDist /// radius around origin /// Get an ObjectDistance enumerator /// IEnumerable to be used with foreach - public IEnumerable GetNPCsInRadius(float x, float y, float z, ushort radius, bool withDistance, bool ignoreZ) - { - return GetInRadius(Zone.eGameObjectType.NPC, x, y, z, radius, withDistance, ignoreZ); - } - public IEnumerable GetNPCsInRadius(Vector3 center, ushort radius, bool withDistance, bool ignoreZ) - => GetInRadius(Zone.eGameObjectType.NPC, center.X, center.Y, center.Z, radius, withDistance, ignoreZ); + public IEnumerable GetNPCsInRadius(Coordinate center, ushort radius, bool withDistance, bool ignoreZ) + => GetInRadius(Zone.eGameObjectType.NPC, center, radius, withDistance, ignoreZ); + + [Obsolete("Use .GetNPCsInRadius(Coordinate,ushort,bool,bool) instead!")] + public IEnumerable GetNPCsInRadius(int x, int y, int z, ushort radius, bool withDistance, bool ignoreZ) + => GetNPCsInRadius(Coordinate.Create(x,y,z), radius, withDistance, ignoreZ); /// /// Gets Players in a radius around a spot @@ -1844,12 +1827,12 @@ public IEnumerable GetNPCsInRadius(Vector3 center, ushort radius, bool withDista /// radius around origin /// Get an ObjectDistance enumerator /// IEnumerable to be used with foreach - public IEnumerable GetPlayersInRadius(float x, float y, float z, ushort radius, bool withDistance, bool ignoreZ) - { - return GetInRadius(Zone.eGameObjectType.PLAYER, x, y, z, radius, withDistance, ignoreZ); - } - public IEnumerable GetPlayersInRadius(Vector3 center, ushort radius, bool withDistance, bool ignoreZ) - => GetInRadius(Zone.eGameObjectType.PLAYER, center.X, center.Y, center.Z, radius, withDistance, ignoreZ); + public IEnumerable GetPlayersInRadius(Coordinate coordinate, ushort radius, bool withDistance, bool ignoreZ) + => GetInRadius(Zone.eGameObjectType.PLAYER, coordinate, radius, withDistance, ignoreZ); + + [Obsolete("Use .GetPlayersInRadius(Coordinate,ushort,bool,bool) instead!")] + public IEnumerable GetPlayersInRadius(int x, int y, int z, ushort radius, bool withDistance, bool ignoreZ) + => GetPlayersInRadius(Coordinate.Create(x,y,z), radius, withDistance, ignoreZ); /// /// Gets Doors in a radius around a spot @@ -1860,12 +1843,12 @@ public IEnumerable GetPlayersInRadius(Vector3 center, ushort radius, bool withDi /// radius around origin /// Get an ObjectDistance enumerator /// IEnumerable to be used with foreach - public virtual IEnumerable GetDoorsInRadius(float x, float y, float z, ushort radius, bool withDistance) - { - return GetInRadius(Zone.eGameObjectType.DOOR, x, y, z, radius, withDistance, false); - } - public IEnumerable GetDoorsInRadius(Vector3 center, ushort radius, bool withDistance) - => GetInRadius(Zone.eGameObjectType.DOOR, center.X, center.Y, center.Z, radius, withDistance, false); + public virtual IEnumerable GetDoorsInRadius(Coordinate center, ushort radius, bool withDistance) + => GetInRadius(Zone.eGameObjectType.DOOR, center, radius, withDistance, false); + + [Obsolete("Use .GetDoorsInRadius(Coordinate,ushort,bool) instead!")] + public IEnumerable GetDoorsInRadius(int x, int y, int z, ushort radius, bool withDistance) + => GetDoorsInRadius(Coordinate.Create(x,y,z), radius, withDistance); #endregion @@ -2004,95 +1987,86 @@ public void Reset() public abstract class DistanceEnumerator : ObjectEnumerator { - protected float m_X; - protected float m_Y; - protected float m_Z; + protected Coordinate coordinate; - public DistanceEnumerator(float x, float y, float z, ArrayList elements) + public DistanceEnumerator(int x, int y, int z, ArrayList elements) + : this(Coordinate.Create(x, y, z), elements) { } + + public DistanceEnumerator(Coordinate coordinate, ArrayList elements) : base(elements) { - m_X = x; - m_Y = y; - m_Z = z; + this.coordinate = coordinate; } } - /// - /// This enumerator returns the object and the distance towards the object - /// public class PlayerDistanceEnumerator : DistanceEnumerator { - public PlayerDistanceEnumerator(float x, float y, float z, ArrayList elements) - : base(x, y, z, elements) - { - } + public PlayerDistanceEnumerator(int x, int y, int z, ArrayList elements) + : base(Coordinate.Create(x, y, z), elements) { } + + public PlayerDistanceEnumerator(Coordinate coordinate, ArrayList elements) + : base(coordinate,elements) { } public override object Current { get { GamePlayer obj = (GamePlayer)m_currentObj; - return new PlayerDistEntry(obj, Vector3.Distance(obj.Position, new Vector3(m_X, m_Y, m_Z))); + return new PlayerDistEntry(obj, (int)obj.Coordinate.DistanceTo(coordinate)); } } } - /// - /// This enumerator returns the object and the distance towards the object - /// public class NPCDistanceEnumerator : DistanceEnumerator { - public NPCDistanceEnumerator(float x, float y, float z, ArrayList elements) - : base(x, y, z, elements) - { - } + public NPCDistanceEnumerator(int x, int y, int z, ArrayList elements) + : base(Coordinate.Create(x, y, z), elements) { } + + public NPCDistanceEnumerator(Coordinate coordinate, ArrayList elements) + : base(coordinate,elements) { } public override object Current { get { GameNPC obj = (GameNPC)m_currentObj; - return new NPCDistEntry(obj, Vector3.Distance(obj.Position, new Vector3(m_X, m_Y, m_Z))); + return new NPCDistEntry(obj, (int)obj.Coordinate.DistanceTo(coordinate)); } } } - /// - /// This enumerator returns the object and the distance towards the object - /// public class ItemDistanceEnumerator : DistanceEnumerator { - public ItemDistanceEnumerator(float x, float y, float z, ArrayList elements) - : base(x, y, z, elements) - { - } + public ItemDistanceEnumerator(int x, int y, int z, ArrayList elements) + : base(Coordinate.Create(x, y, z), elements) { } + + public ItemDistanceEnumerator(Coordinate coordinate, ArrayList elements) + : base(coordinate,elements) { } public override object Current { get { GameStaticItem obj = (GameStaticItem)m_currentObj; - return new ItemDistEntry(obj, Vector3.Distance(obj.Position, new Vector3(m_X, m_Y, m_Z))); + return new ItemDistEntry(obj, (int)obj.Coordinate.DistanceTo(coordinate)); } } } - /// - /// This enumerator returns the object and the distance towards the object - /// public class DoorDistanceEnumerator : DistanceEnumerator { - public DoorDistanceEnumerator(float x, float y, float z, ArrayList elements) - : base(x, y, z, elements) - { - } + public DoorDistanceEnumerator(int x, int y, int z, ArrayList elements) + : base(Coordinate.Create(x, y, z), elements) { } + + public DoorDistanceEnumerator(Coordinate coordinate, ArrayList elements) + : base(coordinate,elements) { } public override object Current { get { IDoor obj = (IDoor)m_currentObj; - return new DoorDistEntry(obj, Vector3.Distance(obj.Position, new Vector3(m_X, m_Y, m_Z))); + return new DoorDistEntry(obj, (int)obj.Coordinate.DistanceTo(coordinate)); } } } diff --git a/GameServer/world/TeleportArea.cs b/GameServer/world/TeleportArea.cs index b08696d2..f8ef885e 100644 --- a/GameServer/world/TeleportArea.cs +++ b/GameServer/world/TeleportArea.cs @@ -21,6 +21,7 @@ using DOL.GS; using DOL.Database; +using DOL.GS.Geometry; using DOL.GS.PacketHandler; namespace DOL.GS @@ -52,9 +53,8 @@ protected void OnTeleport(GamePlayer player, Teleport destination) if (player.InCombat == false && GameRelic.IsPlayerCarryingRelic(player) == false) { player.LeaveHouse(); - GameLocation currentLocation = new GameLocation("TeleportStart", player.CurrentRegionID, player.Position, player.Heading); - player.MoveTo((ushort)destination.RegionID, destination.X, destination.Y, destination.Z, (ushort)destination.Heading); - GameServer.ServerRules.OnPlayerTeleport(player, currentLocation, destination); + player.MoveTo(destination.GetPosition()); + GameServer.ServerRules.OnPlayerTeleport(player, destination); } } @@ -66,5 +66,7 @@ protected void OnTeleport(GamePlayer player, Teleport destination) /// public class TeleportPillarArea : TeleportArea { + public override bool IsContaining(Coordinate spot, bool ignoreZ) + => base.IsContaining(spot, checkZ: false); } } diff --git a/GameServer/world/WorldMgr.cs b/GameServer/world/WorldMgr.cs index 8348c706..7c2e94e3 100644 --- a/GameServer/world/WorldMgr.cs +++ b/GameServer/world/WorldMgr.cs @@ -30,10 +30,10 @@ using DOL.GS.PacketHandler; using DOL.GS.Utils; using DOL.Config; +using DOL.GS.Geometry; using DOL.GS.Housing; using log4net; -using System.Numerics; namespace DOL.GS { @@ -983,11 +983,7 @@ public static void RegisterZone(ZoneData zoneData, ushort zoneID, ushort regionI /// true public static bool StartRegionMgrs() { - m_regions.FreezeWhile(dict => - { - foreach (Region reg in dict.Values) - reg.StartRegionMgr(); - }); + m_regions.FreezeWhile(dict => dict.Values.ToList()).ForEach(r => r.StartRegionMgr()); return true; } @@ -998,13 +994,8 @@ public static void StopRegionMgrs() { if (log.IsDebugEnabled) log.Debug("Stopping region managers..."); - - m_regions.FreezeWhile(dict => - { - foreach (Region reg in dict.Values) - reg.StopRegionMgr(); - - }); + + m_regions.FreezeWhile(dict => dict.Values.ToList()).ForEach(r => r.StopRegionMgr()); if (log.IsDebugEnabled) log.Debug("Region managers stopped."); @@ -1277,145 +1268,6 @@ public static void RemoveSessionID(int id) return; } - //Various functions to get a list of players/mobs/items - #region getdistance - /// - /// Get's the distance of two GameObjects - /// - /// Object1 - /// Object2 - /// The distance in units or -1 if they are not the same Region - [Obsolete("Use Point3D.GetDistance")] - public static float GetDistance(GameObject obj1, GameObject obj2) - { - if (obj1 == null || obj2 == null || obj1.CurrentRegion != obj2.CurrentRegion) - return -1; - return GetDistance(obj1.X, obj1.Y, obj1.Z, obj2.X, obj2.Y, obj2.Z); - } - - /// - /// Get's the distance of two GameObjects - /// - /// Object1 - /// Object2 - /// Factor for Z distance use lower 0..1 to lower Z influence - /// The distance in units or -1 if they are not the same Region - [Obsolete("Use Point3D.GetDistance")] - public static float GetDistance(GameObject obj1, GameObject obj2, float zfactor) - { - if (obj1 == null || obj2 == null || obj1.CurrentRegion != obj2.CurrentRegion) - return -1; - return GetDistance(obj1.X, obj1.Y, obj1.Z, obj2.X, obj2.Y, obj2.Z, zfactor); - } - - /// - /// Gets the distance of two arbitary points in space - /// - /// X of Point1 - /// Y of Point1 - /// Z of Point1 - /// X of Point2 - /// Y of Point2 - /// Z of Point2 - /// The distance - [Obsolete("Use Point3D.GetDistance")] - public static float GetDistance(float x1, float y1, float z1, float x2, float y2, float z2) - { - var xdiff = x1 - x2; - var ydiff = y1 - y2; - var zdiff = z1 - z2; - return (float)Math.Sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff); - } - - /// - /// Gets the distance of two arbitary points in space - /// - /// X of Point1 - /// Y of Point1 - /// Z of Point1 - /// X of Point2 - /// Y of Point2 - /// Z of Point2 - /// Factor for Z distance use lower 0..1 to lower Z influence - /// The distance - [Obsolete("Use Point3D.GetDistance")] - public static float GetDistance(float x1, float y1, float z1, float x2, float y2, float z2, float zfactor) - { - var xdiff = x1 - x2; - var ydiff = y1 - y2; - var zdiff = ((z1 - z2) * zfactor); - return (float)Math.Sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff); - } - - /// - /// Gets the distance of an Object to an arbitary point - /// - /// GameObject used as Point1 - /// X of Point2 - /// Y of Point2 - /// Z of Point2 - /// The distance - [Obsolete("Use Point3D.GetDistance")] - public static float GetDistance(GameObject obj, float x, float y, float z) - { - return GetDistance(obj.X, obj.Y, obj.Z, x, y, z); - } - #endregion get distance - - #region check distance - [Obsolete("Use Point3D.IsWithinRadius")] - public static bool CheckDistance(float x1, float y1, float z1, float x2, float y2, float z2, int radius) - { - return CheckSquareDistance(x1, y1, z1, x2, y2, z2, radius * radius); - } - [Obsolete("Use Point3D.IsWithinRadius")] - public static bool CheckDistance(Vector3 obj, Vector3 obj2, int radius) - { - return CheckDistance(obj.X, obj.Y, obj.Z, obj2.X, obj2.Y, obj2.Z, radius); - } - [Obsolete("Use Point3D.IsWithinRadius")] - public static bool CheckDistance(GameObject obj, float x2, float y2, float z2, int radius) - { - return CheckDistance(obj.X, obj.Y, obj.Z, x2, y2, z2, radius); - } - [Obsolete("Use Point3D.IsWithinRadius")] - public static bool CheckDistance(GameObject obj, GameObject obj2, int radius) - { - if (obj == null || obj2 == null) - return false; - if (obj.CurrentRegion != obj2.CurrentRegion) - return false; - return CheckDistance(obj.X, obj.Y, obj.Z, obj2.X, obj2.Y, obj2.Z, radius); - } - #endregion - #region check square distance - [Obsolete("Use Point3D.IsWithinRadius")] - private static bool CheckSquareDistance(float x1, float y1, float z1, float x2, float y2, float z2, int squareRadius) - { - var xdiff = x1 - x2; - var ydiff = y1 - y2; - var zdiff = z1 - z2; - return (xdiff * xdiff + ydiff * ydiff + zdiff * zdiff <= squareRadius); - } - [Obsolete("Use Point3D.IsWithinRadius")] - private static bool CheckSquareDistance(Vector3 obj, Vector3 obj2, int squareRadius) - { - return CheckSquareDistance(obj.X, obj.Y, obj.Z, obj2.X, obj2.Y, obj2.Z, squareRadius); - } - [Obsolete("Use Point3D.IsWithinRadius")] - private static bool CheckSquareDistance(GameObject obj, float x2, float y2, float z2, int squareRadius) - { - return CheckSquareDistance(obj.X, obj.Y, obj.Z, x2, y2, z2, squareRadius); - } - [Obsolete("Use Point3D.IsWithinRadius")] - private static bool CheckSquareDistance(GameObject obj, GameObject obj2, int squareRadius) - { - if (obj.CurrentRegion != obj2.CurrentRegion) - return false; - return CheckSquareDistance(obj.X, obj.Y, obj.Z, obj2.X, obj2.Y, obj2.Z, squareRadius); - } - #endregion - /// /// Returns the number of playing Clients inside a realm /// @@ -1811,123 +1663,50 @@ public static GameObject GetObjectTypeByIDFromRegion(ushort regionID, ushort oID return obj; } - /// - /// Returns an IEnumerator of GamePlayers that are close to a certain - /// spot in the region - /// - /// Region to search - /// X inside region - /// Y inside region - /// Z inside region - /// Wether or not to return the objects with distance - /// Radius to sarch for GameClients - /// IEnumerator that can be used to go through all players - public static IEnumerable GetPlayersCloseToSpot(ushort regionid, float x, float y, float z, ushort radiusToCheck, bool withDistance) - { - Region reg = GetRegion(regionid); - if (reg == null) - return new Region.EmptyEnumerator(); - return reg.GetPlayersInRadius(x, y, z, radiusToCheck, withDistance, false); - } + [Obsolete("Use GetPlayersCloseToSpot(Position,ushort) instead!")] + public static IEnumerable GetPlayersCloseToSpot(ushort regionid, int x, int y, int z, ushort radiusToCheck, bool withDistance = false) + => GetPlayersCloseToSpot(Position.Create(regionid, x, y, z), radiusToCheck); + + [Obsolete("Use GetPlayersCloseToSpot(Position,ushort) instead!")] + public static IEnumerable GetPlayersCloseToSpot(IGameLocation location, ushort radiusToCheck, bool withDistance = false) + => GetPlayersCloseToSpot(location.Position, radiusToCheck); - /// - /// Returns an IEnumerator of GamePlayers that are close to a certain - /// spot in the region - /// - /// the game location to search from - /// Radius to sarch for GameClients - /// IEnumerator that can be used to go through all players - public static IEnumerable GetPlayersCloseToSpot(IGameLocation location, ushort radiusToCheck) + public static IEnumerable GetPlayersCloseToSpot(Position position, ushort radiusToCheck, bool withDistance = false) { - var p = location.Position; - return GetPlayersCloseToSpot(location.RegionID, p.X, p.Y, p.Z, radiusToCheck, false); - } - - /// - /// Returns an IEnumerator of GamePlayers that are close to a certain - /// spot in the region - /// - /// Region to search - /// the 3D point to search from - /// Radius to sarch for GameClients - /// IEnumerator that can be used to go through all players - public static IEnumerable GetPlayersCloseToSpot(ushort regionid, Vector3 point, ushort radiusToCheck) - { - return GetPlayersCloseToSpot(regionid, point.X, point.Y, point.Z, radiusToCheck, false); - } - - /// - /// Returns an IEnumerator of GamePlayers that are close to a certain - /// spot in the region - /// - /// Region to search - /// X inside region - /// Y inside region - /// Z inside region - /// Radius to sarch for GameClients - /// IEnumerator that can be used to go through all players - public static IEnumerable GetPlayersCloseToSpot(ushort regionid, float x, float y, float z, ushort radiusToCheck) - { - return GetPlayersCloseToSpot(regionid, x, y, z, radiusToCheck, false); - } - - /// - /// Returns an IEnumerator of GameNPCs that are close to a certain - /// spot in the region - /// - /// Region to search - /// X inside region - /// Y inside region - /// Z inside region - /// Radius to sarch for GameNPCs - /// Wether or not to return the objects with distance - /// IEnumerator that can be used to go through all NPCs - public static IEnumerable GetNPCsCloseToSpot(ushort regionid, float x, float y, float z, ushort radiusToCheck, bool withDistance) - { - Region reg = GetRegion(regionid); + Region reg = GetRegion(position.RegionID); if (reg == null) return new Region.EmptyEnumerator(); - return reg.GetNPCsInRadius(x, y, z, radiusToCheck, withDistance, false); + return reg.GetPlayersInRadius(position.Coordinate, radiusToCheck, false, withDistance); } - /// - /// Returns an IEnumerator of GameNPCs that are close to a certain - /// spot in the region - /// - /// Region to search - /// X inside region - /// Y inside region - /// Z inside region - /// Radius to sarch for GameNPCs - /// IEnumerator that can be used to go through all NPCs - public static IEnumerable GetNPCsCloseToSpot(ushort regionid, float x, float y, float z, ushort radiusToCheck) + [Obsolete("Use GetNPCsCloseToSpot(Position,ushort) instead!")] + public static IEnumerable GetNPCsCloseToSpot(ushort regionid, int x, int y, int z, ushort radiusToCheck, bool withDistance = false) + => GetNPCsCloseToSpot(Position.Create(regionid, x, y, z), radiusToCheck); + + [Obsolete("Use GetNPCsCloseToSpot(Position,ushort) instead!")] + public static IEnumerable GetNPCsCloseToSpot(IGameLocation location, ushort radiusToCheck, bool withDistance = false) + => GetNPCsCloseToSpot(location.Position, radiusToCheck); + + public static IEnumerable GetNPCsCloseToSpot(Position position, ushort radiusToCheck, bool withDistance = false) { - return GetNPCsCloseToSpot(regionid, x, y, z, radiusToCheck, false); + Region reg = GetRegion(position.RegionID); + if (reg == null) return new Region.EmptyEnumerator(); + return reg.GetNPCsInRadius(position.Coordinate, radiusToCheck, false, withDistance); } - public static IEnumerable GetNPCsCloseToSpot(ushort regionid, Vector3 pos, ushort radiusToCheck, bool withDistance) - => GetNPCsCloseToSpot(regionid, pos.X, pos.Y, pos.Z, radiusToCheck, withDistance); - public static IEnumerable GetNPCsCloseToSpot(ushort regionid, Vector3 pos, ushort radiusToCheck) - => GetNPCsCloseToSpot(regionid, pos.X, pos.Y, pos.Z, radiusToCheck, false); + [Obsolete("Use GetItemsCloseToSpot(Position,ushort) instead!")] + public static IEnumerable GetItemsCloseToSpot(ushort regionid, int x, int y, int z, ushort radiusToCheck, bool withDistance = false) + => GetNPCsCloseToSpot(Position.Create(regionid, x, y, z), radiusToCheck); + + [Obsolete("Use GetItemsCloseToSpot(Position,ushort) instead!")] + public static IEnumerable GetItemsCloseToSpot(IGameLocation location, ushort radiusToCheck, bool withDistance = false) + => GetItemsCloseToSpot(location.Position, radiusToCheck); - /// - /// Returns an IEnumerator of GameItems that are close to a certain - /// spot in the region - /// - /// Region to search - /// X inside region - /// Y inside region - /// Z inside region - /// Radius to sarch for GameItems - /// Wether or not to return the objects with distance - /// IEnumerator that can be used to go through all items - public static IEnumerable GetItemsCloseToSpot(ushort regionid, float x, float y, float z, ushort radiusToCheck, bool withDistance) + public static IEnumerable GetItemsCloseToSpot(Position position, ushort radiusToCheck, bool withDistance = false) { - Region reg = GetRegion(regionid); - if (reg == null) - return new Region.EmptyEnumerator(); - - return reg.GetItemsInRadius(x, y, z, radiusToCheck, withDistance); + Region reg = GetRegion(position.RegionID); + if (reg == null) return new Region.EmptyEnumerator(); + return reg.GetItemsInRadius(position.Coordinate, radiusToCheck, withDistance); } /// diff --git a/GameServer/world/WorldUpdateThread.cs b/GameServer/world/WorldUpdateThread.cs index b08ca27b..540442be 100644 --- a/GameServer/world/WorldUpdateThread.cs +++ b/GameServer/world/WorldUpdateThread.cs @@ -372,8 +372,10 @@ public static void UpdatePlayerHousing(GamePlayer player, uint nowTicks) // Get All House in Region IDictionary housesDict = HouseMgr.GetHouses(player.CurrentRegionID); - // Build Vincinity List - var houses = housesDict.Values.Where(h => h != null && player.IsWithinRadius(h.Position, HousingConstants.HouseViewingDistance)).ToArray(); + // Build Vicinity List + var houses = housesDict.Values + .Where(h => h != null && player.Coordinate.DistanceTo(h.Position) <= HousingConstants.HouseViewingDistance) + .ToArray(); try { diff --git a/GameServer/world/Zone.cs b/GameServer/world/Zone.cs index e6990c02..dc506e87 100644 --- a/GameServer/world/Zone.cs +++ b/GameServer/world/Zone.cs @@ -26,7 +26,7 @@ using DOL.Language; using DOL.GS.Utils; using log4net; -using System.Numerics; +using DOL.GS.Geometry; namespace DOL.GS { @@ -39,7 +39,7 @@ public class Zone : ITranslatableObject /* This file has been extensively modified for the new subzone management system So for old version please have a look in old release - */ + */ private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -161,14 +161,15 @@ public void Remove() private string m_Description; /// - /// The XOffset of this Zone inside the region + /// The Offset of this Zone inside the region /// - private readonly int m_XOffset; + public Vector Offset { get; init; } + + [Obsolete("Use .Offset instead!")] + public int XOffset => Offset.X; - /// - /// The YOffset of this Zone inside the region - /// - private readonly int m_YOffset; + [Obsolete("Use .Offset instead!")] + public int YOffset => Offset.Y; /// /// The Width of the Zone in Coordinates @@ -229,8 +230,7 @@ public Zone(Region region, ushort id, string desc, int xoff, int yoff, int width m_Region = region; m_ID = id; m_Description = desc; - m_XOffset = xoff; - m_YOffset = yoff; + Offset = Vector.Create(xoff, yoff); m_Width = width; m_Height = height; m_zoneSkinID = zoneskinID; @@ -400,22 +400,6 @@ public string Description set { m_Description = value; } } - /// - /// Returns the XOffset of this Zone - /// - public int XOffset - { - get { return m_XOffset; } - } - - /// - /// Returns the YOffset of this Zone - /// - public int YOffset - { - get { return m_YOffset; } - } - /// /// Returns the Width of this Zone /// @@ -481,37 +465,18 @@ private short GetSubZoneOffset(int lineSubZoneIndex, int columnSubZoneIndex) /// X position /// Y position /// The SubZoneIndex - private short GetSubZoneIndex(float p_X, float p_Y) + private short GetSubZoneIndex(Coordinate loc) { - int xDiff = (int)(p_X - m_XOffset); - int yDiff = (int)(p_Y - m_YOffset); + int xDiff = loc.X - Offset.X; + int yDiff = loc.Y - Offset.Y; - if ((xDiff < 0) || (xDiff > 65535) || (yDiff < 0) || (yDiff > 65535)) - { - // the object is out of the zone + var isOutOfZone = (xDiff < 0) || (xDiff > 65535) || (yDiff < 0) || (yDiff > 65535); + if (isOutOfZone) return -1; - } - else - { - // the object is in the zone - //DOLConsole.WriteWarning("GetSubZoneIndex : " + SUBZONE_NBR_ON_ZONE_SIDE + ", " + SUBZONE_NBR + ", " + SUBZONE_SHIFT + ", " + SUBZONE_ARRAY_Y_SHIFT); - - xDiff >>= SUBZONE_SHIFT; - yDiff >>= SUBZONE_SHIFT; - - return GetSubZoneOffset(yDiff, xDiff); - } - } - - - /// - /// Get the index of the subzone from the GameObject position - /// - /// The GameObject - /// The index of the subzone - private short GetSubZoneIndex(GameObject p_Obj) - { - return GetSubZoneIndex(p_Obj.Position.X, p_Obj.Position.Y); + + xDiff >>= SUBZONE_SHIFT; + yDiff >>= SUBZONE_SHIFT; + return GetSubZoneOffset(yDiff, xDiff); } @@ -523,7 +488,7 @@ public void ObjectEnterZone(GameObject p_Obj) { if (!m_initialized) InitializeZone(); - int subZoneIndex = GetSubZoneIndex(p_Obj); + int subZoneIndex = GetSubZoneIndex(p_Obj.Coordinate); if ((subZoneIndex >= 0) && (subZoneIndex < SUBZONE_NBR)) { SubNodeElement element = new SubNodeElement(); @@ -570,7 +535,7 @@ private void ObjectEnterZone(eGameObjectType objectType, SubNodeElement element) { if (!m_initialized) InitializeZone(); - int subZoneIndex = GetSubZoneIndex(element.data); + int subZoneIndex = GetSubZoneIndex(element.data.Coordinate); if (log.IsDebugEnabled) { @@ -603,16 +568,16 @@ private void ObjectEnterZone(eGameObjectType objectType, SubNodeElement element) /// the radius to check against /// an initial (eventually empty but initialized, i.e. never null !!) list of objects /// partialList augmented with the new objects verigying both type and radius in the current Zone - internal ArrayList GetObjectsInRadius(eGameObjectType type, float x, float y, float z, ushort radius, ArrayList partialList, bool ignoreZ) + internal ArrayList GetObjectsInRadius(eGameObjectType type, Coordinate coordinate, ushort radius, ArrayList partialList, bool ignoreZ) { if (!m_initialized) InitializeZone(); // initialise parameters uint sqRadius = (uint)radius * (uint)radius; - int referenceSubzoneIndex = GetSubZoneIndex(x, y); + int referenceSubzoneIndex = GetSubZoneIndex(coordinate); int typeIndex = (int)type; - - int xInZone = (int)(x - m_XOffset); // x in zone coordinates - int yInZone = (int)(y - m_YOffset); // y in zone coordinates + + int xInZone = coordinate.X - Offset.X; // x in zone coordinates + int yInZone = coordinate.Y - Offset.Y; // y in zone coordinates int cellNbr = (radius >> SUBZONE_SHIFT) + 1; // radius in terms of subzone number int xInCell = xInZone >> SUBZONE_SHIFT; // xInZone in terms of subzone coord @@ -667,7 +632,7 @@ internal ArrayList GetObjectsInRadius(eGameObjectType type, float x, float y, fl { // we are in the subzone of the observation point // => check all distances for all objects in the subzone - UnsafeAddToListWithDistanceCheck(startElement, x, y, z, sqRadius, typeIndex, currentSubZoneIndex, partialList, inZoneElements, outOfZoneElements, ignoreZ); + UnsafeAddToListWithDistanceCheck(startElement, coordinate, sqRadius, typeIndex, currentSubZoneIndex, partialList, inZoneElements, outOfZoneElements, ignoreZ); UnsafeUpdateSubZoneTimestamp(currentSubZoneIndex, typeIndex); } } @@ -700,7 +665,7 @@ internal ArrayList GetObjectsInRadius(eGameObjectType type, float x, float y, fl lock (startElement) { - UnsafeAddToListWithDistanceCheck(startElement, x, y, z, sqRadius, typeIndex, currentSubZoneIndex, partialList, inZoneElements, outOfZoneElements, ignoreZ); + UnsafeAddToListWithDistanceCheck(startElement, coordinate, sqRadius, typeIndex, currentSubZoneIndex, partialList, inZoneElements, outOfZoneElements, ignoreZ); UnsafeUpdateSubZoneTimestamp(currentSubZoneIndex, typeIndex); } } @@ -777,9 +742,7 @@ private void UnsafeAddToListWithoutDistanceCheck(SubNodeElement startElement, in private void UnsafeAddToListWithDistanceCheck( SubNodeElement startElement, - float x, - float y, - float z, + Coordinate coordinate, uint sqRadius, int typeIndex, int subZoneIndex, @@ -813,7 +776,7 @@ private void UnsafeAddToListWithDistanceCheck( } else { - if (CheckSquareDistance(x, y, z, currentObject.Position.X, currentObject.Position.Y, currentObject.Position.Z, sqRadius, ignoreZ) && !partialList.Contains(currentObject)) + if (CheckSquareDistance(coordinate, currentObject.Coordinate, sqRadius, ignoreZ) && !partialList.Contains(currentObject)) { // the current object exists, is Active and still in the current subzone // moreover it is in the right range and not yet in the result set @@ -938,7 +901,7 @@ private bool ShouldElementMove(SubNodeElement currentElement, int typeIndex, int { // the current object exists, is Active and still in the Region where this Zone is located - int currentElementSubzoneIndex = GetSubZoneIndex(currentObject.Position.X, currentObject.Position.Y); + int currentElementSubzoneIndex = GetSubZoneIndex(currentObject.Coordinate); if (currentElementSubzoneIndex == -1) { @@ -1039,7 +1002,7 @@ private void PlaceElementsInOtherZones(DOL.GS.Collections.Hashtable elements) for (int i = 0; i < currentList.Count; i++) { currentElement = (SubNodeElement)currentList[i]; - currentZone = ZoneRegion.GetZone(currentElement.data.Position); + currentZone = ZoneRegion.GetZone(currentElement.data.Coordinate); if (currentZone != null) { @@ -1062,11 +1025,27 @@ private void PlaceElementsInOtherZones(DOL.GS.Collections.Hashtable elements) /// Z of Point2 /// the square distance to check for /// The distance - public static bool CheckSquareDistance(float x1, float y1, float z1, float x2, float y2, float z2, uint sqDistance, bool ignoreZ) + public static bool CheckSquareDistance(Coordinate locA, Coordinate locB, uint squaredDistance, bool ignoreZ) { - if (ignoreZ) - return Vector2.DistanceSquared(new Vector2(x1, y1), new Vector2(x2, y2)) <= sqDistance; - return Vector3.DistanceSquared(new Vector3(x1, y1, z1), new Vector3(x2, y2, z2)) <= sqDistance; + int xDiff = locA.X - locB.X; + var dist = ((long)xDiff) * xDiff; + + if (dist > squaredDistance) return false; + + int yDiff = locA.Y - locB.Y; + dist += ((long)yDiff) * yDiff; + + if (dist > squaredDistance) return false; + + if (ignoreZ == false) + { + int zDiff = locA.Z - locB.Z; + dist += ((long)zDiff) * zDiff; + } + + if (dist > squaredDistance) return false; + + return true; } @@ -1138,31 +1117,13 @@ private bool CheckMaxDistance(int x, int y, int xLeft, int xRight, int yTop, int #region Area functions - /// - /// Convinientmethod for Region.GetAreasOfZone(), - /// since zone.Region.getAreasOfZone(zone,x,y,z) is a bit confusing ... - /// - /// - /// - public IList GetAreasOfSpot(System.Numerics.Vector3 spot) - { - return GetAreasOfSpot(spot, true); - } - - public IList GetAreasOfSpot(int x, int y, int z) - { - return m_Region.GetAreasOfZone(this, x, y, z); - } - - public IList GetAreasOfSpot(System.Numerics.Vector3 spot, bool checkZ) - { - return m_Region.GetAreasOfZone(this, spot, checkZ); - } - public IList GetAreas() { return m_Region.GetAreasOfZone(this); } + + public IList GetAreasOfSpot(Coordinate spot) + => m_Region.GetAreasOfZone(this, spot, true); public IList GetAreas(Predicate predicate) { diff --git a/GameServer/world/ZonePointEffects.cs b/GameServer/world/ZonePointEffects.cs index 250f0f63..de32ce14 100644 --- a/GameServer/world/ZonePointEffects.cs +++ b/GameServer/world/ZonePointEffects.cs @@ -22,6 +22,7 @@ using DOL.Events; using DOL.Database; +using DOL.GS.Geometry; using System.Numerics; namespace DOL.GS.GameEvents @@ -50,7 +51,7 @@ public static void OnScriptsCompiled(DOLEvent e, object sender, EventArgs args) // processing all the ZP IList zonePoints = GameServer.Database.SelectAllObjects(); - foreach (ZonePoint z in zonePoints) + foreach (var z in zonePoints) { if (z.SourceRegion == 0) continue; @@ -64,8 +65,7 @@ public static void OnScriptsCompiled(DOLEvent e, object sender, EventArgs args) GameNPC npc = new GameNPC(zp); - npc.CurrentRegionID = z.SourceRegion; - npc.Position = new Vector3(z.SourceX, z.SourceY, z.SourceZ); + npc.Position = z.GetSourcePosition().With(npc.Orientation); npc.Name = r.Description; npc.GuildName = "ZonePoint (Open)"; if (r.IsDisabled) npc.GuildName = "ZonePoint (Closed)"; diff --git a/GameServer/world/geometry/AABoundingBox.cs b/GameServer/world/geometry/AABoundingBox.cs index 6fd2c4e6..9b36196c 100644 --- a/GameServer/world/geometry/AABoundingBox.cs +++ b/GameServer/world/geometry/AABoundingBox.cs @@ -6,7 +6,7 @@ namespace DOL.GS.Geometry public readonly struct AABoundingBox : ICollider { public readonly Vector3 Min; - public readonly Vector3 Max; + public readonly System.Numerics.Vector3 Max; public AABoundingBox Box => this; public AABoundingBox(Vector3 min, Vector3 max) diff --git a/GameServer/world/geometry/LosCheckMgr.cs b/GameServer/world/geometry/LosCheckMgr.cs index d7e1dc5c..5df6436b 100644 --- a/GameServer/world/geometry/LosCheckMgr.cs +++ b/GameServer/world/geometry/LosCheckMgr.cs @@ -24,11 +24,12 @@ using log4net; using System.Threading.Tasks; using System.IO; -using System.Numerics; using System.Globalization; using DOL.GS.Geometry; +using System.Numerics; using System.Threading; using System.Diagnostics; +using Vector3 = System.Numerics.Vector3; namespace DOL.GS { @@ -71,9 +72,18 @@ public static float GetCollisionDistance(GameObject origin, GameObject target, r { if (origin.CurrentRegion != target.CurrentRegion) return float.PositiveInfinity; - var height = new Vector3(0, 0, 64); // maybe we should calculate that from the model id and size -- 64inch seems to be okay-ish for players - return GetCollisionDistance(origin.CurrentRegion, origin.Position + height, target.Position + height, ref stats); + var height = DOL.GS.Geometry.Vector.Create(0, 0, 64); // maybe we should calculate that from the model id and size -- 64inch seems to be okay-ish for players + return GetCollisionDistance(origin.CurrentRegion, (origin.Coordinate + height).ToSysVector3(), (target.Coordinate + height).ToSysVector3(), ref stats); + } + + public static float GetCollisionDistance(Region region, Coordinate origin, Coordinate target, ref RaycastStats stats) + { + var height = DOL.GS.Geometry.Vector.Create(0, 0, 64); // maybe we should calculate that from the model id and size -- 64inch seems to be okay-ish for players + return GetCollisionDistance(region, (origin + height).ToSysVector3(), (target + height).ToSysVector3(), ref stats); } + + + public static float GetCollisionDistance(Region region, Vector3 origin, Vector3 target, ref RaycastStats stats) { return GetCollisionDistance(region.ID, origin, target, ref stats); @@ -147,14 +157,14 @@ private static void StressTests() var objects = reg.Objects.Where(o => o != null).ToList(); foreach (var o1 in objects.Take(1000)) foreach (var o2 in objects.Skip(1000).Take(1000)) - GetCollisionDistance(o1.CurrentRegion, o1.Position, o2.Position, ref stats); + GetCollisionDistance(o1.CurrentRegion, o1.Coordinate, o2.Coordinate, ref stats); var sw = new Stopwatch(); sw.Start(); stats = new RaycastStats(); foreach (var o1 in objects) foreach (var o2 in objects) - GetCollisionDistance(o1.CurrentRegion, o1.Position, o2.Position, ref stats); + GetCollisionDistance(o1.CurrentRegion, o1.Coordinate, o2.Coordinate, ref stats); sw.Stop(); long count = objects.Count * objects.Count; var raySeconds = stats.nbTests * 1000 / sw.ElapsedMilliseconds; @@ -167,7 +177,7 @@ private static void StressTests() stats = new RaycastStats(); foreach (var o1 in objects) foreach (var o2 in objects) - GetCollisionDistance(o1.CurrentRegion, o1.Position, o2.Position, ref stats); + GetCollisionDistance(o1.CurrentRegion, o1.Coordinate, o2.Coordinate, ref stats); sw.Stop(); count = objects.Count * objects.Count; raySeconds = stats.nbTests * 1000 / sw.ElapsedMilliseconds; diff --git a/GameServer/world/pathing/GamePath.cs b/GameServer/world/pathing/GamePath.cs index 32e831fc..77223358 100644 --- a/GameServer/world/pathing/GamePath.cs +++ b/GameServer/world/pathing/GamePath.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using System.Numerics; +using DOL.GS.Geometry; +using System.Collections.Generic; namespace DOL.GS { @@ -17,7 +17,7 @@ public enum MarkerModel public string Name; public Region Region; public bool HasLavaEffect = false; - public List<(GameLocation point, short speed, MarkerModel model)> Points = new List<(GameLocation point, short speed, MarkerModel model)>(); + public List<(Coordinate point, short speed, MarkerModel model)> Points = new List<(Coordinate point, short speed, MarkerModel model)>(); public List DebugObjs = new List(); @@ -27,7 +27,7 @@ public GamePath(string name, Region region) Region = region; } - public void Append(GameLocation point, short speed, MarkerModel model = MarkerModel.Brown) + public void Append(Coordinate point, short speed, MarkerModel model = MarkerModel.Brown) { Points.Add((point, speed, model)); } @@ -40,10 +40,9 @@ public void Show() { //Create a new object var obj = new GameStaticItem(); - obj.Position = pt.Position + Vector3.UnitZ; + obj.Position = Position.Create(Region.ID, pt); obj.CurrentRegion = Region; - obj.Heading = pt.Heading; - obj.Name = $"{pt.Name}--{speed} spd"; + obj.Name = $"{pt.ToString()}--{speed} spd"; obj.Model = 2965; switch (model) { diff --git a/GameServer/world/pathing/IPathingMgr.cs b/GameServer/world/pathing/IPathingMgr.cs index 9692e8ba..0ff2583d 100644 --- a/GameServer/world/pathing/IPathingMgr.cs +++ b/GameServer/world/pathing/IPathingMgr.cs @@ -1,5 +1,6 @@ using System.Numerics; using System.Threading.Tasks; +using DOL.GS.Geometry; namespace DOL.GS { @@ -16,29 +17,15 @@ public interface IPathingMgr /// void Stop(); - /// - /// Returns a path that prevents collisions with the navmesh, but floats freely otherwise - /// - /// - /// Start in GlobalXYZ - /// End in GlobalXYZ - /// - WrappedPathingResult GetPathStraight(Zone zone, Vector3 start, Vector3 end); + (LinePath Path,PathingError Error) GetPathStraightAsync(Zone zone, Coordinate start, Coordinate end); - /// - /// Returns a random point on the navmesh around the given position - /// - /// Zone - /// Start in GlobalXYZ - /// End in GlobalXYZ - /// null if no point found, Vector3 with point otherwise - Vector3? GetRandomPoint(Zone zone, Vector3 position, float radius); + Vector3? GetRandomPointAsync(Zone zone, Coordinate center, float radius); /// /// Returns the closest point on the navmesh, if available, or no point found. /// Returns the input position if no navmesh is available /// - Vector3? GetClosestPoint(Zone zone, Vector3 position, float xRange = 256f, float yRange = 256f, float zRange = 256f); + Vector3? GetClosestPointAsync(Zone zone, Coordinate position, float xRange = 256f, float yRange = 256f, float zRange = 256f); /// /// True if pathing is enabled for the specified zone @@ -52,4 +39,4 @@ public interface IPathingMgr /// bool IsAvailable { get; } } -} \ No newline at end of file +} diff --git a/GameServer/world/pathing/LocalPathingMgr.cs b/GameServer/world/pathing/LocalPathingMgr.cs index 2d7b35ee..f9baf1ed 100644 --- a/GameServer/world/pathing/LocalPathingMgr.cs +++ b/GameServer/world/pathing/LocalPathingMgr.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using DOL.GS.Geometry; using log4net; namespace DOL.GS @@ -22,33 +24,30 @@ public class LocalPathingMgr : IPathingMgr private enum dtStatus : uint { // High level status. - DT_SUCCESS = 1u << 30, // Operation succeed. + DT_SUCCESS = 1u << 30, // Operation succeed. // Detail information for status. - DT_PARTIAL_RESULT = 1 << 6, // Query did not reach the end location, returning best guess. + DT_PARTIAL_RESULT = 1 << 6, // Query did not reach the end location, returning best guess. } public enum dtStraightPathOptions : uint { - DT_STRAIGHTPATH_NO_CROSSINGS = 0x00, // Do not add extra vertices on polygon edge crossings. - DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, // Add a vertex at every polygon edge crossing where area changes. - DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, // Add a vertex at every polygon edge crossing. + DT_STRAIGHTPATH_NO_CROSSINGS = 0x00, // Do not add extra vertices on polygon edge crossings. + DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, // Add a vertex at every polygon edge crossing where area changes. + DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, // Add a vertex at every polygon edge crossing. } - private const int MAX_POLY = 256; // max vector3 when looking up a path (for straight paths too) + private const int MAX_POLY = 256; // max vector3 when looking up a path (for straight paths too) private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static Dictionary _navmeshPtrs = new Dictionary(); - - private static ThreadLocal> _navmeshQueries = - new ThreadLocal>(() => new Dictionary()); + private static ThreadLocal> _navmeshQueries = new ThreadLocal>(() => new Dictionary()); [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private static extern bool LoadNavMesh(string file, ref IntPtr meshPtr); [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] private static extern bool FreeNavMesh(IntPtr meshPtr); - [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] private static extern bool CreateNavMeshQuery(IntPtr meshPtr, ref IntPtr queryPtr); @@ -57,28 +56,27 @@ public enum dtStraightPathOptions : uint [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] - private static extern dtStatus PathStraight(IntPtr queryPtr, float[] start, float[] end, float[] polyPickExt, - dtPolyFlags[] queryFilter, dtStraightPathOptions pathOptions, ref int pointCount, float[] pointBuffer, - dtPolyFlags[] pointFlags, int[] polyRefs); + private static extern dtStatus PathStraight(IntPtr queryPtr, float[] start, float[] end, float[] polyPickExt, dtPolyFlags[] queryFilter, dtStraightPathOptions pathOptions, ref int pointCount, float[] pointBuffer, dtPolyFlags[] pointFlags); [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] - private static extern dtStatus FindRandomPointAroundCircle(IntPtr queryPtr, float[] center, float radius, - float[] polyPickExt, dtPolyFlags[] queryFilter, float[] outputVector); + private static extern dtStatus FindRandomPointAroundCircle(IntPtr queryPtr, float[] center, float radius, float[] polyPickExt, dtPolyFlags[] queryFilter, float[] outputVector); [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] - private static extern dtStatus FindClosestPoint(IntPtr queryPtr, float[] center, float[] polyPickExt, - dtPolyFlags[] queryFilter, float[] outputVector); + private static extern dtStatus FindClosestPoint(IntPtr queryPtr, float[] center, float[] polyPickExt, dtPolyFlags[] queryFilter, float[] outputVector); [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] - private static extern dtStatus GetPolyAt(IntPtr queryPtr, float[] center, float[] polyPickExt, - dtPolyFlags[] queryFilter, ref uint outputPolyRef, float[] outputVector); + private static extern dtStatus GetPolyAt(IntPtr queryPtr, float[] center, float[] polyPickExt, dtPolyFlags[] queryFilter, ref uint outputPolyRef, float[] outputVector); [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] private static extern dtStatus SetPolyFlags(IntPtr meshPtr, uint polyRef, dtPolyFlags flags); [DllImport("dol_detour", CallingConvention = CallingConvention.Cdecl)] - private static extern dtStatus QueryPolygons(IntPtr queryPtr, float[] center, float[] polyPickExt, - dtPolyFlags[] queryFilter, uint[] outputPolyRefs, ref int outputPolyCount, int maxPolyCount); + private static extern dtStatus QueryPolygons(IntPtr queryPtr, float[] center, float[] polyPickExt, dtPolyFlags[] queryFilter, uint[] outputPolyRefs, ref int outputPolyCount, int maxPolyCount); + + [DllImport("kernel32.dll")] + private static extern IntPtr LoadLibrary(string dllName); + [DllImport("libdl.so")] + private static extern IntPtr dlopen(string file, int mode); private class NavMeshQuery : IDisposable { @@ -89,7 +87,6 @@ public NavMeshQuery(IntPtr navMesh) if (!CreateNavMeshQuery(navMesh, ref this._query)) throw new Exception("can't create NavMeshQuery"); } - public void Dispose() { if (_query != IntPtr.Zero) @@ -105,6 +102,19 @@ public void Dispose() /// public bool Init() { + try + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + if (LoadLibrary("lib\\dol_detour.dll") != IntPtr.Zero) + log.Debug("dol_detour.dll loaded from LoadLibrary \"lib\\dol_detour.dll\""); + if (Environment.OSVersion.Platform == PlatformID.Unix) + if (dlopen("lib/libdol_detour.so", 2 /* RTLD_NOW */) != IntPtr.Zero) + log.Debug("libdol_detour.so loaded from dlopen \"lib/libdol_detour.so\""); + } + catch + { + } + try { var dummy = IntPtr.Zero; @@ -112,7 +122,7 @@ public bool Init() } catch (Exception e) { - log.ErrorFormat("The current process is a {0} process!", (IntPtr.Size == 8 ? "64bit" : "32bit")); + log.ErrorFormat("The current process is a {0} process!", (Environment.Is64BitProcess ? "64bit" : "32bit")); log.ErrorFormat("PathingMgr did not find the dol_detour.dll! Error message: {0}", e.ToString()); return false; } @@ -131,11 +141,10 @@ public void LoadNavMesh(Zone zone) if (_navmeshPtrs.ContainsKey(zone.ID)) throw new Exception($"Loading NavMesh failed for zone {zone.ID}: already loaded"); var id = zone.ID; - var file = $"pathing{Path.DirectorySeparatorChar}zone{id:D3}.nav"; - file = Path.GetFullPath(file); // not sure if c dll can load relative stuff + var file = Path.GetFullPath(Path.Join("pathing", $"zone{id:D3}.nav")); if (!File.Exists(file)) { - //log.ErrorFormat("Loading NavMesh failed for zone {0}! (File not found: {1})", id, file); + log.DebugFormat("Loading NavMesh failed for zone {0}! (File not found: {1})", id, file); return; } @@ -152,7 +161,6 @@ public void LoadNavMesh(Zone zone) log.ErrorFormat("Loading NavMesh failed for zone {0}! (Pointer was zero!)", id); return; } - log.InfoFormat("Loading NavMesh sucessful for zone {0}", id); _navmeshPtrs[zone.ID] = meshPtr; zone.IsPathingEnabled = true; @@ -182,79 +190,51 @@ public void Stop() _navmeshPtrs.Clear(); } + private static float[] ToRecastFloats(Vector3 value) + { + return new[] { value.X * LocalPathingMgr.CONVERSION_FACTOR, value.Z * LocalPathingMgr.CONVERSION_FACTOR, value.Y * LocalPathingMgr.CONVERSION_FACTOR }; + } + private static float[] CoordinateToRecastFloatArray(Coordinate loc) + => new[] { + loc.X * LocalPathingMgr.CONVERSION_FACTOR, + (loc.Z + 8) * LocalPathingMgr.CONVERSION_FACTOR, + loc.Y * LocalPathingMgr.CONVERSION_FACTOR + }; - /// - /// Returns a path that prevents collisions with the navmesh, but floats freely otherwise - /// - /// - /// Start in GlobalXYZ - /// End in GlobalXYZ - /// - public WrappedPathingResult GetPathStraight(Zone zone, Vector3 start, Vector3 end) + public (LinePath,PathingError) GetPathStraightAsync(Zone zone, Coordinate start, Coordinate destination) { - if (!_navmeshPtrs.ContainsKey(zone.ID)) - return new WrappedPathingResult - { - Error = PathingError.NoPathFound, - Points = null, - }; - //GSStatistics.Paths.Inc(); + var linePath = new LinePath(); + if (!_navmeshPtrs.ContainsKey(zone.ID)) return (linePath,PathingError.NoPathFound); - var result = new WrappedPathingResult(); NavMeshQuery query; if (!_navmeshQueries.Value.TryGetValue(zone.ID, out query)) { query = new NavMeshQuery(_navmeshPtrs[zone.ID]); _navmeshQueries.Value.Add(zone.ID, query); } - - var startFloats = (start + Vector3.UnitZ * 8).ToRecastFloats(); - var endFloats = (end + Vector3.UnitZ * 8).ToRecastFloats(); + var startFloats = CoordinateToRecastFloatArray(start); + var endFloats = CoordinateToRecastFloatArray(destination); var numNodes = 0; var buffer = new float[MAX_POLY * 3]; var flags = new dtPolyFlags[MAX_POLY]; dtPolyFlags includeFilter = dtPolyFlags.ALL ^ dtPolyFlags.DISABLED; dtPolyFlags excludeFilter = 0; - var polyExt = new Vector3(64, 64, 256).ToRecastFloats(); + var polyExt = new[] { 2f, 2f, 8f }; //RecastFloatArray dtStraightPathOptions options = dtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS; var filter = new[] { includeFilter, excludeFilter }; - var status = PathStraight(query, startFloats, endFloats, polyExt, filter, options, ref numNodes, buffer, - flags, null); - if ((status & dtStatus.DT_SUCCESS) == 0) - { - result.Error = PathingError.NoPathFound; - result.Points = null; - return result; - } - - var points = new WrappedPathPoint[numNodes]; - var positions = Vector3ArrayFromRecastFloats(buffer, numNodes); + var status = PathStraight(query, startFloats, endFloats, polyExt, filter, options, ref numNodes, buffer, flags); - for (var i = 0; i < numNodes; i++) - { - points[i].Position = positions[i]; - points[i].Flags = flags[i]; - } + if ((status & dtStatus.DT_SUCCESS) == 0) return (linePath, PathingError.NoPathFound); - if ((status & dtStatus.DT_PARTIAL_RESULT) == 0) - result.Error = PathingError.PathFound; - else - result.Error = PathingError.PathFound; - result.Points = points; + linePath = LinePathFromRecastFloats(buffer, numNodes); - return result; + return (linePath,PathingError.PathFound); } - /// - /// Returns a random point on the navmesh around the given position - /// - /// Zone - /// Start in GlobalXYZ - /// End in GlobalXYZ - /// null if no point found, Vector3 with point otherwise - public Vector3? GetRandomPoint(Zone zone, Vector3 position, float radius) + + public Vector3? GetRandomPointAsync(Zone zone, Coordinate center, float radius) { if (!_navmeshPtrs.ContainsKey(zone.ID)) return null; @@ -268,9 +248,8 @@ public WrappedPathingResult GetPathStraight(Zone zone, Vector3 start, Vector3 en query = new NavMeshQuery(_navmeshPtrs[zone.ID]); _navmeshQueries.Value.Add(zone.ID, query); } - var ptrs = _navmeshPtrs[zone.ID]; - var center = (position + Vector3.UnitZ * 8).ToRecastFloats(); + var centerAsFloatArray = CoordinateToRecastFloatArray(center); var cradius = (radius * CONVERSION_FACTOR); var outVec = new float[3]; @@ -280,7 +259,7 @@ public WrappedPathingResult GetPathStraight(Zone zone, Vector3 start, Vector3 en var polyPickEx = new float[3] { 2.0f, 4.0f, 2.0f }; - var status = FindRandomPointAroundCircle(query, center, cradius, polyPickEx, filter, outVec); + var status = FindRandomPointAroundCircle(query, centerAsFloatArray, cradius, polyPickEx, filter, outVec); if ((status & dtStatus.DT_SUCCESS) != 0) result = new Vector3(outVec[0] * INV_FACTOR, outVec[2] * INV_FACTOR, outVec[1] * INV_FACTOR); @@ -291,12 +270,11 @@ public WrappedPathingResult GetPathStraight(Zone zone, Vector3 start, Vector3 en /// /// Returns the closest point on the navmesh (UNTESTED! EXPERIMENTAL! WILL GO SUPERNOVA ON USE! MAYBE!?) /// - public Vector3? GetClosestPoint(Zone zone, Vector3 position, float xRange = 256f, float yRange = 256f, - float zRange = 256f) + public Vector3? GetClosestPointAsync(Zone zone, Coordinate position, float xRange = 256f, float yRange = 256f, float zRange = 256f) { if (!_navmeshPtrs.ContainsKey(zone.ID)) - return position; // Assume the point is safe if we don't have a navmesh - //GSStatistics.Paths.Inc(); + return position.ToSysVector3(); // Assume the point is safe if we don't have a navmesh + //GSStatistics.Paths.Inc(); Vector3? result = null; NavMeshQuery query; @@ -305,16 +283,15 @@ public WrappedPathingResult GetPathStraight(Zone zone, Vector3 start, Vector3 en query = new NavMeshQuery(_navmeshPtrs[zone.ID]); _navmeshQueries.Value.Add(zone.ID, query); } - var ptrs = _navmeshPtrs[zone.ID]; - var center = (position + Vector3.UnitZ * 8).ToRecastFloats(); + var center = ToRecastFloats(position.ToSysVector3() + Vector3.UnitZ * 8); var outVec = new float[3]; var defaultInclude = (dtPolyFlags.ALL ^ dtPolyFlags.DISABLED); var defaultExclude = (dtPolyFlags)0; var filter = new dtPolyFlags[] { defaultInclude, defaultExclude }; - var polyPickEx = new Vector3(xRange, yRange, zRange).ToRecastFloats(); + var polyPickEx = ToRecastFloats(new Vector3(xRange, yRange, zRange)); var status = FindClosestPoint(query, center, polyPickEx, filter, outVec); @@ -328,11 +305,24 @@ private Vector3[] Vector3ArrayFromRecastFloats(float[] buffer, int numNodes) { var result = new Vector3[numNodes]; for (var i = 0; i < numNodes; i++) - result[i] = new Vector3(buffer[i * 3 + 0] * INV_FACTOR, buffer[i * 3 + 2] * INV_FACTOR, - buffer[i * 3 + 1] * INV_FACTOR); + result[i] = new Vector3(buffer[i * 3 + 0] * INV_FACTOR, buffer[i * 3 + 2] * INV_FACTOR, buffer[i * 3 + 1] * INV_FACTOR); return result; } + private LinePath LinePathFromRecastFloats(float[] buffer, int numNodes) + { + var wayPoints = new Coordinate[numNodes]; + var conversionFactor = 32f; + for (var i = 0; i < numNodes; i++) + { + wayPoints[i] = Coordinate.Create( + x: (int)(buffer[i * 3 + 0] * conversionFactor), + y: (int)(buffer[i * 3 + 2] * conversionFactor), + z: (int)(buffer[i * 3 + 1] * conversionFactor)); + } + return LinePath.Create(wayPoints); + } + /// /// True if pathing is enabled for the specified zone /// @@ -345,4 +335,4 @@ public bool HasNavmesh(Zone zone) public bool IsAvailable => true; } -} \ No newline at end of file +} diff --git a/GameServer/world/pathing/NullPathingMgr.cs b/GameServer/world/pathing/NullPathingMgr.cs index 9ec7bbe9..e5a2e931 100644 --- a/GameServer/world/pathing/NullPathingMgr.cs +++ b/GameServer/world/pathing/NullPathingMgr.cs @@ -1,5 +1,5 @@ using System.Numerics; -using System.Threading.Tasks; +using DOL.GS.Geometry; namespace DOL.GS { @@ -17,19 +17,15 @@ public void Stop() { } - public WrappedPathingResult GetPathStraight(Zone zone, Vector3 start, Vector3 end) - { - return new WrappedPathingResult() { Error = PathingError.NavmeshUnavailable }; - } + public (LinePath, PathingError) GetPathStraightAsync(Zone zone, Coordinate start, Coordinate end) + => (new LinePath(), PathingError.NavmeshUnavailable); - public Vector3? GetRandomPoint(Zone zone, Vector3 position, float radius) - { - return null; - } + public Vector3? GetRandomPointAsync(Zone zone, Coordinate center, float radius) + => null; - public Vector3? GetClosestPoint(Zone zone, Vector3 position, float xRange = 256, float yRange = 256, float zRange = 256) + public Vector3? GetClosestPointAsync(Zone zone, Coordinate position, float xRange = 256, float yRange = 256, float zRange = 256) { - return position; + return position.ToSysVector3(); } public bool HasNavmesh(Zone zone) diff --git a/GameServer/world/pathing/PathCalculator.cs b/GameServer/world/pathing/PathCalculator.cs index 7e9926d9..07098fda 100644 --- a/GameServer/world/pathing/PathCalculator.cs +++ b/GameServer/world/pathing/PathCalculator.cs @@ -1,10 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Reflection; using System.Threading; -using System.Threading.Tasks; +using DOL.GS.Geometry; using log4net; namespace DOL.GS @@ -61,9 +61,8 @@ public static bool IsSupported(GameNPC o) /// public GameDoor NextDoor { get; private set; } - private readonly Queue _pathNodes = new(); - private Vector3 _lastTarget = Vector3.Zero; - private GamePath _visualizationPath; + private LinePath path = new LinePath(); + private Coordinate _lastTarget = Coordinate.Nowhere; /// /// Forces the path to be replot on the next CalculateNextTarget(...) @@ -95,40 +94,26 @@ public PathCalculator(GameNPC owner) /// /// /// - private bool ShouldPath(Vector3 target) + private bool ShouldPath(Coordinate target) { return ShouldPath(Owner, target); } - /// - /// Clears all data stored in this calculator - /// - public void Clear() - { - _pathNodes.Clear(); - _lastTarget = Vector3.Zero; - DidFindPath = false; - ForceReplot = true; - } - /// /// True if we should path towards the target point /// - /// - /// - /// - public static bool ShouldPath(GameNPC owner, Vector3 target) + public static bool ShouldPath(GameNPC owner, Coordinate destination) { - if (Vector3.Distance(owner.Position, target) < MIN_PATHING_DISTANCE) + if (owner.Coordinate.DistanceTo(destination) < MIN_PATHING_DISTANCE) return false; // too close to path if (owner.IsFlying) return false; - if (owner.Position.Z <= float.Epsilon) + if (owner.Position.Z <= 0) return false; // this will probably result in some really awkward paths otherwise var zone = owner.CurrentZone; if (zone == null || !zone.IsPathingEnabled) return false; // we're in nirvana - if (owner.CurrentRegion.GetZone(target) != zone) + if (owner.CurrentRegion.GetZone(destination) != zone) return false; // target is in a different zone (TODO: implement this maybe? not sure if really required) return true; } @@ -138,231 +123,69 @@ public static bool ShouldPath(GameNPC owner, Vector3 target) /// /// Semaphore to prevent multiple replots /// - private int calculatorState = (int)CalcState.IDLE; - - enum CalcState : int - { - IDLE = 0, - REPLOTTING = 1, - } + private int isReplottingPath = IDLE; + const int IDLE = 0, REPLOTTING = 1; - private void ReplotPath(Vector3 target) + private void ReplotPath(Coordinate destination) { - lock (_pathNodes) - _lastTarget = target; // Try acquiring a pathing lock - if (Interlocked.CompareExchange(ref calculatorState, (int)CalcState.REPLOTTING, (int)CalcState.IDLE) != (int)CalcState.IDLE) + if (Interlocked.CompareExchange(ref isReplottingPath, REPLOTTING, IDLE) != IDLE) { // Computation is already in progress. ReplotPathAsync will be called again automatically by .PathTo every few ms return; } + // we make a blocking call here because we are already in a worker thread and inside a lock try { - while (!CalculatePath(target)) - target = _lastTarget; - } - finally - { - if (Interlocked.Exchange(ref calculatorState, (int)CalcState.IDLE) != (int)CalcState.REPLOTTING) - log.Warn("PathCalc semaphore was in IDLE state even though we were replotting. This should never happen"); - } - } - - private bool CalculatePath(Vector3 target) - { - var currentZone = Owner.CurrentZone; - var currentPos = Owner.Position; - var pathingResult = PathingMgr.Instance.GetPathStraight(currentZone, currentPos, target); - - lock (_pathNodes) - { - if (_lastTarget != target) - { - Owner.DebugSend("target changed from {0} to {1}", target, _lastTarget); - return false; - } + var currentZone = Owner.CurrentZone; + var pathingResult = PathingMgr.Instance.GetPathStraightAsync(currentZone, Owner.Coordinate, destination); - _pathNodes.Clear(); if (pathingResult.Error != PathingError.NoPathFound && pathingResult.Error != PathingError.NavmeshUnavailable && - pathingResult.Points != null) + !pathingResult.Path.Start.Equals(Coordinate.Nowhere)) { - DidFindPath = true; - var to = pathingResult.Points.Length; - if (pathingResult.Error == PathingError.PartialPathFound) - { - to = pathingResult.Points.Length; - } - for (int i = 1; i < to; i++) /* remove first node */ - { - var pt = pathingResult.Points[i]; - if (pt.Position.X < -500000) - { - log.Error("PathCalculator.ReplotPath returned weird node: " + pt + " (result=" + pathingResult.Error + - "); this=" + this); - } - _pathNodes.Enqueue(pt); - } - - Owner.DebugSend("Found path to target with {0} nodes for {1} (VisualizePath={2})", pathingResult.Points.Length, Owner.Name, VisualizePath); - - // Visualize the path? - if (VisualizePath) - { - DoVisualizePath(pathingResult); - } - else if (_visualizationPath != null) - { - _visualizationPath.Hide(); - _visualizationPath = null; - } - } - else - { - //noPathFoundMetric.Mark(); - DidFindPath = false; - Owner.DebugSend("No path to destination found for {0}", Owner.Name); + path = pathingResult.Path; } + _lastTarget = destination; ForceReplot = false; } - - return true; - } - - private void DoVisualizePath(WrappedPathingResult pathingResult) - { - _visualizationPath?.Hide(); - _visualizationPath = new GamePath($"path({Owner.Name})", Owner.CurrentRegion) { HasLavaEffect = false }; - foreach (var node in pathingResult.Points) + finally { - var model = GamePath.MarkerModel.Green; - if ((node.Flags & dtPolyFlags.DOOR) != 0) - model = GamePath.MarkerModel.Red; - else if ((node.Flags & dtPolyFlags.SWIM) != 0) - model = GamePath.MarkerModel.Blue; - else if ((node.Flags & dtPolyFlags.JUMP) != 0) - model = GamePath.MarkerModel.Yellow; - _visualizationPath.Append(new GameLocation("", Owner.CurrentRegionID, node.Position, 0), Owner.MaxSpeed, model); + if (Interlocked.Exchange(ref isReplottingPath, IDLE) != REPLOTTING) + { + log.Warn("PathCalc semaphore was in IDLE state even though we were replotting. This should never happen"); + } } - //Owner.DebugSend("Visualizing Path"); - _visualizationPath.Show(); } - /// - /// Calculates the next point this NPC should walk to to reach the target - /// - /// - /// Next path node, or null if target reached. Throws a NoPathToTargetException if path is blocked/returns> - public Tuple CalculateNextTarget(Vector3? destination = null) + public Coordinate CalculateNextLineSegment(Coordinate destination) { - var target = destination ?? _lastTarget; - - if (!ShouldPath(target)) + if (!ShouldPath(destination)) { - Owner.DebugSend("Skipping pathing for target {0}", target); - DidFindPath = true; // not needed - return new Tuple(null, NoPathReason.NOPROBLEM); + return Coordinate.Nowhere; } - Interlocked.Increment(ref Statistics.PathToCalculateNextTargetCalls); - // Check if we can reuse our path. We assume that we ourselves never "suddenly" warp to a completely // different position. - if (ForceReplot || !_lastTarget.IsInRange(target, MIN_TARGET_DIFF_REPLOT_DISTANCE)) - { - Owner.DebugSend("Target moved too far from original target or forced replot; replotting path"); - ReplotPath(target); - } - - // Find the next node in the path to the target, but skip points that are too close - while (_pathNodes.Count > 0 && Owner.Position.IsInRange(_pathNodes.Peek().Position, NODE_REACHED_DISTANCE)) - { - Owner.DebugSend("Pathing node reached; removing"); - _pathNodes.Dequeue(); - } - - // Scan the next few nodes for a potential door - // TODO(mlinder): Implement support for doors - NextDoor = null; - /*foreach (var node in _pathNodes.Take(1)) { - if ((node.Flags & dtPolyFlags.DOOR) != 0) { - var currentNode = node; - try { - NextDoor = - DoorMgr.GetDoorsInRadius(Owner.Region, node.Position, DOOR_SEARCH_DISTANCE) - .MinBy(x => x.Position.DistanceSquared(currentNode.Position)); - // TODO(mlinder): Confirm whether this actually makes sure that the path goes through a door, and not just next to it? - } catch (InvalidOperationException) { - // TODO(mlinder): this is really inefficient b/c of exception handling, duh - Owner.DebugSend("Did not find door in radius"); - } - break; - } - } - - // Open doors automagically (maybe not the best place to do this?) - if (NextDoor != null) { - Owner.DebugSend("There is a door on the next segment: {0}", NextDoor); - if (!DealWithDoorOnPath(NextDoor)) - { - return new Tuple(null, NoPathReason.DOOR_EN_ROUTE); - } - }*/ - - if (_pathNodes.Count == 0) + if (ForceReplot || _lastTarget.DistanceTo(destination) > MIN_TARGET_DIFF_REPLOT_DISTANCE) { - // Path end reached, or no path found - Owner.DebugSend("No nodes remaining for {0}; choosing direct path", Owner.Name); - if (!DidFindPath) - { - return new Tuple(null, NoPathReason.RECAST_FOUND_NO_PATH); - } - return new Tuple(null, NoPathReason.UNKNOWN); // no more nodes (or no path) + ReplotPath(destination); } - // Just walk to the next pathing node - var next = _pathNodes.Peek(); - Owner.DebugSend("Sending NPC {0} to {1} to reach {2} (remaining nodes={3}; dist={4})", Owner.Name, next, target, _pathNodes.Count, Vector3.Distance(next.Position, Owner.Position)); - - return new Tuple(next.Position, NoPathReason.NOPROBLEM); - } - - /** Periodically called when a closeby door is on our path to the target. */ - private bool DealWithDoorOnPath(GameDoor nextDoor) - { - return true; - - if (!Owner.Position.IsInRange(nextDoor.Position, nextDoor.InteractDistance)) + while (path.PointCount > 0 && Owner.Coordinate.DistanceTo(path.CurrentWayPoint) <= NODE_REACHED_DISTANCE) { - return true; // Next door is still too far away + path.SelectNextWayPoint(); } - /* TODO: add missing property/method - if (nextDoor.IsOpen) - { - Owner.DebugSend("There is a door on the way, but it is open: {0}", nextDoor); - return true; - } + // Find the next node in the path to the target, but skip points that are too close + var nextWayPoint = path.CurrentWayPoint; - Owner.DebugSend("Trying to open door: {0}", nextDoor); - if (nextDoor.InteractLiving(Owner, false)) - { - // Door should either be open now, or we should have been teleported to the other side - Owner.DebugSend("Interact with door succeeded; door should be open now"); - return true; - } - */ + if (path.PointCount == 0) return Coordinate.Nowhere; // no more nodes (or no path) - // Door is blocked/other realm - Owner.DebugSend("Interact with door failed; stopping movement"); - Owner.StopFollowing(); - Owner.StopMoving(); - return false; + return nextWayPoint; } public override string ToString() - { - return $"PathCalc[Target={_lastTarget}, Nodes={_pathNodes.Count}, NextNode={(_pathNodes.Count > 0 ? _pathNodes.Peek().ToString() : null)}, NextDoor={NextDoor}]"; - } + => $"PathCalc[Target={_lastTarget}, Nodes={path.PointCount}, NextNode={(path.PointCount > 0 ? path.CurrentWayPoint.ToString() : null)}, NextDoor={NextDoor}]"; } } diff --git a/GameServer/world/pathing/PathingMgr.cs b/GameServer/world/pathing/PathingMgr.cs index 93453066..4e577353 100644 --- a/GameServer/world/pathing/PathingMgr.cs +++ b/GameServer/world/pathing/PathingMgr.cs @@ -52,4 +52,4 @@ public static void Stop() /// public static IPathingMgr Instance { get; private set; } = NullPathingMgr; } -} +} \ No newline at end of file diff --git a/GameServer/world/pathing/Structs.cs b/GameServer/world/pathing/Structs.cs index dac38404..81a7910e 100644 --- a/GameServer/world/pathing/Structs.cs +++ b/GameServer/world/pathing/Structs.cs @@ -1,26 +1,7 @@ using System; -using System.Numerics; namespace DOL.GS { - public struct WrappedPathingResult - { - public PathingError Error; - public WrappedPathPoint[] Points; - } - - - public struct WrappedPathPoint - { - public Vector3 Position; - public dtPolyFlags Flags; - - public override string ToString() - { - return $"({Position}, {Flags})"; - } - } - [Flags] public enum dtPolyFlags : ushort { diff --git a/Tests/IntegrationTests/GameServer/gameutils/RegionTest.cs b/Tests/IntegrationTests/GameServer/gameutils/RegionTest.cs index de3ffb77..5dcfe46b 100644 --- a/Tests/IntegrationTests/GameServer/gameutils/RegionTest.cs +++ b/Tests/IntegrationTests/GameServer/gameutils/RegionTest.cs @@ -17,104 +17,103 @@ * */ using System; -using System.Numerics; using DOL.Events; using DOL.GS; +using DOL.GS.Geometry; using NUnit.Framework; namespace DOL.Integration.Server { - [TestFixture] - public class RegionTest : ServerTests - { - public static bool notified = false; - - public RegionTest() - { - } - - [Test, Explicit] - public void AddObject() - { - Region region = WorldMgr.GetRegion(1); - GameObject obj = new GameNPC(); - obj.Name = "TestObject"; - obj.Position = new Vector3(400000, 200000, 2000); - obj.CurrentRegion = region; - - obj.AddToWorld(); - - if (obj.ObjectID < 0) - Assert.Fail("Failed to add object to Region. ObjectId < 0"); - - Assert.AreEqual(region.GetObject((ushort)obj.ObjectID), obj); - } - - - [Test, Explicit] - public void AddArea() - { - Region region = WorldMgr.GetRegion(1); - IArea insertArea = region.AddArea(new Area.Circle(null, 1000, 1000, 0, 500)); - - Assert.IsNotNull(insertArea); - - var areas = region.GetAreasOfSpot(501, 1000, 0); - Assert.IsTrue(areas.Count > 0); - - bool found = false; - foreach (IArea ar in areas) - { - if (ar == insertArea) - { - found = true; - break; - } - } - Assert.IsTrue(found); - - // - areas = region.GetAreasOfSpot(1499, 1000, 2000); - Assert.IsTrue(areas.Count > 0); - - found = false; - foreach (IArea ar in areas) - { - if (ar == insertArea) - { - found = true; - break; - } - } - Assert.IsTrue(found); - - - //Notify test - notified = false; - - GamePlayer player = CreateMockGamePlayer(); - - insertArea.RegisterPlayerEnter(new DOLEventHandler(NotifyTest)); - insertArea.OnPlayerEnter(player); - - Assert.IsTrue(notified); - - region.RemoveArea(insertArea); - - areas = region.GetAreasOfSpot(1499, 1000, 2000); - Assert.IsTrue(areas.Count == 0); - - } - - public static void NotifyTest(DOLEvent e, object sender, EventArgs args) - { - Console.WriteLine("notified"); - notified = true; - } - - [Test] - public void RemoveObject() - { - } - } + [TestFixture] + public class RegionTest : ServerTests + { + public static bool notified = false; + + public RegionTest() + { + } + + [Test, Explicit] + public void AddObject() + { + GameObject obj = new GameNPC(); + obj.Name="TestObject"; + obj.Position = Position.Create(regionID: 1, x: 400000, y: 200000, z: 2000); + + obj.AddToWorld(); + + if (obj.ObjectID<0) + Assert.Fail("Failed to add object to Region. ObjectId < 0"); + + Assert.AreEqual(obj.CurrentRegion.GetObject((ushort)obj.ObjectID),obj); + } + + + [Test, Explicit] + public void AddArea() + { + Region region = WorldMgr.GetRegion(1); + var circleLocation = Coordinate.Create(1000,1000,0); + IArea insertArea = region.AddArea(new Area.Circle(null,circleLocation,500)); + + Assert.IsNotNull(insertArea); + + var areas = region.GetAreasOfSpot(Coordinate.Create(501,1000,0)); + Assert.IsTrue(areas.Count>0); + + bool found = false; + foreach( IArea ar in areas) + { + if (ar == insertArea) + { + found = true; + break; + } + } + Assert.IsTrue(found); + + // + areas = region.GetAreasOfSpot(Coordinate.Create(1499,1000,2000)); + Assert.IsTrue(areas.Count>0); + + found = false; + foreach( IArea ar in areas) + { + if (ar == insertArea) + { + found = true; + break; + } + } + Assert.IsTrue(found); + + + //Notify test + notified=false; + + GamePlayer player = CreateMockGamePlayer(); + + insertArea.RegisterPlayerEnter(new DOLEventHandler(NotifyTest)); + insertArea.OnPlayerEnter(player); + + Assert.IsTrue(notified); + + region.RemoveArea(insertArea); + + areas = region.GetAreasOfSpot(Coordinate.Create(1499,1000,2000)); + Assert.IsTrue(areas.Count==0); + + } + + public static void NotifyTest(DOLEvent e, object sender, EventArgs args) + { + Console.WriteLine("notified"); + notified = true; + } + + [Test] + public void RemoveObject() + { + } + } } diff --git a/Tests/IntegrationTests/TestPacketLib.cs b/Tests/IntegrationTests/TestPacketLib.cs index 1bf3c5a3..dfacd16c 100644 --- a/Tests/IntegrationTests/TestPacketLib.cs +++ b/Tests/IntegrationTests/TestPacketLib.cs @@ -25,9 +25,9 @@ using DOL.GS.Quests; using DOL.Database; using DOL.AI.Brain; +using DOL.GS.Geometry; using DOL.GS.Keeps; using DOL.GS.Housing; -using System.Numerics; using DOL.GS.Profession; namespace DOL.Tests @@ -628,11 +628,11 @@ public void SendChangeTarget(GameObject newTarget) { if (SendChangeTargetMethod != null) SendChangeTargetMethod(this, newTarget); } - public Action SendChangeGroundTargetMethod { get; set; } - public void SendChangeGroundTarget(Vector3 newTarget) - { - if (SendChangeGroundTargetMethod != null) SendChangeGroundTargetMethod(this, newTarget); - } + public Action SendChangeGroundTargetMethod { get; set; } + [Obsolete("Use .SendChangeGroundTarget(Coordinate) instead!")] + public void SendChangeGroundTarget(System.Numerics.Vector3 newTarget) + => SendChangeGroundTarget(Coordinate.Create((int)newTarget.X, (int)newTarget.Y, (int)newTarget.Z)); + public void SendChangeGroundTarget(Coordinate newTarget) => SendChangeGroundTargetMethod?.Invoke(this, newTarget); public Action SendPetWindowMethod { get; set; } public void SendPetWindow(GameLiving pet, ePetWindowAction windowAction, eAggressionState aggroState, eWalkState walkState) { @@ -689,6 +689,7 @@ public void SendLivingDataUpdate(GameLiving living, bool updateStrings) if (SendLivingDataUpdateMethod != null) SendLivingDataUpdateMethod(this, living, updateStrings); } public Action SendSoundEffectMethod { get; set; } + public void SendSoundEffect(ushort soundId, Position position, ushort radius) { } public void SendSoundEffect(ushort soundId, ushort zoneId, ushort x, ushort y, ushort z, ushort radius) { if (SendSoundEffectMethod != null) SendSoundEffectMethod(this, soundId, zoneId, x, y, z, radius); @@ -914,6 +915,10 @@ public void SendMinotaurRelicMapRemove(byte id) if (SendMinotaurRelicMapRemoveMethod != null) SendMinotaurRelicMapRemoveMethod(this, id); } public Action SendMinotaurRelicMapUpdateMethod { get; set; } + public void SendMinotaurRelicMapUpdate(byte id, Position position) + { + if (SendMinotaurRelicMapUpdateMethod != null) SendMinotaurRelicMapUpdateMethod(this, id, position.RegionID, position.X, position.Y, position.Z); + } public void SendMinotaurRelicMapUpdate(byte id, ushort region, int x, int y, int z) { if (SendMinotaurRelicMapUpdateMethod != null) SendMinotaurRelicMapUpdateMethod(this, id, region, x, y, z); diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 2b88eaee..3730a606 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -46,7 +46,7 @@ - + diff --git a/Tests/UnitTests/Geometry/UT_Angle.cs b/Tests/UnitTests/Geometry/UT_Angle.cs new file mode 100644 index 00000000..b4e1d247 --- /dev/null +++ b/Tests/UnitTests/Geometry/UT_Angle.cs @@ -0,0 +1,92 @@ +using System; +using NUnit.Framework; +using DOL.GS.Geometry; + +namespace DOL.UnitTests; + +[TestFixture] +public class UT_Angle +{ + [Test] + public void Equals_TwoNewAnglesWithZeroDegrees_True() + { + var angleA = Angle.Degrees(0); + var angleB = Angle.Degrees(0); + + Assert.That(angleA.Equals(angleB), Is.True); + } + + [Test] + public void Equals_TwoDifferentAngles_False() + { + var angleA = Angle.Degrees(0); + var angleB = Angle.Degrees(1); + + Assert.That(angleA.Equals(angleB), Is.False); + } + + [Test] + public void Equals_MinusOneDegreesAnd359Degrees_True() + { + var angleA = Angle.Degrees(-1); + var angleB = Angle.Degrees(359); + + Assert.That(angleA.Equals(angleB), Is.True); + } + + [Test] + public void Heading_One_InHeadingIsOne() + { + var angle = Angle.Heading(1); + + var expected = 1; + var actual = angle.InHeading; + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void Degrees_One_InDegreesIsOne() + { + var angle = Angle.Heading(1); + + var expected = 1; + var actual = angle.InHeading; + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void PlusOperator_OneHeadingWithOneHeading_TwoHeading() + { + var actual = Angle.Heading(1) + Angle.Heading(1); + + var expected = Angle.Heading(2); + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void MinusOperator_OneHeadingMinusOneHeading_AngleZero() + { + var actual = Angle.Heading(1) - Angle.Heading(1); + + var expected = Angle.Zero; + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void Radians_One2048thPi_OneHeading() + { + var actual = Angle.Radians(Math.PI/2048); + + var expected = Angle.Heading(1); + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void Radians_One180thPi_OneDegree() + { + var actual = Angle.Radians(Math.PI/180); + + var expected = Angle.Degrees(1); + Assert.That(actual, Is.EqualTo(expected)); + } +} diff --git a/Tests/UnitTests/Geometry/UT_Motion.cs b/Tests/UnitTests/Geometry/UT_Motion.cs new file mode 100644 index 00000000..50b39148 --- /dev/null +++ b/Tests/UnitTests/Geometry/UT_Motion.cs @@ -0,0 +1,44 @@ +using DOL.GS.Geometry; +using NUnit.Framework; + +namespace DOL.UnitTests; + +[TestFixture] +public class UT_Motion +{ + [Test] + public void GetLocationAfter_Zero_Start() + { + var start = Position.Zero; + + var actual = Motion.Create(start, destination: Coordinate.Nowhere, withSpeed: 0) + .GetPositonAfter(0); + + Assert.That(actual, Is.EqualTo(start)); + } + + [Test] + public void GetLocationAfter_FromZeroAfter1000MilliSecondsWithSpeed100AndOrientationZero_Plus100Y() + { + var start = Position.Zero; + var motion = Motion.Create(start, destination: Coordinate.Nowhere, withSpeed: 100); + + var actual = motion.GetPositonAfter(1000); + + var expected = start + Vector.Create(y: 100); + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void GetLocationAfter_FromZeroAfter1000MilliSecondsWithSpeed100AndOrientationZeroAndDestination50Y_Destination() + { + var start = Position.Zero; + var destination = start + Vector.Create(y: 50); + var motion = Motion.Create(start, destination.Coordinate, withSpeed: 100); + + var actual = motion.GetPositonAfter(1000); + + var expected = destination; + Assert.That(actual, Is.EqualTo(destination)); + } +} diff --git a/Tests/UnitTests/Geometry/UT_Vector.cs b/Tests/UnitTests/Geometry/UT_Vector.cs new file mode 100644 index 00000000..5821c7f1 --- /dev/null +++ b/Tests/UnitTests/Geometry/UT_Vector.cs @@ -0,0 +1,115 @@ +using System; +using DOL.GS.Geometry; +using NUnit.Framework; + +namespace DOL.UnitTests; + +[TestFixture] +public class UT_Vector +{ + [Test] + public void Equals_TwoNewVectors_True() + { + var vectorA = Vector.Create(); + var vectorB = Vector.Create(); + + Assert.That(vectorA.Equals(vectorB), Is.True); + } + + [Test] + public void Equals_VectorWithDifferentX_False() + { + var vectorA = Vector.Create(x: 0); + var vectorB = Vector.Create(x: 1); + + Assert.That(vectorA.Equals(vectorB), Is.False); + } + + [Test] + public void PlusOperator_TwoVectorsWithLengthOne_VectorWithLength2() + { + var vector = Vector.Create(orientation: Angle.Zero, length: 1); + + var actual = (vector + vector).Length; + + var expectedLength = 2; + Assert.That(actual, Is.EqualTo(expectedLength)); + } + + [Test] + public void Create_OrientationZeroWithLengthOne_SameAsVectorWithYOne() + { + var actual = Vector.Create(orientation: Angle.Zero, length: 1); + + var expected = Vector.Create(y: 1); + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void Create_Orientation45DegreesWithLengthOneHundred_VectorWithXMinus71AndY71() + { + var actual = Vector.Create(orientation: Angle.Degrees(45), length: 100); + + var expected = Vector.Create(x: -71, y: 71); + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void RotatedClockwise_VectorXOneHundredBy90Degrees_VectorWithYOneHundred() + { + var vector = Vector.Create(x: 100); + + var actual = vector.RotatedClockwise(Angle.Degrees(90)); + + var expected = Vector.Create(y: 100); + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void RotatedClockwise_VectorXOneHundredBy45Degrees_VectorWithX71AndY71() + { + var vector = Vector.Create(x: 100); + + var actual = vector.RotatedClockwise(Angle.Degrees(45)); + + //rounded + var expected = Vector.Create(x: 71, y: 71); + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void RotatedClockwise_VectorX50By45Degrees_VectorWithX35AndY35() + { + var vector = Vector.Create(x: 50); + + var actual = vector.RotatedClockwise(Angle.Degrees(45)); + + //rounded + var expected = Vector.Create(x: 35, y: 35); + Assert.That(actual, Is.EqualTo(expected)); + } + + + + [Test] + public void Length_VectorX1Y2Z2_3() + { + var vector = Vector.Create(x: 1, y: 2, z: 2); + + var actual = vector.Length; + + var expected = 3d; + Assert.That(actual, Is.EqualTo(expected)); + } + + [Test] + public void Length2D_VectorX3Y4Z100_5() + { + var vector = Vector.Create(x: 3, y: 4, z: 100); + + var actual = vector.Length2D; + + var expected = 5d; + Assert.That(actual, Is.EqualTo(expected)); + } +}