Jump to content

[LE] FormList - RandomInt question


maxarturo

Recommended Posts

Hi once again.


Is there a way to generate a 'RandomInt' an choose a random reference from inside a 'FormList'.


Before i removed all 'FormLists' from my mod, i did experiment with this, but i didn't bother too much with it.

The issue back then, except the slowness of FormLists, was that no matter what 'RandomInt' was generated it would always run the first reference in the FormList, no to mention the 100 maximum 'RandomInt' limit, but anyway... that's another issue.


There is a big chance that i did a potato on those experiments that were made just before i decided to delete all FormLists and never bother with them again.


I'm asking this question cause lately i've been very busy at work and my free time has been reduced to almost '0', and i would hate to loose 1 weekend experimenting in something that maybe it can not be done, while i could invest that time to actually do some work on the mod.


Thank you very much and have a nice weekend.

Link to comment
Share on other sites

If you are doing multiple random forms from the same list then this would be better:

Int MaxEntry = MyFormList.GetSize() - 1
Form RandomFormOne = MyFormList.GetAt(Utility.RandomInt(0,MaxEntry)
Form RandomFormTwo = MyFormList.GetAt(Utility.RandomInt(0,MaxEntry)

And if you want multiple random forms without repeats:

Int MaxEntry = MyFormList.GetSize() - 1
Int RandomEntryOne = Utility.RandomInt(0,MaxEntry)
Int RandomEntryTwo = Utility.RandomInt(0,MaxEntry)
Int RandomEntryThree = Utility.RandomInt(0,MaxEntry)
While RandomEntryTwo == RandomEntryOne
  ;when RET is the same as REO roll again
  RandomEntryTwo = Utility.RandomInt(0,MaxEntry)
EndWhile
While (RandomEntryThree == RandomEntryTwo) || (RandomEntryThree == RandomEntryTwo)
  ;when RETh is the same as RET or REO roll again
  RandomEntryThree = Utility.RandomInt(0,MaxEntry)
EndWhile
Form RandomFormOne = MyFormList.GetAt(RandomEntryOne)
Form RandomFormTwo = MyFormList.GetAt(RandomEntryTwo)
Form RandomFormThree = MyFormList.GetAt(RandomEntryThree)

And if you want to go down the rabbit hole like I did tonight...

 

 

And if your list has greater than 101 entries (if 0 is included there are 101 possible random values between 0 and 100):

;event / function begin
Form RandomForm
Int MaxEntry = MyFormList.GetSize() - 1
Int RIGroups = 0 ;count of groups consisting of 101 entries
If MaxEntry > 101 ; 0 - 100 consists of 101 entries
  While MaxEntry > 101
    MaxEntry -= 101
    RIGroups += 1
  EndWhile
  RandomForm = GetRandomForm(MyFormList,RIGroups,MaxEntry)
Else
  RandomForm = GetRandomForm(MyFormList,RIGroups,MaxEntry)
EndIf
;do something with RandomForm here
;event / function end
 
Form Function GetRandomForm(FormList TheList, Int ListGroup, Int RemEntries)
  Form Entry
  If ListGroup == 0 
    Entry = TheList.GetAt(Utility.RandomInt(0,RemEntries)
  Else
    Int AllGroups = ListGroup + 1 ; full groups of 101 plus any remainder
    Int PreRoll = Utility.RandomInt(0,AllGroups)
    If PreRoll == AllGroups ;remaining entries group selected
      Int MaxRange = RemEntries - (ListGroup * 101)
      Int EntryRoll = Utility.RandomInt(0,MaxRange)
      Int RandomEntry = (ListGroup * 101) + EntryRoll
      Entry = TheList.GetAt(RandomEntry)
    Else
      Int EntryRoll = Utility.RandomInt(0,100)
      Int RandomEntry = (PreRoll * 101) + EntryRoll
      Entry = TheList.GetAt(RandomEntry)
    EndIf
  EndIf
  If Entry ;make sure we have a valid form
    Return Entry ;return the form
  EndIf
EndFunction

 

 

 

There are just examples to show that it is not always best or possible to string everything in a single line. :cool:

Link to comment
Share on other sites

Yes I agree if you're going to do multiple forms that way is better. For a single instance though I prefer to keep it in the same line. Also you're missing some brackets:

 

Int MaxEntry = MyFormList.GetSize() - 1
Form RandomFormOne = MyFormList.GetAt(Utility.RandomInt(0,MaxEntry))
Form RandomFormTwo = MyFormList.GetAt(Utility.RandomInt(0,MaxEntry))
Link to comment
Share on other sites

Thank you dylbill & IsharaMeradin for your reply and interest.


I'll look at your suggestions some time later today, after i get off from work.


I don't have time right now and i just took a quick look at them, and i have 3 questions.


@ dylbill

1) What does the minus one "-1" represent in:

Form RandomForm = MyFormList.GetAt(Utility.RandomInt(0, (MyFormlist.GetSize() - 1)))


2) Which line from the 2 lines you posted is faster?, and what's the difference?.


@ dylbill & IsharaMeradin

3) Is calling a "RandomInt" fanction for a reference inside a "FormList" faster than calling / checking for a reference inside a "FormList", which we all know is slow, and the bigger the "FormList" is, the slower the function.


* I might have some more questions later on, when i get to actually see / study / start contracting what i have in mind.



And again, thank you both very much, you have no idea how much time you both have saved me, precious time!!, that for the next month+ i won't have available.

Link to comment
Share on other sites

The first line I posted is faster because it doesn't use the formlist.getsize() function. The difference is that the second line sets the max for the randomInt as the size of the formlist, while using just Utility.RandomInt() gets a random Int between 0 and 100. The - 1 is because formlists and pretty much everything in the ck and papyrus are 0 based. You have to add a -1 because let's say the formlist has 10 forms, the possible entries are from 0 to 9, not 0 to 10.

 

If speed is your concern, using arrays is most certainly faster.

Edited by dylbill
Link to comment
Share on other sites

 

Yes I agree if you're going to do multiple forms that way is better. For a single instance though I prefer to keep it in the same line. Also you're missing some brackets:

 

Int MaxEntry = MyFormList.GetSize() - 1
Form RandomFormOne = MyFormList.GetAt(Utility.RandomInt(0,MaxEntry))
Form RandomFormTwo = MyFormList.GetAt(Utility.RandomInt(0,MaxEntry))

 

That is why I don't like nesting too many things in a single line. Easy to loose track of the brackets and "puddles".

 

 

@maxarturo

I do not know about the speed of things. I know that arrays are faster in general. But if you need a list that is used by multiple scripts / records, a formlist is the way to go. Especially if it is not viable to link to a master script containing the array.

Link to comment
Share on other sites

It's easy to access array's from other scripts if you set them up as properties.

 

In one script:

Scriptname MyScript extends Quest
ObjectReference[] Property MyRefs Auto 

In another script:

MyScript Property ScriptRef auto ;In the ck, choose the quest the script is attached to. 

Event SomeEvent()
    Int MaxEntry = ScriptRef.MyRefs.Length - 1    
    ScriptRef.MyRefs[Utility.RandomInt(0, MaxEntry)].SomeFunction() ;random entry from array 
EndEvent

Arrays and Formlists both have advantages and disadvantages. Arrays are faster because you don't need to use a Get function to get the form. Formlists can have multiple types of forms, where arrays cannot. Also, formlists can be multi-dimensional, meaning you can have a formlist of formlists where as in papyrus you cannot have an array of arrays.

 

Here's how to get a random entry from a formlist of formlists:

 

Formlist Property MyFormLists Auto ; a formlist of formlists

Event SomeEvent()
    Int MaxEntryA = MyFormlists.GetSize() - 1 
    FormList ListA = MyFormlists.GetAt(Utility.RandomInt(0, MaxEntryA)) as formlist ;finds random formlist
    
    Int MaxEntryB = ListA.GetSize() 
    Form RandomForm = MyFormlists.GetAt(Utility.RandomInt(0, MaxEntryB)) ;finds random form
EndEvent
Link to comment
Share on other sites

  • Recently Browsing   0 members

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