Jump to content

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


hex_ratt

Recommended Posts

I actually found out something amazin and im back on the flying rideable dragon QUEST hehe, basically what im doing right now is create my own ride system, where the player controls the dragon and not the other way around, what program u guys use to record a video?
Link to comment
Share on other sites

  • Replies 304
  • Created
  • Last Reply

Top Posters In This Topic

Well, after hours of trying to get a proper animation to work, I belive I surrender, my ring works perfect now it just lacks a proper animation, I was hoping if somebody could port a couple things from oblivion, one being the Wings of archangel from midas magic, and the sky dive animation, with those 2 my mod will be complete, else I better start learning 3dsmax lol.

 

I guess you have ssen the mod by now aynway, but here are wings:

http://skyrim.nexusmods.com/downloads/file.php?id=10658

 

What I was wondering about converting stuff from Oblivionif it would also be possible to get VipCxjs Air Fight System for Oblivion working in Skyrim as well? To me it seems that his script somehow managed to include custom animations as well as spellcasting/meleeattacks.

http://tes.nexusmods.com/downloads/file.php?id=36903

 

 

you all must be team up to making this real

Skeleton wing

http://skyrim.nexusm...ile.php?id=6332

 

+ FavoredSouls Angels will be perfect

 

 

I actually found out something amazin and im back on the flying rideable dragon QUEST hehe, basically what im doing right now is create my own ride system, where the player controls the dragon and not the other way around, what program u guys use to record a video?

 

what I've been working is actually using porroone's script and incorporating the angel wings... so, yeah. haha hopefully it'll be cool. I know jack about animations, I'm just switching the properties a bit...

Link to comment
Share on other sites

I actually found out something amazin and im back on the flying rideable dragon QUEST hehe, basically what im doing right now is create my own ride system, where the player controls the dragon and not the other way around, what program u guys use to record a video?

 

Ok this sounds fun. Gimmie some file names and object refs you're looking at. We're gonna burn this mother down.

Link to comment
Share on other sites

Turns out I had to rewrite the code a lil while back since, as it turns out, the script forced me into the ground which caused a slingshot effect most know as the Giant's Club Launch. After correcting it, the Havok effects refused to kick back in which caused me to float there. So I had to ditch the setposition() function and look at ApplyHavokImpulse(). This seemed to be a good idea as its description for objects seemed perfect, but as it turns out the player character doesn't have a mass registered to the engine so ApplyHavokImpulse would be useless since the base mass factor of the character is defaulted to 0 with no obvious way to set it. So finally I'm currently looking into the SetMotionType() function which I think might have been implemented into the Script Dragon SDK incorrectly. Regularly in Papyrus the function would require a reference object and a sub-string to set for either Dynamic or Keyframed modes and oddly enough the Script Dragon version requires a uint and so I have NO idea what the numerical values for Dynamic/Keyframed modes are.

 

/* 
THE DRAGONBORN LEGACY Script Dragon
*/

#include "common\skyscript.h"
#include "common\obscript.h"
#include "common\types.h"
#include "common\enums.h"
#include "common\plugin.h"
#include <math.h>

#define CONFIG_FILE "DragonbornLegacy.ini"
#define SCR_NAME "DLMain"



void flySim(BYTE *FlapKey, PlayerCharacter *ref, bool bAutoFly, int *iFlapCD)
{
float fPosX = ObjectReference::GetPositionX((TESObjectREFR *)ref);
float fPosY = ObjectReference::GetPositionY((TESObjectREFR *)ref);
float fPosZ = ObjectReference::GetPositionZ((TESObjectREFR *)ref);
float fAngX = ObjectReference::GetAngleX((TESObjectREFR *)ref); //East - West?
float fAngY = ObjectReference::GetAngleY((TESObjectREFR *)ref); //North - South?
float fAngZ = ObjectReference::GetAngleZ((TESObjectREFR *)ref); //Up - Down
float fDragonForm = 3; //0 = regular player race, 1 = first shout level, 2 = 2nd shout word, 3 = 3rd shout word
float fThrust = 0;
float fPeakThrustTime;
if (fDragonForm > 1){
	if (GetKeyPressed(*FlapKey)){
		if (*iFlapCD == 0){
			*iFlapCD = 1000; //1 second.
			PrintNote("Flap CD: %i.", *iFlapCD);
		}
	}
	if(*iFlapCD > 0){
		fPeakThrustTime = *iFlapCD/2; //Times the amount of thrust given by the wings
		*iFlapCD -= 1;
		fThrust = 1000;
		fPosZ -= fThrust;
		ObjectReference::SetMotionType((TESObjectREFR *)ref, 0, false);

	}else{

	}
}
}

void main()
{
BYTE FlapKey = IniReadInt(CONFIG_FILE, "Flight", "FlapKey", 0);
bool bAutoFly = IniReadInt(CONFIG_FILE, "Flight", "bAutoFlap", 0);
PrintNote("[%s] started, press '%s' to use", SCR_NAME, GetKeyName(FlapKey).c_str());
int iFlapCD = 0;
while (TRUE)
{
	if (true){
		CActor *player = Game::GetPlayer(); 
		flySim(&FlapKey, (PlayerCharacter *)player, bAutoFly, &iFlapCD);
	}
	Wait(0);
}
}

 

I'm still in the middle of rearranging the code so some of the syntax won't make sense.

 

Also note that right now I'm just trying to work on a collision-friendly up/down button.

 

Thanks for the code. I'm working on a more "physically realistic" model for the flight shown above (not going to deal with animations, not currently). I was thinking of using the amount of time that the flight key was held down as a rough approximation of work (W = Fd) and then calculaying out the resulting velocity using energy conservation. Will be posting results later.

Link to comment
Share on other sites

@Poroone

 

Could you post your latest script for flight please? I want to see how you did it in papyrus so I can try to steer closer to something plausible in C++. I'm just hitting brick walls here. That is unless you're still using the translate function...

Edited by Budz42
Link to comment
Share on other sites

Ugh, enough of working over this tonight.

A lot of stuff is still commented out as I'm still testing.

 

Features:

- Control of flight speed

- Control of maximum flight duration

- "Drifting" after maximum flight duration

- Height based on Z axis (i.e. look up to go up)

- Time step control (adjust this how you see fit)

 

Overall, the flight does work, but the animations are wonky.

 

I still need a way to get PlayIdle to work in Script Dragon. Ideas?

 

/* 
       THE DRAGONBORN LEGACY Script Dragon
	Code modified by jimhsu
*/

#include "common\skyscript.h"
#include "common\obscript.h"
#include "common\types.h"
#include "common\enums.h"
#include "common\plugin.h"
#include <math.h>

#define CONFIG_FILE "FlightTest.ini"
#define SCR_NAME "FlightTest"
#define PI 3.14159265


void flySim(BYTE *FlapKey, PlayerCharacter *ref, bool bAutoFly, int *iFlapCD, float *fFlightSpeed, float *fSpeed, int *iFlightTimeMax, float fTimeStep)
{
       float fPosX = ObjectReference::GetPositionX((TESObjectREFR *)ref);
       float fPosY = ObjectReference::GetPositionY((TESObjectREFR *)ref);
       float fPosZ = ObjectReference::GetPositionZ((TESObjectREFR *)ref);
       float fAngX = ObjectReference::GetAngleX((TESObjectREFR *)ref); //East - West?
       float fAngY = ObjectReference::GetAngleY((TESObjectREFR *)ref); //North - South?
       float fAngZ = ObjectReference::GetAngleZ((TESObjectREFR *)ref); //Up - Down
       float fDragonForm = 3; //0 = regular player race, 1 = first shout level, 2 = 2nd shout word, 3 = 3rd shout word
       float fThrust = 0;
       float fPeakThrustTime;
	float fAngleFactor = 3;
	bool isFlying = false;

       if (fDragonForm > 1){
			// Roughly W = F*d
			// d = vt where t = iFlapCD and v is flight speed.
               if (GetKeyPressed(*FlapKey)){
					if (*iFlapCD < *iFlightTimeMax)
					{
						*iFlapCD += (int)(1000 * fTimeStep);
					}
					isFlying = true;
               }
               if(*iFlapCD > 0 && isFlying && *iFlapCD < *iFlightTimeMax){ //timestep
					Utility::SetINIFloat("fInAirFallingCharGravityMult:Havok",0.0);
					*fSpeed = *fFlightSpeed;
					//*fSpeed = *fFlightSpeed * ((float)(*iFlightTimeMax-*iFlapCD) / (float)*iFlightTimeMax); // for 1 second
					//fPeakThrustTime = *iFlapCD/2; //Times the amount of thrust given by the wings
					float newAngle = fAngleFactor*fAngX;
					if (fAngX > 0)
					{
						newAngle = 0;
					}
					if (fAngX < (-90/fAngleFactor))
					{
						newAngle = -90;
					}
					fPosZ += *fSpeed * (fTimeStep) * sin(-newAngle*PI/180.0);
					//fPosX += *fSpeed * (fTimeStep) * sin(fAngZ*PI/180.0);
					//fPosY += *fSpeed * (fTimeStep) * cos(fAngZ*PI/180.0);
					//PrintNote("Flap: Speed: %f; X: %f; Y: %f; Z: %f; angle: %f", *fSpeed, fPosX, fPosY, fPosZ, fAngZ);
					ObjectReference::SetMotionType((TESObjectREFR *)ref, 0, false);
					ObjectReference::TranslateTo((TESObjectREFR *)ref,fPosX,fPosY,fPosZ,fAngX,fAngY,fAngZ,(int)(1000 * fTimeStep),90.0);
					//Actor::PlayIdle((CActor *)ref, (TESIdleForm *)Game::GetFormById(686366));
					// *iFlapCD -= (int)(1000 * fTimeStep)/2;
					// PrintNote("Flap CD reached: %i.", *iFlapCD);
					//*iFlapCD -= (int)(1000 * fTimeStep);
               }else if(isFlying) {
				//ObjectReference::StopTranslation((TESObjectREFR *)ref);
				ObjectReference::TranslateTo((TESObjectREFR *)ref,fPosX,fPosY,fPosZ,fAngX,fAngY,fAngZ,(int)(1000 * fTimeStep),90.0);
				Utility::SetINIFloat("fInAirFallingCharGravityMult:Havok",0.2);
				//Actor::PlayIdle((CActor *)ref, (TESIdleForm *)Game::GetFormById(686366));
				
			}
			else{
				ObjectReference::StopTranslation((TESObjectREFR *)ref);
				Utility::SetINIFloat("fInAirFallingCharGravityMult:Havok",1.35);
				if (*iFlapCD > 0) {
					*iFlapCD -= (int)(1000 * fTimeStep);
					if (*iFlapCD < 0) {
						*iFlapCD = 0;
					}
					if (*iFlapCD == 0) {
						PrintNote("Flap CD reset: %i.", *iFlapCD);
					}
				}
               }
       }
}

void main()
{
       BYTE FlapKey = IniReadInt(CONFIG_FILE, "Flight", "FlapKey", 0);
       bool bAutoFly = IniReadInt(CONFIG_FILE, "Flight", "bAutoFlap", 0);
	int iFlightTimeMax = IniReadInt(CONFIG_FILE, "Flight", "iFlightTimeMax", 5000);
	float fFlightSpeed = IniReadInt(CONFIG_FILE, "Flight", "fFlightSpeed", 1000);
       PrintNote("[%s] started, press '%s' to use", SCR_NAME, GetKeyName(FlapKey).c_str());
       int iFlapCD = 0;
	float fSpeed = 0.0;
	float fTimeStep = 0.5;
       while (TRUE)
       {
               if (true){
                       CActor *player = Game::GetPlayer(); 
                       flySim(&FlapKey, (PlayerCharacter *)player, bAutoFly, &iFlapCD, &fFlightSpeed, &fSpeed, &iFlightTimeMax, fTimeStep);
               }
               Wait(fTimeStep*1000);
       }
}

Edited by jimhsu
Link to comment
Share on other sites

Here is my latest flying code, im using it as a magic effect now so its a bit of a structural change, but nothing important.

 

Scriptname __PlyFly extends activeMagicEffect
Action property ActionJump auto
Idle property flyAnim auto
Idle property JumpStart auto
Armor property RingFF auto
Actor property Player auto
import utility
import form
import game
import debug
import ObjectReference

float bearing
float elevation
float speed
float posx
float posy
float posz


Event OnEffectStart(Actor Player, Actor Caster)
Player = Game.GetPlayer()
if Player.IsEquipped(RingFF)
	Utility.SetIniFloat("fInAirFallingCharGravityMult:Havok",0)
	while Player.IsEquipped(RingFF)
		Fly()
	endWhile
endIf
endEvent

function Fly()
SendAnimationEvent(Player,"JumpFall")
if Player.IsRunning() || Player.IsSprinting()
	posx = Player.GetPositionX()
	posy = Player.GetPositionY()
	posz = Player.GetPositionZ()
	bearing = Player.GetAngleZ()
	elevation = Player.GetAngleX()
	if Player.IsSprinting()
		speed = 2000
	else
		speed = 1000
	endIf
	

	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*2))
	Player = Game.GetPlayer()
	
	Player.TranslateTo(posx,posy,posz,Player.GetAngleX(),Player.GetAngleY(),Player.GetAngleZ(),speed,1)
	
else
	Player.StopTranslation()
endIf

endFunction


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

 

Here is something else, maybe somebody can help me with the math..

 

Scriptname _DragonFly extends Actor  

Action property ActionJump auto
Idle property flyAnim auto
Idle property JumpStart auto
idle property Hover auto
Armor property RingFF auto
Actor property Player auto
import utility
import form
import game
import debug
import ObjectReference

float Ride
float bearing
float elevation
float speed
float posx
float posy
float posz
float dposx
float dposy
float dposz

auto State Idle
Event OnActivate(ObjectReference akSelf)
	Utility.SetIniFloat("fInAirFallingCharGravityMult:Havok",0)
	Player = Game.GetPlayer()
	Ride = 1
	self.SetMotionType(self.Motion_Fixed)
	SendAnimationEvent(self,"GetUpBegin")
	Player.SetVehicle(self)
	if Ride == 1
		Fly()
		GoToState("Deactivate")
	endIf
endEvent
endState

function Fly()
while Ride == 1
	SendAnimationEvent(Player,"HorseEnter")
	self.SetAngle(Player.GetAngleX(),0,Player.GetAngleZ())
	if Player.IsRunning() || Player.IsSprinting()
		
		posx = Player.GetPositionX()
		posy = Player.GetPositionY()
		posz = Player.GetPositionZ()
		dposx = self.GetPositionX()
		dposy = self.GetPositionY()
		dposz = self.GetPositionZ()
		bearing = Player.GetAngleZ()
		elevation = Player.GetAngleX()
		if Player.IsSprinting()
			speed = 2000
		else
			speed = 1000
		endIf
		

		if bearing < 90 
			posx += (bearing)*speed
			posy += (90 - bearing)*speed
			dposx += (bearing)*speed
			dposy += (90 - (bearing))*speed
		elseif bearing > 90 && bearing < 180
			posx +=(180 - bearing)*speed
			posy +=(90 - bearing)*speed
			dposx +=(180 - (bearing))*speed
			dposy +=(90 - (bearing))*speed
		elseif bearing > 180 && bearing < 270
			posx += (180 - bearing)*speed
			posy += (bearing - 270)*speed
			dposx += (180 - (bearing))*speed
			dposy += ((bearing) - 270)*speed
		elseif bearing > 270
			posx += (bearing - 360)*speed
			posy += (bearing - 270)*speed
			dposx += ((bearing) - 360)*speed
			dposy += ((bearing) - 270)*speed
		endif
		posz = Player.GetPositionZ() - (elevation*(speed*2))
		Player = Game.GetPlayer()
		Player.TranslateTo(dposx,dposy,posz + 200,Player.GetAngleX(),Player.GetAngleY(),Player.GetAngleZ(),speed,1)
		self.TranslateTo(posx,posy,posz,Player.GetAngleX(),Player.GetAngleY(),Player.GetAngleZ(),speed,1)
		
	else
		self.StopTranslation()
		Player.TranslateTo(self.GetPositionX(),self.GetPositionY(),self.GetPositionZ() + 200,0,0,0,2000,1)
	endIf
endWhile
endFunction

State Deactivate
Event OnActivate(ObjectReference akSelf)
	Debug.MessageBox("sup")
	self.StopTranslation()
	Player.StopTranslation()
	Ride = 0
endEvent
endState		

 

So basically what im trying to do here is translate 2 objects at the same time, one being the player playing the ride animation (which works amazing for flying) and the other being a dragon, the issue is since the dragon is bigger than the player, when I turn around the z angle gets messed, so what I need is a way to compare both angles and extrapolate a difference for the player to follow.

Edited by porroone
Link to comment
Share on other sites

@porroone: that works great. I've made a simple toggle switch for your mod using Script Dragon:

 

/* 
USE THIS ONE AS A TEMPLATE FOR YOUR SCRIPT PLUGINS
*/

#include "common\skyscript.h"
#include "common\obscript.h"
#include "common\types.h"
#include "common\enums.h"
#include "common\plugin.h"

#define CONFIG_FILE "RingofFlying.ini"
#define SCR_NAME "RingofFlying"

void main()
{
       BYTE FlyKey = IniReadInt(CONFIG_FILE, "Flight", "FlyKey", 0);
	bool toggle = IniReadInt(CONFIG_FILE, "Flight", "Toggle", 1);
	bool getFlying = false;
	float waittime = 0;
       PrintNote("[%s] started, press '%s' to use", SCR_NAME, GetKeyName(FlyKey).c_str());
       while (TRUE)
       {
               if (GetKeyPressed(FlyKey))
			{
				if (toggle && !getFlying && waittime == 0)
				{
					getFlying = true;
					waittime = 2000;
				}
				else if (toggle && getFlying && waittime == 0)
				{
					getFlying = false;
					waittime = 2000;
				}
				else if (!toggle)
				{
					getFlying = true;
				}
			}
			else {
				if (!toggle)
				{
					getFlying = false;
				}
			}
			if (getFlying){
                       Utility::SetINIFloat("fInAirFallingCharGravityMult:Havok",0.0);
					Actor::SetActorValue(Game::GetPlayer(),"Variable09",1);
               }
			else {
					Utility::SetINIFloat("fInAirFallingCharGravityMult:Havok",1.35);
					Actor::SetActorValue(Game::GetPlayer(),"Variable09",0);
			}
			if (waittime > 0) {
				waittime -= 10;
			}
			if (waittime < 0) {
				waittime = 0;
			}
			Wait(10);
       }
}

 

Here are the modifications to your code for the switch to work:

 

Scriptname aaFlyRingScript extends activemagiceffect  

Armor property RingFF auto
Actor property Player auto
import utility
import form
import game
import debug
import ObjectReference

float bearing
float elevation
float speed
float posx
float posy
float posz


Event OnEffectStart(Actor Player, Actor Caster)
       Player = Game.GetPlayer()
       if Player.IsEquipped(RingFF)
               Utility.SetIniFloat("fInAirFallingCharGravityMult:Havok",0)
               while Player.IsEquipped(RingFF)
                       Fly()
               endWhile
       endIf
endEvent

function Fly()
	if (Player.GetActorValue("Variable09") == 1)
		SendAnimationEvent(Player,"JumpFall")
		if Player.IsRunning() || Player.IsSprinting()
				posx = Player.GetPositionX()
				posy = Player.GetPositionY()
				posz = Player.GetPositionZ()
				bearing = Player.GetAngleZ()
				elevation = Player.GetAngleX()
				if Player.IsSprinting()
						speed = 2000
				else
						speed = 1000
				endIf
				

				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*2))
				Player = Game.GetPlayer()
				
				Player.TranslateTo(posx,posy,posz,Player.GetAngleX(),Player.GetAngleY(),Player.GetAngleZ(),speed,1)
				
		else
				Player.StopTranslation()
		endIf
	Else
		Player.StopTranslation()
	endif
       
endFunction


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

 

This allows the flying effect to be toggleable by a simple user switch instead of equipping/unequipping.

 

As it's complicated to set up (involving both Papyrus and Script Dragon), I can release it for the benefit of the community with your permission of course.

 

If someone has a better idea than using unused ActorValues to store data across scripting engines, let me know.

 

Anyways, this took way too long, so I'll go back and play the actual game. With flying of course.

Edited by jimhsu
Link to comment
Share on other sites

The only minor nagging bugs are a) "landing" anims infrequently playing in midair (esp when going up), b) the flight toggle not working well when the player is on the ground (jump to fix any problems), and c) collision through the ground (that will be tricky to fix though). Still, I think at least a pre-release is in order for the 98% of users that don't check these forums. Edited by jimhsu
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...