Jump to content

Would my Script work?


GornoDD

Recommended Posts

Posted

Hi. Im working on a bukkake scene for my mod. To  make this happen I need a script to recuit multiple actors  and force them into an alias so I can set them up for a scene. Now I came up with this 

Function BKSelector()
Actor BKActor1 = Sexlab.FindAvailableActor(PlayerRef, radius = 2000.0, FindGender = 1)
BKActorAlias1.forceRefTo(BKActor1)
Actor BKActor2 = Sexlab.FindAvailableActor(PlayerRef, radius = 2000.0, FindGender = 1, IgnoreRef1 = BKActor1)
BKActorAlias2.forceRefTo(BKActor2)
Actor BKActor3 = Sexlab.FindAvailableActor(PlayerRef, radius = 2000.0, FindGender = 1, IgnoreRef1 = BKActor1, IgnoreRef2 = BKActor2)
BKActorAlias3.forceRefTo(BKActor3)
Actor BKActor4 = Sexlab.FindAvailableActor(PlayerRef, radius = 2000.0, FindGender = 1, IgnoreRef1 = BKActor1, IgnoreRef2 = BKActor2, IgnoreRef3 = BKActor3)
BKActorAlias4.forceRefTo(BKActor4)
Actor BKActor5 = Sexlab.FindAvailableActor(PlayerRef, radius = 2000.0, FindGender = 1, IgnoreRef1 = BKActor1, IgnoreRef2 = BKActor2, IgnoreRef3 = BKActor3, IgnoreRef4 = BKActor4)
BKActorAlias5.forceRefTo(BKActor5)
EndFunction
 
Problem is, that I dont know if I can actually abuse the Sexlab.FindAvailbaleActor Function to force a couple of dudes into these aliases. Also the function doesnt allow more than 4 IgnoreRef excludes, but bukkake would need some more I guess :D
 
So I hope some helpful coders can have a look and give me their thaught on this matter
Posted

Do a different approach:

 

Actor[] theActors = new Actor[16] ; "I consider that the number of aliases is 16, change the value with the correct number"
int numFoundActors = 0
ReferenceAlias[] Property BKActors Auto ; "Fill this property with your aliases"
Actor Property PlayerRef Auto
 
Function fillAliases()
  Cell c = PlayerRef.getParentCell()
  int num = c.getNumRefs(62)
  while num && numFoundActors < 16
    num -= 1
    Actor a = c.GetNthRef(num, 62) as Actor
    if a && a!=PlayerRef && !a.isDisabled() && !a.isDead() && !a.isChild() && !a.IsBleedingOut() && !a.IsUnconscious() && !a.isInFaction(SexLabAnimatingFaction) && theActors.find(a)==-1 && !a.IsOnMount()
      theActors[numFoundActors] = a
      numFoundActors += 1
    endIf
  endWhile
 
  ; "Now fill the aliases with the actors"
  while numFoundActors
    numFoundActors -= 1
    bkAliases[numFoundActors].forceRefTo(theActors[numFoundActors]_
  endWhile
EndFunction

 

Warning because all possible actors will be found, there is no check here about races (so a Dog or an Horse will fill as actors too.)

You can add another test to understand if the actor is a creature or not. (By faction, by keyword, directly by race, etc.)

 

 

Posted

Do a different approach:

Actor[] theActors = new Actor[16] ; "I consider that the number of aliases is 16, change the value with the correct number"
int numFoundActors = 0
ReferenceAlias[] Property BKActors Auto ; "Fill this property with your aliases"
Actor Property PlayerRef Auto
 
Function fillAliases()
  Cell c = PlayerRef.getParentCell()
  int num = c.getNumRefs(62)
  while num && numFoundActors < 16
    num -= 1
    Actor a = c.GetNthRef(num, 62) as Actor
    if a && a!=PlayerRef && !a.isDisabled() && !a.isDead() && !a.isChild() && !a.IsBleedingOut() && !a.IsUnconscious() && !a.isInFaction(SexLabAnimatingFaction) && theActors.find(a)==-1 && !a.IsOnMount()
      theActors[numFoundActors] = a
      numFoundActors += 1
    endIf
  endWhile
 
  ; "Now fill the aliases with the actors"
  while numFoundActors
    numFoundActors -= 1
    bkAliases[numFoundActors].forceRefTo(theActors[numFoundActors]_
  endWhile
EndFunction

Warning because all possible actors will be found, there is no check here about races (so a Dog or an Horse will fill as actors too.)

You can add another test to understand if the actor is a creature or not. (By faction, by keyword, directly by race, etc.)

 

Pheeww thats pretty steep to understand for a script-beginner like me. Now from what I understand this function does is to check your cell (what if its on the outside world?) for characters (62 defines that). Then you exclude every beeing that isnt suited (childs etc.). These get to be assigned as actors.

 

Here comes the part I dont get. Its mostly because my understanding of Arrays is quite lackluster. The ReferenceAlias[] Array gets assiged with all the numFoundActors?

 

This Function is pretty sick man. But do is need to fill in stuff into the arrays? When copy pasting this it gives me quite some errors

Posted

Step by step code explained (the explanation of each line is in the comment above the line):

 

 

; "We define an array of Actors to store what we will find in the player cell. This array is temporary, and only used to find the actors and then fill the Aliases."
Actor[] theActors = new Actor[16] ; "I consider that the number of aliases is 16, change the value with the correct number"
; "This variable is used to remember how many actors we found, because Arrays in Papyrus cannot be dynamic (sort-of), I create it already with the max number of possible aliases, and then I keep track of how many actors I found."
int numFoundActors = 0
; "This is the property that will store your reference aliases. It is an array to assign the actors with ease"
ReferenceAlias[] Property BKActors Auto ; "Fill this property with your aliases"
; "This property is the quickest possible way to find the player"
Actor Property PlayerRef Auto
 
Function fillAliases()
  ; "The Cell c will contain the cell (can be interior but also en exterior cell, where the player is"
  Cell c = PlayerRef.getParentCell()
  ; "Here we ask SKSE to count the number of Actors in the cell"
  int num = c.getNumRefs(62)
  ; "We cycle for all actors, and until we have not too many actors"
  while num && numFoundActors < 16
    ; "The cycle goes backward to improve the performance"
    num -= 1
    ; "This gets the actual actor. getNthRef gives you as result an ObjectReference, we need to cast it to an Actor (that is a specific ObejctRef) to do the checkings"
    Actor a = c.GetNthRef(num, 62) as Actor
    ; "Here we check if the actor is good. The second-last check it is controlling that the actor is not already in the resulting array (it may happen, so we have to check.)"
    if a && a!=PlayerRef && !a.isDisabled() && !a.isDead() && !a.isChild() && !a.IsBleedingOut() && !a.IsUnconscious() && !a.isInFaction(SexLabAnimatingFaction) && theActors.find(a)==-1 && !a.IsOnMount()
      ; "This will fill the first available slot of the array with the actor we found as good."
      theActors[numFoundActors] = a
      ; "Now we set the first available slot to the next one"
      numFoundActors += 1
    endIf
  endWhile
 
  ; "The variable numFoundActors will be exactly the number of actors we found. We use it, backwards for performance, to fill the Aliases with the actors we found."
  ; "Now fill the aliases with the actors"
  while numFoundActors
    ; "Backward for performance"
    numFoundActors -= 1
    ; "the nth alias will be forced to the nth found actor"
    bkAliases[numFoundActors].forceRefTo(theActors[numFoundActors])
  endWhile
EndFunction
 

 

The RefAlias[] array will get filled with the found actors. Of course only the first elements, because the number of found actors can be less than the number of possible references.

If this will create problems on your Scene, then before assigning, clean the refaliases with some code like:

 

int i = bkAliases.length
while i
  i -= 1
  knAliases[i].clear()
endWhile

 

If you have compile errors, please post them.

I did not try this code. I wrote it directly here.

 

 

Posted

Don't forget to have a look to my Papyrus guide, that includes also sections to build a MCM and SexLab.

Posted

Don't forget to have a look to my Papyrus guide, that includes also sections to build a MCM and SexLab.

 

Ok I actually have time to continue with modding. I tryed copy pasting your code (wich I now hope to understand) into a quest script file.

wich then looks like this 

Scriptname Fm_MainQuestUtil extends Quest  
 
Actor[] theActors = new Actor[16] ; "I consider that the number of aliases is 16, change the value with the correct number"
int numFoundActors = 0
ReferenceAlias[] Property BKActors Auto ; "Fill this property with your aliases"
Actor Property PlayerRef Auto
 
Function fillAliases()
  Cell c = PlayerRef.getParentCell()
  int num = c.getNumRefs(62)
  while num && numFoundActors < 16
    num -= 1
    Actor a = c.GetNthRef(num, 62) as Actor
    if a && a!=PlayerRef && !a.isDisabled() && !a.isDead() && !a.isChild() && !a.IsBleedingOut() && !a.IsUnconscious() && !a.isInFaction(SexLabAnimatingFaction) && theActors.find(a)==-1 && !a.IsOnMount()
      theActors[numFoundActors] = a
      numFoundActors += 1
    endIf
  endWhile
 
  ; "Now fill the aliases with the actors"
  while numFoundActors
    numFoundActors -= 1
    bkAliases[numFoundActors].forceRefTo(theActors[numFoundActors]_
  endWhile
EndFunction
 
But I get these errors
 

Starting 1 compile threads for 1 files...
Compiling "Fm_MainQuestUtil"...
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(3,20): no viable alternative at input 'new'
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(3,29): required (...)+ loop did not match anything at input '['
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(3,8): Unknown user flag Actor
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(23,66): missing RPAREN at '_'
No output generated for Fm_MainQuestUtil, compilation failed.

Posted

Hello.

 

On a Quest script you cannot initialize arrays on the fly. Change the code to the following, to have the array initialization done in the OnInit event.

And the last error is just a typo in the code. There is an underscore at the end of the line that should not be there, and there is a missing parenthesis.

 

 

Scriptname Fm_MainQuestUtil extends Quest  
 
Actor[] theActors
int numFoundActors
ReferenceAlias[] Property BKActors Auto ; "Fill this property with your aliases"
Actor Property PlayerRef Auto
 
Event OnInit()
  theActors = new Actor[16] ; "I consider that the number of aliases is 16, change the value with the correct number"
  numFoundActors = 0
EndEvent
 
Function fillAliases()
  Cell c = PlayerRef.getParentCell()
  int num = c.getNumRefs(62)
  while num && numFoundActors < 16
    num -= 1
    Actor a = c.GetNthRef(num, 62) as Actor
    if a && a!=PlayerRef && !a.isDisabled() && !a.isDead() && !a.isChild() && !a.IsBleedingOut() && !a.IsUnconscious() && !a.isInFaction(SexLabAnimatingFaction) && theActors.find(a)==-1 && !a.IsOnMount()
      theActors[numFoundActors] = a
      numFoundActors += 1
    endIf
  endWhile
 
  ; "Now fill the aliases with the actors"
  while numFoundActors
    numFoundActors -= 1
    bkAliases[numFoundActors].forceRefTo(theActors[numFoundActors])
  endWhile
EndFunction
 
Posted

 

Hello.

 

On a Quest script you cannot initialize arrays on the fly. Change the code to the following, to have the array initialization done in the OnInit event.

And the last error is just a typo in the code. There is an underscore at the end of the line that should not be there, and there is a missing parenthesis.


 

Im getting new errors here

 

 

Starting 1 compile threads for 1 files...

Compiling "Fm_MainQuestUtil"...
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(19,137): variable SexLabAnimatingFaction is undefined
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(28,4): variable bkAliases is undefined
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(28,4): only arrays can be indexed
D:\Games_Files\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\Fm_MainQuestUtil.psc(28,30): none is not a known user-defined type
No output generated for Fm_MainQuestUtil, compilation failed.

 
The Faction I can add as property. But how to add the aliases as property? They are created by the array?
Posted

 

The Faction I can add as property. But how to add the aliases as property? They are created by the array?

 

 

Just a couple of properties missing their definition:

 

 

Faction Property SexLabAnimatingFaction Auto
ReferenceAlias[] Property bkAliases Auto
Posted

Or you can try it by distance rather than by cell like so,

Scriptname Fm_MainQuestUtil extends Quest  

ReferenceAlias[] Property BKAliases Auto ; 
Actor Property PlayerRef Auto

Function FillAliases()
   INT i = 16
   FLOAT fRange = 200.0
     While i > 0
	Actor GoodActor = Game.FindRandomActorFromRef(PlayerRef, fRange)
	    If (IsActor(GoodActor))
	       BKAliases[i].ForceRefTo(GoodActor)
            EndIf
	    If fRange < 8000.0
	      fRange *= 2.0
            EndIf
	i -= 1
     EndWhile
EndFunction

Bool Function IsActor(Actor akActor)
	; No children
	If akActor.IsChild() 
	   RETURN False
	EndIf
	; Not the player
	If akActor == PlayerRef 
	   RETURN False
	EndIf
	; Only actors flagged as NPC
	If akActor.HasKeywordString("ActorTypeNpc") == False 
	   RETURN False
	EndIf
	; Only males or females - no animals. 
	If akActor.GetLeveledActorBase().GetSex() < 0 
	   RETURN False
	EndIf
    RETURN True
EndFunction
Posted

FindRandomActorFromRef is way slower that checking the full list of actors in the cell. (about 20 times slower on exterior cells, and about 5 times slower on interior cells.) Because this function checks the 9 cells around the player.

And getSex() is not reliable to understand if the actor is a creature or not.

 

Another general note. The function FindRandomActorFromRef may return NONE in case there is no actor. You should test this case.

Last general note. To have a goo performance, on functions that may be called continously, it is better to reduce the number of lines, and in the condition checking place before the checking that are more light.

Something like:

 

Bool Function IsActor(Actor akActor)
return akActor && akActor!=PlayerRef && !akActor.isChild() && akActor.HasKeywordString("ActorTypeNpc") && akActor.GetLeveledActorBase().GetSex()>=0
EndFunction

 

Same result but with less than half of the lines, and with the condition placed in order of computational cost.

 

Posted

FindRandomActorFromRef is way slower that checking the full list of actors in the cell. (about 20 times slower on exterior cells, and about 5 times slower on interior cells.) Because this function checks the 9 cells around the player.

And getSex() is not reliable to understand if the actor is a creature or not.

 

Another general note. The function FindRandomActorFromRef may return NONE in case there is no actor. You should test this case.

Last general note. To have a goo performance, on functions that may be called continously, it is better to reduce the number of lines, and in the condition checking place before the checking that are more light.

Something like:

 

Bool Function IsActor(Actor akActor)
return akActor && akActor!=PlayerRef && !akActor.isChild() && akActor.HasKeywordString("ActorTypeNpc") && akActor.GetLeveledActorBase().GetSex()>=0
EndFunction
 

Same result but with less than half of the lines, and with the condition placed in order of computational cost.

 

 

Good to know about FindRandomActorFromRef, but I thought it will only check up to the distance specified, in my case 200 increments.

The problem with finding actors inside one cell is if the player is at the edge of said cell, it will not see actors in the other cell even if they were very close to the player, possibly returning none with an actor sitting right next to the player.

 

It makes sense about the one liner.

Posted

 

Good to know about FindRandomActorFromRef, but I thought it will only check up to the distance specified, in my case 200 increments.

 

The problem with finding actors inside one cell is if the player is at the edge of said cell, it will not see actors in the other cell even if they were very close to the player, possibly returning none with an actor sitting right next to the player.

 

It makes sense about the one liner.

 

 

Yes. The extra cost of FinRandomActor is that the actor are search in a total of 9 cells for exterior cells, and from 2 cells for interior.

Of course if you search only by the current cell, and you are close to the cell border, then you may miss many actors.

 

What to do should be dependent on how often you do the checking.

If it is once from time to time, then FindActors is fine.

If you need this in a clock spell or in a cycle that is executed more than once every 10 minutes, then better to find actors in the current cell.

Posted

FindRandomActorFromRef is way slower that checking the full list of actors in the cell. (about 20 times slower on exterior cells, and about 5 times slower on interior cells.) Because this function checks the 9 cells around the player.

And getSex() is not reliable to understand if the actor is a creature or not.

 

Another general note. The function FindRandomActorFromRef may return NONE in case there is no actor. You should test this case.

Last general note. To have a goo performance, on functions that may be called continously, it is better to reduce the number of lines, and in the condition checking place before the checking that are more light.

Something like:

Bool Function IsActor(Actor akActor)
return akActor && akActor!=PlayerRef && !akActor.isChild() && akActor.HasKeywordString("ActorTypeNpc") && akActor.GetLeveledActorBase().GetSex()>=0
EndFunction

Same result but with less than half of the lines, and with the condition placed in order of computational cost.

 

Dude your like my big idol in this. Now there still is the problem, that for a proper bukkake scene I need exclusively male actors. Is that even possible?

Posted

Just one little change in the condition:

 

Bool Function IsActor(Actor akActor)
  return akActor && akActor!=PlayerRef && !akActor.isChild() && akActor.HasKeywordString("ActorTypeNpc") && akActor.GetLeveledActorBase().GetSex()==0
EndFunction
Posted

So what you are saying is that FindRandomActorFromRef will check for all actors close to the ref in 9 outside cells and 2 inside cells ignoring the specified range?

Posted

So what you are saying is that FindRandomActorFromRef will check for all actors close to the ref in 9 outside cells and 2 inside cells ignoring the specified range?

 

Not exactly.

Exteriors cells are big squared cells.

The game engine keeps an active reference of the current player cell and the 8 neighborhood cells. (N, NE, E, SE, S, SW, W, NW)

These are the cells that have to be searched for FindActor by distance.

If the distance is more than two cells, then no actor will be found.

For interior cells, where there are no neighborhood cells, usually the checking is done only from the cell where you were coming from using the "teleport door".

Some people reported that this number of cell may increase if all the cells are interior. I don't know exactly how many cells are checked.

 

But I did some performance checking about 1 year ago.

And FindActor (all variants) are way slower than checking the actors in the current cell.

Posted

OK, but according to CK.com FindRandomActorFromRef will only check for actors up to the specified range, not in all the surrounding cells.

For example,
Player is in the middle of an outside cell, if I limit the search to 200 units around the player, is that still slower than checking for all actors in the current cell?

I don't mean to hijack this thread but I am curious. ;)

Posted

OK, but according to CK.com FindRandomActorFromRef will only check for actors up to the specified range, not in all the surrounding cells.

 

For example,

Player is in the middle of an outside cell, if I limit the search to 200 units around the player, is that still slower than checking for all actors in the current cell?

 

I don't mean to hijack this thread but I am curious. ;)

 

The CK documentation is telling you the result. And yes, you will get as result only the actors that are inside the distance.

But the actual implementation is heavy. because the actual distance of each actor has to be calculated.

Pseudo code (the actual code is in C++):

 

 

Actor Function FindActor(float distance)
  Actor[] possibilties = new Actor[128]
  int numFound = 0
  Cell[] cells = getThe9CellsAroundThePlayer()
  int c = 9
  while c
    c -= 1
    int num = findAllActorsInTheCell(cells[c])
    while num
      num -= 1
      Actor aPossibleActor = getNthActor(cell[c], num)
      if PlayerRef.getDistance(aPossibleActor)
        possibilities[numFound] = aPossibleActor
        numFound += 1
      endIf
    endWhile
  endWhile
  if numFound == 0
    return none
  else
    return possibilities[Utility.randomInt(0, numFound - 1)]
  endIf
EndFunction
Posted

The best and fastest i had ever seen is fisburger's solution. Every time i need to catch actors around in my mods i implement it. Just dig into SexLab Aroused Redux (if i remember correct - quest slaScanAll).
 

Posted

 

Hello.

 

On a Quest script you cannot initialize arrays on the fly. Change the code to the following, to have the array initialization done in the OnInit event.

And the last error is just a typo in the code. There is an underscore at the end of the line that should not be there, and there is a missing parenthesis.

Scriptname Fm_MainQuestUtil extends Quest  
 
Actor[] theActors
int numFoundActors
ReferenceAlias[] Property BKActors Auto ; "Fill this property with your aliases"
Actor Property PlayerRef Auto
 
Event OnInit()
  theActors = new Actor[16] ; "I consider that the number of aliases is 16, change the value with the correct number"
  numFoundActors = 0
EndEvent
 
Function fillAliases()
  Cell c = PlayerRef.getParentCell()
  int num = c.getNumRefs(62)
  while num && numFoundActors < 16
    num -= 1
    Actor a = c.GetNthRef(num, 62) as Actor
    if a && a!=PlayerRef && !a.isDisabled() && !a.isDead() && !a.isChild() && !a.IsBleedingOut() && !a.IsUnconscious() && !a.isInFaction(SexLabAnimatingFaction) && theActors.find(a)==-1 && !a.IsOnMount()
      theActors[numFoundActors] = a
      numFoundActors += 1
    endIf
  endWhile
 
  ; "Now fill the aliases with the actors"
  while numFoundActors
    numFoundActors -= 1
    bkAliases[numFoundActors].forceRefTo(theActors[numFoundActors])
  endWhile
EndFunction
 

 

Ok finally got back on working on my mod. Now that I have setup the scene and actually tried to call the function I found that somehow it just doesnt work.

 

I setup the thing, that I call the function on a dialogue topic and start the scene with the same topic (forcestart). This technoicallly should force a couple of dudes into aliases. But nothing happens actually

Posted

Let "debug.trace" be your bitch.

Put a bunch of debug.trace in your code to check what is the flow and what is inside the variables.

 

Posted

The best and fastest i had ever seen is fisburger's solution. Every time i need to catch actors around in my mods i implement it. Just dig into SexLab Aroused Redux (if i remember correct - quest slaScanAll).

Please pay attention to this post.

 

You DO NOT NEED ALL THAT CODE, not a single line of it! (Yes, it's good code, it's just not needed in this case).

 

You are trying to fill Quest Aliases and the game has a BUILT-IN function for doing exactly that (no scripting needed!). In the case mentioned in fact there IS code but that code takes the automatically filled aliases from the quest and puts them into an array for use elsewhere in the mod, exactly the opposite from what this code is doing.

 

Just set the right flags and conditions on the aliases and they will automatically be filled when the quest starts (as long as enough of the right type of NPCs are available to fill them all).

 

Put all the conditions (distance, sex, no children etc) into conditions on each alias for the quest.

 

CPU is right about the cell scan being faster that the FindRandomActorFromRef call but faster yet is not using Papyrus scripting when you don't need it.

Posted

GornoDD, sorry, but the major problem that you want to catch all Skyrim at once from "quick start". Your mod will be stopped or abandoned if you will ask about ANY problem that happens and wait for... what? Provided links and script "parts" will do not make yours work till you "utilize" it. Or your mod becomes something like another CPU's mod. "Dig in" other mods, learn, and "dig out" with own ideas.

There is nothing to say except RTFM related to Papyrus scripting. Even CPU has own time, own mind, own mods to update. Sorry that I said this, but your way seems go ahead with another brains.

I DO NOT want to break you from stop learning Skyrim scripting. But "без труда... рыбка в 'нетуда' ". Sorry, not Russian, but own.

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

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