Jump to content

Can Flora "Harvest" be activated by script?


Recommended Posts

Does anyone know if there is a way to activate the "Harvest" of a flora? This would include the vegetables grown in settlements as well as the edible wild flora throughout the Commonwealth.

 

I want a player to be able to eat the flora ingredient (corn, tato, gourd, melon, thistle, etc) fresh off the plant without having to take it and then go into the inventory to use it.

 

It is easy to get the object reference for the plant but I can't figure out how to get at the ingredient so that I can script its use by the player and then removal so that it is consumed.

Edited by GrimGrim31
Link to comment
Share on other sites

There is no harvest function or script queryable ingredient, you will have to provide base object lookup tables (forms/arrays) to do that.

 

Plus there is no IsHarvested state query :sad:

 

This is a workaround I have used:

 

 

 

FormList Property pSKK_MWFloraList Auto Const Mandatory
FormList Property pSKK_MWFoodList Auto Const Mandatory
GlobalVariable Property pSKK_MWFoodScalar Auto Const Mandatory
ActorValue Property pSKK_MWIsHarvested Auto Const Mandatory
ActorValue Property pSKK_MWTimeStamp Auto Const Mandatory

Function HarvestPlant(ObjectReference ThisPlant)
If (ThisPlant.GetBaseObtect() is Flora) && (ThisPlant.GetValue(pSKK_MWIsHarvested) == 0)
   Flora ThisFlora = ThisPlant.GetBaseObject()
   Int iIndex = pSKK_MWFloraList.Find(ThisFlora)
   If (iIndex > -1)
      Potion ThisFood = pSKK_MWFoodList.GetAt(iIndex) as Potion
      Int iFoodCount = pSKK_MWFoodScalar.GetValue() as Int 
      pPlayerREF.AddItem(ThisFood, aiCount = iFoodCount, abSilent = False)
      ThisPlant.SetHarvested(TRUE) ;There is no IsHarvested query :(
      ThisPlant.SetValue(pSKK_MWIsHarvested, 1) ;So managing regrowth in script
      ThisPlant.SetValue(pSKK_MWTimeStamp, Utility.GetCurrentGameTime()) ;On a per workshop ResetWorkshop timer 
   EndIf
EndIf

Function UnharvestPlant(ObjectReference ThisPlant) ; called by ResetWorkshop on GetRefsLinkedToMe array.
If (Utility.GetCurrentGameTime() >= (ThisPlant.GetValue(pSKK_MWTimestamp) + 1)) ;One game day regrowth regardless of Timescale
   ThisPlant.SetHarvested(False)
   ThisPlant.SetValue(pSKK_MWIsHarvested, 0)
   ThisPlant.SetValue(pSKK_MWTimeStamp, -1)
EndIf
EndFunction

 

 

Link to comment
Share on other sites

Activate()(I feel as though this will activate anything that has an activation prompt of some kind(harvest, sit, take, open, etc)) will harvest flora and is a way to check if they were harvested because it returns a boolean. The issue with that though is that you can't simply check the return value just to see if it's ready to be harvested because it'll harvest if the return value is true, and you might not want that.

 

For snatching the ingrediant and using it immediately, OnItemAdded? I don't know how to go about "using" something straight from the inventory through script, sounds like a fun little thing to try an accomplish.

Edited by AnishaDawn
Link to comment
Share on other sites

Thank you. You have both given me some ideas to try.

 

My script already triggers some of the desired effects for the player (a nice chewing sound and reduction of hunger). I will try some script changes based on your suggestions. A successful end state is when the player no longer gets that harvest activation button, the flora plant is set to a harvested state, and no ingredient from that harvest is left in the player's inventory. Right now, the button doesn't turn off so the player can trigger it as many times as he/she wants. While that will satisfy world hunger, it is not very immersive.

 

The script as currently written is in the spoiler below. It is a perk script added to the perk (not as a fragment). While NPCBrahminIdleChew is the name of the sound descriptor variable, I actually fill the property with a different chewing sound FX that is much longer and noisier. Apparently, Brahmins are quiet chewers. The script works great for loose fruits and vegetables since I built a form list for them to use as a condition of perk activation. The form list also includes the flora plants so that the activator button is overwritten, but you know that I still have to solve the problem of getting the flora plants to turn off.

 

 

 

ActorValue Property Hunger Auto
Actor Property Owner Auto
Actor Property Target Auto
sound Property NPCBrahminIdleChew Auto Const
{plays each bite}
int PlayEatingSound = 0
;-- Functions ---------------------------------------
Event OnEntryRun(int auiEntryID, ObjectReference akTarget, Actor akOwner)
Form baseForm = akTarget.GetBaseObject()
Potion itemPotion = baseForm as Potion
Game.GetPlayer().EquipItem(itemPotion as Form, False, True)
akTarget.SendStealAlarm(akOwner)
Game.GetPlayer().AddItem(akTarget as Form, 1, True)
PlayEatingSound = NPCBrahminIdleChew.play(akOwner)
Sound.SetInstanceVolume(PlayEatingSound, 1)
Hunger = Game.getformfromfile(0x000801, "SurvivetheWasteland.esp") as ActorValue
Debug.Notification("You eat the " + akTarget.GetDisplayName() + ".")
Game.GetPlayer().ModValue(Hunger, 10)
Game.GetPlayer().RemoveItem(baseForm, 1, True, None)
EndEvent

Link to comment
Share on other sites

Thats all in the script I posted above. All of it done for you.

 

Well, unless you have blocked me and cant see the messages.

How are you able to compare an object reference to Flora?

 

If (ThisPlant is Flora)

 

I get a type mismatch when I try to do that. EDIT: I was able to set the condition using If akTarget.GetBaseObject() as Flora

 

Do you use your own script to regrow the plants so that they can be harvested again? Oh wait, you have it set so they regrow every 24 hours.

 

Your script seems to have a lot more going on than just harvesting an ingredient from a plant. It looks like I need to create two formlists, two actor values, and a global value.

 

Is your food scalar usually set to one in your ESP?

 

Do the plants in game get harvested? It looks like you set up an alternate system for harvesting. I don't see where it changes the plant objects' condition so that the game knows that the plant is harvested. EDIT: OK, sorry, I figured it out. I feel silly now that I see that setharvested is a function in the game.

Edited by GrimGrim31
Link to comment
Share on other sites

OK, thanks to both of you I was able to get an almost satisfactory solution to my problem. The new script is in the spoiler. It is a bit long now and still includes lines for my failed attempt to use an AddInventoryEventFilter paired with the Event OnItemAdded. I commented them out but did not delete them yet. The compiler wasn't happen with them. It wanted me to make them native but when I did that, it would not accept any of my functions in the OnAddedItem Event.

 

 

 

Formlist Property _MY_FloraList Auto Const
Formlist Property _MY_FoodList Auto Const
ActorValue Property Hunger Auto
ActorValue Property _MY_FloraIsHarvested Auto Const Mandatory
ActorValue Property _MY_FloraHarvestTimestamp Auto Mandatory
Actor Property Owner Auto
Actor Property Target Auto
Actor Property pPlayerREF Auto
sound Property NPCBrahminIdleChew Auto Const
{plays each bite}
int PlayEatingSound = 0
;-- Functions ---------------------------------------
Event OnEntryRun(int auiEntryID, ObjectReference akTarget, Actor akOwner)
Hunger = Game.getformfromfile(0x000801, "SurvivetheWasteland.esp") as ActorValue
If (Utility.GetCurrentGameTime() >= (akTarget.GetValue(_MY_FloraHarvestTimestamp) + 1)) ;One game day regrowth regardless of Timescale
akTarget.SetValue(_MY_FloraIsHarvested, 0)
akTarget.SetValue(_MY_FloraHarvestTimestamp, -1)
EndIf
If Game.GetPlayer().GetValue(Hunger) < 0.0 && akTarget.GetBaseObject() as Flora
; AddInventoryEventFilter(_MY_FoodList)
akTarget.Activate(Game.GetPlayer(), True)
; akTarget.SendStealAlarm(akOwner)
Debug.Notification("You eat the " + akTarget.GetDisplayName() + ".")
akTarget.setharvested(True)
akTarget.SetValue(_MY_FloraIsHarvested, 1)
akTarget.SetValue(_MY_FloraHarvestTimestamp, Utility.GetCurrentGameTime())
Flora ThisFlora = akTarget.GetBaseObject() as Flora
Int iIndex = _MY_FloraList.Find(ThisFlora)
If (iIndex > -1)
Potion ThisFood = _MY_FoodList.GetAt(iIndex) as Potion
Debug.Notification("Tried to remove " + ThisFood.GetDisplayName() + ".")
pPlayerREF.RemoveItem(ThisFood, 1, abSilent = False)
pPlayerREF.AddItem(ThisFood, 1, abSilent = False)
EndIf
PlayEatingSound = NPCBrahminIdleChew.play(akOwner)
Sound.SetInstanceVolume(PlayEatingSound, 1)
Game.GetPlayer().ModValue(Hunger, 10)
ElseIf Game.GetPlayer().GetValue(Hunger) < 0.0 && akTarget.GetBaseObject() as Potion
Form baseForm = akTarget.GetBaseObject()
Potion itemPotion = baseForm as Potion
Game.GetPlayer().EquipItem(itemPotion as Form, False, True)
Game.GetPlayer().AddItem(akTarget as Form, 1, True)
Debug.Notification("You eat the " + akTarget.GetDisplayName() + ".")
Game.GetPlayer().RemoveItem(baseForm, 1, True, None)
PlayEatingSound = NPCBrahminIdleChew.play(akOwner)
Sound.SetInstanceVolume(PlayEatingSound, 1)
Game.GetPlayer().ModValue(Hunger, 10)
Else
Debug.Notification("You are not hungry now.")
EndIf
EndEvent
; Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
; Debug.Notification("You eat the " + akItemReference.GetDisplayName() + ".")
; Game.GetPlayer().RemoveItem(akBaseItem, aiItemCount)
; EndEvent

The only thing that isn't working correctly is the removal of the flora ingredient once I have activated the flora. The problem is that the formlists for Food and Flora contain different numbers of items. Food has 30 items and Flora has 53. This disparity is because Flora includes multiple plants of the same type whenever Bethesda had more than one mesh for that plant. For example, the corn stalk in Flora has two versions but they both produce the same ingredient, Corn. So using the index from the Flora list to remove the right item from the Food List isn't working yet. Using OnItemAdded would be a lot simpler because it would have the form and object ref of the food item added to the inventory which would make removal easy.
Edited by GrimGrim31
Link to comment
Share on other sites

Variables or properties of a desired type can have those types assigned them through casting of the base object as demonstrated in his script. It's not needed to use SetHarvested() on Flora that was harvested through Activate() because it sets that "flag" by nature of the activation. Activate() basically allows one to activate things remotely. He gets around using Activate() by searching through a list of flora that was found and then adding the ingredient to the inventory and calling SetHarvest() on the Flora.

 

On to the thing about the 30 things and 53 things - well I would just add as many ingredients to the foodlist that are the same as the number of Flora that has multiple versions if that makes sense. 53 foods = 53 flora.

Link to comment
Share on other sites

Last night before bed I suddenly realized how to solve this puzzle. It's easy. I don't actually need to activate the plant since I don't want the ingredient added to my inventory or the message that it was added. All I want are the effects of eating the ingredient and the flora to be harvested so that my character cannot eat the ingredient again until the right amount of time has passed. So I don't need the Activate command in this script but I will need the actor values for harvested and the time stamp as well as the setharvested() and the effects already in my script.

 

It should be a few simple edits to the existing script. I just need to remove the Activate and make sure that the plant Actor Values are correct for harvested and then resetting the plant after the right amount of time has passed (similar to SKK50's unharvest function).

 

Casting is something that I am still learning. I have used it correctly a few times but also experience some errors on other attempts. I wasn't able to do it the same way that SKK50 did. I had to use "as Flora" instead of "is Flora".

Link to comment
Share on other sites

There's one thing you can be sure of: Objectreferences can always be cast to the types of their base objects. This is necessary for functions that will not take ObjectReferences in their params but their types instead or for functions that cant be called on objectreferences but their types.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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