Fixes for NPC Spawning in/on Collidables (ref #301)

This commit is contained in:
AconiteX
2021-05-10 15:00:40 -04:00
parent 20231330df
commit bc5aaa33cc
3 changed files with 78 additions and 54 deletions

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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;
}