Added Butterflies Unchained 1.1 by runesick
This commit is contained in:
parent
46a4d3ce4a
commit
ea329209ee
@ -763,6 +763,7 @@ XP32 Maximum Skeleton Extended - XPMSE by Groovtama
|
||||
Vanilla Script (micro)Optimizations by subhuman0100
|
||||
Unnecessarily Fixed Fixed Dragon Stalking Fix by tarlazo and KirbonatedBeverage
|
||||
Precision Creatures by NickaNak (werewolf behaviors)
|
||||
Butterflies Unchained by runesick
|
||||
|
||||
Japanese Fonts
|
||||
"Corporate Mingcho" made by LOGOTYPE.JP Jimukyoku
|
||||
|
@ -759,6 +759,7 @@ XP32 Maximum Skeleton Extended - XPMSE by Groovtama
|
||||
Vanilla Script (micro)Optimizations by subhuman0100
|
||||
Unnecessarily Fixed Fixed Dragon Stalking Fix by tarlazo and KirbonatedBeverage
|
||||
Precision Creatures by NickaNak (werewolf behaviors)
|
||||
Butterflies Unchained by runesick
|
||||
|
||||
Japanese Fonts
|
||||
"Corporate Mingcho" made by LOGOTYPE.JP Jimukyoku
|
||||
|
@ -759,6 +759,7 @@ XP32 Maximum Skeleton Extended - XPMSE by Groovtama
|
||||
Vanilla Script (micro)Optimizations by subhuman0100
|
||||
Unnecessarily Fixed Fixed Dragon Stalking Fix by tarlazo and KirbonatedBeverage
|
||||
Precision Creatures by NickaNak (werewolf behaviors)
|
||||
Butterflies Unchained by runesick
|
||||
|
||||
Japanese Fonts
|
||||
"Corporate Mingcho" made by LOGOTYPE.JP Jimukyoku
|
||||
|
@ -310,6 +310,13 @@ Function SetSpawnerProperties()
|
||||
PlayerRef = Game.GetPlayer()
|
||||
endFunction
|
||||
|
||||
Function SetPositionVariance(float xVar, float yVar, float minZVar, float maxZVar)
|
||||
fPositionVarianceX = xVar
|
||||
fPositionVarianceY = yVar
|
||||
fPositionVarianceZMin = minZVar
|
||||
fPositionVarianceZMax = maxZVar
|
||||
EndFunction
|
||||
|
||||
; Checks that the critter is all initialized, and if so, kick off the behavior
|
||||
Function CheckStateAndStart()
|
||||
; ; Debug.TraceConditional("Critter " + self + "bDefaultPropertiesInitialized=" + bDefaultPropertiesInitialized + ", bSpawnerVariablesInitialized=" + bSpawnerVariablesInitialized, bCritterDebug)
|
||||
|
@ -8,11 +8,20 @@ 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 = 10.0 auto
|
||||
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}
|
||||
@ -23,7 +32,7 @@ float Property fTranslationSpeedVariance = 50.0 auto
|
||||
float Property fFleeTranslationSpeed = 300.0 auto
|
||||
{The movement speed when fleeing from the player}
|
||||
float Property fBellShapePathHeight = 150.0 auto
|
||||
{The height of the bell shaped path}
|
||||
{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
|
||||
@ -44,8 +53,20 @@ 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
|
||||
|
||||
@ -55,6 +76,8 @@ 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()
|
||||
|
||||
@ -82,6 +105,14 @@ Event OnStart()
|
||||
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
|
||||
|
||||
@ -241,8 +272,111 @@ Function FlockToPlayer()
|
||||
SplineTranslateTo(ftargetX, ftargetY, ftargetZ, ftargetAngleX, 0.0, ftargetAngleZ, fpathCurve, fFlockTranslationSpeed, fMaxRotationSpeed)
|
||||
endFunction
|
||||
|
||||
; Finds a new plant to fly to
|
||||
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 (!newPlant.IsHarvested() || 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))
|
||||
|
||||
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)
|
||||
else
|
||||
wanderRangeX = RandomFloat(fMinWander, fMaxWander) * RandomInt(-1, 1)
|
||||
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
|
||||
@ -255,7 +389,7 @@ ObjectReference Function PickNextPlant()
|
||||
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)
|
||||
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]
|
||||
@ -280,22 +414,51 @@ Function GoToNewPlant(float afSpeed)
|
||||
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)))
|
||||
if (newPlant.HasNode(landingMarkerName))
|
||||
BellShapeTranslateToRefNodeAtSpeedAndGotoState(CurrentPlant, landingMarkerName, fBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
||||
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 (newPlant.HasNode(firstMarkerName))
|
||||
BellShapeTranslateToRefNodeAtSpeedAndGotoState(CurrentPlant, firstMarkerName, fBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
||||
BellShapeTranslateToRefNodeAtSpeedAndGotoState(CurrentPlant, firstMarkerName, adjustedBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
||||
else
|
||||
; traceConditional(self + " could not find landing marker " + firstMarkerName + " on plant " + newPlant, bCritterDebug)
|
||||
BellShapeTranslateToRefAtSpeedAndGotoState(CurrentPlant, fBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
||||
BellShapeTranslateToRefAtSpeedAndGotoState(CurrentPlant, adjustedBellShapePathHeight, afSpeed, fMaxRotationSpeed, "AtPlant")
|
||||
endIf
|
||||
endIf
|
||||
else
|
||||
@ -308,7 +471,7 @@ endFunction
|
||||
|
||||
Function WarpToNewPlant()
|
||||
; Find a plant reference, trying to pick a different one than the current one
|
||||
ObjectReference newPlant = PickNextPlant()
|
||||
ObjectReference newPlant = PickSpawnPlant()
|
||||
|
||||
if (newPlant != none)
|
||||
; Update the current plant to the new one
|
||||
|
Loading…
Reference in New Issue
Block a user