Basically you have a scripted spell. Suprisingly, you don't actually need a script for this spell at all. That's right, completely bare bones. What you need instead is a Projectile. This Projectile then has an explosion. This explosion then has a placed object.
This placed object does most of the work. It has a NullTextureSet, and has the following script (it is a MiscItem). By the way for everything I talk about in here there needs to be one copy for one color portal, and another for the other portal. So, two spell projectiles, spells, magic effects, miscItems, etc. All the scripts are identical, you just need to set the properties differently.
Scriptname PCKP_ScriptPortalMover extends ObjectReferenceObjectReference Property Portal autoObjectReference Property PortalProjTrigger AutoObjectReference Property PortalTrigger autoevent OnLoad()Portal.MoveTo(self)Utility.Wait(0.10)PortalTrigger.MoveTo(Portal)PortalProjTrigger.MoveTo(Portal)self.Disable()Utility.Wait(1)self.delete()endEvent
Now, to explain the properties. Portal is the Art, it just looks like a portal. Doesn't actually do anything. They are located in a room that is a duplicate of the CTest room, but you could store them anywhere. PortalTrigger is an activator that when stepped into shoots stuff out the other portal. PortalProjTrigger has the exact same script as PortalTrigger, but the activator acts on L_PROJECTILEZONE rather than L_ACTORZONE.
The script on the portal triggers is thus:
Scriptname PCKP_PortalScript extends ObjectReferenceObjectReference Property OtherPortal AutoGlobalVariable Property JustPorted autoevent OnTriggerEnter(ObjectReference akActionRef)if JustPorted.GetValue() as int ==0 JustPorted.SetValue(1) akActionRef.MoveTo(OtherPortal,0,0,0,false)endIfendEventevent OnTriggerLeave(ObjectReference akActionRef)Utility.Wait(1.0)JustPorted.SetValue(0)endEvent
and that's it!
QUESTIONS FOR FUTURE DEVELOPMENT:
1) The most glaring flaw of these portals is that they do not rotate such that the direction they are facing is perpendicular to the surface that they are cast on. If I could do that, I could probably figure out a workaround for the other problems.
2) MoveTo does not conserve momentum at all, meaning even if I did manage to figure out what direction to face the darn things I would need another function to determine the velocity and angle of the entrant, then give a Force Push command on the other side in the adjusted direction. Even this seems...problematic.
3) I can't think of a way to make surfaces upon which the portal cannot be cast. The only idea I've got is to make a custom wall or something, add it to a list, and use a FindClosestRefOFAnyTypeInList combined with a getdistance function, and if its really small then to not move the portal.
Potential solution to problem 1:
Have the spawned object create six X markers with placeatme functions in directions above, below, left right forward and backward of it. Then it fires spells at these XMarkers. They all spawn objects that OnLoad get their own XYZ coordinates and set a DoNotAcceptNewInput Global to 1 for a few seconds (basically making it so that the other spells don't override the first one to hit's data). Then the XYZ coordinates are matched to the Portal's XYZ coordinates, and a vector is generated. The portal is then rotated to face in the negative of this vector.
The problem I see with this is that it would be enormously computationally complex. Anyone see a better solution?
EDIT: Tried my solution to problem two, doesn't work. I dunno why. Is there a problem with this script?
Scriptname PCKP_ScriptPortalMover extends ObjectReference ObjectReference Property Portal autoObjectReference Property PortalTrigger autoFormList Property BlackList autoevent OnLoad()ObjectReference DarkWood = Game.FindClosestReferenceOfAnyTypeInListFromRef(BlackList, self, 50.0)if DarkWood==NONE Portal.MoveTo(self) Utility.Wait(0.10) PortalTrigger.MoveTo(Portal) PortalProjTrigger.MoveTo(Portal)endIfself.Disable()Utility.Wait(1)self.delete()endEventObjectReference Property PortalProjTrigger Auto