From bc5aaa33cc6fc71378c9a457c6ee3a5d24ac9898 Mon Sep 17 00:00:00 2001 From: AconiteX <63141077+AconiteX@users.noreply.github.com> Date: Mon, 10 May 2021 15:00:40 -0400 Subject: [PATCH] Fixes for NPC Spawning in/on Collidables (ref #301) --- .../game/script/library/groundquests.java | 91 +++++++++---------- .../script/quest/task/ground/encounter.java | 20 +++- .../script/systems/npc_lair/npc_lair.java | 21 ++++- 3 files changed, 78 insertions(+), 54 deletions(-) diff --git a/sku.0/sys.server/compiled/game/script/library/groundquests.java b/sku.0/sys.server/compiled/game/script/library/groundquests.java index 94cdee5f6..6328f3ac9 100755 --- a/sku.0/sys.server/compiled/game/script/library/groundquests.java +++ b/sku.0/sys.server/compiled/game/script/library/groundquests.java @@ -713,69 +713,68 @@ public class groundquests extends script.base_script } public static location getRandom2DLocationAroundLocation(obj_id player, float relativeOffsetX, float relativeOffsetZ, float minimumDistance, float maximumDistance) throws InterruptedException { - boolean onAFloor = isOnAFloor(player); - location playerLocation = getLocation(player); - boolean inACell = (playerLocation.cell != null) && (playerLocation.cell != obj_id.NULL_ID); + final boolean onAFloor = isOnAFloor(player); + final location playerLocation = getLocation(player); + final boolean inACell = (playerLocation.cell != null) && (playerLocation.cell != obj_id.NULL_ID); location newLocation = new location(playerLocation); newLocation.x += relativeOffsetX; newLocation.z += relativeOffsetZ; newLocation = utils.getRandomLocationInRing(newLocation, minimumDistance, maximumDistance); - if (!isValidQuestSpawnPoint(player, newLocation, onAFloor, inACell)) - { - float xDelta = (playerLocation.x - newLocation.x) * 2; - float zDelta = (playerLocation.z - newLocation.z) * 2; - if (newLocation.x < playerLocation.x) - { - newLocation.x += xDelta; - } - else - { - newLocation.x -= xDelta; - } - if (!isValidQuestSpawnPoint(player, newLocation, onAFloor, inACell)) - { - if (newLocation.z < playerLocation.z) - { - newLocation.z += zDelta; + // try to find a suitable location around the player relative to the requested params + int count = 0; + float xDelta = 0f; + float zDelta = 0f; + while(!isValidQuestSpawnPoint(player, newLocation, onAFloor, inACell) && count < 100) { + if (count % 2 == 0) { + xDelta = (playerLocation.x - newLocation.x) * 2f; + if (newLocation.x < playerLocation.x) { + newLocation.x += xDelta; + } else { + newLocation.x -= xDelta; } - else - { + } else { + zDelta = (playerLocation.z - newLocation.z) * 2f; + if (newLocation.z < playerLocation.z) { + newLocation.z += zDelta; + } else { newLocation.z -= zDelta; } - if (!isValidQuestSpawnPoint(player, newLocation, onAFloor, inACell)) - { - if (newLocation.x < playerLocation.x) - { - newLocation.x += xDelta; - } - else - { - newLocation.x -= xDelta; - } - if (!isValidQuestSpawnPoint(player, newLocation, onAFloor, inACell)) - { - newLocation = (location)playerLocation.clone(); - } + } + if(getDistance(playerLocation, newLocation) > maximumDistance) { + if(rand(0, 1) == 0) { + newLocation.x = playerLocation.x + rand(minimumDistance, maximumDistance); + } else { + newLocation.z = playerLocation.z + rand(minimumDistance, maximumDistance); } } + count++; } - if (onAFloor) - { + if(count >= 100) { + // if we can't find a suitable location, return really close around the player, but still random for effect + WARNING("groundquests.getRandom2DLocationAroundLocation() was unable to find a suitable location for "+player+" at "+playerLocation.area+" "+playerLocation.x+" "+playerLocation.z); + newLocation = (location)playerLocation.clone(); + newLocation.x += rand(-2f, 2f); + newLocation.z += rand(-2f, 2f); + } + if (onAFloor) { newLocation.y = getFloorHeightAtRelativePointOnSameFloorAsObject(player, newLocation.x - playerLocation.x, newLocation.z - playerLocation.z); - } - else - { + } else { newLocation.y = getHeightAtLocation(newLocation.x, newLocation.z); } return newLocation; } public static boolean isValidQuestSpawnPoint(obj_id player, location newLocation, boolean onAFloor, boolean inACell) throws InterruptedException { - boolean validPoint = true; - location playerLocation = getLocation(player); - if (validPoint) - { - validPoint = !getCollidesWithObject(newLocation, 1.0f); + final location playerLocation = getLocation(player); + boolean validPoint = !getCollidesWithObject(newLocation, 2f); // FYI this method doesn't appear to do anything + // prevent spawns inside building walls when location should be outside in world + if(validPoint && !inACell) { + obj_id[] objects = getNonCreaturesInRange(newLocation, 0.5f); + for (obj_id o : objects) { + if(getTemplateName(o).contains("building")) { + return false; + } + } } if (validPoint && onAFloor) { diff --git a/sku.0/sys.server/compiled/game/script/quest/task/ground/encounter.java b/sku.0/sys.server/compiled/game/script/quest/task/ground/encounter.java index 95f944836..78c3a8759 100755 --- a/sku.0/sys.server/compiled/game/script/quest/task/ground/encounter.java +++ b/sku.0/sys.server/compiled/game/script/quest/task/ground/encounter.java @@ -1,10 +1,7 @@ package script.quest.task.ground; import script.dictionary; -import script.library.ai_lib; -import script.library.create; -import script.library.groundquests; -import script.library.utils; +import script.library.*; import script.location; import script.obj_id; @@ -60,9 +57,11 @@ public class encounter extends script.quest.task.ground.base_task { location l = null; location locTest = getLocation(self); + boolean inCell = false; if (!isIdValid(locTest.cell)) { l = groundquests.getRandom2DLocationAroundLocation(self, relativeOffsetX, relativeOffsetZ, minRadius, maxRadius); + inCell = true; } else { @@ -72,6 +71,19 @@ public class encounter extends script.quest.task.ground.base_task } obj_id creature = create.createCreature(creatureType, l, true); if(isValidId(creature)) { + if(!inCell) + { + location creatureLoc = getLocation(creature); + int respawnCount = 0; + while(respawnCount < 5 && creatureLoc.y != getHeightAtLocation(creatureLoc.x, creatureLoc.z)) { + // creature is standing on something it shouldn't be + destroyObject(creature); + l = groundquests.getRandom2DLocationAroundLocation(self, relativeOffsetX, relativeOffsetZ, minRadius, maxRadius); + creature = create.createCreature(creatureType, l, true); + creatureLoc = getLocation(creature); + respawnCount++; + } + } setObjVar(creature, objvarOnCreatureOwner, self); setObjVar(creature, objvarOnCreatureQuestCrc, questCrc); setObjVar(creature, objvarOnCreatureTaskId, taskId); diff --git a/sku.0/sys.server/compiled/game/script/systems/npc_lair/npc_lair.java b/sku.0/sys.server/compiled/game/script/systems/npc_lair/npc_lair.java index 15877b57b..dc31d0795 100755 --- a/sku.0/sys.server/compiled/game/script/systems/npc_lair/npc_lair.java +++ b/sku.0/sys.server/compiled/game/script/systems/npc_lair/npc_lair.java @@ -1,10 +1,7 @@ package script.systems.npc_lair; -import script.dictionary; +import script.*; import script.library.*; -import script.location; -import script.obj_id; -import script.string_id; public class npc_lair extends script.theme_park.poi.base { @@ -51,6 +48,22 @@ public class npc_lair extends script.theme_park.poi.base { removeObjVar(self, "npc_lair.target"); } + // fix for lairs that accidentally spawn inside quarantine zone walls because + // the walls don't match the shape of the region and this is easier to fix than + // relocating a ton of walls + if(locTest.area.equalsIgnoreCase("dathomir")) { + region[] regions = getRegionsAtPoint(locTest); + for(region r : regions) { + if(r.getName().equalsIgnoreCase("@dathomir_region_names:mountain_2")) { + obj_id[] objects = getObjectsInRange(self, 15f); + for (obj_id o : objects) { + if(getTemplateName(o).contains("military_wall")) { + destroyObject(self); + } + } + } + } + } initializePoi(self); return SCRIPT_CONTINUE; }