/************************************************************************* * ModernUO * * Copyright 2019-2023 - ModernUO Development Team * * Email: hi@modernuo.com * * File: RegionSpawner.cs * * * * 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 3 of the License, or * * (at your option) any later version. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *************************************************************************/ using System; using System.Text.Json; using ModernUO.Serialization; using Server.Json; using Server.Regions; namespace Server.Engines.Spawners; [SerializationGenerator(0)] public partial class RegionSpawner : Spawner { [SerializableField(0, getter: "private", setter: "private")] private string _spawnRegionName; private BaseRegion _spawnRegion; [Constructible(AccessLevel.Developer)] public RegionSpawner() { } [Constructible(AccessLevel.Developer)] public RegionSpawner(string spawnedName) : base(spawnedName) { } [Constructible(AccessLevel.Developer)] public RegionSpawner( int amount, int minDelay, int maxDelay, int team, int homeRange, params string[] spawnedNames ) : this( amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), team, homeRange, spawnedNames ) { } [Constructible(AccessLevel.Developer)] public RegionSpawner( int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, params string[] spawnedNames ) : base(amount, minDelay, maxDelay, team, homeRange, spawnedNames) { } public RegionSpawner(DynamicJson json, JsonSerializerOptions options) : base(json, options) { json.GetProperty("map", options, out Map map); json.GetProperty("region", options, out string spawnRegion); _spawnRegion = Region.Find(spawnRegion, map) as BaseRegion; _spawnRegion?.InitRectangles(); } [CommandProperty(AccessLevel.Developer)] public BaseRegion SpawnRegion { get => _spawnRegion; set { _spawnRegion = value; SpawnRegionName = _spawnRegion?.Name; _spawnRegion?.InitRectangles(); InvalidateProperties(); } } public override void ToJson(DynamicJson json, JsonSerializerOptions options) { base.ToJson(json, options); json.SetProperty("region", options, SpawnRegion.Name); } public override void GetSpawnerProperties(IPropertyList list) { base.GetSpawnerProperties(list); if (Running && _spawnRegion != null) { list.Add(1076228, $"{"region:"}\t{_spawnRegion.Name}"); // ~1_DUMMY~ ~2_DUMMY~ } } public override Point3D GetSpawnPosition(ISpawnable spawned, Map map) { if (_spawnRegion == null || map == null || map == Map.Internal || map != _spawnRegion.Map || _spawnRegion.TotalWeight <= 0) { return Location; } bool waterMob, waterOnlyMob; if (spawned is Mobile mob) { waterMob = mob.CanSwim; waterOnlyMob = mob.CanSwim && mob.CantWalk; } else { waterMob = false; waterOnlyMob = false; } // Try 10 times to find a valid location. for (var i = 0; i < 10; i++) { var rand = Utility.Random(_spawnRegion.TotalWeight); var x = int.MinValue; var y = int.MinValue; for (var j = 0; j < _spawnRegion.RectangleWeights.Length; j++) { var curWeight = _spawnRegion.RectangleWeights[j]; if (rand < curWeight) { var rect = _spawnRegion.Rectangles[j]; x = rect.Start.X + rand % rect.Width; y = rect.Start.Y + rand / rect.Width; break; } rand -= curWeight; } var mapZ = map.GetAverageZ(x, y); if (waterMob) { if (IsValidWater(map, x, y, Z)) { return new Point3D(x, y, Z); } if (IsValidWater(map, x, y, mapZ)) { return new Point3D(x, y, mapZ); } } if (!waterOnlyMob) { if (map.CanSpawnMobile(x, y, Z)) { return new Point3D(x, y, Z); } if (map.CanSpawnMobile(x, y, mapZ)) { return new Point3D(x, y, mapZ); } } } return HomeLocation; } [AfterDeserialization(false)] private void AfterDeserialization() { _spawnRegion = Region.Find(_spawnRegionName, Map) as BaseRegion; _spawnRegion?.InitRectangles(); } }