Jump to content

Safe height to spawn around the Outpost


SameOldBard

Recommended Posts

6 hours ago, HeyYou said:

Drop a marker first? Place it fairly high, then drop it to the ground. Spawn your npc at the marker. (I used to do this in morrowind, used a dead rat as the marker. :D)

What if the marker is not dead when dropped and I register to it's OnDeath event before moving it to a high position?

I'm guessing the position it will have by the time I get the event will be precise enough hehe. So, the solution is a bit dead rat hehehe

Link to comment
Share on other sites

Posted (edited)
On 4/12/2024 at 11:21 PM, HeyYou said:

That *should* work..... unless the rat doesn't die on impact. 😄 (short fall height.)

In the end, it did work. But even with a high fall height it still had a success rate of 76%. I tried it a 1000 times to get a proper valid percentage.

I am not interely sure why that is so. I was at 1 side of the Outpost and had them being dropped at random places around the Outpost, basically at the border area. I also set their HP to 1 before dropping.

Maybe those that did not die where at an area that maybe was not fully loaded or something? Does anyone know?

 

Anyway, with a couple of retries I could have a 100% success rate, so, it worked for my mod needs. I should have replied before, but I've been playtesting it while working on my other mod which I'm planning to release together with the one using this system.

 

Here's a snippet with how I have it set up here. Maybe someone can spot why I have the 24% failure to die rate (Sorry, I don't follow Bethesda's scripting coding pattern):

 

ScriptName SomeScript

; Using the player as the spawner
Actor Property PlayerRef Auto Const mandatory
; A minibot, specifically: 0x000C1F4F
Form Property MarkerRef Auto Const mandatory

; Field set by the OnDeath event
Form _deadMarker

; Amount of time we want to wait for the Marker to die
int _timesToTryAgain = 15

Actor function SpawnActor()
	; I am not stashing the Beacon as the player may want to remove it while this script is running. So we can have a way to fail if that happens
	ObjectReference workshop = GetWorkshop()

	if(workshop == NONE)
		Trace("SpawnActor: Could not get a Workshop")
		return
	endIf

	float buildRadius = workshop.GetValue(OutpostBuildAreaRadius)

	; We ask for a Marker to be placed at the same Height as the Outpost Radius, should be 150 by default
	Actor marker = GetSpawnMarker(buildRadius)

	; Waits for a few seconds to allow it to bounce
	Utility.Wait(10)

	; Creates an actor at the Marker position disabled so we don't see it beside the player
	Actor actorSpawned = PlayerRef.PlaceActorAtMe(actorToSpawn as ActorBase, 4, None, true, true, false, NONE, false)

	; Moves to the Marker position and enables it
	actorSpawned.SetPosition(marker.GetPositionX(), marker.GetPositionY(), marker.GetPositionZ())
	actorSpawned.Enable(true)

	; Get's rid of the Marker
	marker.DisableNoWait(false)
	marker.Delete()

	return actorSpawned
endFunction

Actor function GetSpawnMarker(float height)
	int timesAwaited = 0
	int retries = 0

	; Tries to get a marker right away
	Actor spawnMarker = GetDeadDrop(height)

	; Repeats until we have a marker dying
	while(_deadMarker != spawnMarker)
		; Checking every second
		Utility.Wait(1)

		timesAwaited += 1

		; If we waited for more than the maximum amount of time (15 seconds)
		if(timesAwaited >= _timesToTryAgain)
			timesAwaited = 0

			; Clear the data of the marker that failed to die and delete it
			ClearRegisteredEvents(spawnMarker)

			spawnMarker.DisableNoWait(false)
			spawnMarker.Delete()

			; Drop a new marker and retry
			spawnMarker = GetDeadDrop(height)

			retries += 1
		endIf
	endWhile

	; We got a marker, let's clean up and return the object
	_deadMarker = NONE

	ClearRegisteredEvents(spawnMarker)

	return spawnMarker
endFunction

Actor function GetDeadDrop(float height)
	ObjectReference workshop = GetWorkshop()

	if(workshop == NONE)
		Trace("SpawnActor: Could not get a Workshop")
		return
	endIf

	float xPos = workshop.GetPositionX()
	float yPos = workshop.GetPositionY()
	float zPos = workshop.GetPositionZ()

	float buildRadius = workshop.GetValue(OutpostBuildAreaRadius)

	; Let's get a random point in the circle of the outpost border
	float angle = Utility.RandomFloat(0.0, 359.999)

	float newX = xPos + (buildRadius * Math.cos(angle))
	float newY = yPos + (buildRadius * Math.sin(angle))
	float newZ = zPos + height

	; Create the marker, wait for it to load and set it's alpha to 0. Not exactly transparent but good enough
	Actor spawnMarker = PlayerRef.PlaceActorAtMe(MarkerRef as ActorBase, 0, workshop.GetCurrentLocation(), true, false, false, NONE, false)
	spawnMarker.WaitFor3DLoad()
	spawnMarker.SetAlpha(0, False)

	if(!spawnMarker.Is3DLoaded())
		Trace("3D is not loaded!")
	endIf

	; Get ready for it's death
	RegisterForRemoteEvent(spawnMarker, "OnDeath")

	; Set's health to 1 and drop it from the wanted position!
	spawnMarker.SetValue(Game.GetHealthAV(), 1)
	spawnMarker.SetPosition(newX, newY, newZ)

	; Waiting again, in case there is some loading to be done at the other side of the map.
	spawnMarker.WaitFor3DLoad()

	return spawnMarker
endFunction

function ClearRegisteredEvents(Actor actorRef)
	; Clean up!
	UnregisterForRemoteEvent(actorRef, "OnDeath")
endFunction

event Actor.OnDeath(Actor deadActor, Actor akKiller)
	UnregisterForRemoteEvent(deadActor, "OnDeath")

	ObjectReference workshop = GetWorkshop()

	if(workshop == NONE)
		Trace("OnDeath: Could not get a Workshop")
		return
	endIf

	if(deadActor.HasKeyword(MarkerKeyword))
		; Yay! We got a dead one!
		_deadMarker = deadActor
		return
	endIf
endEvent

 

Cheers,

OldBard

Edited by SameOldBard
Link to comment
Share on other sites

  • 2 weeks later...
Posted (edited)

I just found something quite odd happening when using a similar solution in another mod I am working on.

I tried dropping the bots and although I was dropping 16 of them at once, only 1 of them was dying. The others were not. For some reason. Some further investigation (tracing + searching for them) showed me that they were actually being spawned right at a safe place in the ground at the right position I wanted them to.

Some more tests and I had was something like this:

float xPos = _workshop.GetPositionX()
float yPos = _workshop.GetPositionY()
float zPos = _workshop.GetPositionZ()

float buildRadius = _workshop.GetValue(OutpostBuildAreaRadius)

float newX = xPos + (buildRadius * Math.cos(angle))
float newY = yPos + (buildRadius * Math.sin(angle))
float newZ = zPos + buildRadius * 2

Actor spawnMarker = _workshop.PlaceActorAtMe(MarkerRef as ActorBase, 0, NONE, true, true, false, NONE, false)
spawnMarker.SetValue(Game.GetHealthAV(), 1)

spawnMarker.SetPosition(newX, newY, newZ)
Trace("Placing Marker at: " + spawnMarker.GetPositionX() + ", " + spawnMarker.GetPositionY() + ", " + spawnMarker.GetPositionZ() + ". Initial Z: " + zPos + ", new Z: " + newZ)
spawnMarker.Enable(false)
spawnMarker.WaitFor3DLoad()
Trace("Placing Marker at: " + spawnMarker.GetPositionX() + ", " + spawnMarker.GetPositionY() + ", " + spawnMarker.GetPositionZ() + ". Initial Z: " + zPos + ", new Z: " + newZ)

With the output being...

Before enabling:

Placing Marker at: 504.698944, -284.563171, 305.337381. Initial Z: 5.337381, new Z: 305.337372

After enabling:
Placing Marker at: 504.698944, -284.563171, 2.863391. Initial Z: 5.337381, new Z: 305.337372

I ran it again and again and it seems consistent. It is as if when the actors are enabled they are auto moved to the ground safely. Does anyone know if that is reliable? Has anyone had similar results?

OldBard.

Edited by SameOldBard
Link to comment
Share on other sites

1 hour ago, SameOldBard said:

It is as if when the actors are enabled they are auto moved to the ground safely. Does anyone know if that is reliable? Has anyone had similar results?

Sometimes fast travel glitches and you zone into a planet before creatures spawn.  When that happens you see them placed in the air, fairly high up, and then drop to the ground.  So apparently yes, things get spawned above the possible terrain height and then auto moved down.

Link to comment
Share on other sites

Indeed I saw that happening every now and them. My concern though is about reliability as I need those for setting up solo level positions.

I guess I can check the Z after enabling. If it is about the same as the high one I set before enabling then I would know that it was not automatically placed at ground level.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...