Jump to content

Proof that a player can fly in Skyrim well may be more like swimming


hex_ratt

Recommended Posts

Well if you do not call a registerForUpdate(x) the OnUpdate event wont run, still I wouldnt advise to use it, use a loop instead, im not sure which version of my script are u using, I have several on different pages, look for the last one, thats the good one.
Link to comment
Share on other sites

  • Replies 304
  • Created
  • Last Reply

Top Posters In This Topic

As far as performance though, I would put in a Utility.Wait(0.001) somewhere in the script so that the interpreter sees it as a latent function. (Do not use a wait time of 0 seconds, according to the wiki page.) I've gotten some crashes when this has not been done. Edited by jimhsu
Link to comment
Share on other sites

I used the code you posted on Page 4 of this thread. Here is the current iteration.

 

Scriptname DV_BatFormTraits extends ActiveMagicEffect  

import Game
import Sound
import Form
import Debug
import Utility
import GlobalVariable
import Actor
Actor Property Player Auto
Spell Property DVampireBatForm Auto
Spell Property DVampireBatFormToggle Auto
Idle Property SwimStart Auto
Idle Property swimStop Auto
Idle Property JumpFall Auto
bool Property bIsOn Auto
bool Property bVal Auto
EffectShader Property DVCelerityShadow Auto
float bearing
float elevation
float speed
float posx
float posy
float posz
float move
float dtime



Event OnEffectStart(Actor Target, Actor Caster)

ObjectReference PCVamp = GetPlayer()

if !Caster.HasSpell(DVampireBatFormToggle)	
           Caster.AddSpell(DVampireBatFormToggle, false)
		Caster.SetAlpha(0)
		
           DVCelerityShadow.Play(Caster)			
		Game.GetPlayer().SetAllowFlying()
           Game.ForceThirdPerson()
		Utility.Wait(1.0)
		SendAnimationEvent(PCVamp ,"JumpFall")
		;bVal = True
		Utility.SetIniFloat("fInAirFallingCharGravityMult:Havok",0)
		while Caster.HasSpell(DVampireBatFormToggle)
                Fly()
           endwhile
elseif Caster.HasSpell(DVampireBatFormToggle)
           Caster.RemoveSpell(DVampireBatFormToggle)
		
		Caster.SetAlpha(1)
		DVCelerityShadow.Stop(Caster)
		Game.GetPlayer().SetAllowFlying()
		Utility.Wait(1.0)
		;bVal = False
endif


;Toggle()

EndEvent


function Fly()
       if Player.IsRunning()
               posx = Player.GetPositionX()
               posy = Player.GetPositionY()
               posz = Player.GetPositionZ()
               bearing = Player.GetAngleZ()
               elevation = Player.GetAngleX()

               speed = 1000

               if bearing < 90 
                       posx += (bearing)*speed
                       posy += (90 - bearing)*speed
               elseif bearing > 90 && bearing < 180
                       posx +=(180 - bearing)*speed
                       posy +=(90 - bearing)*speed

               elseif bearing > 180 && bearing < 270
                       posx += (180 - bearing)*speed
                       posy += (bearing - 270)*speed
                       
               elseif bearing > 270
                       posx += (bearing - 360)*speed
                       posy += (bearing - 270)*speed
                       
               endif
               posz = Player.GetPositionZ() - (elevation*speed)
               Player.TranslateTo(posx,posy,posz,Player.GetAngleX(),Player.GetAngleY(),Player.GetAngleZ(),speed,1)
               if Player.IsSprinting()
                       move = 0
               endIf
               else
                       Player.StopTranslation()
       endIf
endFunction

Event OnTranslationComplete()
       move = 0
       Fly()
endEvent

Function Toggle()

if (bVal == True)
	bIsOn = True
elseif (bVal == False)
	bIsOn = False
endif

EndFunction

Event OnEffectFinish(Actor Player, Actor Caster)
        Player.StopTranslation()
	 Utility.SetIniFloat("fInAirFallingCharGravityMult:Havok",1.35)
EndEvent

 

 

I mixed your code with my own.

The gravity adjustment works. The toggle works. The shader works. The only thing not happening is the translate and I can't figure out why.

Link to comment
Share on other sites

ObjectReference PCVamp = GetPlayer()

       if !Caster.HasSpell(DVampireBatFormToggle)      
           Caster.AddSpell(DVampireBatFormToggle, false)
                       Caster.SetAlpha(0)
                       
           DVCelerityShadow.Play(Caster)                       
                       Game.GetPlayer().SetAllowFlying()
           Game.ForceThirdPerson()
                       Utility.Wait(1.0)
                       SendAnimationEvent(PCVamp ,"JumpFall")
                       ;bVal = True
                       Utility.SetIniFloat("fInAirFallingCharGravityMult:Havok",0)
                       while Caster.HasSpell(DVampireBatFormToggle)
                Fly()
           endwhile
       elseif Caster.HasSpell(DVampireBatFormToggle)
           Caster.RemoveSpell(DVampireBatFormToggle)
                       
                       Caster.SetAlpha(1)
                       DVCelerityShadow.Stop(Caster)
                       Game.GetPlayer().SetAllowFlying()
                       Utility.Wait(1.0)
                       ;bVal = False
       endif

 

Your while condition is inside an If block who's condition is opposite.

 

If ! Caster.hasspell blah blah

 

while Caster.hasspell blah blah

 

end while

 

end if

 

The while never ever gets called in that if case.

 

edit: I see you add the spell... set up a debug to make sure the while is being run. Your code makes sense in line, but opposing conditions like that are a red flag to me that you might be having some issue with the scope of Caster. My theory may still be right depending on how Papyrus was made, but I don't think the scope rules are documented anywhere.

 

 

Re-edit: Second possibility. You may not be assigning the player object to your player property in the creation kit.

 

As a note this code uses GetPlayer(), Game.GetPlayer() (same thing i know), one Player Property, one local Player as an ObjectRef (Never useful unless you need to pass Player as an ObjectRef), as well as multiple event variables that are ALWAYS the player. PICK ONE!

Edited by dontkeepscore
Link to comment
Share on other sites

I was messing around with the TranslateTo options to add 'flight' to my mod, but you'll clip through things.

Then I tried the havok impulse generation. It won't work; you get ragdolled and can't control the direction.

 

What I think WILL work:

1) spawn anobject that's about the size/shape if the player, but transparent

2) apply the impulse to this new non-player object, based on the player's angles

3) TranslateTo the player towards the now flying object

 

No need to mess with gravity either. Landing might hurt though.

 

* 'Flight' is in quotes because I'm thinking of something along the lines of the Fizzy Pop from the first Willy Wonka movie.

Link to comment
Share on other sites

Here's my first step. The bucket is currently tied to a floating marker while I get the code and physics constants set. Example:

http://youtu.be/QS0utkcnbrk

Scriptname EngineerFlyScript extends activemagiceffect  

Idle Property JumpFall  Auto  

float force = 50.0
int fly=0
float aX
float aY
float aZ
float lastX
float lastY
float lastZ
float nowX
float nowY
float nowZ
float iX
float iY
float iZ
float lastTime

ObjectReference TheObject
MiscObject Property ObjectToFollow  Auto  


Event OnEffectStart(Actor Target, Actor Caster)
fly=-4
TheObject = BucketTarget.PlaceAtMe(ObjectToFollow)
TheObject.SetMotionType(TheObject.Motion_Keyframed)

float TrigAngleZ = 0
float LRangle
float UPangle
float currenttime

; hold object in front of user for a second
While(fly < 0)
	LRangle = Game.GetPlayer().GetAngleZ()
	if ( LRangle < 90 )
	  TrigAngleZ = 90 - LRangle
	else
	  TrigAngleZ = 450 - LRangle
	endif
	UPangle = -Game.GetPlayer().GetAngleX()
	;aX = Game.GetPlayer().GetPositionX() + math.cos(UPangle)*math.cos(TrigAngleZ)*300
	;aY = Game.GetPlayer().GetPositionY() + math.cos(UPangle)*math.sin(TrigAngleZ)*300
	;aZ = Game.GetPlayer().GetPositionZ() + 75 + math.sin(UPangle)*300
	aX = BucketTarget.GetPositionX(); + math.cos(UPangle)*math.cos(TrigAngleZ)*300
	aY = BucketTarget.GetPositionY(); + math.cos(UPangle)*math.sin(TrigAngleZ)*300
	aZ = BucketTarget.GetPositionZ(); + 75 + math.sin(UPangle)*300
	TheObject.TranslateTo(aX, aY, aZ, 0, 0, 0, 1000, 0)
	utility.wait(0.5)
	fly = fly +1
	if(fly>-1)
		fly=1
	endIf
endWhile

; set object to be simulater by havoc
TheObject.SetMotionType(TheObject.Motion_Dynamic)

float vX
float vY
float vZ
float speedX
float speedY
float speedZ
float vLength

lastX = TheObject.GetPositionX()
lastY = TheObject.GetPositionY()
lastZ = TheObject.GetPositionZ()
lasttime = Utility.GetCurrentRealTime()

While(fly==1)
	nowX = TheObject.GetPositionX()
	nowY = TheObject.GetPositionY()
	nowZ = TheObject.GetPositionZ()
	
	currenttime = Utility.GetCurrentRealTime()
	speedX = (nowX - lastX)/(currenttime-lasttime)
	speedY = (nowY - lastY)/(currenttime-lasttime)
	speedZ = (nowZ - lastZ)/(currenttime-lasttime)

	LRangle = Game.GetPlayer().GetAngleZ()
	if ( LRangle < 90 )
	  TrigAngleZ = 90 - LRangle
	else
	  TrigAngleZ = 450 - LRangle
	endif
	UPangle = -Game.GetPlayer().GetAngleX()
	;aX = Game.GetPlayer().GetPositionX() + math.cos(UPangle)*math.cos(TrigAngleZ)*300
	;aY = Game.GetPlayer().GetPositionY() + math.cos(UPangle)*math.sin(TrigAngleZ)*300
	;aZ = Game.GetPlayer().GetPositionZ() + 75 + math.sin(UPangle)*300
	aX = BucketTarget.GetPositionX(); + math.cos(UPangle)*math.cos(TrigAngleZ)*300
	aY = BucketTarget.GetPositionY(); + math.cos(UPangle)*math.sin(TrigAngleZ)*300
	aZ = BucketTarget.GetPositionZ(); + 75 + math.sin(UPangle)*300

	vX = aX - TheObject.GetPositionX() - speedX/4
	vY = aY - TheObject.GetPositionY() - speedY/4
	vZ = aZ - TheObject.GetPositionZ() - speedZ/4+80*(currenttime-lasttime) ; adjust for gravity if currently stationary in z
	; do not ever force down... let gravity work
	if(vZ<0)
		vZ = 0
	endIf
	vLength = math.sqrt(vX * vX + vY * vY + vZ * vZ)
	vX = vX / vLength
	vY = vY / vLength
	vZ = vZ / vLength

	; * math.sqrt(math.sqrt(vLength)) / 2
	force = 10
	;TheObject.ApplyHavokImpulse(vX, vY, vZ, force * math.sqrt(vlength))
	if(vLength>60)
		vLength=60
	endIf
	TheObject.ApplyHavokImpulse(vX, vY, vZ, vLength)
	
	if(vLength>300)
		;Game.GetPlayer().TranslateTo(TheObject.GetPositionX(), TheObject.GetPositionY(), TheObject.GetPositionZ(),  Game.GetPlayer().GetAngleX(),  Game.GetPlayer().GetAngleY(),  Game.GetPlayer().GetAngleZ(), 100, 10)
	endIf

	lastX=nowX
	lastY=nowY
	lastZ=nowZ
	lasttime= Utility.GetCurrentRealTime()

	utility.wait(0.25)
endWhile
EndEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster)
fly=0
Utility.SetIniFloat("fInAirFallingCharGravityMult:Havok", 1.35)
UnregisterForUpdate()
Game.GetPlayer().StopTranslation()
EndEvent

Event OnUpdate()
if(fly==1)
  Game.GetPlayer().PlayIdle(JumpFall)
  ;Game.GetPlayer().TranslateTo(aX, aY, aZ, UPangle, Game.GetPlayer().GetAngleY(), LRangle, 200, 200)
  Game.GetPlayer().PushActorAway(Game.GetPlayer(), 1)
  force=1000
  fly=0
  Game.GetPlayer().ApplyHavokImpulse(iX, iY, iZ, force)
  Game.GetPlayer().PlayIdle(JumpFall)
  ;game.ForceFirstPerson()
  ;Game.EnablePlayerControls(abLooking = true)
  ;Utility.Wait(0.1)
  RegisterForSingleUpdate(0.1)
endIf
EndEvent


ObjectReference Property BucketTarget  Auto  

Link to comment
Share on other sites

If there would only be a way to detect collisions, then this whole process would be much more easy to do.

 

Then we could work with the translate to command and would not have to fight with behaviors, which in some cases dont look for collision either.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...