Jump to content

DOWNLOAD MODS

Are you looking for something shiny for your load order? We have many exclusive mods and resources you won't find anywhere else. Start your search now...

LEARN MODDING

Ready to try your hand at making your own mod creations? Visit the Enclave, the original ES/FO modding school, and learn the tricks of the trade from veteran modders...

JOIN THE ALLIANCE

Membership is free and registering unlocks image galleries, project hosting, live chat, unlimited downloads, & more...

[SKY] Need help with Mark & Recall Script


Nalfeyn
 Share

Recommended Posts

How is your trigger set up? Did you put in a debug statement to see if the script is actually being executed? If the script is being executed, then it's a problem with the script. If the script isn't being executed, then it's a problem with the trigger setup.

 

Also, what happens if an NPC walks into your portal? The script would be called with akActionRef pointing to the NPC, but the script would grab the player and move him. It's generally a good idea to check the akActionRef and make sure it is the player who is activating the trigger before doing anything, if only the player is supposed to use it. For example, my teleport objects use code like:

Event OnActivate(ObjectReference akActionRef)

    if akActionRef == PlayerREF
        <do stuff>
    endif 
EndEvent

so that nothing is done unless it is the player who did the activation. Of course, if you have some other means of preventing NPCs from activating your trigger, then the precaution is not needed. But I think it may be a good thing to do anyway, just to make it a habit.

Link to comment
Share on other sites

How is your trigger set up? Did you put in a debug statement to see if the script is actually being executed? If the script is being executed, then it's a problem with the script. If the script isn't being executed, then it's a problem with the trigger setup.

 

Also, what happens if an NPC walks into your portal? The script would be called with akActionRef pointing to the NPC, but the script would grab the player and move him. It's generally a good idea to check the akActionRef and make sure it is the player who is activating the trigger before doing anything, if only the player is supposed to use it. For example, my teleport objects use code like:

Event OnActivate(ObjectReference akActionRef)

    if akActionRef == PlayerREF
        <do stuff>
    endif 
EndEvent

so that nothing is done unless it is the player who did the activation. Of course, if you have some other means of preventing NPCs from activating your trigger, then the precaution is not needed. But I think it may be a good thing to do anyway, just to make it a habit.

Yes, only the player is supposed to use this. 

 

So it should be like : 

Event OnTriggerEnter (ObjectReference akActionRef)
   if akActionRef == PlayerREF
      game.getPlayer().moveTo(xyz. x, y, z, true)
   elseIf akActionRef [not player, don't know the variable] PlayerREF
   endIf
EndEvent 

Is this correct ?

Link to comment
Share on other sites

You don't need the "elseif". If the actor is not the player, then the script just does nothing the way I gave it.

 

The "PlayerREF" only works if you have assigned Game.GetPlayer() to a variable named PlayerREF or set up a property named PlayerREF that already contains the reference to the player. (Actor Property PlayerREF auto -- which is a property that can be autofilled. It's an efficient way to refer to the Player without any calls to the GetPlayer() function.)

 

Otherwise you would have to use:

if akActionRef == Game.GetPlayer()
Link to comment
Share on other sites

So I changed the trigger script and the portal works for now. 

I just have the problem, if I go through the portal and be teleported to the other one, I get in a constant teleportation loop between those two portals. 

 

I used a part of this script : 

Event OnTriggerEnter (ObjectReference akActionRef)
   if akActionRef == game.getPlayer()
      game.getPlayer().moveTo(xyz. x, y, z, true)
   endIf
EndEvent 

Event OnTriggerLeave (ObjectReference akActionRef)
   if akActionRef == game.getPlayer()
      ;do nothing
   endif
EndEvent


Any ideas ?

Link to comment
Share on other sites

The reason for that is that by teleporting to the other portal you activate it's ontriggerenter, and it puts you back to the other one.

 

Easiest solution, have a variable that is set to 1 when you enter a portal and back to 0 when you ontriggerleave....thne in your ontriggerenter have a if statement to check if the variable is 0.

 

That way you can only be teleported again after you have left the portal you exit from.

 

 

Sorry I can only give theory and not script code, I haven't done Skyrim Scripting.

Link to comment
Share on other sites

You could probably use states very effectively to control this. Below is an example script that detects whether a player is within the trigger volume and switches states as he enters or leaves. Trigger volumes are a little odd to work with, since I understand that the OnTriggerLeave event can actually fire before the OnTriggerEnter. So you need to watch the count of objects in the volume.

 

Scriptname fpiDragonTorchControl extends ObjectReference  
{FPI Gallery for Console Home Decorators: Turn the dragon
torch on when the player is within range of the tower's
central dais and off when the player moves away.}

; ---------------------------------------------------------------
; The dragon torch is the load-screen model of the frost dragon
; with the bronze-dragon texture. A BFXFireVolCorner and a
; shadow-casting light are positioned near the dragon's mouth
; to simulate a fire-breath attack. Sadly, the light fades in
; as the player approaches long before the fire activates, and
; it looks pretty lame to see the inanimate fire just sitting
; there. This script, attached to a trigger volume of suitable
; radius around the torch, ensures that the effects are
; synchronized by turning on the fire and then the light only
; when the player is close enough to see the animation.

; Set the fire and light to be initially disabled. Add them
; as linked references to this script with the appropriate
; keyword for each.
; ---------------------------------------------------------------

Keyword Property DragonTorchFire auto ; The BFXFireVolCorner that provides the fire breath
Keyword Property DragonTorchLight auto ; The shadow-casting light that provides the firelight

Int ObjectsInTrigger ; Number of objects in the volume

; ---------------------------------------------------------------

auto State TorchOff

    Event OnBeginState()
        GetLinkedRef(DragonTorchFire).DisableNoWait(True) ; Fadeout fire
        GetLinkedRef(DragonTorchLight).DisableNoWait() ; Turn off shadowlight
    EndEvent

    Event OnTriggerEnter(ObjectReference TriggerRef)
        ObjectsInTrigger = Self.GetTriggerObjectCount()
        if ObjectsInTrigger > 0
            GoToState("TorchOn")
        endif
    EndEvent

    Event OnTriggerLeave(ObjectReference TriggerRef)
        ; Nothing to do since torch is already off
        ObjectsInTrigger = Self.GetTriggerObjectCount()
    EndEvent

EndState

; ---------------------------------------------------------------

State TorchOn

    Event OnBeginState()
        if ObjectsInTrigger == 0
            GoToState("TorchOff")
        else
            GetLinkedRef(DragonTorchFire).EnableNoWait(True) ; Fadein fire
            GetLinkedRef(DragonTorchLight).EnableNoWait() ; Trun on shadowlight
        endif
    EndEvent

    Event OnTriggerEnter(ObjectReference TriggerRef)
        ; Nothing to do since torch is already on
        ObjectsInTrigger = Self.GetTriggerObjectCount()
    EndEvent

    Event OnTriggerLeave(ObjectReference TriggerRef)
        ObjectsInTrigger = Self.GetTriggerObjectCount()
        GoToState("TorchOff")
    EndEvent

EndState

 

I guess you would probably need a state for "portal is in use" and one for "portal is ready to go," so the "in use" state doesn't perform a teleport.  The portal would switch to the "ready" state only after you leave the volume.

Edited by BrettM
Link to comment
Share on other sites

Okay. I guess I now have a "logical" problem. 

 

I have two triggers with their own scripts, script01 and script02, because I need to tell trigger01 to teleport to trigger02, and trigger02 to trigger01.

If I add states in the script for trigger01, which tells the trigger that I used it, how can I tell trigger02, to be inactive ?! 

 

Edit : 

I've tried the following, but this doesnt work. 

;FX
ObjectReference property FXPortalDoor01 auto
ObjectReference property FXPortalDoor02 auto

;Triggers
ObjectReference property PortalTrigger01 auto
ObjectReference property PortalTrigger02 auto

;Markers
ObjectReference property ElinthrialPortalMarker auto
ObjectReference property xMarker01 auto
ObjectReference property xMarker02 auto
ObjectReference property xMarker03 auto
ObjectReference property xMarker04 auto

Event OnTriggerEnter (ObjectReference akActionRef)
	if akActionRef == game.getPlayer()
		if 	(GetState() == "InActive")
			PortalTrigger01.Enable()
			PortalTrigger02.Disable()
			gotoState("Active")
		else
			;do nothing
		endIf
	else
		If    (GetState() == "Active")
			PortalTrigger01.Disable()
			PortalTrigger02.Enable()
			gotoState("InActive")
		else
			;do nothing
		endIf	
	endIf
EndEvent

State Active
	Event OnTriggerEnter (ObjectReference akActionRef)
		if akActionRef == game.getPlayer()
			game.getPlayer().moveTo(xMarker03, 0.000000, 0.000000, 0.000000, true)
			gotoState("Inactive")
		endIf
	endEvent
endState
	
State InActive
	Event OnTriggerLeave (ObjectReference akActionRef)
		if akActionRef == game.getPlayer()
			gotoState("Active")
		endIf	
	endEvent
endState
Edited by Nalfeyn
Link to comment
Share on other sites

The function named "GoToState" is part of every script that another script can call. So script01 can call, say, GoToState("Receive") on script02 to put it into "Receive" mode. When the player exits the receiving portal, it can put itself back into "Send" mode, ready for the player to re-enter to go back to portal01.

 

You will need to have a variable in each script to identify the other, and then cast that reference to the script type when calling a function in it. For example, I have a script called "fpiGalleryItem" with only one function, named "GetGalleryString" that I can attach to any static object. The function does nothing but return a string related to that object. To call that function from another script, I have:

ObjectReference LookupRef  ; Variable used to point to item with the script attached      


Event OnActivate(ObjectReference akActionRef)
    <bunch of code>

    LookupRef = Self.GetLinkedRef()  ; I have the other object as a linked ref in my activator

    String ItemText = (LookupRef as fpiGalleryItem).GetGalleryString() 

    <bunch more code>
EndEvent

Hope this helps. I think using states is a better way to handle the logic here than creating a boolean variable as DaMage suggested. His suggestion would work, of course, but states are a classier way to go because they make it very clear what behavior to expect from a script under what circumstances. What will the script do when it is receiving a player? Just look at the code in the Receive state and you know whether or not it's doing everything necessary and not doing what you don't want it to do. With boolean variables you have to pick through the code to see which statements are accepted or included for a given value of the variable.

 

Edit: You might also want to look at the CK tutorial on scripting a lever, in which a lever activator calls functions on other activators:

Function DisableDoors()
 
    Door01.BlockActivation()
    Door02.BlockActivation()
    Door03.BlockActivation()
 
EndFunction

If you think of one trigger as the lever and the doors as the other triggers, you can see how this would work. The BlockActivation function is a built-in part of ObjectReference.

Edited by BrettM
Link to comment
Share on other sites

Okay. This confuses me. 

He doesnt use the "LookupRef" ?

 

Edit: 

So I got this for now :

Event OnTriggerEnter (ObjectReference akActionRef)
	if akActionRef == game.getPlayer()
		game.getPlayer().moveTo(xMarker03, 0.000000, 0.000000, 0.000000, true)
		PortalTrigger02.BlockActivation()
	endIf	
endEvent

Event OnTriggerLeave (ObjectReference akActionRef)
	if akActionRef == game.getPlayer()
		PortalTrigger02.BlockActivation(false)
	endif
endEvent	

and how can I add a lookupref to it ? 

by simple doing the following ?

ObjectReference LookupRef PortalTrigger01 auto
ObjectReference LookupRef PortalTrigger02 auto

;and if I want to say "event on this ref" i have to do :

LookupRef = Self.GetlinkedRef()
Edited by Nalfeyn
Link to comment
Share on other sites

The code you posted first looks to me as if it would almost work.

 

1. You are moving the player to the second portal before you block it from activating. If the block doesn't get there until after the player does, then why wouldn't it still send him back? It seems to me that those two statements should be reversed, so you block portal 2 before sending the player into it.

 

2. Is your "OnTriggerLeave" event in the code for portal 1? After the player arrives at portal 2, he will be leaving that trigger, not the portal 1 trigger that he entered. So portal 1 won't unblock portal 2 until after the player returns and leaves the portal 1 trigger. Except that he can't return through portal 2, because it's still blocked. It seems to me that the OnTriggerLeave event in each script needs to use Self.BlockActivation(false), instead of sending the message to the other portal.

 

3. As far as I know, blocking activation only prevents the OnActivate event from doing anything. But your teleporting is being done by the OnTriggerEnter event. If that isn't affected by BlockActivation, then blocking activation doesn't seem like it would solve your problem. But, I don't know much about trigger volumes, since I've only written one of them, which was mostly borrowed from another script. All of the triggers I used in the FPI Gallery mod are player-activated, other than the example I gave you of code with states.

 

So, the logic would be:

 

1. Player enters trigger of portal 1.

2. Portal 1 somehow disables the teleport function of portal 2 so that it can't teleport the player right back.

3. Portal 1 sends the player to portal 2.

4. Player leaves the portal 2 trigger.

5. Portal 2 makes its own teleport function active again so it is ready when the player enters that trigger the next time.

 

Since I haven't studied your scripts and have never written any spells, perhaps I am misunderstanding the logic of what you're trying to do and the above is all wrong.

 

If it matches your idea, though, then it seems there are two states for the trigger to be in: Sending (or Active) state, where it only cares about players entering the trigger, and Receiving (or Inactive) state, where it only cares about players leaving the trigger. The sending trigger must somehow tell the target trigger that a player is about to come there and it should prepare itself to receive him. It would have to involve some kind of function call between the two trigger scripts, like a "PrepareToReceive()" function in each script that is only called by the other.

 

If you already have a valid reference to the other script so that you can call functions on it, then you don't need to set up a reference variable like LookupRef. I had to do it in the code I showed you because the only reference I had was in the linked list of the activator. If you have some other way of getting the reference, then you don't need a linked list or a way to get references out of it.

Edited by BrettM
Link to comment
Share on other sites

Okay, I really dont know what else to do now. 

I tried to find something to say : 

State : Active
State : InActive

Event OnTriggerEnter
 If linkedRef currentStateis Active
  getPlayer.moveto
 else
  ;do nothing
 endif
endEvent

Event OnTriggerLeave
 If (ObjectReference akActionRef)
  setState to Active
 endif
endEvent

I tried something like that : 

Scriptname ElinthrialPortalTrigger01 extends ObjectReference  

;Triggers
ObjectReference property PortalTrigger01 auto

;Markers
ObjectReference property ElinthrialPortalMarker auto
ObjectReference property PlayerxMarker auto
ObjectReference property GetLinkedRef


Event OnTriggerEnter (ObjectReference akActionRef)
	if akActionRef == game.getplayer()
		if (GetLinkedRef.isEnabled())
			game.getPlayer().moveTo(PlayerxMarker, 0.000000, 0.000000, 0.000000, true)
		else
			;do nothing
		endif
	endIf		
endEvent

Event OnTriggerLeave (ObjectReference akActionRef)
	if akActionRef == game.getPlayer()
		GetLinkedRef.enable()
	endIf
endEvent		

Wont work either.

 

I really have no idea what else to do. 

I want to finally finish this shit !!!

Pleaaaaase help me. 

I've learned alot about scripting in the last days, and I've read so much articles about scripting on a bunch of pages, but I think that this is quite too much for me atm. 

It's also hard for me to read AND understand all those pages, because they are mostly in english.

Edited by Nalfeyn
Link to comment
Share on other sites

A State is not like a variable that you put off in some corner and set and test to decide what to do. A State is like an Event or a Function. It has a beginning and an end, with code in between. Events and Functions are boxes that surround code. So are States. The main difference is that an Event or Function surrounds ordinary code. A State, however, surrounds Events and Functions. It is a like a big carton that holds several small boxes of candy. So the structure of a script that uses States should look something like:

State Active

    Event OnTriggerEnter
       <code>
    EndEvent

    Event OnTriggerLeave
       <code>
    EndEvent

EndState

State Inactive

    Event OnTriggerEnter
        <code>
    EndEvent

    Event OnTriggerLeave
        <code>
    EndEvent

EndState

Each State has its own copy of each event, and the system knows which State the script is in. So, when a player enters the trigger, the system will call the copy of the Event that is in the State that is currently in effect. The Events can do completely different things in different States, so you write the Active version of OnTriggerEnter to move the player and the Inactive version to do nothing.

 

Trying to explain things and pointing you to tutorials is about all the help I can give. I don't know what else I can do short of writing your scripts for you, and I just don't have the time for that. Also, I have never written any magic spell scripts, so I would have to study how that is done before I could do it.

 

I still don't understand why you can't just use the script that Willie generously offered from his Leveler's Tower mod, and just put your fancy portal doors in place of his Riften load doors. That script is guaranteed to work, since Willie is an expert scripter.

Link to comment
Share on other sites

So, I got help from Willie ... 

but now it's complaining about sth again : 

Scriptname ElinthrialPortalTrigger01 extends ObjectReference  

;FX
ObjectReference property FXPortalDoor01 auto
ObjectReference property FXPortalDoor02 auto

;Triggers
ObjectReference property PortalTrigger01 auto
ObjectReference property PortalTrigger02 auto

;Markers
ObjectReference property PlayerxMarker

;GlobalVariables
Global property ElinthrialPortalTriggerVar auto

;Events

Event OnTriggerEnter (ObjectReference akActionRef)
	if akActionRef == game.getPlayer()
  		float myVal = ElinthrialPortalTriggerVar.GetValue()
			if myVal == 1
   				ElinthrialPortalTriggerVar.SetValue(0)
   				game.getPlayer().moveto(PlayerxMarker, 0.000000, 0.000000, 0.000000, true)	
			endif
 	endif
EndEvent

Event OnTriggerLeave (ObjectReference akActionRef)
 	if akActionRef == game.getPlayer()
  		ElinthrialPortalTriggerVar.setValue(1)
 	endif
EndEvent

Starting 1 compile threads for 1 files...
Compiling "ElinthrialPortalTrigger01"...
E:\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\ElinthrialPortalTrigger01.psc(15,0): mismatched input 'Global' expecting FUNCTION
E:\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\ElinthrialPortalTrigger01.psc(0,0): error while attempting to read script ElinthrialPortalTrigger01: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
No output generated for ElinthrialPortalTrigger01, compilation failed.

Batch compile of 1 files finished. 0 succeeded, 1 failed.
Failed on ElinthrialPortalTrigger01

What's wrong now ? 

Link to comment
Share on other sites

From the CK Wiki:

 
"Mismatched (input/character) 'X' expecting Y

The compiler expected Y, but found X instead. This is usually the result of a malformed line or misspelled keyword.

 

So the first thing to do is to take a look at line 15 and see if something is misspelled or otherwise not correct. This kind of thing can happen because of errors in the lines that come before the line it is complaining about.

 

Because you did not put the Auto keyword on the property above the global variable (PlayerxMarker), the compiler is expecting the next line to be a function for getting or setting the value of PlayerxMarker. It is expecting to see code that looks like the code for a Full Property, but instead it sees another property declaration.

 

 
"Error while attempting to read script X: <message>"

This is an internal compiler error that is usually the result of a failed error recovery mechanism. Try fixing any errors reported before this one.

 

This error should go away as soon as you fix the first error.

Link to comment
Share on other sites

So now ... after I did everything you both said, i get this : 

Scriptname ElinthrialPortalTriggerScript01 extends ObjectReference  

;FX
ObjectReference property FXPortalDoor01 auto
ObjectReference property FXPortalDoor02 auto

;Triggers
ObjectReference property PortalTrigger01 auto
ObjectReference property PortalTrigger02 auto

;Markers
ObjectReference property PlayerxMarker auto

;GlobalVariables
GlobalVariable property ElinthrialPortalTriggerVar auto

;Events

Event OnTriggerEnter (ObjectReference akActionRef)
	if akActionRef == game.getPlayer()
  		float myVal = ElinthrialPortalTriggerVar.GetValue()
			if myVal == 1
   				ElinthrialPortalTriggerVar.SetValue(0)
   				game.getPlayer().moveto(PlayerxMarker, 0.000000, 0.000000, 0.000000, true)	
			endif
 	endif
EndEvent

Event OnTriggerLeave (ObjectReference akActionRef)
 	if akActionRef == game.getPlayer()
  		ElinthrialPortalTriggerVar.setValue(1)
 	endif
EndEvent

Starting 1 compile threads for 1 files...
Compiling "ElinthrialPortalTriggerScript01"...
E:\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\ElinthrialPortalTriggerScript01.psc(8,25): cannot name a variable or property the same as a known type or script
No output generated for ElinthrialPortalTriggerScript01, compilation failed.

Batch compile of 1 files finished. 0 succeeded, 1 failed.
Failed on ElinthrialPortalTriggerScript01
Link to comment
Share on other sites

Apparently the compiler thinks you have a script somewhere named PortalTrigger01, and you are trying to declare a property with the same name as the script. The simple thing to do would be to change the name of the property to something else.

 

Is that the entire script? If so, I don't understand why you have the first four properties in it at all, since they are never used anywhere in the code you show there. Why can't you just take the FX and Trigger properties out entirely?

 

What you have there compiles perfectly on my system without the first four properties:

Scriptname ElinthrialPortalTriggerScript01 extends ObjectReference  

;Markers
ObjectReference property PlayerxMarker auto

;GlobalVariables
GlobalVariable property ElinthrialPortalTriggerVar auto

;Events

Event OnTriggerEnter (ObjectReference akActionRef)
    if akActionRef == game.getPlayer()
          float myVal = ElinthrialPortalTriggerVar.GetValue()
            if myVal == 1
                   ElinthrialPortalTriggerVar.SetValue(0)
                   game.getPlayer().moveto(PlayerxMarker, 0.000000, 0.000000, 0.000000, true)    
            endif
     endif
EndEvent

Event OnTriggerLeave (ObjectReference akActionRef)
     if akActionRef == game.getPlayer()
          ElinthrialPortalTriggerVar.setValue(1)
     endif
EndEventStarting 

1 compile threads for 1 files...
Compiling "ElinthrialPortalTriggerScript01"...
Starting assembly of ElinthrialPortalTriggerScript01
0 error(s), 0 warning(s)
Assembly succeeded

Compilation succeeded.

Edited by BrettM
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...