blizzless-diiis/src/DiIiS-NA/D3-GameServer/GSSystem/GeneratorsSystem/WorldGenerator.cs
Lucca Faria Ferri 97a8bfa8a3 Quests and MPQ work.
Fixed quest to find 2 orbs on the rotten forest;
Fixed load actors to load an actor file that could not be found - as many actors rely on a name which is not always provided on the enum by using a [SnoFileName("TheActual SnoFileName")];
Changed FileFormats.Actor to FileFormats.ActorData
2023-02-02 11:52:36 -08:00

2776 lines
124 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DiIiS_NA.Core.Extensions;
using DiIiS_NA.Core.Logging;
using DiIiS_NA.Core.MPQ;
using DiIiS_NA.Core.Helpers.Math;
using DiIiS_NA.Core.MPQ.FileFormats;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.Math;
using DiIiS_NA.GameServer.Core.Types.Collision;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
using DiIiS_NA.GameServer.GSSystem.GameSystem;
using World = DiIiS_NA.GameServer.GSSystem.MapSystem.World;
using Scene = DiIiS_NA.GameServer.GSSystem.MapSystem.Scene;
using Affix = DiIiS_NA.GameServer.GSSystem.ItemsSystem.Affix;
using DiIiS_NA.Core.Storage;
using DiIiS_NA.Core.Storage.WorldSceneBase.Entities;
using DiIiS_NA.GameServer.Core.Types.Scene;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Interactions;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
{
public class DRLGEmuScene
{
public int SnoID;
public Asset Asset;
public int Weather;
public int Music;
public int LevelArea;
public DRLGEmuScene(int _SnoID, int _Weather, int _Music, int _LevelArea)
{
SnoID = _SnoID;
Weather = _Weather;
Music = _Music;
LevelArea = _LevelArea;
}
}
public class WorldGenerator
{
static readonly Logger Logger = LogManager.CreateLogger();
private static readonly ActorSno[] d1ModeHiddenActors = new ActorSno[]
{
ActorSno._x1_mysticintro_npc,
ActorSno._tristramfemale,
ActorSno._a1_uniquevendor_armorer,
ActorSno._x1_lore_mysticnotes,
ActorSno._templarnpc_imprisoned,
ActorSno._adventurer_d_templarintrounique,
ActorSno._x1_catacombs_jeweler,
ActorSno._waypoint,
};
public Game Game { get; set; }
public WorldGenerator(Game game)
{
Game = game;
}
public static Dictionary<int, int> DefaultConversationLists = new();
private readonly List<int> LoadedLevelAreas = new();
public void CheckLevelArea(World world, int levelAreaSNO)
{
if (SpawnGenerator.Spawns.ContainsKey(levelAreaSNO) && SpawnGenerator.Spawns[levelAreaSNO].lazy_load)
if (!LoadedLevelAreas.Contains(levelAreaSNO))
{
LoadedLevelAreas.Add(levelAreaSNO);
// Load monsters for level area
foreach (var scene in _lazyLevelAreas[levelAreaSNO])
{
LoadMonstersLayout(world, levelAreaSNO, scene);
}
}
}
public World Generate(WorldSno worldSNO)
{
if (!MPQStorage.Data.Assets[SNOGroup.Worlds].ContainsKey((int)worldSNO))
{
Logger.Error("Can't find a valid world definition for sno: {0}", worldSNO);
return null;
}
var worldAsset = MPQStorage.Data.Assets[SNOGroup.Worlds][(int)worldSNO];
Dictionary<int, List<Scene>> levelAreas = new Dictionary<int, List<Scene>>();
World world = new World(Game, worldSNO);
bool DRLGEmuActive = false;
world.worldData = (DiIiS_NA.Core.MPQ.FileFormats.World)worldAsset.Data;
if (worldSNO == WorldSno.a2dun_swr_swr_to_oasis_level01)
world.worldData.DynamicWorld = true;
//445736 - p4_forest_snow_icecave_01
if (world.worldData.DynamicWorld && !worldSNO.IsNotDynamicWorld()) //Gardens of Hope - 2 lvl is NOT random
{
if (!Config.Instance.DRLGemu)
Logger.Warn("DRLG-Emu is Disabled.");
string DRLGVersion = "1.8";
var WorldContainer = DBSessions.WorldSession.Query<DRLG_Container>().Where(dbt => dbt.WorldSNO == (int)worldSNO).ToList();
if (WorldContainer.Count > 0 && worldSNO != WorldSno.a1trdun_level05_templar && Config.Instance.DRLGemu)
{
DRLGEmuActive = true;
Logger.Warn("World - {0} [{1}] is dynamic! Found container, DRLG-Emu v{2} Activated!", worldAsset.Name, worldAsset.SNOId, DRLGVersion);
}
else if (!GenerateRandomDungeon(worldSNO, world.worldData))
{
Logger.Error("DRLG-Emu v{2} - World - {0} [{1}] is dynamic! DRLG Engine can't find container! Template system is not configured for this world.", worldAsset.Name, worldAsset.SNOId, DRLGVersion);
return null;
}
else
{
Logger.Warn("DRLG-Emu v{2} - World - {0} [{1}] is dynamic! DRLG Engine can't find container! Template system is started.", worldAsset.Name, worldAsset.SNOId, DRLGVersion);
if (world.worldData.DRLGParams != null)
{
world.NextLocation = new MessageSystem.Message.Fields.ResolvedPortalDestination
{
WorldSNO = world.worldData.DRLGParams[0].NextWorld,
DestLevelAreaSNO = world.worldData.DRLGParams[0].NextLevelArea,
StartingPointActorTag = world.worldData.DRLGParams[0].NextStartingPoint
};
world.PrevLocation = new MessageSystem.Message.Fields.ResolvedPortalDestination
{
WorldSNO = world.worldData.DRLGParams[0].PrevWorld,
DestLevelAreaSNO = world.worldData.DRLGParams[0].PrevLevelArea,
StartingPointActorTag = world.worldData.DRLGParams[0].PrevStartingPoint
};
}
else
{
Logger.Warn("DRLG-Emu v{2} - World - {0} [{1}] is dynamic! DRLG Engine can't find container! Template system is not configured for this world.", worldAsset.Name, worldAsset.SNOId, DRLGVersion);
return null;
}
}
}
else
{
world.PrevLocation = new MessageSystem.Message.Fields.ResolvedPortalDestination
{
WorldSNO = (int)WorldSno.__NONE,
DestLevelAreaSNO = -1,
StartingPointActorTag = -1
};
}
if (DRLGEmuActive)
{
List<List<DRLGEmuScene>> containers = new List<List<DRLGEmuScene>> { };
List<DRLGEmuScene> enterChunks = new List<DRLGEmuScene> { };
List<DRLGEmuScene> exitChunks = new List<DRLGEmuScene> { };
List<DRLGEmuScene> wayChunks = new List<DRLGEmuScene> { };
List<DRLGEmuScene> endChunks = new List<DRLGEmuScene> { };
List<DRLGEmuScene> fillerChunks = new List<DRLGEmuScene> { };
var WorldContainer = DBSessions.WorldSession.Query<DRLG_Container>().Where(dbt => dbt.WorldSNO == (int)world.SNO).First();
var tiles = DBSessions.WorldSession.Query<DRLG_Tile>().Where(dbt => dbt.Head_Container == (int)WorldContainer.Id).ToList();
REP:
tiles = DBSessions.WorldSession.Query<DRLG_Tile>().Where(dbt => dbt.Head_Container == (int)WorldContainer.Id).ToList();
//All Scenes
foreach (var Tile in tiles)
{
switch (Tile.Type)
{
case 0: //enter
enterChunks.Add(new DRLGEmuScene(Tile.SNOHandle_Id, Tile.SNOWeather, Tile.SNOMusic, Tile.SNOLevelArea));
break;
case 1: //exits
exitChunks.Add(new DRLGEmuScene(Tile.SNOHandle_Id, Tile.SNOWeather, Tile.SNOMusic, Tile.SNOLevelArea));
break;
case 2: //way
wayChunks.Add(new DRLGEmuScene(Tile.SNOHandle_Id, Tile.SNOWeather, Tile.SNOMusic, Tile.SNOLevelArea));
break;
case 3: //dead ends
endChunks.Add(new DRLGEmuScene(Tile.SNOHandle_Id, Tile.SNOWeather, Tile.SNOMusic, Tile.SNOLevelArea));
break;
case 4: //fillers
fillerChunks.Add(new DRLGEmuScene(Tile.SNOHandle_Id, Tile.SNOWeather, Tile.SNOMusic, Tile.SNOLevelArea));
break;
}
}
containers.Add(enterChunks);
containers.Add(exitChunks);
containers.Add(wayChunks);
containers.Add(endChunks);
containers.Add(fillerChunks);
if (world.SNO.IsGenerated())
while (true)
{
DRLGGenerateProcess(world, containers, fillerChunks, WorldContainer.RangeofScenes);
if (world.worldData.SceneParams.ChunkCount > 15)
break;
}
else
{
try
{
DRLGGenerateProcess(world, containers, fillerChunks, WorldContainer.RangeofScenes);
}
catch
{
Logger.Info("DRLG generator found an error in the calculation, repeat.");
goto REP;
}
}
Logger.Info("DRLG work - Completed");
}
var clusters = new Dictionary<int, SceneCluster>();
if (world.worldData.SceneClusterSet != null)
{
foreach (var cluster in world.worldData.SceneClusterSet.SceneClusters)
clusters[cluster.ClusterId] = cluster;
}
float minX = 0.0f;
float minY = 0.0f;
minX = world.worldData.SceneParams.SceneChunks.Min(x => x.PRTransform.Vector3D.X);
minY = world.worldData.SceneParams.SceneChunks.Min(x => x.PRTransform.Vector3D.Y);
var clusterCount = new Dictionary<int, int>();
foreach (var sceneChunk in world.worldData.SceneParams.SceneChunks)
{
var cID = sceneChunk.SceneSpecification.ClusterID;
if (cID != -1 && clusters.ContainsKey(cID))
{
if (!clusterCount.ContainsKey(cID))
clusterCount[cID] = 0;
clusterCount[cID]++;
}
}
// For each cluster generate a list of randomly selected subcenes /fasbat
var clusterSelected = new Dictionary<int, List<SubSceneEntry>>();
foreach (var cID in clusterCount.Keys)
{
var selected = new List<SubSceneEntry>();
clusterSelected[cID] = selected;
var count = clusterCount[cID];
foreach (var group in clusters[cID].SubSceneGroups) // First select from each subscene group /fasbat
{
for (int i = 0; i < group.I0 && count > 0; i++, count--) //TODO Rename I0 to requiredCount? /fasbat
{
var subSceneEntry = RandomHelper.RandomItem(group.Entries, entry => entry.Probability);
selected.Add(subSceneEntry);
}
if (count == 0)
break;
}
while (count > 0) // Fill the rest with defaults /fasbat
{
//Default subscenes are not currently stored in db, use first if available
//var subSceneEntry = RandomHelper.RandomItem(clusters[cID].Default.Entries, entry => entry.Probability);
if (clusters[cID].SubSceneGroups.Count > 0)
{
var subSceneEntry = RandomHelper.RandomItem(clusters[cID].SubSceneGroups.First().Entries, entry => entry.Probability);
selected.Add(subSceneEntry);
}
count--;
}
}
if (!(world.IsPvP && World.PvPMapLoaded))
foreach (var sceneChunk in world.worldData.SceneParams.SceneChunks)
{
var position = sceneChunk.PRTransform.Vector3D - new Vector3D(minX, minY, 0);
var scene = new Scene(world, position, sceneChunk.SNOHandle.Id, null)
{
MiniMapVisibility = (world.Game.PvP || world.IsPvP),
RotationW = sceneChunk.PRTransform.Quaternion.W,
RotationAxis = sceneChunk.PRTransform.Quaternion.Vector3D,
SceneGroupSNO = -1,
Specification = sceneChunk.SceneSpecification,
TileType = sceneChunk.SceneSpecification.OnPathBits
};
if (sceneChunk.SceneSpecification.ClusterID != -1)
{
if (!clusters.ContainsKey(sceneChunk.SceneSpecification.ClusterID))
{
Logger.Trace("Referenced clusterID {0} not found for chunk {1} in world {2}", sceneChunk.SceneSpecification.ClusterID, sceneChunk.SNOHandle.Id, worldSNO);
}
else
{
var entries = clusterSelected[sceneChunk.SceneSpecification.ClusterID];
if (entries.TryPickRandom(out var subSceneEntry))
{
entries.Remove(subSceneEntry);
}
else
Logger.Error("No SubScenes defined for cluster {0} in world {1}", sceneChunk.SceneSpecification.ClusterID, world.GlobalID);
Vector3D pos = FindSubScenePosition(sceneChunk);
if (pos == null)
{
Logger.Error("No scene position marker for SubScenes of Scene {0} found", sceneChunk.SNOHandle.Id);
}
else
{
if (subSceneEntry != null)
{
if (MPQStorage.Data.Assets[SNOGroup.Scene].ContainsKey(subSceneEntry.SNOScene))
{
var subScenePosition = scene.Position + pos;
var subscene = new Scene(world, subScenePosition, subSceneEntry.SNOScene, scene)
{
MiniMapVisibility = false,
RotationW = sceneChunk.PRTransform.Quaternion.W,
RotationAxis = sceneChunk.PRTransform.Quaternion.Vector3D,
Specification = sceneChunk.SceneSpecification
};
scene.Subscenes.Add(subscene);
subscene.LoadMarkers();
}
else
{
Logger.Error("Scene not found in mpq storage: {0}", subSceneEntry.SNOScene);
}
}
}
}
}
scene.LoadMarkers();
// add scene to level area dictionary
foreach (var levelArea in scene.Specification.SNOLevelAreas)
{
if (levelArea != -1)
{
if (!levelAreas.ContainsKey(levelArea))
levelAreas.Add(levelArea, new List<Scene>());
levelAreas[levelArea].Add(scene);
}
}
}
if (world.IsPvP)
World.PvPMapLoaded = true;
//world.LevelAreasData = levelAreas;
if (worldSNO == WorldSno.a1trdun_level05_templar)
world.SpawnMonster(ActorSno._waypoint, new Vector3D { X = 700.67f, Y = 580.128f, Z = 0.1f });
try
{
if (!world.IsPvP)
LoadLevelAreas(levelAreas, world);
}
catch (Exception e)
{
Logger.WarnException(e, "loadLevelAreas exception: ");
}
#region patches
switch (worldSNO)
{
case WorldSno.x1_pand_ext_2_battlefields: //x1_pand_ext_2_battlefields
RandomSpawnInWorldWithLevelArea(world, ActorSno._x1_pandext_siegerune);
RandomSpawnInWorldWithLevelArea(world, ActorSno._x1_pandext_siegerune);
break;
case WorldSno.x1_westm_zone_03:
RandomSpawnInWorldWithLevelArea(world, ActorSno._x1_deathmaiden_unique_fire_a);
RandomSpawnInWorldWithLevelArea(world, ActorSno._x1_deathmaiden_unique_fire_a);
RandomSpawnInWorldWithLevelArea(world, ActorSno._x1_deathmaiden_unique_fire_a);
break;
case WorldSno.trdun_leoric_level03: //Setting portal to the third floor of the Agony's Halls near the entrance to the Butcher.
Vector3D Scene0Pos = world.GetSceneBySnoId(78824).Position;
world.SpawnMonster(ActorSno._waypoint, new Vector3D(Scene0Pos.X + 149.0907f, Scene0Pos.Y + 106.7075f, Scene0Pos.Z));
break;
case WorldSno.x1_westm_graveyard_deathorb:
FilterWaypoints(world);
break;
case WorldSno.x1_lr_tileset_hexmaze:
foreach (var actor in world.GetActorsBySNO(
ActorSno._x1_pand_hexmaze_en_lore_sister1_chest,
ActorSno._x1_pand_hexmaze_en_lore_sister2_chest,
ActorSno._x1_pand_hexmaze_en_lore_sister3_chest,
ActorSno._x1_pand_hexmaze_en_enchantress
)) actor.Destroy();
break;
case WorldSno.trout_town: //mercenary
var templar = world.GetActorBySNO(ActorSno._templar);
var hasmalth = world.GetActorBySNO(ActorSno._x1_malthael_npc);
if (hasmalth == null)
{
ActorSystem.Implementations.Hirelings.MalthaelHireling malthaelHire = new ActorSystem.Implementations.Hirelings.MalthaelHireling(world, ActorSno._x1_malthael_npc_nocollision, templar.Tags)
{
RotationAxis = new Vector3D(0f, 0f, 0.4313562f),
RotationW = 0.9021817f,
Attributes =
{
[GameAttribute.Team_Override] = 2
}
};
malthaelHire.EnterWorld(new Vector3D(3017.266f, 2851.986f, 24.04533f));
}
foreach (var door in world.GetActorsBySNO(ActorSno._house_door_trout_newtristram))
door.Destroy();
if (Game.CurrentAct == 3000)
{
var TownDoor = world.GetActorBySNO(ActorSno._trout_newtristram_gate_town);
TownDoor.Attributes[GameAttribute.Team_Override] = 2;
TownDoor.Attributes[GameAttribute.Untargetable] = true;
TownDoor.Attributes[GameAttribute.NPC_Is_Operatable] = false;
TownDoor.Attributes[GameAttribute.Operatable] = false;
TownDoor.Attributes[GameAttribute.Operatable_Story_Gizmo] = false;
TownDoor.Attributes[GameAttribute.Disabled] = true;
TownDoor.Attributes[GameAttribute.Immunity] = true;
TownDoor.Attributes.BroadcastChangedIfRevealed();
}
break;
case WorldSno.a1trdun_level04: //Cathedral Level 2
foreach (var actor in world.GetActorsBySNO(ActorSno._g_portal_townportal_red))
{
foreach (var sp in actor.GetActorsInRange<StartingPoint>(20f)) sp.Destroy();
actor.Destroy(); //g_Portal_TownPortal_Red
}
break;
case WorldSno.a1trdun_level06: //Cathedral Level 4
foreach (var actor in world.GetActorsBySNO(ActorSno._g_portal_townportal_red))
{
foreach (var sp in actor.GetActorsInRange<StartingPoint>(20f)) sp.Destroy();
actor.Destroy(); //g_Portal_TownPortal_Red
}
break;
case WorldSno.a1trdun_level05_templar: //Cathedral Level 3
foreach (var actor in world.GetActorsBySNO(
ActorSno._x1_mysticintro_npc,
ActorSno._tristramfemale,
ActorSno._omninpc_tristram_male_e,
ActorSno._x1_lore_mysticnotes,
ActorSno._a1_uniquevendor_armorer
)) actor.Destroy();
foreach (var actor in world.GetActorsBySNO(ActorSno._g_portal_townportal_red))
{
foreach (var sp in actor.GetActorsInRange<StartingPoint>(20f)) sp.Destroy();
actor.Destroy(); //g_Portal_TownPortal_Red
}
break;
case WorldSno.a2dun_swr_swr_to_oasis_level01: //kill useless portal in location if game not in adventure mode
if (Game.CurrentAct != 3000)
foreach (var waypoint in world.GetActorsBySNO(ActorSno._waypoint)) waypoint.Destroy();
break;
case WorldSno.a2dun_zolt_head_random01: //remove blood pool
foreach (var act in world.GetActorsBySNO(ActorSno._a2dun_zolt_blood_container_02)) act.Destroy();
break;
case WorldSno.a2dun_aqd_special_01: //Main Drain. Remove useless portals.
foreach (var port in world.Actors.Values)
if (port is Portal portal)
if (portal.Destination.WorldSNO == (int)WorldSno.a2dun_aqd_special_b_level01)
portal.Destroy();
break;
case WorldSno.a3dun_keep_level04: //kill useless portal in location if game not in adventure mode
if (Game.CurrentAct != 3000)
foreach (var waypoint in world.GetActorsBySNO(ActorSno._waypoint)) waypoint.Destroy();
break;
#region kill all portals in demonic rifts on the first floor of the gardens (now and on the second floor), because there are a lot of them), the script will create a script to destroy the demon. Add the voice of Diablo to several areas;
case WorldSno.a4dun_garden_of_hope_01: //1st floor of the gardens
foreach (var hellPortal in world.GetActorsBySNO(ActorSno._a4_heaven_gardens_hellportal))
hellPortal.Destroy();
break;
case WorldSno.a4dun_garden_of_hope_random: //2nd floor of the gardens
foreach (var hellPortal in world.GetActorsBySNO(ActorSno._a4_heaven_gardens_hellportal))
hellPortal.Destroy();
break;
#endregion
case WorldSno.a4dun_spire_level_00:
var leahGhost = world.SpawnMonster(ActorSno._a4dun_aspect_ghost_07, new Vector3D(570f, 570f, 0.1f)) as InteractiveNPC;
leahGhost.Conversations.Clear();
leahGhost.Conversations.Add(new ConversationInteraction(198600));
leahGhost.Attributes[GameAttribute.Conversation_Icon, 0] = 6;
leahGhost.Attributes.BroadcastChangedIfRevealed();
break;
//428f, 836f, -20.3f
case WorldSno.a4dun_spire_level_01:
var zoltunGhost = world.SpawnMonster(ActorSno._a4dun_aspect_ghost_02, new Vector3D(428f, 836f, -2f)) as InteractiveNPC;
zoltunGhost.Conversations.Clear();
zoltunGhost.Conversations.Add(new ConversationInteraction(198402));
zoltunGhost.Attributes[GameAttribute.Conversation_Icon, 0] = 6;
zoltunGhost.Attributes.BroadcastChangedIfRevealed();
break;
case WorldSno.a3dun_ruins_frost_city_a_02:
foreach (var waypoint in world.GetActorsBySNO(ActorSno._waypoint)) waypoint.Destroy();
break;
case WorldSno.p43_ad_oldtristram:
foreach (var waypoint in world.GetActorsBySNO(ActorSno._trout_oldtristram_exit_gate)) waypoint.Destroy();
break;
case WorldSno.x1_tristram_adventure_mode_hub:
//Display only one seller
world.ShowOnlyNumNPC(ActorSno._a1_uniquevendor_miner_intown_01, 0);
//Display only one mystic
world.ShowOnlyNumNPC(ActorSno._pt_mystic, 1);
var Door = world.GetActorBySNO(ActorSno._trout_newtristram_gate_town);
Door.Attributes[GameAttribute.Team_Override] = 2;
Door.Attributes[GameAttribute.Untargetable] = true;
Door.Attributes[GameAttribute.NPC_Is_Operatable] = false;
Door.Attributes[GameAttribute.Operatable] = false;
Door.Attributes[GameAttribute.Operatable_Story_Gizmo] = false;
Door.Attributes[GameAttribute.Disabled] = true;
Door.Attributes[GameAttribute.Immunity] = true;
Door.Attributes.BroadcastChangedIfRevealed();
break;
case WorldSno.p43_ad_cathedral_level_01: //1st floor of the cathedral (D1 mode)
case WorldSno.p43_ad_cathedral_level_02: //2nd floor of the cathedral (D1 mode)
case WorldSno.p43_ad_cathedral_level_03: //3rd floor of the cathedral (D1 mode)
case WorldSno.p43_ad_cathedral_level_04: //4th floor of the cathedral (D1 mode)
case WorldSno.p43_ad_catacombs_level_05: //5th floor of the cathedral (D1 mode)
case WorldSno.p43_ad_catacombs_level_06: //6th floor of the cathedral (D1 mode)
case WorldSno.p43_ad_catacombs_level_07: //7th floor of the cathedral (D1 mode)
case WorldSno.p43_ad_catacombs_level_08: //8th floor of the cathedral (D1 mode)
foreach (var actor in world.GetActorsBySNO(d1ModeHiddenActors))
actor.Destroy();
foreach (var actor in world.GetActorsBySNO(ActorSno._g_portal_townportal_red))
{
foreach (var startingPoint in actor.GetActorsInRange<StartingPoint>(20f)) startingPoint.Destroy();
actor.Destroy(); //g_Portal_TownPortal_Red
}
break;
}
#endregion
#region Global patch when generating
foreach (var oldPoint in world.GetActorsBySNO(ActorSno._x1_openworld_lootrunportal, ActorSno._x1_openworld_tiered_rifts_portal,
ActorSno._x1_openworld_tiered_rifts_challenge_portal, ActorSno._x1_westm_bridge_scoundrel))
{
oldPoint.Destroy();
}
foreach (var oldPoint in world.GetActorsBySNO(ActorSno._placedgold)) { foreach(var plr in world.Game.Players.Values) world.SpawnGold(oldPoint, plr); oldPoint.Destroy(); }
if(world.SNO != WorldSno.a1trdun_level05_templar)
foreach (var oldPoint in world.GetActorsBySNO(ActorSno._x1_openworld_tiered_rifts_challenge_portal)) { oldPoint.Destroy(); }//109209 - Bone Walls from the Cathedral
#endregion
return world;
}
public void RandomSpawnInWorldWithLevelArea(World world, ActorSno monsterSno, int levelArea = -1)
{
List<Scene> scenes = world.Scenes.Values.ToList();
if (levelArea != -1) scenes = scenes.Where(sc => sc.Specification.SNOLevelAreas[0] == levelArea && !sc.SceneSNO.Name.ToLower().Contains("filler")).ToList();
else scenes = scenes.Where(sc => !sc.SceneSNO.Name.ToLower().Contains("filler")).ToList();
Vector3D SSV = scenes.PickRandom().Position;
Vector3D startingPoint = null;
while (true)
{
startingPoint = new Vector3D(SSV.X + RandomHelper.Next(0, 240), SSV.Y + RandomHelper.Next(0, 240), SSV.Z);
if (world.CheckLocationForFlag(startingPoint, DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk))
break;
}
world.SpawnMonster(monsterSno, startingPoint);
}
public void FilterWaypoints(World world, int sceneSno = -1)
{
var waypoints = world.GetActorsBySNO(ActorSno._waypoint);
if (sceneSno != -1) waypoints = waypoints.Where(wp => wp.CurrentScene.SceneSNO.Id == sceneSno).ToList();
if (waypoints.Count > 1)
{
int randomPoint = RandomHelper.Next(0, waypoints.Count);
for (int i = 0; i < waypoints.Count; i++)
{
if (i != randomPoint)
waypoints[i].Destroy();
}
}
}
/// <summary>
/// Status of an added exit to world
/// Used when a new tile is needed in a specific place
/// </summary>
public enum ExitStatus
{
Free, //no tile in that direction
Blocked, //"wall" in that direction
Open //"path" in that direction
}
public static void DRLGGenerateProcess(World world, List<List<DRLGEmuScene>> container, List<DRLGEmuScene> fillers, long range)
{
if (world.worldData.SceneParams == null)
world.worldData.CreateNewSceneParams();
world.worldData.SceneParams.SceneChunks.Clear();
List<Vector3D> busyChunks = new List<Vector3D> { };
List<Vector3D> reservedChunks = new List<Vector3D> { };
Dictionary<char[], Vector3D> waitChunks = new Dictionary<char[], Vector3D> { };
Dictionary<char[], Vector3D> nextWaitChunks = new Dictionary<char[], Vector3D> { };
bool hasExit = false;
List<List<DRLGEmuScene>> DRLGContainers = container;
List<DRLGEmuScene> FillerChuncks = fillers;
char currentNav = '.';
DRLGEmuScene currentScene = null;
foreach (var Container in DRLGContainers)
foreach (var Scene in Container)
try
{
Scene.Asset = MPQStorage.Data.Assets[SNOGroup.Scene][Scene.SnoID];
}
catch
{
Logger.Error("Scene {0}, not added on DRLG", Scene.SnoID);
}
bool rift = world.SNO.IsGenerated();
//Getting Enter
var loadedScene = new SceneChunk();
currentScene = DRLGContainers[0].PickRandom();
loadedScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
loadedScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), new Vector3D(0, 0, 0));
loadedScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(loadedScene); //Add Chunk
busyChunks.Add(loadedScene.PRTransform.Vector3D); //Cords Busy
SceneChunk prestScene = loadedScene;
Vector3D placeToNewScene = new Vector3D();
var nextScene = new SceneChunk();
char[] toWaitChunks;
var splits = prestScene.SNOHandle.Name.Split('_');
int positionOfNav = 2;
if (splits[0].ToLower().StartsWith("p43") ||
splits[2].ToLower().Contains("random") ||
splits[2].ToLower().Contains("corrupt"))
positionOfNav = 3;
else if (prestScene.SNOHandle.Name.StartsWith("x1_Pand"))
positionOfNav = 4;
int RangetoNext = (int)range;
//First Switch
switch (prestScene.SNOHandle.Name.Split('_')[positionOfNav])
{
case "S":
currentNav = 'N';
while (true)
{
if (prestScene.SNOHandle.Name.StartsWith("x1_Pand"))
positionOfNav = 3;
currentScene = DRLGContainers[2].PickRandom();
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
break;
}
placeToNewScene = new Vector3D(prestScene.PRTransform.Vector3D.X + RangetoNext, prestScene.PRTransform.Vector3D.Y, prestScene.PRTransform.Vector3D.Z);
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var Point in toWaitChunks)
if (Point != currentNav)
switch (Point)
{
//Куда застраивать в названии
//S - Строить направо +240:0
//N - Строить налево -240:0
//E - Строить вверх 0:+240
//W - Строить вниз 0:-240
case 'S': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'N': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'E': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
case 'W': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
nextScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
nextScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
nextScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(nextScene); //Add scene
busyChunks.Add(nextScene.PRTransform.Vector3D); //Occupy cell
prestScene = nextScene;
break;
case "N":
currentNav = 'S';
while (true)
{
if (prestScene.SNOHandle.Name.StartsWith("x1_Pand"))
positionOfNav = 3;
currentScene = DRLGContainers[2].PickRandom();
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
break;
}
placeToNewScene = new Vector3D(prestScene.PRTransform.Vector3D.X - RangetoNext, prestScene.PRTransform.Vector3D.Y, prestScene.PRTransform.Vector3D.Z);
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var point in toWaitChunks)
if (point != currentNav)
switch (point)
{
//S - build to the right +240:0
case 'S': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//N - build to the left -240:0
case 'N': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//E - build up 0:+240
case 'E': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
//W - build down 0:-240
case 'W': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
nextScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
nextScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
nextScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(nextScene); //Добавить сцену
busyChunks.Add(nextScene.PRTransform.Vector3D); //Занять клетку
prestScene = nextScene;
break;
case "E":
currentNav = 'W';
while (true)
{
if (prestScene.SNOHandle.Name.StartsWith("x1_Pand"))
positionOfNav = 3;
currentScene = DRLGContainers[2].PickRandom();
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
break;
}
placeToNewScene = new Vector3D(prestScene.PRTransform.Vector3D.X, prestScene.PRTransform.Vector3D.Y + RangetoNext, prestScene.PRTransform.Vector3D.Z);
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var Point in toWaitChunks)
if (Point != currentNav)
switch (Point)
{
//Куда застраивать в названии
//S - Строить направо +240:0
//N - Строить налево -240:0
//E - Строить вверх 0:+240
//W - Строить вниз 0:-240
case 'S': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'N': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'E': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
case 'W': waitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
nextScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
nextScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
nextScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(nextScene); //Добавить сцену
busyChunks.Add(nextScene.PRTransform.Vector3D); //Занять клетку
prestScene = nextScene;
break;
case "W":
currentNav = 'E';
while (true)
{
if (prestScene.SNOHandle.Name.StartsWith("x1_Pand"))
positionOfNav = 3;
currentScene = DRLGContainers[2].PickRandom();
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
break;
}
placeToNewScene = new Vector3D(prestScene.PRTransform.Vector3D.X, prestScene.PRTransform.Vector3D.Y - RangetoNext, prestScene.PRTransform.Vector3D.Z);
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var point in toWaitChunks)
if (point != currentNav)
switch (point)
{
//S - Build to the right +240:0
case 'S': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//N - Build to the left -240:0
case 'N': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//E - Build up 0:+240
case 'E': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
//W - Build down 0:-240
case 'W': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
nextScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
nextScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
nextScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(nextScene); // add scene
busyChunks.Add(nextScene.PRTransform.Vector3D); //occupy cell
prestScene = nextScene;
break;
case "EW":
var nextscene1 = new SceneChunk();
currentNav = 'E';
while (true)
{
currentScene = DRLGContainers[2].PickRandom();
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
break;
}
placeToNewScene = new Vector3D(prestScene.PRTransform.Vector3D.X, prestScene.PRTransform.Vector3D.Y - RangetoNext, prestScene.PRTransform.Vector3D.Z);
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var point in toWaitChunks)
if (point != currentNav)
switch (point)
{
//S - Build to the right +240:0
case 'S': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//N - Build to the left -240:0
case 'N': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//E - Build up 0:+240
case 'E': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
//W - Build down 0:-240
case 'W': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
nextscene1.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
nextscene1.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
nextscene1.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(nextscene1); //Добавить сцену
busyChunks.Add(nextscene1.PRTransform.Vector3D); //Занять клетку
currentNav = 'W';
while (true)
{
currentScene = DRLGContainers[2].PickRandom();
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
break;
}
placeToNewScene = new Vector3D(prestScene.PRTransform.Vector3D.X, prestScene.PRTransform.Vector3D.Y + RangetoNext, prestScene.PRTransform.Vector3D.Z);
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var point in toWaitChunks)
if (point != currentNav)
switch (point)
{
//S - Build to the right +240:0
case 'S': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//N - Build to the left -240:0
case 'N': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//E - Build up 0:+240
case 'E': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
//W - Build down 0:-240
case 'W': waitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
nextScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
nextScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
nextScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(nextScene); //Добавить сцену
busyChunks.Add(nextScene.PRTransform.Vector3D); //Занять клетку
prestScene = nextScene;
break;
}
int DRLGDeep = 5;
if (rift)
DRLGDeep = 20;
//Deep and exits
for (int i = 0; i <= DRLGDeep; i++)
{
foreach (var waitedScene in waitChunks)
{
var newScene = new SceneChunk();
switch (waitedScene.Key[0])
{
case 'S':
currentNav = 'N';
while (true)
{
if (i > DRLGDeep - 1)
{
if (hasExit)
{
currentScene = DRLGContainers[3].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
else
{
currentScene = DRLGContainers[1].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav)) //Exit
{
hasExit = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
else
{
currentScene = DRLGContainers[2].PickRandom();
#region проверка на будущее
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
bool ForceStop = false;
foreach (var point in toWaitChunks)
if (point != waitedScene.Key[0])
switch (point)
{
//S - Build to the right
case 'S':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
//N - Build to the left
case 'N':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
//E - Build up
case 'E':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
//W - Build down
case 'W':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
}
#endregion
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
else if (ForceStop)
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
placeToNewScene = waitedScene.Value;
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var point in toWaitChunks)
if (point != currentNav)
switch (point)
{
//S - Build right +240:0
case 'S': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//N - Build left -240:0
case 'N': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
//E - Build up 0:+240
case 'E': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
//W - Build down 0:-240
case 'W': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
newScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
newScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
newScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(newScene); //Добавить сцену
busyChunks.Add(newScene.PRTransform.Vector3D); //Занять клетку
prestScene = newScene;
break;
case 'N':
currentNav = 'S';
while (true)
{
if (i > DRLGDeep - 1)
{
if (hasExit)
{
currentScene = DRLGContainers[3].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
else
{
currentScene = DRLGContainers[1].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav)) //Exit
{
hasExit = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
else
{
currentScene = DRLGContainers[2].PickRandom();
#region проверка на будущее
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
bool forceStop = false;
foreach (var point in toWaitChunks)
if (point != waitedScene.Key[0])
switch (point)
{
//S - Build to the right +240:0
case 'S':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
forceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
//N - Build to the left -240:0
case 'N':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
forceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
//E - Build up 0:+240
case 'E':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
forceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
//W - Build down 0:-240
case 'W':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;// else PosOfNav = 3;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
forceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
}
#endregion
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
else if (forceStop)
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
placeToNewScene = waitedScene.Value;
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var Point in toWaitChunks)
if (Point != currentNav)
switch (Point)
{
//S - Build to the right +240:0
//N - Build to the left -240:0
//E - Build up 0:+240
//W - Build down 0:-240
case 'S': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'N': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'E': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
case 'W': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
newScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
newScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
newScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(newScene); //Добавить сцену
busyChunks.Add(newScene.PRTransform.Vector3D); //Занять клетку
prestScene = newScene;
break;
case 'E':
currentNav = 'W';
while (true)
{
if (i > DRLGDeep - 1)
{
if (hasExit)
{
currentScene = DRLGContainers[3].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
else
{
currentScene = DRLGContainers[1].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav)) //Exit
{
hasExit = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
else
{
currentScene = DRLGContainers[2].PickRandom();
#region проверка на будущее
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
bool ForceStop = false;
foreach (var Point in toWaitChunks)
if (Point != waitedScene.Key[0])
switch (Point)
{
//S - Build to the right +240:0
//N - Build to the left -240:0
//E - Build up 0:+240
//W - Build down 0:-240
case 'S':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom();//CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
case 'N':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom();//CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
case 'E':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
case 'W':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
}
#endregion
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
else if (ForceStop)
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
placeToNewScene = waitedScene.Value;
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var Point in toWaitChunks)
if (Point != currentNav)
switch (Point)
{
//S - Build to the right +240:0
//N - Build to the left -240:0
//E - Build up 0:+240
//W - Build down 0:-240
case 'S': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'N': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'E': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
case 'W': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
newScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
newScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
newScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(newScene); //Add scene
busyChunks.Add(newScene.PRTransform.Vector3D); //occupy the cell
prestScene = newScene;
break;
case 'W':
currentNav = 'E';
while (true)
{
if (i > DRLGDeep - 1)
{
if (hasExit)
{
currentScene = DRLGContainers[3].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
else
{
currentScene = DRLGContainers[1].PickRandom();
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav)) //Exit
{
hasExit = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
else
{
currentScene = DRLGContainers[2].PickRandom();
#region проверка на будущее
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
bool ForceStop = false;
foreach (var Point in toWaitChunks)
if (Point != waitedScene.Key[0])
switch (Point)
{
//S - Build to the right +240:0
//N - Build to the left -240:0
//E - Build up 0:+240
//W - Build down 0:-240
case 'S':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
case 'N':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
case 'E':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
case 'W':
if (busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)) ||
(reservedChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))))
while (true)
{
currentScene = DRLGContainers[3].PickRandom(); // CurrentScene Switch
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length == 1) //End
{
ForceStop = true;
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
break;
}
#endregion
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 4;
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(currentNav) & currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray().Length > 1) //Way
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
else if (ForceStop)
{
if (currentScene.Asset.Name.ToLower().Contains("hexmaze_edge") || currentScene.Asset.Name.ToLower().Contains("hexmaze_exit")) positionOfNav = 3;
break;
}
}
}
placeToNewScene = waitedScene.Value;
toWaitChunks = currentScene.Asset.Name.Split('_')[positionOfNav].ToCharArray();
foreach (var Point in toWaitChunks)
if (Point != currentNav)
switch (Point)
{
//S - Build to the right +240:0
//N - Build to the left -240:0
//E - Build up 0:+240
//W - Build down 0:-240
case 'S': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X + RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'N': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X - RangetoNext, placeToNewScene.Y, placeToNewScene.Z)); break;
case 'E': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y + RangetoNext, placeToNewScene.Z)); break;
case 'W': if (!busyChunks.Contains(new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z))) nextWaitChunks.Add(Point.ToString().ToArray(), new Vector3D(placeToNewScene.X, placeToNewScene.Y - RangetoNext, placeToNewScene.Z)); break;
}
newScene.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
newScene.PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), placeToNewScene);
newScene.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
world.worldData.SceneParams.SceneChunks.Add(newScene); //Add scene
busyChunks.Add(newScene.PRTransform.Vector3D); //occupy the cell
prestScene = newScene;
break;
}
}
waitChunks.Clear();
foreach (var nextChunk in nextWaitChunks)
{
bool unique = true;
//we don't put scene on scene!
foreach (var busyChunk in busyChunks) //check already created
if (nextChunk.Value == busyChunk)
unique = false;
foreach (var reservedChunk in reservedChunks)
if (nextChunk.Value == reservedChunk) //check reserve
unique = false;
if (unique)
{
reservedChunks.Add(nextChunk.Value);
waitChunks.Add(nextChunk.Key, nextChunk.Value);
}
}
nextWaitChunks.Clear();
reservedChunks.Clear();
}
//Force Check Exit
if (!hasExit)
{
bool first = false;
bool finish = false;
var newSceneChunk = new SceneChunk();
foreach (var chunk in world.worldData.SceneParams.SceneChunks)
{
if (!hasExit)
{
//skip first chunk
if (!first) { first = true; continue; }
//we start to find dead ends
//if (CurrentScene.Asset.Name.Split('_')[PosOfNav].Contains(CurrentNav) & CurrentScene.Asset.Name.Split('_')[PosOfNav].ToCharArray().Length == 1) //Way
if (chunk.SNOHandle.Name.Split('_')[positionOfNav].ToCharArray().Length == 1)
{
char Nav = chunk.SNOHandle.Name.Split('_')[positionOfNav].ToCharArray()[0];
while (true)
{
currentScene = DRLGContainers[1].PickRandom();
if (currentScene.Asset.Name.Split('_')[positionOfNav].Contains(Nav)) //Exit
{
hasExit = true;
break;
}
}
newSceneChunk.SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID);
newSceneChunk.PRTransform = chunk.PRTransform;
newSceneChunk.SceneSpecification = new SceneSpecification(
0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1,
new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)),
new int[4] { 0, 0, 0, 0 }, 0));
finish = true;
}
}
if (finish)
{
//premature completion and adding an exit
world.worldData.SceneParams.SceneChunks.Add(newSceneChunk); //Add scene
world.worldData.SceneParams.SceneChunks.Remove(chunk);
break;
}
}
}
//Forming Range
float chunkMinX = -480;
float chunkMaxX = 0;
float chunkMinY = -480;
float chunkMaxY = 0;
foreach (var chunk in world.worldData.SceneParams.SceneChunks)
{
if (chunk.PRTransform.Vector3D.X > chunkMaxX) chunkMaxX = chunk.PRTransform.Vector3D.X;
if (chunk.PRTransform.Vector3D.Y > chunkMaxY) chunkMaxY = chunk.PRTransform.Vector3D.Y;
}
chunkMaxX += RangetoNext;
chunkMaxY += RangetoNext;
//Fillers
List<SceneChunk> FillerChunks = new List<SceneChunk>();
if (FillerChuncks.Count > 0)
{
float x = chunkMinX;
float y = chunkMinY;
while (x < chunkMaxX)
{
float returnToMinY = chunkMinY;
while (y < chunkMaxY)
{
bool busy = false;
foreach (var chunk in world.worldData.SceneParams.SceneChunks)
if (Math.Abs(chunk.PRTransform.Vector3D.X - x) < 0.001 & Math.Abs(chunk.PRTransform.Vector3D.Y - y) < 0.001)
{
busy = true;
break;
}
if (!busy)
{
currentScene = DRLGContainers[4].PickRandom();
var newscene = new SceneChunk
{
SNOHandle = new SNOHandle(SNOGroup.Scene, currentScene.SnoID),
PRTransform = new PRTransform(new Quaternion(new Vector3D(0f, 0f, 0f), 1), new Vector3D(x, y, 0)),
SceneSpecification = new SceneSpecification(0, new Vector2D(0, 0), new int[4] { rift ? world.SNO != world.Game.WorldOfPortalNephalem ? 288684 : 288482 : currentScene.LevelArea, rift ? currentScene.LevelArea : -1, -1, -1 },
-1, -1, -1, -1, -1, -1, currentScene.Music, -1, -1, -1, currentScene.Weather, -1, -1, -1, -1, -1, new SceneCachedValues(-1, -1, -1, new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new AABB(new Vector3D(-1, -1, -1), new Vector3D(-1, -1, -1)), new int[4] { 0, 0, 0, 0 }, 0))
};
FillerChunks.Add(newscene);
}
busy = false;
y += RangetoNext;
}
y = returnToMinY;
x += RangetoNext;
}
}
world.worldData.SceneParams.ChunkCount = world.worldData.SceneParams.SceneChunks.Count;
foreach (var fil in FillerChunks)
{
world.worldData.SceneParams.SceneChunks.Add(fil); //Add scene
}
world.DRLGEmuActive = true;
}
private bool GenerateRandomDungeon(WorldSno worldSNO, DiIiS_NA.Core.MPQ.FileFormats.World worldData)
{
//if ((worldData.DRLGParams == null)||(worldData.DRLGParams.Count == 0))
//return false;
if (worldData.SceneParams == null)
{
worldData.SceneParams = new SceneParams()
{
ChunkCount = 0 ,
SceneChunks = new List<SceneChunk>()
{
}
};
}
worldData.SceneParams.ChunkCount = 0;
worldData.SceneParams.SceneChunks.Clear();
Dictionary<int, TileInfo> tiles = new Dictionary<int, TileInfo>();
Logger.Debug("Generating random world: {0}", worldSNO);
//Each DRLGParam is a level
if ((worldData.DRLGParams != null) && (worldData.DRLGParams.Count > 0))
for (int paramIndex = 0; paramIndex < worldData.DRLGParams.Count; paramIndex++)
{
var drlgparam = worldData.DRLGParams[paramIndex];
//Logger.Debug("DRLGParams: LevelArea: {0}", drlgparam.LevelArea);
foreach (var tile in drlgparam.Tiles)
{
Logger.Trace("RandomGeneration: TileType: {0}", (TileTypes)tile.TileType);
tiles.Add(tile.SNOScene, tile);
}
TileInfo entrance = new TileInfo();
//HACK for Defiled Crypt as there is no tile yet with type 200. Maybe changing in DB would make more sense than putting this hack in
// [11]: {[161961, Mooege.Common.MPQ.MPQAsset]}Worlds\\a1trDun_Cave_Old_Ruins_Random01.wrl
if (worldSNO == WorldSno.a1trdun_cave_old_ruins_random01)
{
entrance = tiles[131902];
tiles.Remove(131902);
}
else
entrance = GetTileInfo(tiles, TileTypes.Entrance);
Dictionary<Vector3D, TileInfo> worldTiles = new Dictionary<Vector3D, TileInfo>();
if (DRLGTemplate.Templates.ContainsKey(worldSNO))
{
DRLGTemplate.DRLGLayout world_layout = DRLGTemplate.Templates[worldSNO].PickRandom();
int coordY = 0;
foreach (List<int> row in world_layout.map)
{
int coordX = 0;
foreach (int cell in row)
{
if (cell != -1)
{
Vector3D TilePosition = new Vector3D(drlgparam.ChunkSize * (coordY + 1), drlgparam.ChunkSize * (coordX + 1), 0);
if (coordX == world_layout.enterPositionX && coordY == world_layout.enterPositionY)
{
if (cell <= 115)
worldTiles.Add(TilePosition, GetTileInfo(tiles, TileTypes.Entrance, cell));
else
worldTiles.Add(TilePosition, GetTile(tiles, cell));
}
else
if (coordX == world_layout.exitPositionX && coordY == world_layout.exitPositionY)
{
if (cell <= 115)
worldTiles.Add(TilePosition, GetTileInfo(tiles, TileTypes.Exit, cell));
else
worldTiles.Add(TilePosition, GetTile(tiles, cell));
}
else
{
if (cell <= 115)
worldTiles.Add(TilePosition, GetTileInfo(tiles, TileTypes.Normal, cell));
else
worldTiles.Add(TilePosition, GetTile(tiles, cell));
}
}
coordX++;
}
coordY++;
}
}
else
{
Vector3D initialStartTilePosition = new Vector3D(480, 480, 0);
worldTiles.Add(initialStartTilePosition, entrance);
AddAdjacentTiles(worldTiles, entrance, drlgparam.ChunkSize, tiles, 0, initialStartTilePosition);
AddFillers(worldTiles, tiles, drlgparam.ChunkSize);
}
foreach (var tile in worldTiles)
{
AddTile(worldData, tile.Value, tile.Key);
}
//AddFiller
Logger.Debug("RandomGeneration: LevelArea: {0}", drlgparam.LevelArea);
foreach (var chunk in worldData.SceneParams.SceneChunks)
{
if (drlgparam.LevelArea != -1)
{
chunk.SceneSpecification.SNOLevelAreas[0] = drlgparam.LevelArea;
chunk.SceneSpecification.SNOWeather = drlgparam.Weather;
}
if (worldSNO == WorldSno.x1_bog_01) //A5 marsh
{
if (chunk.PRTransform.Vector3D.Y < 960 || chunk.PRTransform.Vector3D.X < 720)
chunk.SceneSpecification.SNOLevelAreas[0] = 258142;
}
}
//ProcessCommands(drlgparam, worldData, paramIndex);
}
//Coordinates are added after selection of tiles and map
//Leave it for Defiler Crypt debugging
//AddTile(world, tiles[132218], new Vector3D(720, 480, 0));
//AddTile(world, tiles[132203], new Vector3D(480, 240, 0));
//AddTile(world, tiles[132263], new Vector3D(240, 480, 0));
//return world;
return true;
}
/// <summary>
/// Adds filler tiles around the world
/// </summary>
/// <param name="worldTiles"></param>
/// <param name="tiles"></param>
private void AddFillers(Dictionary<Vector3D, TileInfo> worldTiles, Dictionary<int, TileInfo> tiles, int chunkSize)
{
Dictionary<Vector3D, TileInfo> fillersToAdd = new Dictionary<Vector3D, TileInfo>();
foreach (var tile in worldTiles)
{
Dictionary<TileExits, Vector3D> adjacentPositions = GetAdjacentPositions(tile.Key, chunkSize);
foreach (var position in adjacentPositions)
{
//Add filler to all free tiles (all exits should have been filled and the blocked ones don't need anything else)
if (GetExitStatus(worldTiles, position.Value, position.Key) == ExitStatus.Free && !worldTiles.ContainsKey(position.Value))
{
//random filler
if (!fillersToAdd.ContainsKey(position.Value))
fillersToAdd.Add(position.Value, GetTileInfo(tiles, 0));
}
}
}
foreach (var tile in fillersToAdd)
{
worldTiles.Add(tile.Key, tile.Value);
}
}
/// <summary>
/// Adds tiles to all exits of a tile
/// </summary>
/// <param name="worldTiles">Contains a list of already added tiles.</param>
/// <param name="tileInfo">Originating tile</param>
/// <param name="tiles">List of tiles to choose from</param>
/// <param name="counter">Contains how many tiles were added. When counter reached it will look for an exit.
/// If exit was not found look for deadend(filler?). </param>
/// <param name="position">Position of originating tile.</param>
/// <param name="x">Originating tile world x position</param>
private int AddAdjacentTiles(Dictionary<Vector3D, TileInfo> worldTiles, TileInfo tileInfo, int chunkSize, Dictionary<int, TileInfo> tiles, int counter, Vector3D position)
{
Logger.Trace("Counter: {0}, ExitDirectionbitsOfGivenTile: {1}", counter, tileInfo.ExitDirectionBits);
var lookUpExits = GetLookUpExitBits(tileInfo.ExitDirectionBits);
Dictionary<TileExits, Vector3D> randomizedExitTypes = GetAdjacentPositions(position, chunkSize, true).Where(exit => (lookUpExits & (int)exit.Key) > 0 && !worldTiles.ContainsKey(exit.Value)).ToDictionary(pair => pair.Key, pair => pair.Value);
//add adjacent tiles for each randomized direction
//var lastExit = randomizedExitTypes.Last();
foreach (var exit in randomizedExitTypes)
{
if (worldTiles.ContainsKey(exit.Value)) continue;
worldTiles.Add(exit.Value, null);
if (exit.Key == randomizedExitTypes.Last().Key) //continuing passage
counter = AddadjacentTileAtExit(worldTiles, tiles, chunkSize, counter, exit.Value, false);
else
counter = AddadjacentTileAtExit(worldTiles, tiles, chunkSize, counter, exit.Value, true);
}
return counter;
}
private bool CheckAdjacentTiles(Dictionary<Vector3D, TileInfo> worldTiles, TileInfo tileInfo, int chunkSize, Dictionary<int, TileInfo> tiles, Vector3D position)
{
var lookUpExits = GetLookUpExitBits(tileInfo.ExitDirectionBits);
Dictionary<TileExits, Vector3D> randomizedExitTypes = GetAdjacentPositions(position, chunkSize, true).Where(exit => (lookUpExits & (int)exit.Key) > 0 && !worldTiles.ContainsKey(exit.Value)).ToDictionary(pair => pair.Key, pair => pair.Value);
//add adjacent tiles for each randomized direction
foreach (var exit in randomizedExitTypes)
{
if (GetTileInfo(tiles, (int)TileTypes.Normal, GetAdjacentExitStatus(worldTiles, exit.Value, chunkSize), true) == null) return false;
}
return true;
}
/// <summary>
/// Adds an adjacent tile in the given exit position
/// </summary>
/// <param name="worldTiles"></param>
/// <param name="tiles"></param>
/// <param name="counter"></param>
/// <returns></returns>
private int AddadjacentTileAtExit(Dictionary<Vector3D, TileInfo> worldTiles, Dictionary<int, TileInfo> tiles, int chunkSize, int counter, Vector3D position, bool lookingForCork)
{
TileTypes tileTypeToFind = TileTypes.Normal;
//Find if other exits are in the area of the new tile to add
bool incCounter = true;
if (counter > 30)
{
worldTiles.Remove(position);
return counter;
}
if (lookingForCork) incCounter = false;
Dictionary<TileExits, ExitStatus> exitStatus = GetAdjacentExitStatus(worldTiles, position, chunkSize);
if (counter > 5) //TODO: this value must be set according to difficulty
{
if (!ContainsTileType(worldTiles, TileTypes.Exit))
tileTypeToFind = TileTypes.Exit;
lookingForCork = true;
}
if (tiles.ContainsKey(199783) && counter > 0)
{
lookingForCork = true; //hack for aqueducs deep
}
TileInfo newTile = GetTileInfo(tiles, (int)tileTypeToFind, exitStatus, lookingForCork);
if (tiles.ContainsKey(67021) && tiles.ContainsKey(91612) && !ContainsTileType(worldTiles, TileTypes.EventTile1) && incCounter)
{
newTile = GetTile(tiles, 67021); //hack for Kormac's spawn scene
}
if (tiles.ContainsKey(91612) && counter == 1 && incCounter)
{
newTile = GetTile(tiles, 91612); //hack for Kormac's stash scene
}
if (tiles.ContainsKey(72876) && incCounter)
{
if (!ContainsTileType(worldTiles, TileTypes.EventTile1))
newTile = GetTile(tiles, 72876); //hack for Stonefort: cat 1
if (counter == 1)
newTile = GetTile(tiles, 111118); //hack for Stonefort: corner
if (counter == 2)
newTile = GetTile(tiles, 71341); //hack for Stonefort: cat 2
}
if (tiles.ContainsKey(69230) && counter == 1 && incCounter)
{
newTile = GetTile(tiles, 69230); //hack for ZK archives
}
if (newTile == null)
{
if (tiles.ContainsKey(109296) || tiles.ContainsKey(96987))
newTile = GetTile(tiles, 74907);
else
newTile = GetTileInfo(tiles, (int)TileTypes.Exit, exitStatus, lookingForCork); //trying to find from exits
if (newTile == null)
{
worldTiles.Remove(position);
return counter;
}
}
worldTiles[position] = newTile;
int threshold = 0;
if (!lookingForCork && !tiles.ContainsKey(72876)) //stonefort safe
while (!CheckAdjacentTiles(worldTiles, newTile, chunkSize, tiles, position))
{
newTile = GetTileInfo(tiles, (int)tileTypeToFind, exitStatus, lookingForCork);
worldTiles[position] = newTile;
threshold++;
if (threshold > 10) break;
}
Logger.Trace("Added tile: Type: {0}, SNOScene: {1}, ExitTypes: {2}", newTile.TileType, newTile.SNOScene, newTile.ExitDirectionBits);
counter = AddAdjacentTiles(worldTiles, newTile, chunkSize, tiles, (incCounter ? counter + 1 : counter), position);
return counter;
}
/// <summary>
/// Returns the status of all exits for a specified position
/// </summary>
/// <param name="worldTiles">Tiles already added to world</param>
/// <param name="position">Position</param>
private Dictionary<TileExits, ExitStatus> GetAdjacentExitStatus(Dictionary<Vector3D, TileInfo> worldTiles, Vector3D position, int chunkSize)
{
Dictionary<TileExits, ExitStatus> exitStatusDict = new Dictionary<TileExits, ExitStatus>();
//Compute East adjacent Location
Vector3D positionEast = new Vector3D(position.X + chunkSize, position.Y, position.Z);
ExitStatus exitStatusEast = GetExitStatus(worldTiles, positionEast, TileExits.West);
exitStatusDict.Add(TileExits.East, exitStatusEast);
Vector3D positionWest = new Vector3D(position.X - chunkSize, position.Y, position.Z);
ExitStatus exitStatusWest = GetExitStatus(worldTiles, positionWest, TileExits.East);
exitStatusDict.Add(TileExits.West, exitStatusWest);
Vector3D positionNorth = new Vector3D(position.X, position.Y + chunkSize, position.Z);
ExitStatus exitStatusNorth = GetExitStatus(worldTiles, positionNorth, TileExits.South);
exitStatusDict.Add(TileExits.North, exitStatusNorth);
Vector3D positionSouth = new Vector3D(position.X, position.Y - chunkSize, position.Z);
ExitStatus exitStatusSouth = GetExitStatus(worldTiles, positionSouth, TileExits.North);
exitStatusDict.Add(TileExits.South, exitStatusSouth);
return exitStatusDict;
}
/// <summary>
/// Returns a dictionary of all positions adjacent to a tile
/// </summary>
/// <param name="position"></param>
/// <param name="isRandom"></param>
private Dictionary<TileExits, Vector3D> GetAdjacentPositions(Vector3D position, int chunkSize, bool isRandom = false)
{
Vector3D positionEast = new Vector3D(position.X - chunkSize, position.Y, 0);
Vector3D positionWest = new Vector3D(position.X + chunkSize, position.Y, 0);
Vector3D positionNorth = new Vector3D(position.X, position.Y - chunkSize, 0);
Vector3D positionSouth = new Vector3D(position.X, position.Y + chunkSize, 0);
//get a random direction
Dictionary<TileExits, Vector3D> exitTypes = new Dictionary<TileExits, Vector3D>
{
{ TileExits.East, positionEast },
{ TileExits.West, positionWest },
{ TileExits.North, positionNorth },
{ TileExits.South, positionSouth }
};
if (!isRandom)
return exitTypes;
//randomize
Dictionary<TileExits, Vector3D> randomExitTypes = new Dictionary<TileExits, Vector3D>();
var count = exitTypes.Count;
//Randomise exit directions
for (int i = 0; i < count; i++)
{
//Chose a random exit to test
Vector3D chosenExitPosition = exitTypes.PickRandom().Value;
var chosenExitDirection = (from pair in exitTypes
where pair.Value == chosenExitPosition
select pair.Key).FirstOrDefault();
randomExitTypes.Add(chosenExitDirection, chosenExitPosition);
exitTypes.Remove(chosenExitDirection);
}
return randomExitTypes;
}
private bool ContainsTileType(Dictionary<Vector3D, TileInfo> worldTiles, TileTypes tileType)
{
foreach (var tileInfo in worldTiles)
{
if (tileInfo.Value == null) continue;
if (tileInfo.Value.TileType == (int)tileType) return true;
}
return false;
}
/// <summary>
/// Provides the exit status given position and exit (NSEW)
/// </summary>
/// <param name="worldTiles"></param>
/// <param name="position"></param>
/// <param name="exit"></param>
/// <returns></returns>
private ExitStatus GetExitStatus(Dictionary<Vector3D, TileInfo> worldTiles, Vector3D position, TileExits exit)
{
if (!worldTiles.ContainsKey(position) || worldTiles[position] == null) return ExitStatus.Free;
else
{
//if (worldTiles[position] == null) return ExitStatus.Blocked;
if ((worldTiles[position].ExitDirectionBits & (int)exit) > 0) return ExitStatus.Open;
else return ExitStatus.Blocked;
}
}
/// <summary>
/// Provides what entrances to look-up based on an entrance set of bits
/// N means look for S
/// S means look for N
/// W means look for E
/// E means look for W
/// basically switch first two bits and last two bits
/// </summary>
/// <param name="exitDirectionBits"></param>
/// <returns></returns>
private int GetLookUpExitBits(int exitDirectionBits)
{
return (((exitDirectionBits & ~3) & (int)0x4U) << 1 | ((exitDirectionBits & ~3) & (int)0x8U) >> 1)
+ (((exitDirectionBits & ~12) & (int)0x1U) << 1 | ((exitDirectionBits & ~12) & (int)0x2U) >> 1);
}
/// <summary>
/// Get tileInfo with specific requirements
/// </summary>
/// <param name="tiles"></param>
/// <param name="exitDirectionBits"></param>
/// <param name="tileType"></param>
/// <param name="exitStatus"></param>
/// <returns></returns>
private TileInfo GetTileInfo(Dictionary<int, TileInfo> tiles, int tileType, Dictionary<TileExits, ExitStatus> exitStatus, bool isCork)
{
//get all exits that need to be in the new tile
int mustHaveExits = 0;
Dictionary<int, TileInfo> acceptedTiles = tiles;
foreach (TileExits exit in Enum.GetValues(typeof(TileExits)))
{
if (exitStatus[exit] == ExitStatus.Open) mustHaveExits += (int)exit;
//delete from the pool of tiles those that do have exits that are blocked
if (exitStatus[exit] == ExitStatus.Blocked || (isCork && exitStatus[exit] == ExitStatus.Free))
{
acceptedTiles = acceptedTiles.Where(pair => (pair.Value.ExitDirectionBits & (int)exit) == 0).ToDictionary(pair => pair.Key, pair => pair.Value);
}
}
Logger.Trace("Looking for tile with Exits: {0}", mustHaveExits);
if (isCork)
return GetTileInfo(acceptedTiles
.Where(pair => pair.Value.TileType == tileType)
.ToDictionary(pair => pair.Key, pair => pair.Value), mustHaveExits);
return GetTileInfo(acceptedTiles
.Where(pair => pair.Value.TileType == tileType && !Enum.IsDefined(typeof(TileExits), pair.Value.ExitDirectionBits))
.ToDictionary(pair => pair.Key, pair => pair.Value), mustHaveExits);
}
/// <summary>
/// Returns a tileinfo from a list of tiles that has specific exit directions
/// </summary>
/// <param name="tiles"></param>
/// <param name="exitDirectionBits"></param>
/// <returns></returns>
private TileInfo GetTileInfo(Dictionary<int, TileInfo> tiles, int exitDirectionBits)
{
//if no exit direction bits return filler
if (exitDirectionBits == 0)
{
//return filler
return GetTileInfo(tiles, TileTypes.Filler);
}
List<TileInfo> tilesWithRightDirection = (from pair in tiles where ((pair.Value.ExitDirectionBits & exitDirectionBits) > 0) select pair.Value).ToList();
if (tilesWithRightDirection.Count == 0)
{
Logger.Trace("Did not find matching tile");
//TODO: Never return null. Try to find other tiles that match entry pattern and rotate
//There should be a field that defines if tile can be rotated
return null;
}
return tilesWithRightDirection.PickRandom();
}
private TileInfo GetTile(Dictionary<int, TileInfo> tiles, int snoId)
{
if (!tiles.ContainsKey(snoId)) return null;
return tiles.First(x => x.Key == snoId).Value;
}
/// <summary>
/// Returns a tileinfo from a list of tiles that has a specific type
/// </summary>
/// <param name="tiles"></param>
/// <param name="tileType"></param>
/// <returns></returns>
private TileInfo GetTileInfo(Dictionary<int, TileInfo> tiles, TileTypes tileType)
{
var tilesWithRightType = tiles.Values.Where(tile => tile.TileType == (int)tileType);
return tilesWithRightType.PickRandom();
}
private TileInfo GetTileInfo(Dictionary<int, TileInfo> tiles, TileTypes tileType, int exitDirectionBits)
{
if (exitDirectionBits == 0)
{
//return filler
return GetTileInfo(tiles, TileTypes.Filler);
}
List<TileInfo> tilesWithRightTypeAndDirection;
if (tileType == TileTypes.Normal)
tilesWithRightTypeAndDirection = (from pair in tiles where (pair.Value.TileType is 100 or 101 or 102 && pair.Value.ExitDirectionBits == exitDirectionBits) select pair.Value).ToList<TileInfo>();
else
tilesWithRightTypeAndDirection = (from pair in tiles where (pair.Value.TileType == (int)tileType && pair.Value.ExitDirectionBits == exitDirectionBits) select pair.Value).ToList<TileInfo>();
if (tilesWithRightTypeAndDirection.Any())
return RandomHelper.RandomItem(tilesWithRightTypeAndDirection, entry => entry.Probability);
Logger.Error("Did not find matching tile for template! Type: {0}, Direction: {1}", tileType, exitDirectionBits);
return null;
}
private void AddTile(DiIiS_NA.Core.MPQ.FileFormats.World worldData, TileInfo tileInfo, Vector3D location)
{
var sceneChunk = new SceneChunk
{
SNOHandle = new SNOHandle(tileInfo.SNOScene),
PRTransform = new PRTransform
{
Quaternion = new Quaternion
{
W = 1.0f,
Vector3D = new Vector3D(0, 0, 0)
},
Vector3D = new Vector3D()
}
};
sceneChunk.PRTransform.Vector3D = location;
var spec = new SceneSpecification
{
//scene.Specification = spec;
Cell = new Vector2D() { X = 0, Y = 0 },
CellZ = 0,
SNOLevelAreas = new[] { -1, -1, -1, -1 },
SNOMusic = -1,
SNONextLevelArea = -1,
SNONextWorld = -1,
SNOPresetWorld = -1,
SNOPrevLevelArea = -1,
SNOPrevWorld = -1,
SNOReverb = -1,
SNOWeather = 50542,
SNOCombatMusic = -1,
SNOAmbient = -1,
ClusterID = -1,
PrevEntranceGUID = 14,
DRLGIndex = 5,
SceneChunk = -1,
OnPathBits = tileInfo.TileType, //we can make it TileType value
SceneCachedValues = new SceneCachedValues
{
CachedValuesValid = 63,
NavMeshSizeX = 96,
NavMeshSizeY = 96
}
};
//Logger.Trace("Adding Tile: SNOscene {0}", tileInfo.SNOScene);
var sceneFile = MPQStorage.Data.Assets[SNOGroup.Scene][tileInfo.SNOScene];
var sceneData = (DiIiS_NA.Core.MPQ.FileFormats.Scene)sceneFile.Data;
spec.SceneCachedValues.AABB1 = sceneData.AABBBounds;//new AABB(){Min = new Vector3D(0, 0, 0), Max = new Vector3D(240, 240, 240)};//
spec.SceneCachedValues.AABB2 = sceneData.AABBMarketSetBounds;//new AABB(){Min = new Vector3D(0, 0, 0), Max = new Vector3D(240, 240, 240)};//
spec.SceneCachedValues.Unknown4 = new int[4] { 0, 0, 0, 0 };
sceneChunk.SceneSpecification = spec;
worldData.SceneParams.SceneChunks.Add(sceneChunk);
worldData.SceneParams.ChunkCount++;
//System.Threading.Thread.Sleep(3);
}
private static readonly Dictionary<int, float> GizmosToSpawn = new()
{
{51300, 0.3f}, //chest common
{138989, 0.3f}, //healthwell_global
{176074, 0.06f}, //blessed
{176075, 0.06f}, //enlightened
{176076, 0.06f}, //fortune
{176077, 0.06f}, //frenzied
{79319, 0.06f}, //bloody chest
{62860, 0.05f}, //Chest_rare
{373463, 0.05f}, //PoolOfReflection
//135384, //shrine_global
};
private static readonly List<int> Goblins = new()
{
{5984},
{5985},
{5987},
{5988}
};
private readonly Dictionary<int, List<Scene>> _lazyLevelAreas = new();
/// <summary>
/// Loads content for level areas. Call this after scenes have been generated and after scenes have their GizmoLocations
/// set (this is done in Scene.LoadActors right now)
///
/// Each Scene has one to four level areas assigned to it. I dont know if that means
/// the scene belongs to both level areas or if the scene is split
/// Scenes marker tags have generic GizmoLocationA to Z that are used
/// to provide random spawning possibilities.
/// For each of these 26 LocationGroups, the LevelArea has a entry in its SpawnType array that defines
/// what type of actor/encounter/adventure could spawn there
///
/// It could for example define, that for a level area X, out of the four spawning options
/// two are randomly picked and have barrels placed there
/// </summary>
/// <param name="levelAreas">Dictionary that for every level area has the scenes it consists of</param>
/// <param name="world">The world to which to add loaded actors</param>
private void LoadLevelAreas(Dictionary<int, List<Scene>> levelAreas, World world)
{
Dictionary<PRTransform, DiIiS_NA.Core.MPQ.FileFormats.ActorData> dict = new Dictionary<PRTransform, DiIiS_NA.Core.MPQ.FileFormats.ActorData>();
foreach (int la in levelAreas.Keys)
{
SNOHandle levelAreaHandle = new SNOHandle(SNOGroup.LevelArea, la);
if (!levelAreaHandle.IsValid)
{
Logger.Warn("Level area {0} does not exist", la);
continue;
}
var levelArea = levelAreaHandle.Target as LevelArea;
List<PRTransform> gizmoLocations = new List<PRTransform>();
for (int i = 0; i < 26; i++)
{
// Merge the gizmo starting locations from all scenes and
// their subscenes into a single list for the whole level area
foreach (var scene in levelAreas[la])
{
if (scene.GizmoSpawningLocations[i] != null)
gizmoLocations.AddRange(scene.GizmoSpawningLocations[i]);
foreach (Scene subScene in scene.Subscenes)
{
if (subScene.GizmoSpawningLocations[i] != null)
gizmoLocations.AddRange(subScene.GizmoSpawningLocations[i]);
}
}
}
List<PRTransform> finalLocationsList = new List<PRTransform>();
foreach (PRTransform currValue in gizmoLocations)
{
if (!finalLocationsList.Contains(currValue) && world.CheckLocationForFlag(currValue.Vector3D, DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk))
{
finalLocationsList.Add(currValue);
}
}
gizmoLocations = finalLocationsList; //sorting with no duplications
if (world.SNO == WorldSno.a2dun_cave_mapdungeon_level01) //Mysterious Cave lv 1
{
var handle = new SNOHandle(207706);
if (handle == null || gizmoLocations.Count == 0) continue;
LazyLoadActor(handle, gizmoLocations.PickRandom(), world, ((DiIiS_NA.Core.MPQ.FileFormats.ActorData)handle.Target).TagMap);
}
else
foreach (var location in gizmoLocations)
{
if (FastRandom.Instance.Next(100) < 1)
{
SNOHandle gizmoHandle = null;
float seed = (float)FastRandom.Instance.NextDouble();
foreach (var pair in GizmosToSpawn)
{
if (seed < pair.Value)
{
gizmoHandle = new SNOHandle(pair.Key);
break;
}
else
seed -= pair.Value;
}
if (gizmoHandle == null) continue;
LazyLoadActor(gizmoHandle, location, world, ((DiIiS_NA.Core.MPQ.FileFormats.ActorData)gizmoHandle.Target).TagMap);
}
}
if (gizmoLocations.Count > 0 && world.Game.MonsterLevel >= Program.MaxLevel && FastRandom.Instance.Next(100) < 30)
{
var handleChest = new SNOHandle(96993); //leg chest
if (handleChest == null) continue;
var goldenChest = LoadActor(handleChest, gizmoLocations.PickRandom(), world, ((DiIiS_NA.Core.MPQ.FileFormats.ActorData)handleChest.Target).TagMap);
if (goldenChest > 0)
(world.GetActorByGlobalId(goldenChest) as LegendaryChest).ChestActive = true;
}
if (world.DRLGEmuActive)
{
int wid = (int)world.SNO;
// Load monsters for level area
foreach (var scene in levelAreas.First().Value)
{
if (!SpawnGenerator.Spawns.ContainsKey(wid)) break;
if (SpawnGenerator.Spawns[wid].lazy_load)
{
_lazyLevelAreas.Add(wid, levelAreas.First().Value);
break;
}
else
LoadMonstersLayout(world, wid, scene);
}
#region unique spawn
//unique spawn
if (SpawnGenerator.Spawns.ContainsKey(wid) && SpawnGenerator.Spawns[wid].dangerous.Count > 0 && FastRandom.Instance.NextDouble() < 0.5)
{
var randomUnique = new SNOHandle(SpawnGenerator.Spawns[wid].dangerous.PickRandom());
var scene = levelAreas.First().Value.PickRandom();
int x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
int y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
int threshold = 0;
while ((scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Flags & DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.NoSpawn) != 0)
{
threshold++;
if (threshold >= 20)
{
break;
//continue;
}
x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
}
var uniq = LoadActor(
randomUnique,
new PRTransform
{
Vector3D = new Vector3D
{
X = (float)(x * 2.4 + scene.Position.X) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Y = (float)(y * 2.4 + scene.Position.Y) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Z = scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Z + scene.Position.Z
},
Quaternion = Quaternion.FacingRotation((float)(FastRandom.Instance.NextDouble() * Math.PI * 2))
},
world,
new TagMap()
);
if (uniq > 0)
if (world.GetActorByGlobalId(uniq) as Unique != null)
(world.GetActorByGlobalId(uniq) as Unique).CanDropKey = true;
}
#endregion
#region goblin spawn
//goblin spawn
if (SpawnGenerator.Spawns.ContainsKey(wid) && SpawnGenerator.Spawns[wid].can_spawn_goblin && FastRandom.Instance.NextDouble() < 0.5)
{
var randomGoblin = new SNOHandle(Goblins.PickRandom());
if (world.Game.IsHardcore) randomGoblin = new SNOHandle(3852);
var scene = levelAreas.First().Value.PickRandom();
int x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
int y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
int threshold = 0;
while ((scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Flags & DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.NoSpawn) != 0)
{
threshold++;
if (threshold >= 20)
{
break;
//continue;
}
x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
}
LazyLoadActor(
randomGoblin,
new PRTransform
{
Vector3D = new Vector3D
{
X = (float)(x * 2.4 + scene.Position.X) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Y = (float)(y * 2.4 + scene.Position.Y) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Z = scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Z + scene.Position.Z
},
Quaternion = Quaternion.FacingRotation((float)(FastRandom.Instance.NextDouble() * Math.PI * 2))
},
world,
new TagMap()
);
}
#endregion
}
else
{
//
// Load monsters for level area
foreach (var scene in levelAreas[la])
{
if (!SpawnGenerator.Spawns.ContainsKey(la)) break;
if (SpawnGenerator.Spawns[la].lazy_load)
{
_lazyLevelAreas.Add(la, levelAreas[la]);
break;
}
else
LoadMonstersLayout(world, la, scene);
}
#region unique spawn
//unique spawn
if (SpawnGenerator.Spawns.ContainsKey(la) && SpawnGenerator.Spawns[la].dangerous.Count > 0 && FastRandom.Instance.NextDouble() < 0.5)
{
var randomUnique = new SNOHandle(SpawnGenerator.Spawns[la].dangerous.PickRandom());
var scene = levelAreas[la].PickRandom();
int x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
int y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
int threshold = 0;
while ((scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Flags & DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.NoSpawn) != 0)
{
threshold++;
if (threshold >= 20)
{
break;
//continue;
}
x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
}
var uniq = LoadActor(
randomUnique,
new PRTransform
{
Vector3D = new Vector3D
{
X = (float)(x * 2.4 + scene.Position.X) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Y = (float)(y * 2.4 + scene.Position.Y) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Z = scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Z + scene.Position.Z
},
Quaternion = Quaternion.FacingRotation((float)(FastRandom.Instance.NextDouble() * Math.PI * 2))
},
world,
new TagMap()
);
if (uniq > 0)
if (world.GetActorByGlobalId(uniq) as Unique != null)
(world.GetActorByGlobalId(uniq) as Unique).CanDropKey = true;
}
#endregion
#region goblin spawn
//goblin spawn
if (SpawnGenerator.Spawns.ContainsKey(la) && SpawnGenerator.Spawns[la].can_spawn_goblin && FastRandom.Instance.NextDouble() < 0.5)
{
var randomGoblin = new SNOHandle(Goblins.PickRandom());
if (world.Game.IsHardcore) randomGoblin = new SNOHandle(3852);
var scene = levelAreas[la].PickRandom();
int x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
int y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
int threshold = 0;
while ((scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Flags & DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.NoSpawn) != 0)
{
threshold++;
if (threshold >= 20)
{
break;
//continue;
}
x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
}
LazyLoadActor(
randomGoblin,
new PRTransform
{
Vector3D = new Vector3D
{
X = (float)(x * 2.4 + scene.Position.X) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Y = (float)(y * 2.4 + scene.Position.Y) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Z = scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Z + scene.Position.Z
},
Quaternion = Quaternion.FacingRotation((float)(FastRandom.Instance.NextDouble() * Math.PI * 2))
},
world,
new TagMap()
);
}
#endregion
}
}
}
public void LoadMonstersLayout(World world, int la, Scene scene)
{
if (scene.Populated) return;
scene.Populated = true;
if (!SpawnGenerator.Spawns.ContainsKey(la)) return;
if (scene.SceneData.NoSpawn) return;
List<Affix> packAffixes = new List<Affix>();
int packs_count = world.worldData.DynamicWorld ? 5 : 4;
packs_count += (Game.Difficulty / 3);
if (world.worldData.DRLGParams != null && world.worldData.DRLGParams.Count > 0)
{
if (world.worldData.DRLGParams.First().ChunkSize == 120)
packs_count -= 2;
if (world.worldData.DRLGParams.First().ChunkSize > 240)
packs_count += 2;
}
if (Game.Difficulty > 4)
packs_count += SpawnGenerator.Spawns[la].additional_density;
var groupId = 0;
for (int i = 0; i < packs_count; i++)
{
int x = FastRandom.Instance.Next(scene.NavMesh.SquaresCountX);
int y = FastRandom.Instance.Next(scene.NavMesh.SquaresCountY);
groupId = FastRandom.Instance.Next();
if ((scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Flags & DiIiS_NA.Core.MPQ.FileFormats.Scene.NavCellFlags.NoSpawn) == 0)
{
bool isElite = (FastRandom.Instance.NextDouble() < 0.03);
if (isElite)
{
#region elite spawn
int randomMeleeMonsterId = -1;
int randomRangedMonsterId = -1;
if (SpawnGenerator.Spawns[la].melee.Count > 0) randomMeleeMonsterId = SpawnGenerator.Spawns[la].melee.PickRandom();
if (SpawnGenerator.Spawns[la].range.Count > 0) randomRangedMonsterId = SpawnGenerator.Spawns[la].range.PickRandom();
SNOHandle meleeMonsterHandle = (randomMeleeMonsterId == -1 ? null : new SNOHandle(randomMeleeMonsterId));
SNOHandle rangedMonsterHandle = (randomRangedMonsterId == -1 ? null : new SNOHandle(randomRangedMonsterId));
if (rangedMonsterHandle == null) rangedMonsterHandle = meleeMonsterHandle;
else
if (meleeMonsterHandle == null) meleeMonsterHandle = rangedMonsterHandle;
for (int n = 0; n < 5; n++)
{
if (n == 0 || FastRandom.Instance.NextDouble() < 0.85)
{
uint actor = LoadActor(
(n == 0 ? (FastRandom.Instance.NextDouble() < 0.5 ? meleeMonsterHandle : rangedMonsterHandle) : meleeMonsterHandle),
new PRTransform
{
Vector3D = new Vector3D
{
X = (float)(x * 2.4 + scene.Position.X) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Y = (float)(y * 2.4 + scene.Position.Y) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Z = scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Z + scene.Position.Z
},
Quaternion = Quaternion.FacingRotation((float)(FastRandom.Instance.NextDouble() * Math.PI * 2))
},
world,
new TagMap(),
(n == 0 ? MonsterType.Elite : MonsterType.EliteMinion),
groupId
);
if (actor > 0)
if (n == 0)
packAffixes = MonsterAffixGenerator.Generate(world.GetActorByGlobalId(actor), Math.Min(world.Game.Difficulty + 1, 5));
else
MonsterAffixGenerator.CopyAffixes(world.GetActorByGlobalId(actor), packAffixes);
}
}
}
#endregion
else
{
bool isChampion = (FastRandom.Instance.NextDouble() < 0.07);
if (!isChampion)
#region default spawn
{
int randomMeleeMonsterId = -1;
int randomRangedMonsterId = -1;
if (SpawnGenerator.Spawns[la].melee.Count > 0) randomMeleeMonsterId = SpawnGenerator.Spawns[la].melee.PickRandom();
if (SpawnGenerator.Spawns[la].range.Count > 0) randomRangedMonsterId = SpawnGenerator.Spawns[la].range.PickRandom();
SNOHandle meleeMonsterHandle = (randomMeleeMonsterId == -1 ? null : new SNOHandle(randomMeleeMonsterId));
SNOHandle rangedMonsterHandle = (randomRangedMonsterId == -1 ? null : new SNOHandle(randomRangedMonsterId));
//int maxMobsInStack = (SpawnGenerator.IsMelee(la, randomMonsterId) ? 6 : (SpawnGenerator.IsDangerous(la, randomMonsterId) ? 1 : 3));
for (int n = 0; n < 6; n++)
{
if (n == 0 || FastRandom.Instance.NextDouble() < 0.6)
{
LazyLoadActor(
(meleeMonsterHandle == null ? rangedMonsterHandle : (rangedMonsterHandle == null ? meleeMonsterHandle : (FastRandom.Instance.NextDouble() < 0.65 ? meleeMonsterHandle : rangedMonsterHandle))),
new PRTransform
{
Vector3D = new Vector3D
{
X = (float)(x * 2.4 + scene.Position.X) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Y = (float)(y * 2.4 + scene.Position.Y) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Z = scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Z + scene.Position.Z
},
Quaternion = Quaternion.FacingRotation((float)(FastRandom.Instance.NextDouble() * Math.PI * 2))
},
world,
new TagMap(),
MonsterType.Default
);
}
}
}
#endregion
else //spawn champions
#region champion spawn
{
SNOHandle championHandle = new SNOHandle(SpawnGenerator.Spawns[la].melee.PickRandom());
groupId = FastRandom.Instance.Next();
for (int n = 0; n < 4; n++)
{
if (n == 0 || FastRandom.Instance.NextDouble() < 0.85)
{
uint actor = LoadActor(
championHandle,
new PRTransform
{
Vector3D = new Vector3D
{
X = (float)(x * 2.4 + scene.Position.X) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Y = (float)(y * 2.4 + scene.Position.Y) + (float)(FastRandom.Instance.NextDouble() * 20 - 10),
Z = scene.NavMesh.Squares[y * scene.NavMesh.SquaresCountX + x].Z + scene.Position.Z
},
Quaternion = Quaternion.FacingRotation((float)(FastRandom.Instance.NextDouble() * Math.PI * 2))
},
world,
new TagMap(),
MonsterType.Champion,
groupId
);
if (actor > 0)
if (n == 0)
packAffixes = MonsterAffixGenerator.Generate(world.GetActorByGlobalId(actor), Math.Min(world.Game.Difficulty + 1, 5));
else
MonsterAffixGenerator.CopyAffixes(world.GetActorByGlobalId(actor), packAffixes);
}
}
}
#endregion
}
}
else i--;
}
}
//TODO: Move this out as loading actors can happen even after world was generated
public uint LoadActor(SNOHandle actorHandle, PRTransform location, World world, TagMap tagMap, MonsterType monsterType = MonsterType.Default, int groupId = 0)
{
try
{
var actorSno = (ActorSno)actorHandle.Id; // TODO: maybe we can replace SNOHandle
if (world.QuadTree
.Query<Waypoint>(new Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 60f))
.Count > 0 ||
world.QuadTree
.Query<Portal>(new Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 5f)).Count >
0)
{
Logger.Debug("Load actor {0} ignored - waypoint nearby.", actorSno);
return 0;
}
var actor = ActorFactory.Create(world, actorSno, tagMap);
switch (monsterType)
{
case MonsterType.Champion:
actor = new Champion(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
case MonsterType.Elite:
actor = new Rare(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
case MonsterType.EliteMinion:
actor = new RareMinion(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
}
if (actor == null)
{
if (actorSno != ActorSno.__NONE)
Logger.Warn("ActorFactory did not load actor {0}", actorHandle);
return 0;
}
actor.RotationW = location.Quaternion.W;
actor.RotationAxis = location.Quaternion.Vector3D;
actor.EnterWorld(location.Vector3D);
return actor.GlobalID;
}
catch (Exception ex)
{
Logger.Error("Error loading actor {0} at {1}", actorHandle.Id, location);
return 0;
}
}
public void LazyLoadActor(SNOHandle actorHandle, PRTransform location, World world, TagMap tagMap, MonsterType monsterType = MonsterType.Default)
{
var actorSno = (ActorSno)actorHandle.Id; // TODO: maybe we can replace SNOHandle
if (world.QuadTree.Query<Waypoint>(new DiIiS_NA.GameServer.Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 60f)).Count > 0 ||
world.QuadTree.Query<Portal>(new DiIiS_NA.GameServer.Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 40f)).Count > 0)
{
Logger.Debug("Load actor {0} ignored - waypoint nearby.", actorSno);
return;
}
ActorFactory.LazyCreate(world, actorSno, tagMap, location.Vector3D, ((actor, spawn_pos) =>
{
switch (monsterType)
{
case MonsterType.Champion:
actor = new Champion(world, actorSno, tagMap);
break;
case MonsterType.Elite:
actor = new Rare(world, actorSno, tagMap);
break;
case MonsterType.EliteMinion:
actor = new RareMinion(world, actorSno, tagMap);
break;
}
if (actor == null)
{
if (actorSno != ActorSno.__NONE)
Logger.Warn("ActorFactory did not load actor {0}", actorSno);
}
else
{
actor.RotationW = location.Quaternion.W;
actor.RotationAxis = location.Quaternion.Vector3D;
actor.EnterWorld(spawn_pos);
}
})); // try to create it.;
}
public enum MonsterType
{
Default,
Champion,
Elite,
EliteMinion
}
/// <summary>
/// Loads all markersets of a scene and looks for the one with the subscene position
/// </summary>
private Vector3D FindSubScenePosition(SceneChunk sceneChunk)
{
var mpqScene = MPQStorage.Data.Assets[SNOGroup.Scene][sceneChunk.SNOHandle.Id].Data as DiIiS_NA.Core.MPQ.FileFormats.Scene;
foreach (var markerSet in mpqScene.MarkerSets)
{
var mpqMarkerSet = MPQStorage.Data.Assets[SNOGroup.MarkerSet][markerSet].Data as MarkerSet;
foreach (var marker in mpqMarkerSet.Markers)
if (marker.Type == MarkerType.SubScenePosition)
return marker.PRTransform.Vector3D;
}
return null;
}
}
}