522 lines
19 KiB
Plaintext
522 lines
19 KiB
Plaintext
scriptName CritterMoth extends Critter
|
|
{Main Behavior script for moths and butterflies}
|
|
|
|
import Utility
|
|
import form
|
|
import debug
|
|
|
|
; Properties (set through the editor)
|
|
FormList property PlantTypes auto
|
|
{ The list of plant types this moth can be attracted to}
|
|
FormList property IgnoreHarvestedPlants auto
|
|
{ plants we want to ignore when they're harvested }
|
|
FormList property GroundPlants auto ; jazbay
|
|
FormList property VeryShortPlants auto ; cabbage, leek, nirnroot, canis root, hanging moss 3, spiky grass
|
|
FormList property ShortPlants auto ; mountain flowers, cotton, dragon's tongue, hanging moss 2
|
|
FormList property TallPlants auto ; snowberry
|
|
FormList property VeryTallPlants auto ; juniper
|
|
|
|
ObjectReference fLastPlant
|
|
|
|
; Constants
|
|
float Property fTimeAtPlantMin = 5.0 auto
|
|
{The Minimum time a Moth stays at a plant}
|
|
float Property fTimeAtPlantMax = 15.0 auto
|
|
{The Maximum time a Moth stays at a plant}
|
|
float Property fActorDetectionDistance = 300.0 auto
|
|
{The Distance at which an actor will trigger a flee behavior}
|
|
float Property fTranslationSpeedMean = 150.0 auto
|
|
{The movement speed when going from plant to plant, mean value}
|
|
float Property fTranslationSpeedVariance = 50.0 auto
|
|
{The movement speed when going from plant to plant, variance}
|
|
float Property fFleeTranslationSpeed = 300.0 auto
|
|
{The movement speed when fleeing from the player}
|
|
float Property fBellShapePathHeight = 150.0 auto
|
|
{The maximum height of the bell shaped path}
|
|
float Property fFlockPlayerXYDist = 100.0 auto
|
|
{When flocking the player, the XY random value to add to its location}
|
|
float Property fFlockPlayerZDistMin = 50.0 auto
|
|
{When flocking the player, the min Z value to add to its location}
|
|
float Property fFlockPlayerZDistMax = 200.0 auto
|
|
{When flocking the player, the max Z value to add to its location}
|
|
float Property fFlockTranslationSpeed = 300.0 auto
|
|
{When flocking the player, the speed at which to move}
|
|
float Property fMinScale = 0.5 auto
|
|
{Minimum initial scale of the Moth}
|
|
float Property fMaxScale = 1.2 auto
|
|
{Maximum initial scale of the Moth}
|
|
float property fMinTravel = 64.0 auto
|
|
{Minimum distance a wandering moth/butterfly will travel}
|
|
float property fMaxTravel = 512.0 auto
|
|
{Maximum distance a wandering moth/butterfly will travel}
|
|
string property LandingMarkerPrefix = "LandingSmall0" auto
|
|
{Prefix of landing markers on plants, default="LandingSmall0"}
|
|
float property fMaxRotationSpeed = 90.0 auto
|
|
{Max rotation speed while mocing, default = 90 deg/s}
|
|
float property fLeashMultiplier = 4.0 auto
|
|
{Increase the spawning range from the intial spawn point}
|
|
float property fSearchDistance = 250.0 auto
|
|
{Butterflies will search this distance for their next perch, increasing by fSearchIncrease each time it fails to find a plant.}
|
|
float property fSearchIncrease = 250.0 auto
|
|
float property fMinWander = 500.0 auto
|
|
float property fMaxWander = 1500.0 auto
|
|
{ How far away will butterflies wander from their current perch before searching for a perch}
|
|
|
|
; Variables
|
|
; Averages of x, y, z positions to track butterfly movement and keep them moving from old areas
|
|
float avgX = 0.0
|
|
float avgY = 0.0
|
|
float avgZ = 0.0
|
|
int iPlantTypeCount = 0
|
|
Actor closestActor = none
|
|
|
|
; Constants
|
|
float fWaitingToDieTimer = 10.0
|
|
|
|
|
|
; Called by the spawner to kick off the processing on this Moth
|
|
Event OnStart()
|
|
LoadPlantLists()
|
|
|
|
; Pick a plant type that we're attracted to
|
|
iPlantTypeCount = PlantTypes.GetSize()
|
|
|
|
; Vary size a bit
|
|
SetScale(RandomFloat(fMinScale, fMaxScale))
|
|
|
|
; Switch state and trigger a callback immediately
|
|
; ; Debug.TraceConditional("Moth " + self + " warping to state AtPlant", bCritterDebug)
|
|
|
|
; test moved to Critter [indent retained] [USKP 2.0.1]
|
|
WarpToNewPlant()
|
|
; ; Debug.TraceConditional("Moth " + self + " registering for update", bCritterDebug)
|
|
|
|
; Enable the critter
|
|
Enable()
|
|
|
|
if CheckFor3D(self)
|
|
; Switch to keyframe state
|
|
SetMotionType(Motion_Keyframed, false)
|
|
|
|
; Get ready to start moving
|
|
RegisterForSingleUpdate(0.0)
|
|
else
|
|
DisableAndDelete(false)
|
|
endIf
|
|
endEvent
|
|
|
|
Function LoadPlantLists()
|
|
;Form cabbage = Game.GetFormFromFile(0x000BCF48, "Skyrim.esm")
|
|
;if !VeryShortPlants.HasForm(cabbage)
|
|
; debug.trace("[Butterflies Unchained] Loading cabbage form into form list..")
|
|
; VeryShortPlants.AddForm(cabbage)
|
|
;endif
|
|
endFunction
|
|
|
|
; The Current plant object
|
|
ObjectReference currentPlant = none
|
|
|
|
;/ clear TargetObject [USKP 2.0.1]
|
|
/;
|
|
Function TargetClear()
|
|
currentPlant = none
|
|
endFunction
|
|
|
|
; Moth is at the plant
|
|
State AtPlant
|
|
|
|
Event OnUpdate()
|
|
; Is the player too far?
|
|
if CheckViableDistance()
|
|
;/// [USKP 2.0.1]
|
|
; Kill this critter
|
|
DisableAndDelete()
|
|
elseif (spawner.iCurrentCritterCount > spawner.iMaxCritterCount) || (spawner.iCurrentCritterCount < 0)
|
|
; something's up with the spawner. Kill critters until it recovers
|
|
; debug.trace(self+" updated, but spawner ("+spawner+") has bad iCurrentCritterCount ("+spawner.iCurrentCritterCount+")")
|
|
disableAndDelete()
|
|
else
|
|
///;
|
|
if (ShouldFlockAroundPlayer())
|
|
; Player is close enough and has the ingredient we're attracted to,
|
|
; If applicable, play takeoff animation
|
|
DoPathStartStuff()
|
|
|
|
; Flock to the player
|
|
FlockToPlayer()
|
|
else
|
|
if (Spawner && Spawner.IsActiveTime())
|
|
; Check whether we should flee and move faster
|
|
float fspeed = 0.0
|
|
if (closestActor != none)
|
|
; ;Debug.Trace(self + " Oh noes! there is an Actor " + closestActor + " nearby, Flee")
|
|
; Move fast
|
|
fspeed = fFleeTranslationSpeed
|
|
else
|
|
; Move at regular speed
|
|
fspeed = RandomFloat(fTranslationSpeedMean - fTranslationSpeedVariance, fTranslationSpeedMean + fTranslationSpeedVariance)
|
|
endIf
|
|
|
|
; Time to take off for another plant
|
|
GoToNewPlant(fspeed)
|
|
else
|
|
; Time to go to bed,
|
|
BellShapeTranslateToRefAtSpeedAndGotoState(Spawner, fBellShapePathHeight, fTranslationSpeedMean, fMaxRotationSpeed, "KillForTheNight")
|
|
endIf
|
|
endIf
|
|
bCalculating = False; [USKP 2.0.4]
|
|
endIf
|
|
closestActor = none; [USKP 2.0.4]
|
|
endEvent
|
|
|
|
Event OnCritterGoalReached()
|
|
; traceConditional(self + " reached goal", bCritterDebug)
|
|
if PlayerRef; interlock, but never delete during Translation [USKP 2.0.1]
|
|
closestActor = Game.FindClosestActorFromRef(self, fActorDetectionDistance)
|
|
if closestActor
|
|
; There is an actor right there, trigger the update right away, so we'll flee
|
|
; ; Debug.TraceConditional("Moth " + self + " registering for update", bCritterDebug)
|
|
RegisterForSingleUpdate(0.0)
|
|
else
|
|
; Wait at the plant, then take off again
|
|
; ; Debug.TraceConditional("Moth " + self + " registering for update", bCritterDebug)
|
|
RegisterForSingleUpdate(RandomFloat(fTimeAtPlantMin, fTimeAtPlantMax))
|
|
endIf
|
|
endIf
|
|
EndEvent
|
|
|
|
endState
|
|
|
|
; When the player has the ingredient we're interested in, follow him
|
|
State FollowingPlayer
|
|
|
|
;! Event OnCritterGoalReached()
|
|
Event OnUpdate(); [USKP 2.0.1]
|
|
; prevent repeat calculations [USKP 2.0.4]
|
|
If bCalculating
|
|
return
|
|
EndIf
|
|
bCalculating = True; [USKP 2.0.3]
|
|
; Are we too far from our spawner?
|
|
if (Spawner && Spawner.GetDistance(self) < fLeashLength && ShouldFlockAroundPlayer())
|
|
; Nope, flock to the player
|
|
FlockToPlayer()
|
|
else
|
|
; Go back to the plants
|
|
GoToNewPlant(fFlockTranslationSpeed)
|
|
endIf
|
|
bCalculating = False; [USKP 2.0.4]
|
|
endEvent
|
|
|
|
Event OnCritterGoalReached()
|
|
; traceConditional(self + " about to reach goal", bCritterDebug)
|
|
if PlayerRef; interlock, but never delete during Translation [USKP 2.0.1]
|
|
RegisterForSingleUpdate(0.0)
|
|
endIf
|
|
EndEvent
|
|
|
|
endState
|
|
|
|
; When the moths go to sleep, they get deleted
|
|
State KillForTheNight
|
|
|
|
;! Event OnCritterGoalReached()
|
|
Event OnUpdate(); [USKP 2.0.1]
|
|
; We've reached the nest, die
|
|
; debug.trace ("Killing for the night: "+self)
|
|
DisableAndDelete()
|
|
endEvent
|
|
|
|
Event OnCritterGoalReached()
|
|
; traceConditional(self + " about to reach goal", bCritterDebug)
|
|
if PlayerRef; interlock, but never delete during Translation [USKP 2.0.1]
|
|
RegisterForSingleUpdate(0.0)
|
|
endIf
|
|
EndEvent
|
|
|
|
endState
|
|
|
|
; Helper method to indicate whether the player has the ingredient
|
|
bool Function ShouldFlockAroundPlayer()
|
|
; if (PlayerRef.GetDistance(Spawner) > fRadius)
|
|
; return false
|
|
; endIf
|
|
; return (PlayerRef.GetItemCount(IngredientType) > 0)
|
|
return false
|
|
endFunction
|
|
|
|
; Utility method, makes a moth flock to a random point around the player
|
|
Function FlockToPlayer()
|
|
; Switch state
|
|
; ; Debug.TraceConditional("Moth " + self + " going to state FollowingPlayer", bCritterDebug)
|
|
gotoState("FollowingPlayer")
|
|
|
|
; re-check viability [USKP 2.0.3]
|
|
if !(PlayerRef ;/&& CheckCellAttached(self) && Spawner && CheckCellAttached(Spawner)/;)
|
|
RegisterForSingleUpdate(fWaitingToDieTimer)
|
|
return
|
|
endif
|
|
|
|
; Pick a random point around the player
|
|
float ftargetX = PlayerRef.X + RandomFloat(-fFlockPlayerXYDist, fFlockPlayerXYDist)
|
|
float ftargetY = PlayerRef.Y + RandomFloat(-fFlockPlayerXYDist, fFlockPlayerXYDist)
|
|
float ftargetZ = PlayerRef.Z + RandomFloat(fFlockPlayerZDistMin, fFlockPlayerZDistMax)
|
|
float ftargetAngleZ = RandomFloat(-180, 180)
|
|
float ftargetAngleX = RandomFloat(-20, 20)
|
|
float fpathCurve = RandomFloat(fPathCurveMean - fPathCurveVariance, fPathCurveMean + fPathCurveVariance)
|
|
|
|
; Travel to it
|
|
if CheckViability()
|
|
return
|
|
endIf
|
|
SplineTranslateTo(ftargetX, ftargetY, ftargetZ, ftargetAngleX, 0.0, ftargetAngleZ, fpathCurve, fFlockTranslationSpeed, fMaxRotationSpeed)
|
|
endFunction
|
|
|
|
ObjectReference Function PickPlant(float x, float y, float z, float searchDistance, float searchIncrease)
|
|
; re-check viability [USKP 2.0.1]
|
|
if !(PlayerRef ;/&& CheckCellAttached(self) && Spawner && CheckCellAttached(Spawner)/;)
|
|
return none
|
|
endif
|
|
|
|
; Look for a random plant within the radius of the Spawner
|
|
int isafetyCheck = 10; was 5, match FireFly [USKP 2.0.1]
|
|
int distanceScale = 1
|
|
ObjectReference newPlant = CurrentPlant
|
|
|
|
while PlayerRef && isafetyCheck > 0; [USKP 2.0.1b]
|
|
|
|
; Grab a random plant from the list of valid plant types
|
|
newPlant = Game.FindRandomReferenceOfAnyTypeInList(PlantTypes, x, y, z, searchDistance + (searchIncrease * distanceScale))
|
|
|
|
; Check whether the new plant is valid (different from current)
|
|
; and 3D check because critters can attempt to pick disabled Nirnroots [USKP 2.0.1]
|
|
; and not too close to an actor
|
|
if (newPlant != none && newPlant != currentPlant && !newPlant.IsDisabled() \
|
|
&& Game.FindClosestActorFromRef(newPlant, fActorDetectionDistance) == none \
|
|
&& CheckCellAttached(newPlant) && CheckFor3D(newPlant) && newPlant != fLastPlant)
|
|
float plantX = newPlant.GetPositionX()
|
|
float plantY = newPlant.GetPositionY()
|
|
float plantZ = newPlant.GetPositionZ()
|
|
float distanceFromAvg = Math.sqrt(Math.pow(plantX - avgX, 2) + Math.pow(plantY - avgY, 2) + Math.pow(plantZ - avgZ, 2))
|
|
|
|
; Enforce distance from average position, unless we are on our last safety check.
|
|
; In which case we allow it to pass to stop the butterfly from despawning
|
|
if (distanceFromAvg >= fMinWander || isafetyCheck == 1)
|
|
Form plantForm
|
|
|
|
; Fixes butterfly hovering by setting the height according to the plant
|
|
if (GroundPlants == none || VeryShortPlants == none \
|
|
|| ShortPlants == none || TallPlants == none \
|
|
|| VeryTallPlants == none)
|
|
Debug.Trace("[Butterflies Unchained] One or more of your mods adds a butterfly that requires a compatibility patch for optimal performance. You may encounter hovering butterflies in the meantime.")
|
|
else
|
|
plantForm = newPlant.GetBaseObject()
|
|
if (GroundPlants.Find(plantForm) != -1)
|
|
SetPositionVariance(10.0, 10.0, 5.0, 10.0)
|
|
elseif (VeryShortPlants.Find(plantForm) != -1)
|
|
SetPositionVariance(10.0, 10.0, 20.0, 30.0)
|
|
elseif (ShortPlants.Find(plantForm) != -1)
|
|
SetPositionVariance(15.0, 15.0, 35.0, 50.0)
|
|
elseif (TallPlants.Find(plantForm) != -1)
|
|
SetPositionVariance(15.0, 15.0, 50.0, 90.0)
|
|
elseif (VeryTallPlants.Find(plantForm) != -1)
|
|
SetPositionVariance(15.0, 15.0, 115.0, 140.0)
|
|
else
|
|
SetPositionVariance(15.0, 15.0, 50.0, 100.0)
|
|
endif
|
|
endif
|
|
|
|
if ! bSKSE || !newPlant.IsHarvested() || IgnoreHarvestedPlants == None || IgnoreHarvestedPlants.Find(plantForm) == -1
|
|
return newPlant; [USKP 2.0.1b]
|
|
endif
|
|
endif
|
|
endIf
|
|
|
|
if ((fSearchDistance + (100 * distanceScale)) < fMaxPlayerDistance)
|
|
distanceScale += 1
|
|
endif
|
|
|
|
; Safety counter
|
|
isafetyCheck -= 1
|
|
endWhile
|
|
; [USKP 2.0.1]
|
|
;Debug.Trace("Moth ( " + fSpawnerX + ", " + fSpawnerY + ", " + fSpawnerZ + ") " + self + " couldn't find a valid plant to go to", 1)
|
|
return none
|
|
endFunction
|
|
|
|
; Finds a new plant to fly to
|
|
ObjectReference Function PickNextPlant()
|
|
float wanderRangeX = 0
|
|
float wanderRangeY = 0
|
|
|
|
float posX = self.GetPositionX()
|
|
float posY = self.GetPositionY()
|
|
float posZ = self.GetPositionZ()
|
|
|
|
; create a vector in the direction of the butterfly's movement to encourage exploration
|
|
if (fLastPlant != none)
|
|
float lastPlantX = fLastPlant.GetPositionX()
|
|
float lastPlantY = fLastPlant.GetPositionY()
|
|
float distanceTraveledX = posX - lastPlantX
|
|
float distanceTraveledY = posY - lastPlantY
|
|
|
|
float distanceTraveled = Math.sqrt(Math.pow(distanceTraveledX, 2) + Math.pow(distanceTraveledY, 2))
|
|
|
|
if distanceTraveled > 0
|
|
wanderRangeX = RandomFloat(fMinWander, fMaxWander) * Math.cos(distanceTraveledX / distanceTraveled)
|
|
if (distanceTraveledX < 0) ; more efficient than calling math.abs
|
|
wanderRangeX *= -1
|
|
endif
|
|
wanderRangeY = RandomFloat(fMinWander, fMaxWander) * Math.sin(distanceTraveledY / distanceTraveled)
|
|
endif
|
|
endif
|
|
|
|
if wanderRangeX == 0
|
|
wanderRangeX = RandomFloat(fMinWander, fMaxWander) * RandomInt(-1, 1)
|
|
endif
|
|
|
|
if wanderRangeY == 0
|
|
wanderRangeY = RandomFloat(fMinWander, fMaxWander) * RandomInt(-1, 1)
|
|
endif
|
|
|
|
return PickPlant(posX + wanderRangeX, posY + wanderRangeY, posZ, fSearchDistance, fSearchIncrease)
|
|
endFunction
|
|
|
|
;; To maintain optimal compatibility with other mods, new function was created rather than having parameters added
|
|
ObjectReference Function PickSpawnPlant()
|
|
; re-check viability [USKP 2.0.1]
|
|
if !(PlayerRef ;/&& CheckCellAttached(self) && Spawner && CheckCellAttached(Spawner)/;)
|
|
return none
|
|
endif
|
|
|
|
; Look for a random plant within the radius of the Spawner
|
|
int isafetyCheck = 10; was 5, match FireFly [USKP 2.0.1]
|
|
ObjectReference newPlant = CurrentPlant
|
|
|
|
while PlayerRef && isafetyCheck > 0; [USKP 2.0.1b]
|
|
|
|
; Grab a random plant from the list of valid plant types
|
|
newPlant = Game.FindRandomReferenceOfAnyTypeInList(PlantTypes, fSpawnerX, fSpawnerY, fSpawnerZ, fLeashLength * fLeashMultiplier)
|
|
|
|
; Check whether the new plant is valid (different from current)
|
|
; and 3D check because critters can attempt to pick disabled Nirnroots [USKP 2.0.1]
|
|
; and not too close to an actor
|
|
if (newPlant != none && newPlant != currentPlant && !newPlant.IsDisabled() \
|
|
&& Game.FindClosestActorFromRef(newPlant, fActorDetectionDistance) == none \
|
|
&& CheckCellAttached(newPlant) && CheckFor3D(newPlant))
|
|
return newPlant; [USKP 2.0.1b]
|
|
endIf
|
|
|
|
; Safety counter
|
|
isafetyCheck -= 1
|
|
endWhile
|
|
; [USKP 2.0.1]
|
|
; Debug.Trace("Moth " + self + " couldn't find a valid plant to go to", 1)
|
|
return none
|
|
endFunction
|
|
|
|
; Picks a new plant and fly to it if possible
|
|
Function GoToNewPlant(float afSpeed)
|
|
; Find a plant reference, trying to pick a different one than the current one
|
|
ObjectReference newPlant = PickNextPlant()
|
|
|
|
if (newPlant != none)
|
|
; Update the last plant to the current one
|
|
fLastPlant = currentPlant
|
|
|
|
; Update the current plant to the new one
|
|
currentPlant = newPlant
|
|
|
|
float newPlantX = newPlant.GetPositionX()
|
|
float newPlantY = newPlant.GetPositionY()
|
|
float newPlantZ = newPlant.GetPositionZ()
|
|
|
|
; Update avg coord vals
|
|
if (avgX == 0)
|
|
avgX = newPlantX
|
|
else
|
|
avgX = (avgX + newPlantX) / 2
|
|
endif
|
|
|
|
if (avgY == 0)
|
|
avgY = newPlantY
|
|
else
|
|
avgY = (avgY + newPlantY) / 2
|
|
endif
|
|
|
|
if (avgZ == 0)
|
|
avgZ = newPlantZ
|
|
else
|
|
avgZ = (avgX + newPlantZ) / 2
|
|
endif
|
|
|
|
; Pick random landing node
|
|
; And start moving towards it
|
|
string landingMarkerName = LandingMarkerPrefix + RandomInt(1, 3)
|
|
float newPlantDistance = Math.sqrt(Math.pow(newPlantX - self.GetPositionX(), 2) + Math.pow(newPlantY - self.GetPositionY(), 2) + Math.pow(newPlantZ - self.GetPositionZ(), 2))
|
|
float adjustedBellShapePathHeight = fBellShapePathHeight - (fBellShapePathHeight * (Math.pow(0.995, newPlantDistance)))
|
|
|
|
bool bIsLoaded = newPlant.Is3DLoaded()
|
|
if (bIsLoaded && newPlant.HasNode(landingMarkerName))
|
|
BellShapeTranslateToRefNodeAtSpeedAndGotoState(CurrentPlant, landingMarkerName, adjustedBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
|
else
|
|
; traceConditional(self + " could not find landing marker " + landingMarkerName + " on plant " + newPlant, bCritterDebug)
|
|
|
|
string firstMarkerName = LandingMarkerPrefix + 1
|
|
if (bIsLoaded && newPlant.HasNode(firstMarkerName))
|
|
BellShapeTranslateToRefNodeAtSpeedAndGotoState(CurrentPlant, firstMarkerName, adjustedBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
|
else
|
|
; traceConditional(self + " could not find landing marker " + firstMarkerName + " on plant " + newPlant, bCritterDebug)
|
|
BellShapeTranslateToRefAtSpeedAndGotoState(CurrentPlant, adjustedBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
|
endIf
|
|
endIf
|
|
else
|
|
; This moth is stuck, wait until the player is far enough away that it can delete itself
|
|
; Debug.Trace("Moth " + self + " is stuck and will wait to kill itself", 1)
|
|
gotoState("KillForTheNight"); [USKP 2.0.1]
|
|
RegisterForSingleUpdate(fWaitingToDieTimer)
|
|
endIf
|
|
endFunction
|
|
|
|
Function WarpToNewPlant()
|
|
; Find a plant reference, trying to pick a different one than the current one
|
|
ObjectReference newPlant = PickSpawnPlant()
|
|
|
|
if (newPlant != none)
|
|
; Update the current plant to the new one
|
|
currentPlant = newPlant
|
|
bool bIsLoaded = newPlant.Is3DLoaded()
|
|
|
|
; Pick random landing node
|
|
; And start moving towards it
|
|
string landingMarkerName = LandingMarkerPrefix + RandomInt(1, 3)
|
|
if (bIsLoaded && newPlant.HasNode(landingMarkerName))
|
|
WarpToRefNodeAndGotoState(CurrentPlant, landingMarkerName, "AtPlant")
|
|
else
|
|
; traceConditional(self + " could not find landing marker " + landingMarkerName + " on plant " + newPlant, bCritterDebug)
|
|
string firstMarkerName = LandingMarkerPrefix + 1
|
|
if (bIsLoaded && newPlant.HasNode(firstMarkerName))
|
|
WarpToRefNodeAndGotoState(CurrentPlant, firstMarkerName, "AtPlant")
|
|
else
|
|
; traceConditional(self + " could not find landing marker " + firstMarkerName + " on plant " + newPlant, bCritterDebug)
|
|
WarpToRefAndGotoState(CurrentPlant, "AtPlant")
|
|
endIf
|
|
endIf
|
|
else
|
|
; This moth is stuck, wait until the player is far enough away that it can delete itself
|
|
; Debug.Trace("Moth " + self + " is stuck and will wait to kill itself", 1)
|
|
gotoState("KillForTheNight"); [USKP 2.0.1]
|
|
RegisterForSingleUpdate(fWaitingToDieTimer)
|
|
endIf
|
|
endFunction
|
|
|
|
Function DoPathStartStuff()
|
|
; Transition to the flight state
|
|
SetAnimationVariableFloat("fTakeOff", 1.0); [USKP 2.0.1]
|
|
endFunction
|
|
|
|
Function DoPathEndStuff()
|
|
; Transition to the hover/landed state
|
|
SetAnimationVariableFloat("fTakeOff", 0.0); [USKP 2.0.1]
|
|
endFunction
|