Scripters cove

Discussion and information relevant to creating special missions, new ships, skins etc.

Moderators: winston, another_commander

User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

Is there a simple mathematical way to tell if the player is facing towards a particular entity (for example the main station of a system)?

I've tried various vector combinations comparing the players heading with the .direction() component of the difference in position between the station and the player, and they all seem to also depend on the rotational orientation of the player (if the player is sat still in space but rotating the results of the angleTo, dot and cross products of the above two vectors all vary - a log of all of the functions below change with rotation).

Can anyone shed some light on the best way to go about this, or have I got to wade into the wiki details of vectors?

Code: Select all

this.targetVector = system.mainStation.position.subtract(player.position).direction();
this.playerHeading = player.heading;
this.playerAngle = this.playerHeading.angleTo(this.targetVector);
this.playerDot = this.playerHeading.dot(this.targetVector);
this.playerCross = this.playerHeading.cross(this.targetVector);
User avatar
Frame
---- E L I T E ----
---- E L I T E ----
Posts: 1477
Joined: Fri Mar 30, 2007 8:32 am
Location: Witchspace

Post by Frame »

I´m thinking...

that taking a look at the space compas functions could reveal some of it...
trying to see if i can find the code.(why reinvent the deep bowl) ;-)

gave up on the space compas thingi.. because there is rotational matrixes involved.. not what we want..

however, then proceeded to check the scoop code and found this piece of information

Code: Select all

- (BOOL) canScoop:(ShipEntity*)other
{
	if (other == nil)							return NO;
	if (![self hasScoop])						return NO;
	if ([cargo count] >= max_cargo)				return NO;
	if (scanClass == CLASS_CARGO)				return NO;  // we have no power so we can't scoop
	if ([other scanClass] != CLASS_CARGO)		return NO;
	if ([other cargoType] == CARGO_NOT_CARGO)	return NO;
	
	if ([other isStation])						return NO;

	Vector  loc = vector_between(position, [other position]);
	
	if (dot_product(v_forward, loc) < 0.0f)  return NO;  // Must be in front of us
	if ([self isPlayer] && dot_product(v_up, loc) > 0.0f)  return NO;  // player has to scoop on underside, give more flexibility to NPCs
	
	return YES;
}
and then looked up the vector between function

Code: Select all

#define vector_between(a, b) vector_subtract(b, a)
This gives us code that tells us where we can scoop, in front and below, my educated guees is that v_up, which is a vector_up, that center is 0.0, to far down, then the number goes negative
The same can be done with vector_right..

so quick writing some code here that might work

Code: Select all

let radius_from_player_center = 10 // how for from player center we allow before something becomes active

let rf  =radius_from_player_forward_center
let target_posistion = new Vector(system.mainStation.position)
let loc = new Vector(target_position.substract(player.position))
// maybe need to be the next commented line instead not sure....
// let loc = new Vector(player.position.substract(target_position))

// edited:::: sry..
let ori = player.orientation
ori.w = -ori.w
let ud = ori.vectorUp().dot(loc)
let lr =  ori.vectorRight().dot(loc)

if(ud =< rf && ud  => -rf && lr =< rf && lr => -rf)
{
do something
}
hope it works...

anyway.. remember that player, will in 1.72 need to be player.ship in many instances that deals with the players ship, instead of the characther player "himself".. player.credits will still work afaik... bot not player.position, that will need to be player.ship.position..
Last edited by Frame on Mon Oct 06, 2008 6:31 am, edited 3 times in total.
Bounty Scanner
Number 935
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

A good thought. Having given it some more thought, I'm curious about player.heading, as it's supposed to be equivalent to player.orientation.vectorForward(). That should be roll independent (according to the wiki for both suppositions), but it doesn't seem to be.

I will try the orientation.vectorForward() equivalent first and see if that works any better, but I'm wondering a little if heading is broken in that respect?

It was my expectation that it should be either the angle or more likely the dot product of the heading and the vector between the station and the player should tend to zero as the player points more accurately towards the station. Your code above tends to support that, and also tends to support my thinking that player.orientation.vectorForward() doesn't equal player.heading, and the latter is broken.
Last edited by Thargoid on Mon Oct 06, 2008 6:26 am, edited 1 time in total.
User avatar
Frame
---- E L I T E ----
---- E L I T E ----
Posts: 1477
Joined: Fri Mar 30, 2007 8:32 am
Location: Witchspace

Post by Frame »

oh i forgot... you need to set the player.orientation.w to negative...

so use

Code: Select all

let ori = player.orientation
ori.w = -w
also at the first submit.. accidently used player.position, instead of player.orientation...

and used vectorForward, instead of vectorRight :-/...

corrected
Last edited by Frame on Mon Oct 06, 2008 6:31 am, edited 2 times in total.
Bounty Scanner
Number 935
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

Frame wrote:
oh i forgot... you need to set the player.orientation.w to negative...

so use

Code: Select all

let ori = player.orientation
ori.w = -w
Indeed. Ironically it's ending up more or less the same code I used in Probe to move the launch down 50m from the ship, with a little directional adjustment.

And at the moment none of my code is 1.72 compatible (player --> player.ship). That's a job for the (near) future...
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Proposals look complicated. For a not yet released stuff I wrote:

Code: Select all

this.checkDirection = function()
{
    let heading = this.ship.target.heading
    if (this.ship.target == player && 0 < oolite.compareVersion("1.72"))
    {
        let orientation = player.orientation
        orientation.w = -orientation.w
        heading = orientation.vectorForward()
    }
    let angle = this.ship.heading.angleTo(heading)
    if (angle < 0.08 || angle > 3.06) 
    {Your stuff}
}
Here the NPC ship reacts when the player lines up with the NPC ship. For your situation you must replace heading with the vector player-to-target: target.position.subtract(player.position)
Angle varies between 0 and Math.PI. Never becomes larger or negative.
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

Thanks gents, either way works. The angle method is simpler as Eric says, the only problem with that is that as the player approaches the station, the angle grows, which I'm not sure I like.

The code above won't quite work as it's not in JS (the forward_ bit in the rf definition), but vectorForward() should do the same job.

I think my earlier problem is with the orientation.w issue, as I checked and player.heading and player.orientation.vectorForward() do give the same results.

Ah well, we shall see I guess, on with the scripting...
User avatar
Frame
---- E L I T E ----
---- E L I T E ----
Posts: 1477
Joined: Fri Mar 30, 2007 8:32 am
Location: Witchspace

Post by Frame »

while we are at it...

I wrote the following function, to determine absolute universe coordinates of sub entities...

Usefull for example spawning fake missiles fired from NPC or the player ship.. I imagine this could be used for turrets aswell, while rotation of a turret is not included...

Also this is the code is use to determine excentric docking slits, it puts me dead center of for example commies OXP zgf station docking slit.

Code: Select all

this.subentitycoordinate = function(ship, subentity)
{
	let pos = ship.position	
	let ori = ship.orientation
	let x = subentity.position.x
	let y = subentity.position.y
	let z = subentity.position.z

	let oz = new Vector(pos.add(ori.vectorForward().multiply(z)))
	let oy = new Vector(oz.add(ori.vectorUp().multiply(y)))	
	let ox = new Vector(oy.add(ori.vectorRight().multiply(x)))	
	return ox
}
could be simplified... but i spread it out, so people can see what goes on..
Bounty Scanner
Number 935
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Related to this is how Oolite itself sends ships to a position. This is also done with angles. Ships are never send directly to a fixed position.

Oolite calculates from the distance and the given desired_range, what the maximum angle deviation is for a route that passes the destination within the target range. If the current ship angle is to large it turns the ship every update moment at the ships turn speed into the desired direction. Once it has turned enough to hit the target within the desired range it stops turning. This course is maintained until the actual desired range is reached.

Ships never aim for the destination itself, only for a point within a radius of desired range around the destination. All this is of cause to prevent that all ships go for the exact same endpoint.
User avatar
Micha
Commodore
Commodore
Posts: 815
Joined: Tue Sep 02, 2008 2:01 pm
Location: London, UK
Contact:

Post by Micha »

Eric Walch wrote:
Ships never aim for the destination itself, only for a point within a radius of desired range around the destination. All this is of cause to prevent that all ships go for the exact same endpoint.
Is that why there are so many stages to the docking AI and why (some) ships do a lot of pirouetting about at each point? It'd look a lot neater if the ships didn't keep stopping on the approach (unless, of course, there's a ship in front of them).
The glass is twice as big as it needs to be.
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Micha wrote:
Is that why there are so many stages to the docking AI and why (some) ships do a lot of pirouetting about at each point? It'd look a lot neater if the ships didn't keep stopping on the approach (unless, of course, there's a ship in front of them).
The flight to the station is divided in about 9 tracts. In my memory the station approach went smoother under 1.65. Stopping is caused because the ship reduces speed the more it reaches the desired range. I think this is wrong and the degree of speed reduction should also be dependent of the range itself. I see no point in stopping the ship within a few meters of the range when the desired range itself is a few thousand meters. Chance of this overshooting increases with lower frame rates.

Pirouetting is probably caused by ship characteristics. When the thrust is very low and a high speed is given, the ship overshoots its target and tries to reach it from the other side instead of just leaving it.
Wiggling before the station is also caused by overreacting. I very often see it happen when the frame rate is very low. At every frame the ships position is recalculated and adapted. At frame rates below 10 fps It corrects heading in large jumps. This can lead to constantly overshoot the target heading. When I give such ships a considerably lower turn rate, they stop wiggling and they get their heading right in one go.
User avatar
Micha
Commodore
Commodore
Posts: 815
Joined: Tue Sep 02, 2008 2:01 pm
Location: London, UK
Contact:

Post by Micha »

Hmm, possibly a way to fix this would be to introduce the concept of waypoints. Currently that's implemented by a list of destinations, but ships seems to slow/stop at each destination and calculate their way before heading off to the next one. Whereas with waypoints it could be coded that ships never stop at a waypoint, but smoothly arc towards the next one.
Anyways, should probably take this into a new thread - sorry for hijacking!

PS. I usually run at 40-50fps
The glass is twice as big as it needs to be.
User avatar
Frame
---- E L I T E ----
---- E L I T E ----
Posts: 1477
Joined: Fri Mar 30, 2007 8:32 am
Location: Witchspace

Post by Frame »

I just picked up that Ahruman has storage for arrays in savefile on his todo list...

This is already possible..

It is the "converter" or whatever you can blame for letting it appear that you cannot store arrays in save file...

if the arrays first element starts with a number, then "converter" will think the whole array is a number and will discontinue saving at the first non numeric sign, which in this case is a comma sign...

example

Code: Select all

var num_array = new Array{ 1,2,3,4 }
missionVariables.noarray = num_array
now if you output missionVariables.noarray to the debug console or stderr.txt file.. you will get this

1

however if you do this

Code: Select all

var num_array = new Array{ dummy,1,2,3,4 }
missionVariables.noarray = num_array
Then the out put will correctly be
log("ms:"+missionVariables.noarray)
dummy,1,2,3,4

so you just have to allways start with plain text in order for the "converter" to detect it as text. if you need to use numbers, this is also perfectly fine to use this method... just remember to start with a dummy if you need an array to store in the save file...

So when you need to read in the missionVariables.noarray that is an array
you do it like this

Code: Select all

var readarray = missionVariables.noarray.split(",")
and the readarray will be

readarray[0] = dummy
readarray[1] = 1
readarray[2] = 2
readarray[3] = 3
readarray[4] = 4

As the comma sign is discarded, and you of course do take into account that the first element of the array is a Dummy..

Cheers Frame
Bounty Scanner
Number 935
User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

I should haves said this a while back, but…

In various bits of JavaScript code, I’ve been using the non-standard let keyword instead of the standard var. let declares variables that are only valid until the end of the current scope (typically, a scope is a bit of code surrounded by { braces }), while var declares variables that last until the end of the function. The let semantics are more similar to, well, most other programming languages.

However, due to disagreements in a committee, the ECMAScript 4/JavaScript 2.0 proposal that the SpiderMonkey engine has been tracking has been abandoned, and a different proposal is being developed. It is currently unclear whether let will be included, and if it is, there may be subtle differences in meaning.

For this reason, I recommend against the use if let in new JS code at this time.
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5528
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

A little conundrum that I'm not sure has an easy (or at least an elegant) answer. Is it possible to set the techlevel of a station relative to the system it's spawned in (as opposed to just a fixed tech level different to the system)?

For example, is it possible to set a station to be one tech level higher than the system it's in? I know the inelegant way around it is to use 16 variants of the station with various equivalent_tech_level keys and use a case'd check on the tech level or something similar to spawn the right one, but that's very clunky.

Just wondering if anyone has any input if it's possible another way, or whether a script request is in order. I'm thinking of it towards an upgraded version of Planetfall (already well on the way), to make it actually worth landing on the planet vs docking with the main station.
Post Reply