Jump to content

Any advanced scripters out there want to give this long script a look? Also, need some texturing help.


Recommended Posts

I'm working on a new mod called "LAGO - Linearly Aligning Geometric Objects."

 

Basically, I'm making Lego blocks. They are supposed to snap together like their real-world counterparts. The script I'm writing for them is, to put it mildly, driving me insane.

 

The script is supposed to do, in essence, four things: 1. Orient itself to upright when released from the player's grip, 2. Request nearby blocks position data, 3. Orient itself to the nearest block, and 4. Send position data when a released block nearby requests it.

 

I can't seem to get past the first part. When I release a block, it tries to translate to x0, y0, whether there is a close block or not.

 

The script is in the spoiler, and I've linked a 7z of the mod so far, if you want to see what it does.

 

As for the texturing, I've downloaded a bunch of badass textures from a guy's blog (he allows any use, and of course I will credit/link/Ko-Fi him on the mod page). They include spec and normal maps, but they are... off (have weird shadows/lighting) in game and the Creation Kit (the textures look fine in NifSkope).

 

GKX Lago.7z Google Drive Link

 

 

 

Scriptname _gkx_lagoblocks extends ObjectReference

Struct PositionData
	Float XPos
	Float YPos
	Float ZPos
	Float ZAngle
	Float XSize
	Float YSize
	Float ZSize
EndStruct

Float Property XLength Auto
Float Property YDepth Auto
Float Property ZHeight Auto
Float Property SearchRadius Auto
_gkx_lagoblocks[] BlockScript
_gkx_lagoblocks MyScript
CustomEvent SendMyLocation
CustomEvent RequestLocations

PositionData MyData
PositionData Nearest
PositionData[] CloseBlocks
Int DataIndex = 0
Int NearIndex = 0
Bool Busy1 = FALSE
Bool Busy2 = FALSE
Bool Busy3 = FALSE
Bool Busy4 = FALSE
Bool BeenMoved = FALSE
Bool TranslateMe = FALSE
Float Radius
Float NewRadius
Float SameRadius

Event OnInit()
	MyScript = Self
	RegisterForHitEvent(Self)
	SetMotionType(1)
	SameRadius = ((Math.Min(XLength, YDepth)) / 4.0)
	RegisterForCustomEvent(BlockScript, "RequestLocations")
	RegisterForCustomEvent(BlockScript, "SendMyLocation")
EndEvent

Event OnHit(ObjectReference Target, ObjectReference Aggressor, Form Source, Projectile Proj, bool PAttack, bool SAttack, bool BAttack, bool Blocked, string Material)
	If ((Proj) || (PAttack) || (SAttack) || (BAttack))
		Disable()
		Delete()
	Else
		SetMotionType(1)
	EndIf
EndEvent

Event _gkx_lagoblocks.RequestLocations(_gkx_lagoblocks Sender, Var[] SourceData)
	If (CalcDistance(ArrayToStruct(SourceData)) < SearchRadius) && BeenMoved
		Var[] SendMe = new Var[8]
		SendMe = (StructToArray(MyData))
		SendCustomEvent("SendMyLocation", SendMe)
	EndIf
EndEvent

Event _gkx_lagoblocks.SendMyLocation(_gkx_lagoblocks Sender, Var[] RecData)
	CloseBlocks[DataIndex] = ArrayToStruct(RecData)
	DataIndex += 1
EndEvent

Event OnGrab()
	CloseBlocks.Clear()
	DataIndex = 0
EndEvent

Event OnRelease()
	SetMotionType(2)
	FillCurrentPosition()
	While Busy4
		Utility.Wait(0.1)
	EndWhile
	TranslateTo(MyData.XPos, MyData.YPos, MyData.ZPos, 0.0, 0.0, MyData.ZAngle, 10.0, 1440.0)
	SendCustomEvent("RequestLocations")
	Bool Receiving = TRUE
	Utility.Wait(0.1)
	Int OldLength = CloseBlocks.Length
	While Receiving
		Utility.Wait(0.1)
		If CloseBlocks.Length == OldLength
			Receiving = FALSE
		EndIf
		OldLength = CloseBlocks.Length
	EndWhile
	If CloseBlocks.Length > 0
		FindNearest()
		While Busy1
			Utility.Wait(0.1)
		EndWhile
		MyData = FixMyData(CloseBlocks[NearIndex])
		While Busy2
			Utility.Wait(0.1)
		EndWhile
		CloseBlocks.Clear()
		DataIndex = 0
	Else
		FillCurrentPosition()
		While Busy4
			Utility.Wait(0.1)
		EndWhile
		TranslateMe = TRUE
	EndIf
	If TranslateMe
		TranslateTo(MyData.XPos, MyData.YPos, MyData.ZPos, 0.0, 0.0, MyData.ZAngle, 10.0, 1440.0)
		BeenMoved = TRUE
	Else
		SetMotionType(1)
	EndIf
EndEvent

Function FindNearest()
	Busy1 = TRUE
	Int Count1 = 0
	Float Smallest = SearchRadius
	Float Latest = 0.0
	While (Count1 < CloseBlocks.Length)
		Latest = CalcDistance(CloseBlocks[Count1])
		If Latest < Smallest
			Smallest = Latest
			NearIndex = Count1
		EndIf
		Count1 += 1
	EndWhile
	Busy1 = FALSE
EndFunction

PositionData Function ArrayToStruct(Var[] InputArray)
	PositionData TempPos
	TempPos.Xpos = InputArray[0] as Float
	TempPos.Ypos = InputArray[1] as Float
	TempPos.Zpos = InputArray[2] as Float
	TempPos.ZAngle = InputArray[3] as Float
	TempPos.XSize = InputArray[4] as Float
	TempPos.YSize = InputArray[5] as Float
	TempPos.ZSize = InputArray[6] as Float
	Return TempPos
EndFunction

Var[] Function StructToArray(PositionData InputPos)
	Var[] TempArray = New Var[8]
	TempArray[0] = InputPos.Xpos
	TempArray[1] = InputPos.Ypos
	TempArray[2] = InputPos.Zpos
	TempArray[3] = InputPos.ZAngle
	TempArray[4] = InputPos.XSize
	TempArray[5] = InputPos.YSize
	TempArray[6] = InputPos.ZSize
	TempArray[7] = MyScript
	Return TempArray
EndFunction

Float Function CalcDistance(PositionData CalcData)
	Float XSquared = Math.Pow((MyData.XPos - CalcData.XPos), 2.0)
	Float YSquared = Math.Pow((MyData.YPos - CalcData.YPos), 2.0)
	Float ZSquared = Math.Pow((MyData.ZPos - CalcData.ZPos), 2.0)
	Float Distance = Math.Sqrt(XSquared + YSquared + ZSquared)
	Return Distance
EndFunction

PositionData Function FixMyData(PositionData UseThis)
	Busy2 = TRUE
	PositionData TempData
	Float XYDistance
	Float ZAngleDiff = Math.Abs(UseThis.ZAngle - MyData.ZAngle)
	Float XPosDiff = Math.Abs(UseThis.XPos - MyData.XPos)
	Float YPosDiff = Math.Abs(UseThis.YPos - MyData.YPos)
	Float ZPosDiff = Math.Abs(UseThis.ZPos - MyData.ZPos)
	If (ZAngleDiff <=90.0)
		TempData.ZAngle = UseThis.ZAngle
	ElseIf (ZAngleDiff <= 180.0)
		TempData.ZAngle = (UseThis.ZAngle + 90.0)
	ElseIf (ZAngleDiff <= 270.0)
		If (UseThis.ZAngle > 0)
			TempData.ZAngle = (UseThis.ZAngle - 180.0)
		Else
			TempData.ZAngle = (UseThis.ZAngle + 180.0)
		EndIf
	Else
		TempData.ZAngle = (UseThis.ZAngle - 90.0)
	EndIf

	If (IsSame(MyData.ZPos, UseThis.ZPos, SameRadius))
		TempData.ZPos = UseThis.ZPos
	EndIf
	XYDistance = Hypot(XPosDiff, YPosDiff)

	If (XYDistance <=  SameRadius)
		TempData.XPos = UseThis.XPos
		TempData.YPos = UseThis.YPos
		If (MyData.ZPos > UseThis.ZPos)
			TempData.ZPos = (UseThis.ZSize + MyData.ZPos)
		Else
			TempData.ZPos = (UseThis.ZPos - MyData.ZSize)
		EndIf
	Else
		NewRadius = FixRadius(UseThis, MyData, XYDistance)
		While Busy3
			Utility.Wait(0.1)
		EndWhile
		If !TranslateMe
			TempData.XPos = Self.GetPositionX()
			TempData.YPos = Self.GetPositionY()
			TempData.ZPos = Self.GetPositionZ()
			TempData.ZAngle = Self.GetAngleZ()
		Else
			TempData.XPos = (Math.Cos(TempData.ZAngle) * NewRadius)
			TempData.YPos = (Math.Sin(TempData.ZAngle) * NewRadius)
		EndIf
	EndIf
	Busy2 = FALSE
	Return TempData
EndFunction

Float Function FixRadius(PositionData Source, PositionData Me, Float OldRadius)
	Busy3 = TRUE
	Float SXHalf = (Source.XSize * 0.5)
	Float SYHalf = (Source.YSize * 0.5)
	Float MXHalf = (Me.XSize * 0.5)
	Float MYHalf = (Me.YSize * 0.5)
	Float[] PossRadii = New Float[11]
	PossRadii[0] = SXHalf
	PossRadii[1] = SYHalf
	PossRadii[2] = (SXHalf + MXHalf)
	PossRadii[3] = (SXHalf + MXHalf)
	PossRadii[4] = (SYHalf + MXHalf)
	PossRadii[5] = (SYHalf + MYHalf)
	PossRadii[6] = (Hypot(SXHalf, SYHalf))
	PossRadii[7] = (Hypot(SXHalf, (SXHalf + MXHalf)))
	PossRadii[8] = (Hypot(SXHalf, (SXHalf + MYHalf)))
	PossRadii[9] = (Hypot(SYHalf, (SYHalf + MXHalf)))
	PossRadii[10] = (Hypot(SYHalf, (SYHalf + MYHalf)))
	Int Count1 = 0
	Bool FoundIt = FALSE
	Float Result
	Float TempRadius = (Math.Max(Source.XSize, Source.YSize) / 2.0)
	While (Count1 < 11) && !FoundIt
		FoundIt = IsSame(PossRadii[Count1], OldRadius, TempRadius)
		If FoundIt
			Result = PossRadii[Count1]
		EndIf
		Count1 += 1
	EndWhile
	Busy3 = FALSE
	If !FoundIt || (Count1 >= 11)
		TranslateMe = FALSE
		Return 1000.0
	Else
		TranslateMe = TRUE
		Return Result
	EndIf		
EndFunction

Function NewPosition()
	DataIndex = 0
	FillCurrentPosition()
EndFunction

Bool Function IsSame(Float Num1, Float Num2, Float NumRadius)
	Float DiffNum = (Math.Abs(Num1 - Num2))
	If DiffNum < NumRadius
		Return TRUE
	Else
		Return FALSE
	EndIf
EndFunction

Float Function Hypot(Float Num1, Float Num2)
	Float Result = (Math.Sqrt((Num1 * Num1) + (Num2 * Num2)))
	Return Result
EndFunction

Function FillCurrentPosition()
	Busy4 = TRUE
	MyData.XPos = Self.GetPositionX()
	MyData.YPos = Self.GetPositionY()
	MyData.ZPos = Self.GetPositionZ()
	MyData.ZAngle = Self.GetAngleZ()
	MyData.XSize = XLength
	MyData.YSize = YDepth
	MyData.ZSize = ZHeight
	Busy4 = FALSE
EndFunction

 

 

Link to comment
Share on other sites

My suggestion would be to start adding debug.trace calls in your code to see exactly what is going on. There are simply too many variables and too much complexity to figure out at a glance what exactly is causing the problem (and unfortunately I don't have the time to try and run the mod). Cool idea, though.

 

As an aside, I would suggest you look into changing how you are interacting with your DataIndex / ClosedBlock code, especially your RequestLocations / SendMyLocation events, because it is going to send that to every single instance of your _gkx_lagoblocks, all at once. I can pretty much guarantee you that once you hit a certain number of blocks you will crash the game due to a Papyrus stack overflow. I know this from my own experience in creating a lighting mod for Fallout 4 (and the crashes will likely occur on consoles / older PCs even if you can't reproduce it on your own machine). I would suggest that you change the code to send data to specific blocks in the given radius rather than to every block (which would just be a call to a new function on a specific Objectreference).

Link to comment
Share on other sites

for textures, you have only included one of a white brick wall. it looks quite bad as in, it looks like it was much smaller originally and is now pixelated and low resolution at the size of 1024x1024. Tthe Spec and normal are not right for fallout. Spec looks far to bright and normal.. I have never seen that format. Any image can be converted to work in fallout, but its a lot to type. you seem smart, I have never understood scripting, so If you jus check some tutorial vids on how to convert textures to work in Fallout 4 or Skyrim, I'm sure you will figure it out.

Get Gimp photo editor for free and the DDs plugin for it found on github

Link to comment
Share on other sites

 

As for the texturing, I've downloaded a bunch of badass textures from a guy's blog (he allows any use, and of course I will credit/link/Ko-Fi him on the mod page). They include spec and normal maps, but they are... off (have weird shadows/lighting) in game and the Creation Kit (the textures look fine in NifSkope).

Textures need to be in the right format. I'm using BC3 for dif, BC5 for normals and specular. For further information, I would recommend to watch this vid https://www.youtube.com/watch?v=3cDJ0Rk7hC0

Secondly, as you may have noticed, you have a material file, which can greatly influence how the texture looks in game through different things such as specular multiplier, greyscaling, environment mapping, the used cube etc, so you might want to take a look into that as well/experiment with it.

Link to comment
Share on other sites

I realized after I downloaded them, the textures are 1k 72dpi jpegs. When I get my stimulus money, I'll toss the guy some patreon money for the 4k textures.

 

I did save the normal and speculars as BC5 and the diffuse as BC3, and I used a brick wall BGSM from the game files and just replaced the textures. I don't know,

 

Elric messed up my model. It stripped out the collision data completely...

 

As for the script, I'll do what Reneer suggested

 

Thanks everyone

~GKX

Link to comment
Share on other sites

I realized after I downloaded them, the textures are 1k 72dpi jpegs. When I get my stimulus money, I'll toss the guy some patreon money for the 4k textures.

 

I did save the normal and speculars as BC5 and the diffuse as BC3, and I used a brick wall BGSM from the game files and just replaced the textures. I don't know,

 

Elric messed up my model. It stripped out the collision data completely...

 

As for the script, I'll do what Reneer suggested

 

Thanks everyone

~GKX

If it's the normal brickwall bgsm then it greyscales to a pallet, if I remember it correctly. Try to get rid of the greyscaling and see if this helps.

Edited by DocMoebius
Link to comment
Share on other sites

GenghisKhanX wrote: "I cannot seem to get past the first part. When I release a block, it tries to translate to x0, y0, whether there is a close block or not."

 

1. What is a threadlock?

        WHILE (Busy1)
            Utility.Wait(0.1)    ; Threadlock 1 active
        ENDWHILE

        Busy1 = TRUE        ; *T*
;        ------------
       ; code inside that manipulates script data (variables and/or porperties) and may not interrupted
;        ------------
        Busy1 = False        ; ***

2. How to init an array or a struct variable (user defined record of given types)?

    CloseBlocks = new PositionData[0]        ; create new array (with userdefined struct) of ZERO length
    PositionData PD = new PositionData       ; create new struct

3. Make sure you do not have to many "wait()" inside your code. Its horrible to debug, because of event calling by threads.

 

4. _gkx_lagoblocks

 

Scriptname _gkx_lagoblocks extends ObjectReference
; https://forums.nexusmods.com/index.php?/topic/8587993-any-advanced-scripters-out-there-want-to-give-this-long-script-a-look-also-need-some-texturing-help/

; GenghisKhanX wrote:"
; 1. Orient itself to upright when released from the player's grip
; 2. Request nearby blocks position data
; 3. Orient itself to the nearest block
; 4. Send position data when a released block nearby requests it."

; Issue: "I cannot seem to get past the first part.
;        When I release a block, it tries to translate to x0, y0, whether there is a close block or not."
;--------------------------------------------------------------------------------------------------------

 ;_gkx_lagoblocks   MyScript        ; UnUSED now
 ;_gkx_lagoblocks[] BlockScript     ; !!??

Struct PositionData        ; record structure
    Float XPos
    Float YPos
    Float ZPos
    Float ZAngle
    Float XSize
    Float YSize
    Float ZSize
endStruct

 ;PositionData Nearest              ; UnUSED by default!
  PositionData MyData
  PositionData[] CloseBlocks        ; array of record *** Keep in mind: max array length is 128 ***

; start values
  Float PROPERTY XLength      auto  ; [default=0.0]
  Float PROPERTY YDepth       auto
  Float PROPERTY ZHeight      auto
  Float PROPERTY SearchRadius auto

; default = 0.0
  Float Radius
  Float SameRadius        ; preset by OnInit()
 ;Float NewRadius

; default = 0
  Int DataIndex
 ;Int NearIndex         ; UnUSED

; default = False
  Bool BeenMoved
  Bool TranslateMe
  Bool Busy1
 ;Bool Busy2            ; UnUSED
 ;Bool Busy3            ; UnUSED
  Bool Busy4

; user events
  CustomEvent Request               ; RequestLocations
 ;CustomEvent SendMyLocation        ; UnUSED by now


; -- EVENTs -- 4 + 1

; Destroys the whole array, no Zero length array keeps left
;;;    PositionData[] b
;;;    CloseBlocks = b


EVENT OnInit()
    SameRadius = Math.Min(XLength, YDepth)
    SameRadius = SameRadius * 0.25

    CloseBlocks = new PositionData[0]        ; create new array (with userdefined struct) of ZERO length
    RegisterForHitEvent(self)

; akSender: The ScriptObject that receives the event we want to also receive.
    RegisterForCustomEvent(self, "Request")                ; register A
;;;    RegisterForCustomEvent(self, "SendMyLocation")      ; register B

; https://www.creationkit.com/fallout4/index.php?title=SetMotionType_-_ObjectReference
; int Property Motion_Fixed     = 0 AutoReadOnly
; int Property Motion_Dynamic   = 1 AutoReadOnly
; int Property Motion_Keyframed = 2 AutoReadOnly
; *******************************************
; *** ARE YOUR SURE THIS IS WORKING HERE? ***
; *******************************************
    self.SetMotionType(1)        ; Motion_Dynamic
ENDEVENT

;
;EVENT OnLoad()
;    self.SetMotionType(1)        ; Motion_Dynamic
;ENDEVENT
;

EVENT OnGrab()
; called when SELF has been grabbed by the player (z-keyed).
    myF_Grab()
ENDEVENT


EVENT OnRelease()
; called when SELF has been released by the player (un-z-keyed).

WHILE (Busy4)
    Utility.Wait(0.1)            ; Threadlock 4 active
ENDWHILE

    Busy4 = TRUE            ; *T*
;--------------------------------
    self.SetMotionType(2)            ; Motion_KeyFramed

    FillCurrentPosition()
    myF_Translate()
    myF_Wait()

    IF (CloseBlocks.Length > 0)
        WHILE (Busy1)
            Utility.Wait(0.1)    ; Threadlock 1 active
        ENDWHILE

        Busy1 = TRUE        ; *T*
;        ------------
        FixMyData()
        myF_Grab()
;        ------------
        Busy1 = False       ; ***
    ELSE
        FillCurrentPosition()
        TranslateMe = TRUE
    ENDIF

    IF ( TranslateMe )
        myF_Translate()
        BeenMoved = TRUE
    ELSE
        self.SetMotionType(1)        ; Motion_Dynamic
    ENDIF
;--------------------------------
    Busy4 = False            ; ***
ENDEVENT


EVENT OnHit(ObjectReference akTarget, ObjectReference akAggressor, Form akSource, Projectile akProj, Bool b1, Bool b2, Bool b3, Bool b4, String asMaterialName)
;Event OnHit(ObjectReference akTarget, ObjectReference akAggressor, Form akSource, Projectile akProjectile, \
;            bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked, string asMaterialName)

IF     (akProj)
ELSEIF ( b1 )
ELSEIF ( b2 )
ELSEIF ( b3 )
    self.SetMotionType(1)
;;;    RegisterForHitEvent(self)        ; RE-REGISTER ???
    RETURN    ; - STOP -    not hit by projectile OR powerAttack OR sneakAttack OR bashAttack
ENDIF
;---------------------
    self.DisableNoWait()

    UnRegisterForCustomEvent(self, "Request")              ; unregister (A)
;;;    UnRegisterForCustomEvent(self, "SendMyLocation")    ; unregister (B)

    self.Delete()        ; mark this objectRef for delete, this script as well
ENDEVENT


; (A)
EVENT _gkx_lagoblocks.Request(_gkx_lagoblocks akSender, Var[] akArgs)    ; akArgs = SourceData
    myF_ADD( ArrayToStruct(akArgs) )
ENDEVENT

; (B) °°°obsolete°°°
;EVENT _gkx_lagoblocks.SendMyLocation(_gkx_lagoblocks akSender, Var[] akArgs)   ; akArgs = RecData
;    CloseBlocks.Add( ArrayToStruct(akArgs) )
;    DataIndex += 1
;ENDEVENT


; -- FUNCTIONs -- 13

;------------------
FUNCTION myF_Grab()  ; internal helper
;------------------
; Removes all entries from the array, reducing it to a 0-length array.

IF ( Busy1 )
    ; hanging inside release event
ELSE
    CloseBlocks.Clear()
    DataIndex = 0
ENDIF
ENDFUNCTION


;--------------------------------
FUNCTION myF_ADD(PositionData PD)  ; internal helper
;--------------------------------
IF (BeenMoved) && (CalcDistance(PD) < SearchRadius)
        
    ; Instead of second custom event we add new position data to the array directly!
;;;    SendCustomEvent("SendMyLocation", StructToArray(MyData))    ; call event (B)
;---
    CloseBlocks.Add(PD)
    DataIndex += 1
;---
ENDIF
ENDFUNCTION


;------------------
FUNCTION myF_Wait()  ; ???
;------------------
; https://www.creationkit.com/fallout4/index.php?title=SendCustomEvent_-_ScriptObject
    SendCustomEvent("Request", MyData)                            ; call for event A
    Utility.Wait(0.1)

    int OldLength = CloseBlocks.Length

WHILE (CloseBlocks)
    Utility.Wait(0.1)

    IF (CloseBlocks.Length == OldLength)
        RETURN    ; - STOP -    leave the loop and finish function
    ENDIF

    OldLength = CloseBlocks.Length
ENDWHILE
ENDFUNCTION


;;--------------------------------------------
;Var[] FUNCTION StructToArray(PositionData PD)  ; PD = InputPos
;;--------------------------------------------
;Var[] a = new Var[8]
;
;    a[0] = PD.Xpos
;    a[1] = PD.Ypos
;    a[2] = PD.Zpos
;    a[3] = PD.ZAngle
;    a[4] = PD.XSize
;    a[5] = PD.YSize
;    a[6] = PD.ZSize
;    a[7] = self
;
;    RETURN a        ; ARRAY
;ENDFUNCTION


;-------------------------------------------
PositionData FUNCTION ArrayToStruct(Var[] a)  ; a = InputArray
;-------------------------------------------
; https://www.creationkit.com/fallout4/index.php?title=Struct_Reference
PositionData PD = new PositionData

    PD.Xpos   = a[0] as Float
    PD.Ypos   = a[1] as Float
    PD.Zpos   = a[2] as Float
    PD.ZAngle = a[3] as Float
    PD.XSize  = a[4] as Float
    PD.YSize  = a[5] as Float
    PD.ZSize  = a[6] as Float

    RETURN PD        ; STRUCT
ENDFUNCTION


;-------------------------------------------
Float FUNCTION CalcDistance(PositionData PD)  ; PD = CalcData
;-------------------------------------------
    float fx = MyData.XPos
    float fy = MyData.YPos
    float fz = MyData.ZPos

    fx = fx - PD.XPos
    fx = fx * fx        ;  XSquared
    
    fy = fy - PD.YPos
    fy = fy * fy        ;  YSquared
    
    fz = fz - PD.ZPos
    fz = fz * fz        ;  ZSquared

    RETURN Math.Sqrt(fx + fy + fz)        ; Distance
ENDFUNCTION


;------------------------
Int FUNCTION FindNearBy()
;------------------------
    float R = SearchRadius                                  ; R = Smallest

int n = 0
int i = 0                                                   ; i = Count1
    WHILE (CloseBlocks) && (i < CloseBlocks.Length)
        float f = CalcDistance( CloseBlocks[i] )            ; f = Latest
        IF (f < R)
            R = f        ; decrease search radius
            n = i        ; update return value
        ENDIF
        i = i + 1
    ENDWHILE

    RETURN n             ; NearIndex
ENDFUNCTION


;--------------------------------------------------
Bool FUNCTION IsInside(Float R, Float f1, Float f2)  ; f = NumRadius
;--------------------------------------------------
    float f = Math.ABS(f1 - f2)
    RETURN (f < R)                    ; < TRUE, >= False
ENDFUNCTION


;-------------------
FUNCTION FixMyData()
;-------------------
    int n = FindNearBy()

;;;    Busy2 = TRUE        ; *T*

IF ( CloseBlocks )
ELSE
    RETURN    ; - STOP -    failsafe
ENDIF
;---------------------
; get a pointer to existing struct as part of array "CloseBlocks"
    PositionData SDF = CloseBlocks[n]                        ; SDF = UseThis, n = NearIndex

; create new struct temporarily
    PositionData PD    = new PositionData                    ; PD = TempData

; z-Angle preset
;~~~~~~~~~~~~~~~
    float aZ= SDF.ZAngle
    float f = Math.ABS(aZ - MyData.ZAngle)                   ; f = ZAngleDiff

    IF     (f <= 90.0)                ; 0 .. 90
        PD.ZAngle = aZ

    ELSEIF (f <= 180.0)               ; >90 .. 180
        PD.ZAngle = aZ + 90.0

    ELSEIF (f > 270.0)                ; >270 .. 360
        PD.ZAngle = aZ - 90.0

    ELSE                              ; >180 .. 270
        IF (fz > 0.0)
            PD.ZAngle = aZ - 180.0
        Else
            PD.ZAngle = aZ + 180.0
        EndIf
    ENDIF

; z-Pos pre-check
;~~~~~~~~~~~~~~~~
    f = SDF.ZPos
    IF IsInside(SameRadius, MyData.ZPos, f)
        PD.ZPos = f
    ENDIF

; distance check
;~~~~~~~~~~~~~~~
;;;    Float ZPosDiff = Math.ABS(SDF.ZPos - MyData.ZPos)

    float fx = SDF.XPos
    fx = Math.ABS(fx - MyData.XPos)          ; fx = XPosDiff

    float fy = SDF.YPos
    fy = Math.ABS(fy - MyData.YPos)          ; fy = YPosDiff

;;;    f = Hypo(fx, fy)
    f = Math.Sqrt((fx*fx) + (fy*fy))         ; f = XYDistance

IF (f <= SameRadius)
    fx = SDF.XPos
    PD.XPos = fx

    fy = SDF.YPos
    PD.YPos = fy

    IF (MyData.ZPos > SDF.ZPos)
        PD.ZPos = MyData.ZPos + SDF.ZSize
    ELSE
        PD.ZPos = SDF.ZPos - MyData.ZSize
    ENDIF
ELSE
;;;    WHILE (Busy3)
;;;        Utility.Wait(0.1)    ; Threadlock 3 active
;;;    ENDWHILE
;;;    Busy3 = TRUE        ; *T*

    f = FixRadius(SDF, f)        ; NewRadius = FixRadius(UseThis, MyData, XYDistance)

;;;    Busy3 = False        ; ***

    IF ( TranslateMe )
        PD.XPos = Math.Cos(PD.ZAngle) * f
        PD.YPos = Math.Sin(PD.ZAngle) * f
    ELSE
        PD.XPos   = self.GetPositionX()
        PD.YPos   = self.GetPositionY()
        PD.ZPos   = self.GetPositionZ()
        PD.ZAngle = self.GetAngleZ()
    ENDIF
ENDIF

; do not forget these, if you need size !!!
    PD.XSize  = SDF.XSize        ; = MyData.XSize
    PD.YSize  = SDF.YSize        ; = MyData.YSize
    PD.ZSize  = SDF.ZSize        ; = MyData.ZSize

    MyData = PD        ; update the whole script struct variable
;;;    Busy2 = False        ; ***
ENDFUNCTION


;--------------------------------------
Float FUNCTION Hypo(Float fx, Float fy)
;--------------------------------------
    RETURN Math.Sqrt((fx*fx) + (fy*fy))        ; distance XY
ENDFUNCTION


;--------------------------------------------------
Float FUNCTION FixRadius(PositionData SDF, Float f)
;--------------------------------------------------
;;;    Float SXHalf = (Source.XSize * 0.5)
;;;    Float SYHalf = (Source.YSize * 0.5)
;;;    Float MXHalf = (Me.XSize * 0.5)
;;;    Float MYHalf = (Me.YSize * 0.5)

    float fx
    float fy
    float[] a = new Float[11]                    ; a = PossRadii

    fx = SDF.XSize
    fy = SDF.YSize
    a[0] = fx * 0.5                ; SXHalf
    a[1] = fy * 0.5                ; SYHalf

    float R = Math.Max(fx,fy) * 0.5               ; TempRadius = Math.Max(Source.XSize, Source.YSize) / 2.0

    fx = MyData.XSize * 0.5        ; MXHalf
    fy = MyData.YSize * 0.5        ; MYHalf
    a[2] = a[0] + fx
    a[3] = a[0] + fy        ; TYPO --> PossRadii[3] = (SXHalf + MXHalf)
    a[4] = a[1] + fx
    a[5] = a[1] + fy

    a[6] = Hypo(a[0], a[1])
    a[7] = Hypo(a[0], a[2])        ; (SXHalf + MXHalf)
    a[8] = Hypo(a[0], a[3])
    a[9] = Hypo(a[1], a[4])
    a[10]= Hypo(a[1], a[5])

int i = 0                                        ; i = Count1
WHILE (i < 11)
    IF IsInside(R, a[i], f)                      ; f = OldRadius
        TranslateMe = TRUE
        RETURN a[i]       ; /1 result
    ENDIF
;    ----------
    i = i + 1
ENDWHILE

        TranslateMe = False
        RETURN 1000.0    ; /2 result
ENDFUNCTION


;-----------------------------
FUNCTION FillCurrentPosition()
;-----------------------------
;;;    IF ( CloseBlocks )
;;;        ; array already created
;;;    ELSE                                        ; create new array (with userdefined struct) of ZERO length
;;;        CloseBlocks = new PositionData[0]       ; see OnInit() event
;;;    ENDIF

    IF ( MyData )
        ; struct already created
    ELSE
        MyData = new PositionData                ; create a userdefined struct
    ENDIF

    MyData.XPos   = self.GetPositionX()
    MyData.YPos   = self.GetPositionY()
    MyData.ZPos   = self.GetPositionZ()
    MyData.ZAngle = self.GetAngleZ()
    MyData.XSize  = XLength
    MyData.YSize  = YDepth
    MyData.ZSize  = ZHeight
ENDFUNCTION


;-----------------------
FUNCTION myF_Translate()  ; helper to shrink stack size
;-----------------------
IF ( MyData )
    float fx = MyData.XPos
    float fy = MyData.YPos
    float fz = MyData.ZPos
    float aZ = MyData.ZAngle
    self.TranslateTo(fx,fy,fz, 0.0, 0.0, aZ, 10.0, 1440.0)
ENDIF
ENDFUNCTION


;---------------------
FUNCTION NewPosition()  ; ???
;---------------------
    DataIndex = 0
    FillCurrentPosition()
ENDFUNCTION

 

 

Link to comment
Share on other sites

  • Recently Browsing   0 members

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