ResetRespawnRegrow FloraTreesPlants in a NoResetZone?

Post » Sun Nov 18, 2012 6:21 pm

What I'm trying to figure out is how to reset the flora / harvestable trees in an area that has the "No Reset" flag ticked in the encounter zone. It appears that the Flora/Tree stuff is hard coded since the Flora.psc file is empty and Tree.psc doesn't exist. It appears to extend Activator.psc, but there's nothing in there either. The few relevant things in ObjectReference.psc don't seem to have any affect on flora/trees.

All purchasable vanilla homes are set to "NoResetZone" and therefore, the flora never regrows. The Arch Mage quarters is set to "NONE", so that doesn't apply. I'm basically looking for a workaround to reset flora in the no reset zones where changing the zone isn't practical. But coupled with the lack of a harvested check, I'm pretty stumped.

The Nirnroot plants and the mining ore's don't count since they're actual activators and not flora/trees. because they're not flora, the function in ObjectReference.psc actually work on them. In their scripts, they use something akin to:
Event OnReset()	Self.Reset()	Self.ClearDestruction()	Self.SetDestroyed(False)EndEvent
None of which has any affect on flora/trees.

There also seems to be no way to check if the flora has been harvested or not. I thought IsActivationBlocked might return true after harvesting, but it does not. If you put a script on the flora and a hello world in the OnActivate block, it will hello world even if it's harvested. Which also means it's not being set to "Destroyed". But lacking a "GetDestroyed / IsDestroyed" check, that probably wouldn't help much anyway.

From looking at the flora nif's, I'm pretty baffled on how it works. Some more intuitive ones switch between nodes on activation (flora: mushrooms), but others have me completely at a loss (tree: blue, red, purple flowers, etc). Either way, there doesn't seem to be anything in papyrus that can interact with them.

I've seen some talk of making custom activators that resemble the flora to simulate harvesting, but that would be incompatible with any mod that makes changes to the flora/trees (or would it?). At this point, that doesn't bother me since leaving it default would be compatible with other mods, but it can only be harvested once. What I'm not sure about is if each flora activator would be persistent? I'm not sure of a reasonable amount of persistent flora (25, 50, 100) would be? Also, making it an activator would require language plugins since the on activate text would have to be changed to "Harvest".

If it is made into an activator, how do you switch to the "harvested" mode when activated and then reset it back to the un-harvested mode at a later time? It seems like it would always appear harvestable if it's an activator.

I was also thinking that if there was a harvested check, loop through the cell or formlist of fora and use PlaceAtMe to replace picked ones, but there's no harvested check. So to go that route, I would have to replace all flora every so often. That way if it has been picked or not is irrelevant. I'm just wondering what kind of slowdowns would happen by disabling, deleting and the placing all new flora in an area every 10 days or so. It might be kind of chuggy on cell load every now and then.

I'm also wondering if somehow SKSE could introduce some type of "IsHarvested" check on the flora / object ref's? Or maybe even a "Reset()" for flora/trees akin to the function in the object reference script?

I guess lastly I would like to know if it's possible to attach a script to an object that was placed with PlaceAtMe for flora/trees (not actors)? So that a flora can be placed and the scale/angle mirrored with a DoOnce bool in the script that can be flipped when activated for later checks.

Thanks

Some other threads on this matter:
http://www.gamesas.com/topic/1386742-is-it-possible-to-have-respawning-and-non-respawning-containers-in-same-cell/page__p__21046637__hl__flora%20reset__fromsearch__1#entry21046637
http://www.gamesas.com/topic/1377899-respawning-plants/page__p__20859745__hl__plant%20reset__fromsearch__1#entry20859745
User avatar
Stephanie Kemp
 
Posts: 3329
Joined: Sun Jun 25, 2006 12:39 am

Post » Sun Nov 18, 2012 4:57 am

Weirdly flora is not listed (at all) as part of the CellReset mechanism: http://www.creationkit.com/Cell_Reset

So does cell-reset actually reset the harvested state of a plant? (I'm not saying it doesn't ... I never tested it ... but it is not listed as being one the things that resets)


There IS (so says the wiki) a SKSE function to test whether or not a plant has been harvested (individual level): http://www.creationkit.com/ObjectReference_Script (click SKSE Member Functions in the contents list) ... there is no detail on the wiki about that function, though

So you could ... maybe ... use OnActivate on a plant to set up a check to see if the player actually harvested it (a few seconds after OnActivate has completed)? In fact, a book's first page IS read on Activate ... Is a flower picked on onActivate ... or does OnActivate only give the player the choice of picking it? I'm not sure.


And then there is the OnReset that is applicable to individual objects: http://www.creationkit.com/OnReset_-_ObjectReference

(Check the notes at the bottom of that one). So, it appears this could also be used - if you setup to test for it - to see when a plant has actually been reset (and then do something about it).



I'm not sure I actually answered any of your questions ... but that's about the first time I ever looked at flora, so I enjoyed myself while I was at it!) ;)
User avatar
Chelsea Head
 
Posts: 3433
Joined: Thu Mar 08, 2007 6:38 am

Post » Sun Nov 18, 2012 6:29 am

Weirdly flora is not listed (at all) as part of the CellReset mechanism: http://www.creationkit.com/Cell_Reset

So does cell-reset actually reset the harvested state of a plant? (I'm not saying it doesn't ... I never tested it ... but it is not listed as being one the things that resets)
I'm like 99.9% sure the only way to get plants to reset is if the area they are in resets. Non flora/trees can be overridden with functions in the ObjectReference script. Changing a player home zone to reset make me queasy. The Arch Mage quarters reset, but all of the containers I've seen have "Respawns" unchecked. Otherwise, stuff would be lost and I'm not sure how manually placed items in the area would fare? Would they remain through a reset? I really don't know enough about what's going on behind the scenes to say.

There IS (so says the wiki) a SKSE function to test whether or not a plant has been harvested (individual level): http://www.creationkit.com/ObjectReference_Script (click SKSE Member Functions in the contents list) ... there is no detail on the wiki about that function, though

So you could ... maybe ... use OnActivate on a plant to set up a check to see if the player actually harvested it (a few seconds after OnActivate has completed)? In fact, a book's first page IS read on Activate ... Is a flower picked on onActivate ... or does OnActivate only give the player the choice of picking it? I'm not sure.
Nice! I completely missed that. I even missed it looking through the skse source. Right in front of my face... :tongue:

It does work and that would at least potentially cut down on what needs to be deleted/replaced, which is cool. Either an activator with a formlist of flora in the area that goes through looking for harvested and then deleting and placing new ones. Or attaching a script to each flora ref placed in the ck that disables the original, places a new one and stores the refid of the placed item in an ObjectReference property to check for harvested later on. Unless a script can be attached to a placed ref on-the-fly, the stored ObjectReference property would probably be persistent (meaning all flora is persistent).

The first would probably be a little slow every now and then on cell load, but only a few persistent activators. The second might be a little faster on cell loads, but might bloat saves and what not. If only the "ObjRef.Reset()" worked on them as well, then there would be no persistence needed.

And then there is the OnReset that is applicable to individual objects: http://www.creationkit.com/OnReset_-_ObjectReference

(Check the notes at the bottom of that one). So, it appears this could also be used - if you setup to test for it - to see when a plant has actually been reset (and then do something about it).

I'm not sure I actually answered any of your questions ... but that's about the first time I ever looked at flora, so I enjoyed myself while I was at it!) :wink:
I'm pretty sure this event only fires when the area resets. In a test script I have it notify when events happens and "OnReset" never shows up in a no reset zone.

This is also my first whack at it since I didn't realize they never regrow. To test it, I "coc Whiterun" and pick a few plants near the bridge. Then coc into a cell that uses the NoResetZone and pick a few plants (eg: coc WhiterunBreezeHome [if you own it]). Then go to a completely different cell than Whiterun (eg: coc WarehousePrefabs) and wait 10 days or type:
pcbSetGS iHoursToRespawnCell 1SetGS iHoursToRespawnCellCleared 1
and wait two hours. (per the cell reset article you linked :wink:)

Then go back to Whiterun ("coc Whiterun") and the plants will have regrown around the bridge. Now try the no reset cell ("coc WhiterunBreezeHome") and they will still be harvested.

I'm going to have a few more whacks at it and see what happens.

Thanks
User avatar
Chad Holloway
 
Posts: 3388
Joined: Wed Nov 21, 2007 5:21 am

Post » Sun Nov 18, 2012 4:49 pm

I'm like 99.9% sure the only way to get plants to reset is if the area they are in resets. Non flora/trees can be overridden with functions in the ObjectReference script. Changing a player home zone to reset make me queasy. The Arch Mage quarters reset, but all of the containers I've seen have "Respawns" unchecked. Otherwise, stuff would be lost and I'm not sure how manually placed items in the area would fare? Would they remain through a reset? I really don't know enough about what's going on behind the scenes to say.

If they are Quest Items - in a chest, or not - or player dropped items, then as far as I know they are not reset (even if the quest item is in a chest that does reset ... the quest items stays but any other lists for that container are refreshed)

.... Unless a script can be attached to a placed ref on-the-fly, the stored ObjectReference property would probably be persistent (meaning all flora is persistent).
http://www.creationkit.com/Dynamically_Attaching_Scripts

(If you can find some hook to hang it off (the player entering the cell, or something?)



Best of luck :)
User avatar
Allison Sizemore
 
Posts: 3492
Joined: Wed Jul 19, 2006 6:09 am

Post » Sun Nov 18, 2012 7:39 am

I tried Dynamically Attaching Scripts to Objects from that article, but I'm still fuzzy on a few things. I think there would have to be many alias's (maybe hundreds?) for each flora in the area. I put an activator in the cell that doesn't reset that starts the alias quest OnCellAttach. I only had 1 alias so only 1 of the flora that matched the flora type list was returning anything. So I'm pretty sure there would have to be quite a few alias's and a check to make sure there aren't duplicates. Does it fill one with one ref and then move to the next automatically (it knows if a ref already has an alias)?

Either way, I could only seem to get the "OnInit" event to respond. I'm not sure how to get the OnCellAttach events from an alias script. It would need to be an event that happens every cell load.

That would be nice if it works. I think it would only make the flora in the are persistent while in it. I'm not really sure how to keep track though, since stuff is being created/deleted. The alias stuff is new to me.

I did manage to get something working using formlists, but it would probably be really slow on a large scale. It works ok on a small area though. Using an activator, a formlist filled with flora refs (backup) and a blank formlist to store placed refs for each area (each house gets an activator and 2 formlists). It disables the refs placed by the ck just in case and places a new ref at its location. Then, every 10 days, if any ref in the "placed" formlist has been harvested, it will delete it and place a new one on cell attach. It can also be set to work like the default reset (reset the timer on each visit) to prevent something from going back in one day (picked a day before the reset would have expired).

This can probably be vastly improved upon, but it works as a POC.
Spoiler

Scriptname FloraHelperActivatorScript extends ObjectReference{Flora Helper Activator Script}GlobalVariable Property GameDaysPassed AutoFormList Property g_flFloraList = None Auto ; formlist of flora refs in the same area as this activatorFormList Property g_flFloraPlacedList = None Auto  ; an empty formlist to keep track of placed refs for this areabool Property g_bFromLastVisit = False Auto ; reset the timer every visit like defaultfloat Property g_fDelayHours = 240.0 Auto ; delay in hours between resetsbool Property m_bInit = False Auto Hiddenbool Property m_bHasSKSE = False Auto Hiddenfloat Property m_fLastTrigger = 0.0 Auto HiddenEvent OnInit()	    float fSKSEVer = (SKSE.GetVersion() + SKSE.GetVersionMinor() * 0.01 + SKSE.GetVersionBeta() * 0.0001) as float	    If (fSKSEVer < 1.0509)			    m_bHasSKSE = False			    Debug.Trace("FloraHelperActivatorScript::OnInit: SKSE not found or out of date! Req:1.0509 Ver:" + fSKSEVer)	    Else			    m_bHasSKSE = True	    EndIfEndEventEvent OnCellAttach()	    If (m_bHasSKSE)	    			    If (!m_bInit)					    m_bInit = True					    m_fLastTrigger = GameDaysPassed.GetValue()					    Setup()			    EndIf			    			    If (g_fDelayHours > 0.0)					    If (((GameDaysPassed.GetValue() - m_fLastTrigger) * 24.0) >= g_fDelayHours)							    m_fLastTrigger = GameDaysPassed.GetValue()							    Refresh()					    EndIf			    EndIf			    			    If (g_bFromLastVisit)					    m_fLastTrigger = GameDaysPassed.GetValue()			    EndIf	    EndIfEndEventFunction Setup()	    int iIndex = 0	    int iTotal = g_flFloraList.GetSize()	    	    While (iIndex < iTotal)			    ObjectReference rFloraRef = g_flFloraList.GetAt(iIndex) as ObjectReference			    			    If (rFloraRef as ObjectReference)					    ;ObjectReference rNewFloraRef = Self.PlaceAtMe(rFloraRef.GetbaseObject(), 1, False, True) ; -EDIT-                        ObjectReference rNewFloraRef = rFloraRef.PlaceAtMe(rFloraRef.GetbaseObject(), 1, False, True) ; -EDIT-					    					    MirrorScalePos(rFloraRef, rNewFloraRef)					    					    g_flFloraPlacedList.AddForm(rNewFloraRef)					    					    rNewFloraRef.Enable()					    rFloraRef.Disable()			    EndIf		   			    			    iIndex += 1	    EndWhileEndFunctionFunction Refresh()	    int iIndex = 0	    int iTotal = g_flFloraPlacedList.GetSize()	    	    While (iIndex < iTotal)			    ObjectReference rFloraRef = g_flFloraPlacedList.GetAt(iIndex) as ObjectReference			    			    If (rFloraRef as ObjectReference)					    If (rFloraRef.IsHarvested()) ; skse							    ;ObjectReference rNewFloraRef = Self.PlaceAtMe(rFloraRef.GetbaseObject(), 1, False, True) ; non-persistent, init disabled -EDIT-                                ObjectReference rNewFloraRef = rFloraRef.PlaceAtMe(rFloraRef.GetbaseObject(), 1, False, True) ; non-persistent, init disabled -EDIT-							    							    MirrorScalePos(rFloraRef, rNewFloraRef)							    							    g_flFloraPlacedList.RemoveAddedForm(rFloraRef)							    g_flFloraPlacedList.AddForm(rNewFloraRef)							    							    rNewFloraRef.Enable()							    rFloraRef.Disable()							    rFloraRef.Delete()					    Else							    iIndex += 1					    EndIf			    Else					    iIndex += 1			    EndIf		   	    EndWhileEndFunctionFunction Destroy()	    int iIndex = 0	    ObjectReference rFloraRef = g_flFloraList.GetAt(iIndex) as ObjectReference	    	    While (rFloraRef as ObjectReference)			    rFloraRef.Enable()			    			    iIndex += 1			    rFloraRef = g_flFloraList.GetAt(iIndex) as ObjectReference	    EndWhile	    	    rFloraRef = g_flFloraPlacedList.GetAt(0) as ObjectReference	    	    While (rFloraRef as ObjectReference)			    g_flFloraPlacedList.RemoveAddedForm(rFloraRef)			    			    rFloraRef.Disable()			    rFloraRef.Delete()			    			    rFloraRef = g_flFloraPlacedList.GetAt(0) as ObjectReference	    EndWhile	    	    m_bInit = False	    m_fLastTrigger = 0.0EndFunctionFunction MirrorScalePos(ObjectReference rSourceRef, ObjectReference rDestRef)	    rDestRef.SetScale(rSourceRef.GetScale())	    rDestRef.SetPosition(rSourceRef.GetPositionX(), rSourceRef.GetPositionY(), rSourceRef.GetPositionZ())	    rDestRef.SetAngle(rSourceRef.GetAngleX(), rSourceRef.GetAngleY(), rSourceRef.GetAngleZ())EndFunction

I'll have to try the alias's again after some rest.
User avatar
Zoe Ratcliffe
 
Posts: 3370
Joined: Mon Feb 19, 2007 12:45 am

Post » Sun Nov 18, 2012 7:21 am

I'll have a think about it ... Maybe there is a way of using Dynamic-Attach, but not using Aliases (I never tried that, or spent any time thinking about it)

If I come up with anything I'll post :)


That said: Your FormList method may not be drastically slow. The operations you are doing are pretty quick ... it will just pop it into a new thread and get on with itself, I think

... but then I guess you could end up with a very massive list and iterating that might be painful ... Breaking that list up (maybe into types/species, one list for each?) and then run the "checker" that iterates through the lists on a different "game day" (or just a different game time) would help speed things up (maybe)?
User avatar
asako
 
Posts: 3296
Joined: Wed Oct 04, 2006 7:16 am

Post » Sun Nov 18, 2012 2:01 pm

Ya it would be cool if it was a bit more automatic. The alias's stuff is still throwing me for a loop, something I'm just going to have to keep at for a while.

In a small area, the formlists aren't that bad. It's not really chuggy, it's just that you may see some plants "pop" in regrown on cell attach - as it goes through one by one disabling and enabling. I'm pretty sure I would want to keep tabs on ones that were placed just so that if need be, it can be reverted.

This would probably be impractical on a large scale, but most large areas with flora are already set to reset.

Doing a separate list for each maybe be a little quicker, but the maintenance would probably be very tedious.

I did manage to get it to fill the initial formlist automatically if an additional formlist of flora form types is supplied. So it basically needs 2 empty lists and 1 filled with flora base forms. With some SKSE cell functions, it will loop through the flora and trees (some flora and some not) on cell load and fill the "main" list with the refs placed by the ck. Then it will disable those and place new refs and fill the "placed" list with them. If the "main" list is pre-filled in the CK, it will just use what ever is in there instead of searching the cell during setup.

Either way, the main list is filled with refs placed by the ck and the placed ref is filled with refs placed with PlaceAtMe and can be reverted at any time with Destroy. So it can be used as a temporary workaround or even long term. I still have my fingers crossed that some type of "Reset()" will either get added by Beth or SKSE and eliminate the need for any formlists (loop: if IsHarvested then Reset). If that happens, then a few more doors will open.

Here's a slightly tweaked version of the previous script for the time being:
Spoiler
Scriptname zzFloraHelperActivatorScript extends ObjectReference{Flora Helper Activator Script}GlobalVariable Property GameDaysPassed AutoFormList Property g_flFloraList = None Auto ; formlist of flora refs in the same area as this activator - can be empty if g_flFloraTypesList is notFormList Property g_flFloraPlacedList = None Auto  ; an empty formlist to keep track of placed refs for this areaFormList Property g_flFloraTypesList = None Auto ; formlist of flora forms that are allowed - needed if g_flFloraList is emptybool Property g_bFromLastVisit = False Auto ; reset the timer every visit like defaultfloat Property g_fDelayHours = 240.0 Auto ; delay in hours between resetsbool Property m_bInit = False Auto Hiddenbool Property m_bHasSKSE = False Auto Hiddenbool Property m_bSetup = False Auto Hiddenbool Property m_bStaticList = False Auto Hiddenfloat Property m_fLastTrigger = 0.0 Auto HiddenEvent OnInit()	;Debug.Notification("Flora::OnInit")	SetHasSKSE()EndEventEvent OnCellAttach()	;Debug.Notification("Flora::OnCellAttach")	If (m_bHasSKSE)		If (!m_bInit)			Init()		EndIf				If (!m_bSetup)			If (!m_bInit)				Return			EndIf			If (m_bStaticList)				Setup()			Else				SetupDynamic()			EndIf			;Debug.Notification("Flora::OnCellAttach: Setup Finished")		EndIf				If (g_fDelayHours > 0.0)			If (((GameDaysPassed.GetValue() - m_fLastTrigger) * 24.0) >= g_fDelayHours)				m_fLastTrigger = GameDaysPassed.GetValue()				Refresh()			EndIf		EndIf				If (g_bFromLastVisit)			m_fLastTrigger = GameDaysPassed.GetValue()		EndIf	EndIfEndEventFunction Init()	;Debug.Notification("Flora::Init")	If (!(g_flFloraList as FormList) || !(g_flFloraPlacedList as FormList))		If (!(g_flFloraList as FormList))			Debug.Trace("FloraHelperActivatorScript::Init: Missing formlist g_flFloraList")		EndIf		If (!(g_flFloraPlacedList as FormList))			Debug.Trace("FloraHelperActivatorScript::Init: Missing formlist g_flFloraPlacedList")		EndIf		Return	EndIf		m_bStaticList = (g_flFloraList.GetSize() > 0) as bool	If (!m_bStaticList)		If (!(g_flFloraTypesList as FormList))			Debug.Trace("FloraHelperActivatorScript::Init: Missing formlist g_flFloraTypesList")			Return		ElseIf (g_flFloraTypesList.GetSize() == 0)			Debug.Trace("FloraHelperActivatorScript::Init: Empty type formlist g_flFloraTypesList")			Return		EndIf	EndIf		m_fLastTrigger = GameDaysPassed.GetValue()		m_bInit = TrueEndFunctionFunction Setup()	;Debug.Notification("Flora::Setup")	int iIndex = 0	int iTotal = g_flFloraList.GetSize()	;Debug.Notification("Flora::Setup iTotal:" + iTotal)		While (iIndex < iTotal)		ObjectReference rFloraRef = g_flFloraList.GetAt(iIndex)  as ObjectReference				If (rFloraRef as ObjectReference)			ObjectReference rNewFloraRef = rFloraRef.PlaceAtMe(rFloraRef.GetbaseObject(), 1, False, True)						MirrorScalePos(rFloraRef, rNewFloraRef)						g_flFloraPlacedList.AddForm(rNewFloraRef)						rNewFloraRef.Enable()			rFloraRef.Disable()		EndIf						iIndex += 1	EndWhile		;Debug.Notification("Flora::SetupStatic: g_flFloraList:" + g_flFloraList.GetSize() + " g_flFloraPlacedList:" + g_flFloraPlacedList.GetSize())	m_bSetup = TrueEndFunctionFunction SetupDynamic()	;Debug.Notification("Flora::SetupDynamic")		SetupDynamicType(38) ; kTree = 38	SetupDynamicType(39) ; kFlora = 39		;Debug.Notification("Flora::SetupDynamic: g_flFloraList:" + g_flFloraList.GetSize() + " g_flFloraPlacedList:" + g_flFloraPlacedList.GetSize())	m_bSetup = TrueEndFunctionFunction SetupDynamicType(int iType)	Cell cParentCell = Self.GetParentCell()		int iIndex = 0	int iTotal = cParentCell.GetNumRefs(iType) ; skse	;Debug.Notification("Flora::SetupDynamicType: iTotal" + iTotal + " Type:" + iType)		While (iIndex < iTotal)		ObjectReference rFloraRef = cParentCell.GetNthRef(iIndex, iType) as ObjectReference ; skse				If (rFloraRef as ObjectReference)			If (g_flFloraTypesList.HasForm(rFloraRef.GetBaseObject()))				g_flFloraList.AddForm(rFloraRef)								ObjectReference rNewFloraRef = rFloraRef.PlaceAtMe(rFloraRef.GetbaseObject(), 1, False, True)								MirrorScalePos(rFloraRef, rNewFloraRef)								g_flFloraPlacedList.AddForm(rNewFloraRef)								rNewFloraRef.Enable()				rFloraRef.Disable()			EndIf		EndIf						iIndex += 1	EndWhileEndFunctionFunction Refresh()	;Debug.Notification("Flora::Refresh")		int iIndex = (g_flFloraPlacedList.GetSize() - 1) ; reverse		While (iIndex > -1)		ObjectReference rFloraRef = g_flFloraPlacedList.GetAt(iIndex) as ObjectReference				If (rFloraRef as ObjectReference)			If (rFloraRef.IsHarvested()) ; skse				ObjectReference rNewFloraRef = rFloraRef.PlaceAtMe(rFloraRef.GetbaseObject(), 1, False, True) ; non-persistent, init disabled								MirrorScalePos(rFloraRef, rNewFloraRef)								g_flFloraPlacedList.AddForm(rNewFloraRef)				g_flFloraPlacedList.RemoveAddedForm(rFloraRef)								rNewFloraRef.Enable()				rFloraRef.Disable()				rFloraRef.Delete()			EndIf		EndIf				iIndex -= 1	EndWhile	EndFunctionFunction Destroy()	;Debug.Notification("Flora::Destroy")		int iIndex = 0	ObjectReference rFloraRef = g_flFloraList.GetAt(iIndex) as ObjectReference		While (rFloraRef as ObjectReference)		If (!m_bStaticList)			g_flFloraList.RemoveAddedForm(rFloraRef)		EndIf				rFloraRef.Enable()				iIndex += 1		rFloraRef = g_flFloraList.GetAt(iIndex) as ObjectReference	EndWhile		rFloraRef = g_flFloraPlacedList.GetAt(0) as ObjectReference		While (rFloraRef as ObjectReference)		g_flFloraPlacedList.RemoveAddedForm(rFloraRef)				rFloraRef.Disable()		rFloraRef.Delete()				rFloraRef = g_flFloraPlacedList.GetAt(0) as ObjectReference	EndWhile		m_bInit = False	m_bHasSKSE = False	m_bSetup = False	m_bStaticList = False	m_fLastTrigger = 0.0EndFunctionFunction MirrorScalePos(ObjectReference rSourceRef, ObjectReference rDestRef)	rDestRef.SetScale(rSourceRef.GetScale())	rDestRef.SetPosition(rSourceRef.GetPositionX(), rSourceRef.GetPositionY(), rSourceRef.GetPositionZ())	rDestRef.SetAngle(rSourceRef.GetAngleX(), rSourceRef.GetAngleY(), rSourceRef.GetAngleZ())EndFunctionFunction SetHasSKSE()	m_bHasSKSE = False	float fSKSEVer = (SKSE.GetVersion() + SKSE.GetVersionMinor() * 0.01 + SKSE.GetVersionBeta() * 0.0001) as float	If (fSKSEVer < 1.0509)		Debug.Trace("FloraHelperActivatorScript::SetHasSKSE: SKSE not found or out of date! Req:1.0509 Ver:" + fSKSEVer)	Else		m_bHasSKSE = True	EndIf	;Debug.Notification("Flora::SetHasSKSE: m_bHasSKSE:" + m_bHasSKSE)EndFunction
User avatar
His Bella
 
Posts: 3428
Joined: Wed Apr 25, 2007 5:57 am

Post » Sun Nov 18, 2012 8:59 am

I thought I would share this in case anyone finds it useful.

I created the following script to get flora to respawn in my no-respawn cell:

Spoiler
Scriptname FloraRespawner extends ObjectReference  Float Property RespawnHours AutoObjectReference Property NewReference Auto HiddenFloat MyScaleAuto State NotYetActivated	Event OnActivate(ObjectReference akActionRef)		GoToState("WaitingForRespawn")	EndEventEndStateState WaitingForRespawn	Event OnActivate(ObjectReference akActionRef)		; Ignore activations while in this state.	EndEvent	Event OnBeginState()		; Debug.Notification("Waiting for respawn in " + RespawnHours + " hours.")		Utility.WaitGameTime(RespawnHours)		MyScale = GetScale()		NewReference = PlaceAtMe(GetBaseObject(), 1, False, True)		NewReference.SetScale(MyScale)		(NewReference as FloraRespawner).RespawnHours = RespawnHours		NewReference.EnableNoWait()		DisableNoWait()		Delete()	EndEventEndState

In my case, I duplicated the base flora object (FloraMushroom06 for example) then attached this script to my new base object. I set the RespawnHours property on the base object to the number of hours I want this type of flora to wait before respawning. Then I placed references of this new base object in my cell. For flora I had already placed in the cell I used find-and-replace to replace the objects with my new object.

If you want a particular flora reference to have a different respawn hours value you can set the respawnhours property on the reference itself.

I found that this does not seem to have a noticeable affect on performance. Probably because the script spends most of its time doing nothing but waiting.

I haven't done extensive testing to determine if this adds bloat to save games. But I am hoping it wont since the script deletes the original reference after it creates the replacement.
User avatar
Juliet
 
Posts: 3440
Joined: Fri Jun 23, 2006 12:49 pm

Post » Sun Nov 18, 2012 3:53 pm

I'm pretty sure it would make the "NewReference" property persistent and since it's on each flora, all of them would be - if I understand it correctly. I would like to keep track of the deletes, but using a formlist is the only way I can think of to avoid persistence. Still hacking at the alias's which would only make certain ones persistent while the player is near them.

Anyone know the chance of adding some type of "Reset()" to flora/tree with SKSE? Is is just a flag that needs flipping before it will reset using "rFloraRef.Reset()?
User avatar
Shelby Huffman
 
Posts: 3454
Joined: Wed Aug 08, 2007 11:06 am

Post » Sun Nov 18, 2012 3:07 pm

In addition to what Ez0n3 said I have found a couple of other issues with the script I posted above:

If you go to the console and do a resetinterior it will remove the flora from the interior. I am guessing that is because the script deleted the original flora and the resetinterior can't revert back to it. It's possibly not a huge issue since resetinterior is not really a part of normal gameplay but it is still a bit disconcerting.

It is also difficult to change the respawn hours and have the change take affect in a save game that was saved after activating the flora that had the script (the change works fine if you start a new game). Once again, I suspect that this has something to do with the change in the editor being a change to the original reference and not affecting the in-game item since the in-game item is actually a new reference.

I can live with both of these issue in the mod that I have made for my own use. But I would be reluctant to actually release a mod with this script since future updates to the mod (assuming the updates touched these respawn objects/scripts) would probably be a bit tricky.

All-in-all, I agree with you EzOn3; This would be so much simpler if there was a way to just reset the flora rather than having to delete and replace it.
User avatar
Christine Pane
 
Posts: 3306
Joined: Mon Apr 23, 2007 2:14 am

Post » Sun Nov 18, 2012 2:03 pm

I don't know much about the inner workings of SKSE, but I downloaded http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express (free) and I already had "DirectX 9.0 SDK (Summer 2004)" (ok since it's dx9?) installed and was able to compile skse after adding: Tools->Projects and Solutions->VC++ Directories->Show directories for: "Include files"->"$(DXSDK_DIR)\Include" and "Lib files"->"$(DXSDK_DIR)\Lib".

The source for "IsHarvested()" looks like:
bool IsHarvested(TESObjectREFR* pProduceRef){	UInt8 formType = pProduceRef->baseForm->formType;	if (formType == kFormType_Tree || formType == kFormType_Flora) {		return ((pProduceRef->flags & 0x2000) == 0x2000) ? true : false;	}	return false;}

I just tweaked that just to try removing that flag to see what would happen (didn't see any other places where it removes flags, it is ok to do so?):
bool IsHarvested(TESObjectREFR* pProduceRef){	UInt8 formType = pProduceRef->baseForm->formType;	if (formType == kFormType_Tree || formType == kFormType_Flora) {		//return ((pProduceRef->flags & 0x2000) == 0x2000) ? true : false;		if ((pProduceRef->flags & 0x2000) == 0x2000) {			pProduceRef->flags &= ~(0x2000); // try to reset it			return true;		}	}	return false;}
It's a hacked in attempt to reset it if it has been harvested, to see if it's possible. The flora still appeared "harvested", but the text shows up "Harvest Flora Name" and activating it again gives an ingredient like normal. I think that if the mesh also reset (appeared harvestable again), it would be good to go pretty much. I'm pretty stumped though. I would like to know which flags it has and how they managed to determine "0x2000" controls the harvest flag? :blink:

Any SKSE devs around that can comment on this? Possibly adding some kind of "ClearHarvested()" function? Any clues on how to get the mesh to reset?
User avatar
SUck MYdIck
 
Posts: 3378
Joined: Fri Nov 30, 2007 6:43 am

Post » Sun Nov 18, 2012 7:22 pm

Added, thanks for the suggestion. ObjectReference.SetHarvested(bool isHarvested)
User avatar
jessica Villacis
 
Posts: 3385
Joined: Tue Jan 23, 2007 2:03 pm

Post » Sun Nov 18, 2012 6:00 pm

Added, thanks for the suggestion. ObjectReference.SetHarvested(bool isHarvested)
That's extremely kind of you/your lot

Thanks :)
User avatar
Jesus Lopez
 
Posts: 3508
Joined: Thu Aug 16, 2007 10:16 pm

Post » Sun Nov 18, 2012 3:30 am

Added, thanks for the suggestion. ObjectReference.SetHarvested(bool isHarvested)
Very cool. No persistence, no lists - my eyes are peeled for an update. :biggrin:

Thanks again.
User avatar
Kelsey Hall
 
Posts: 3355
Joined: Sat Dec 16, 2006 8:10 pm

Post » Sun Nov 18, 2012 11:55 am

Added, thanks for the suggestion. ObjectReference.SetHarvested(bool isHarvested)

Excellent! Thank you, ianpatt!
User avatar
Queen Bitch
 
Posts: 3312
Joined: Fri Dec 15, 2006 2:43 pm


Return to V - Skyrim