Jump to content

Neutral Vertibirds - Settler assignment


Rhutos

Recommended Posts

Hi fellas,

A few days before I started to work on settler assignment for my plugin: Neutral Vertibirds.
I had a tough time, because the whole settlement menu seems to be hardcoded (I crawled every script with Notepad++)
First, I tried without any success - to make the Vertibird Actor assignable.
But it seems to be impossible to do this with Actors
If your Actor does not have the "WorkshopWorkObject", "WorkshopAllowCommand" or "WorkshopAllowMove" keyword, there is no "Assign" command, just a "Go to" command whenever you command a settler and highlight the Actor
If you add one of these keywords and try to assign, the engine just tries to command your highlighted Actor
I found no keyword, actor value, script or perk to prevent this. Not one.
So I tried to move on and use the "OnCommandModeGiveCommand (Actor akSender, int aeCommandType, ObjectReference akTarget)" event
The result:
If you try to command a busy settler he sends a "0" (none) command without a target
If you try to command the settler again (or out of action) he sends a "0" (none) command with a nearby, invisible, non selectable ref (I think it's a temporary marker)
I tried to catch these actions:
event Actor.OnCommandModeGiveCommand (Actor akSender, int aeCommandType, ObjectReference akTarget)
	Debug.Trace ("Command! Actor: " + akSender + ", Target: " + akTarget + ", Type: " + aeCommandType)
	Debug.Trace ("Actor's distance to Vertibird: " + akSender.GetDistance (self))
	if (akTarget && aeCommandType == 0)
		Debug.Trace ("target's distance to Vertibird: " + akTarget.GetDistance (self))
		if (akTarget == self || akTarget.GetDistance (self) <= 500.00 && akSender != Pilot)
			Debug.Trace ("The actor is now a pilot!")
			AssignActor (akSender as WorkshopNPCScript)
			AssignPilot (akSender) ;Custom function
		endif
	endif
endevent
Yay! Half of the time it works (if I would change the 500.00 to some higher value It might be work anytime - but even then if you don't want to assign a pilot to the Vertibird...)
But it's imprecise and confusing
So I tried: Use a furniture looks like a Vertibird to catch the command and then switch to the real (Actor) Vertibird.
The Vertibird has to be unable to control anyway - if there is no pilot
I used a furniture with the "WorkshopWorkObject" keyword and the "Vehicles\Vertibird\Vertibird01.nif". Nice! No minigun and wrong airscrew direction, but it's okay - for now.
But hold on! The furniture has a +90 Angle relative to the real Vertibird (the origin seems to be shifted too)
So i tried:
Plan A - Use SetAngle (GetAngleX (), GetAngleY (), GetAngleZ () +/- 90) whenever the furniture or the actor is moving.
Annoying but seems to work - but then the Actor randomly teleports anywhere else...
Plan B - Use NifScope 2.0 Pre-Alpha 4 to rotate the "Vehicles\Vertibird\Vertibird01.nif", rename and save
I don't know what I am doing wrong, but rotating the NiNode does not seem to affect the Collision box
The absolute same problem: The actor is teleport randomly at random times.
I tried:
SetPosition instead of MoveTo (maybe it's more precise?) - Still teleporting
SetMotionType (Motion_Keyframed) if disabled - Still teleporting
Use Debug.EnableCollisions (false) - Still teleporting
Completely remove any Movement functions out of my script - Still random teleports on Enable / Disable
A few other things
So either (the perfect solution) I find a way to make an actor assignable
or
I need to find out why the Actor teleporting around randomly when enabled / disabled
The vertibird furniture script:
Scriptname NTRVertibirdFurnitureScript extends WorkshopObjectScript

group Vertibird
	Keyword Property LinkVehicle Auto Const
	{Vehicle link keyword for reflinking pilot to the vertibird}
	Keyword Property AttachPilot Auto Const
	{Keyword to find the pilot slot use: p-AttachPilot}
	Form Property LvlNTRVertibird Auto Const
	{The real vertibird to create it on the fly}
endgroup
group Messages
	Message Property NTRVertibirdWorkbenchTransferMessage Auto Const
	{"Your items were transfered to the workbench"}
	Message Property NTRVertibirdPlayerTransferMessage Auto Const
	{"Your items were transfered to your inventory"}
	Message Property NTRVFTVertibirdTravelMessage Auto Const
	{"Vertibird were sent to <Location>"}
endgroup
;Hidden refs
ObjectReference Property VertibirdRef Auto Hidden
ObjectReference Property PilotRef Auto Hidden

;Constants
float RESPAWN_TIMER = 3.00 Const ;3 game hours
float MAXIMAL_WORKSHOP_DISTANCE = 80000.00 ;Maximal distance to search for a workshop if the id is missing...

;----------------------------------------------------------
;  Tries to return pilot property - if there isn't try
;  to find it with a while loop
;----------------------------------------------------------
Actor function GetPilot ()
	if !(PilotRef)
		int Index = 1;
		ObjectReference Passenger
		while (PilotRef == none && Index < 6)
			Passenger = GetNthLinkedRef (Index, LinkVehicle)
			if (Passenger)
				if ((VertibirdRef as Actor).IsBeingRiddenBy (Passenger as Actor) && Passenger.HasKeyword (AttachPilot) == true)
					PilotRef = Passenger
				endif
			endif
			Index += 1
		endwhile
	endif
	return (PilotRef as Actor)
endfunction

;----------------------------------------------------------
;  Assign a pilot and link it to the vertibird
;----------------------------------------------------------
function AssignPilot (ObjectReference akPilot)
	NTRVertibirdMainScript MainRef = (VertibirdRef as NTRVertibirdActorScript).NTRVertibirdMain as NTRVertibirdMainScript
	Actor Vertibird = VertibirdRef as Actor
	Actor Pilot
	;Handle previous pilot
	if (GetPilot ())
		Pilot = PilotRef as Actor
		MainRef.RemovePilot (PilotRef)
		Pilot.SetLinkedRef (none, LinkVehicle)
		Pilot.SetVehicle (none)
		if (Vertibird.IsBeingRiddenBy (Pilot)) ;Dismount previous workshop
			Pilot.Dismount ()
		endif
		Pilot.EvaluatePackage (true)
		;Vertibird.EnableAI (false)
	endif
	;Assign new pilot (or none)
	PilotRef = akPilot
	if (PilotRef)
		Pilot = PilotRef as Actor
		Pilot.SetLinkedRef (self, LinkVehicle)
		MainRef.AddPilot (Pilot)
		Pilot.SetVehicle (Vertibird)
		Pilot.EvaluatePackage (true)
		;Vertibird.EnableAI (true)
	endif
	Debug.Trace ("Assigned pilot: " + Pilot)
endfunction

;----------------------------------------------------------
;  Assign the vertibird pilot
;----------------------------------------------------------
function AssignActor (WorkshopNPCScript newActor = None)
	Parent.AssignActor (newActor)
	if (newActor && newActor != PilotRef)
		Debug.Notification ("PILOT!")
		PilotRef = newActor
		AssignActor (none) ;Reset own assignment
		AssignPilot (PilotRef as Actor)
		Disable ()
		VertibirdRef.Enable ()
		GoToState ("Assigned")
		Debug.Trace ("Pos - X: " + X + ", Y: " + Y + ", Z: " + Z)
	endif
endfunction

;--------------------------------------------------------------------
;  Display the send vertibird to settlement menu
;--------------------------------------------------------------------
function SendToMenu ()
	NTRVertibirdActorScript VertibirdScript = VertibirdRef as NTRVertibirdActorScript
	NTRVertibirdMainScript MainRef = VertibirdScript.NTRVertibirdMain as NTRVertibirdMainScript
	Location TargetLoc = OpenWorkshopSettlementMenu ((MainRef.NTRVFT as NTRVFTQuestScript).NTRVertibirdTargetKW)
	if (TargetLoc)
		MainRef.StopAirSupportOnAlias (VertibirdRef)
		(VertibirdScript.NTRVFT as NTRVFTQuestScript).StopOnVertibirdAlias (VertibirdRef)
		VertibirdScript.EvaluatePackage ()
		;TargetLoc.SetLinkedRef (self, NTRVertibirdSettlementLocation)
		WorkshopParent.DisplayMessage (NTRVFTVertibirdTravelMessage, self, TargetLoc)
	endif
endfunction

;--------------------------------------------------------------------
;  Transfers the vertibirds inventory to a workshop
;  If no workshop is found - transfer to the player
;--------------------------------------------------------------------
ObjectReference function TransferItemsToWorkshop (ObjectReference akWorkshop = none)
	Debug.Trace ("Transfer items")
	if !(akWorkshop)
		if (WorkshopID != -1)
			akWorkshop = WorkshopParent.GetWorkshop (WorkshopID)
		else
			akWorkshop = Game.FindClosestReferenceOfType (WorkshopParent.GetWorkshop (0).GetBaseObject (), VertibirdRef.GetPositionX (), VertibirdRef.GetPositionY (), VertibirdRef.GetPositionZ (), MAXIMAL_WORKSHOP_DISTANCE)
		endif
	endif
	int Count = (GetItemCount () - 3)
	if (akWorkshop)
		VertibirdRef.RemoveAllItems (akWorkshop, true)
		if (Count > 0)
			NTRVertibirdWorkbenchTransferMessage.Show ()
		endif
	;Store items in players inventory if there werent any workshops
	else
		VertibirdRef.RemoveAllItems (Game.GetPlayer (), true)
		if (Count > 0)
			NTRVertibirdPlayerTransferMessage.Show ()
		endif
	endif
	return (akWorkshop)
endfunction

function DismissPilot ()
	AssignPilot (none) ;'Drop' pilot
	VertibirdRef.Disable ()
	Enable ()
	GoToState ("Workshop")
	Debug.Trace ("Pos - X: " + X + ", Y: " + Y + ", Z: " + Z)
endfunction

event Actor.OnDeath (Actor akSender, Actor akKiller)
	Debug.Trace ("OnDeath ()")
	if (akSender == VertibirdRef)
		NTRVertibirdActorScript Vertibird = VertibirdRef as NTRVertibirdActorScript
			
		NTRVFTQuestScript VFTQuestRef = Vertibird.NTRVFT as NTRVFTQuestScript
		NTRVertibirdWorkshopScript WorkshopVertibird = (Vertibird as ObjectReference) as NTRVertibirdWorkshopScript
		NTRVertibirdMainScript MainRef = Vertibird.NTRVertibirdMain as NTRVertibirdMainScript
		VFTQuestRef.StopOnVertibirdAlias (Vertibird) ;Stop VFT if it's the VFT Vertibird
		MainRef.StopAirSupportOnAlias (Vertibird) ;Stop air support if it's the air support Vertibird
		Disable ()
		Vertibird.Disable ()
		
		;Find a workshop to 'resurrect' at
		ObjectReference WorkshopRef = WorkshopVertibird.TransferItemsToWorkshop ()
		;Get safe position from a temp marker
		ObjectReference WorkshopMarker
		float [] SafePoint
		if (WorkshopRef)
			WorkshopMarker = WorkshopRef.PlaceAtMe (VFTQuestRef.NTRVertibirdMarkerRef)
		else
			WorkshopMarker = PlaceAtMe (VFTQuestRef.NTRVertibirdMarkerRef)
		endif
		SafePoint = WorkshopMarker.GetSafePosition ()
		WorkshopMarker.Delete () ;Delete marker - not needed anymore			
		;Disable pilot if he's still alive
		Actor Pilot = GetPilot ()
		if (Pilot)
			if (Pilot.IsDead () == false)
				Pilot.Disable ()
			endif
		endif	
		;'Respawn' (actually spawn a new form, because the old one is buggy after ressurect/reset...)
		Utility.WaitGameTime (RESPAWN_TIMER)
		VertibirdRef = PlaceAtMe (Vertibird.GetBaseObject (), 1, true, true)
		if (VertibirdRef)
			(VertibirdRef as NTRVertibirdActorScript).NTRVertibirdFurniture = self
		endif			
		;If safe point was found - teleport it there
		if (SafePoint)
			SetPosition (SafePoint [0], SafePoint [1], SafePoint [2])
		endif			
		;Enable pilot if he's still alive and assign it to the new vertibird
		if (Pilot)
			if (Pilot.IsDead () == false)
				if (VertibirdRef)
					Pilot.MoveTo (VertibirdRef)
					AssignPilot (Pilot)
				endif
				Pilot.Enable ()
			endif
		endif			
		MainRef.RemoveVertibird (Vertibird)
		UnregisterForRemoteEvent (Vertibird, "OnDeath")
		Vertibird.Delete () ;In the end, delete the previous ref
	endif
endevent

;----------------------------------------------------------
;  Handle vertibird death and resurrection
;----------------------------------------------------------
state Assigned
	event OnDistanceGreaterThan (ObjectReference akObj1, ObjectReference akObj2, float afDistance)
		Debug.Trace ("Distance became greater than 100!")
		MoveTo (VertibirdRef)
	endevent
endstate

auto state Workshop
	event OnDistanceGreaterThan (ObjectReference akObj1, ObjectReference akObj2, float afDistance)
		Debug.Trace ("Distance became greater than 100!")
		VertibirdRef.MoveTo (self)
	endevent
	
	;--------------------------------------------------------------------
	;  Handle workshop delete
	;--------------------------------------------------------------------
	function HandleDeletion ()
		TransferItemsToWorkshop ()
		;Remove linked pilot
		Debug.Trace ("Remove pilot")
		if (GetPilot ())
			AssignPilot (none)
		endif
		((VertibirdRef as NTRVertibirdActorScript).NTRVertibirdMain as NTRVertibirdMainScript).RemoveVertibird (VertibirdRef)
		Parent.HandleDeletion ()
	endfunction

	;--------------------------------------------------------------------
	;  Spawn the real vertibird
	;--------------------------------------------------------------------
	function HandleCreation (bool bNewlyBuilt = true)
		Parent.HandleCreation (bNewlyBuilt)
		if (bNewlyBuilt == true)
			AddKeyword (WorkshopParent.WorkshopWorkObject) ;To make it assignable - if you add it to the form you cannot build it
			VertibirdRef = PlaceAtMe (LvlNTRVertibird, 1, true, true)
			(VertibirdRef as NTRVertibirdActorScript).NTRVertibirdFurniture = self
			RegisterForRemoteEvent ((VertibirdRef as Actor), "OnDeath")
			RegisterForDistanceGreaterThanEvent (self, VertibirdRef, 100.00)
		endif
	endfunction
endstate

*edit*

I see I posted it in the wrong subforum. Please move

Link to comment
Share on other sites

Yes I know, what properties are, and how the parent script works

 

I didn't modify any code, I created it by myself.

Just 3 parent functions are overriden and the parent functions are called by them

Link to comment
Share on other sites

  • Recently Browsing   0 members

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