Understanding Global vars and Arguments - Please help.

The place to discuss scripting and game modifications for X³: Terran Conflict and X³: Albion Prelude.

Moderators: Moderators for English X Forum, Scripting / Modding Moderators

Arbitrary_Notion
Posts: 38
Joined: Fri, 24. Dec 04, 00:58
x4

Understanding Global vars and Arguments - Please help.

Post by Arbitrary_Notion »

Hey guys.

I've been working on a variation of the property baron script for the past several days and I've run into a snag. I am rather new to scripting. Back when I was playing X3 some years ago I went through the MSCI handbook but I didn't give scripting a real go until now with TC. I've figured out a good deal just from taking apart other peoples scripts and the scripts that came with the game but there are some things I just can't seem to figure out.

Primarily I would very much appreciate it if one of the scripting masters around here, you know who you are ;), could explain to me exactly what both arguments and global variables are and how to effectivly use and understand them. I have been searching through forums endlessly and all I can seem to find is examples that use them but offer no explaination as to what is actually going on as far as how information is being recieved, held and delivered.

What I'm trying to accomplish at the moment that has me stumped is I have laid out a script that makes it so you can contact a station manager making him an offer to buy his factory, the random price is chosen between the min and max price modified by another random fraction of that total as incentive to sell and the answer is delivered to the player screen via a message box that allows them to agree or decline. As for the station manager himself, since there are no pilots for a station I used the get random named based on the get race function and had it show in the appropriate places on the message box.

Now what I'm stumped with is how can I pass variable values from one script to another. The reply window called up via a question function needs to have both the station managers name and the credit total gathered from the first script. I've been messing around with using a global variable for the station manager's name but I think I might be misunderstanding how it works. I've use the set and get global variable functions and got it to kind of work at one point but it broke again when I attempted to set a second global variable (one to hold the total cost value). Eventually it got stuck with one value that it returned to all get global variable requests no matter what script I ran them from. I have no idea what that was about.

Finally, the last thing I'm trying to figure out is that I need to have the script hold the assigned random race name so that it doesn't change every time an inquiry is made. That part wasn't too hard as I simply checked to see if the variable that was holding the name had a value or not and made a new name only if it didn't. But much more complicated, so it seems, is to have it assign a name to each station independently. I'm ok with it not doing it forever but maybe for a set amount of time or, at the very least, keep the assigned name for the station until a new one in inquiried, then keep that one and so on and so forth.

Just to be clear-Example: player makes offer to station owner (via hotkey). a message comes back specifying that station manager "place name here" will sell for "total amount here". If the player declines and asks again, the total and name will remain the same. He then tries a different station and recieves a message from a station owner with a different name and total that remain constant until the next station is asked.

So, to summerize my questions (sorry this is so long winded), what method works best for passing variable values from one script to the next either directly or indirectly (i.e. hold the value until it's changed by another script)? What are global variables and arguments, what do they do, and how are they best used? And how can I have my script remember the names assigned to stations on a target by target basis or indefinitely?

Also do you it be a good idea for me to invest in some xml training to help me better understand X3TC scripting? The tutorials I've found thus far seem to focus very little on actual scripting.

Thanks in advance for the help. :)
Education is a progressive discovery of our own ignorance.
-Will Durant
User avatar
ScRaT_GER
Posts: 1962
Joined: Tue, 8. Jan 08, 18:19
x3tc

Post by ScRaT_GER »

I don't consider myself a scripting master, but maybe I can help nevertheless. :wink:
Now what I'm stumped with is how can I pass variable values from one script to another.
There are some ways to do that.
The cleanest way is using arguments.

These have to be defined in the script that is called, like this:

1. Open script =)
2. Under the heading "Arguments" you can add new arguments to the script.
2.1 Select the empty line under the heading "Arguments"
2.2 You will have to assign a name to the argument (if you choose "race" for example, you can use it later as $race)
2.3 Choose the variable-type (e.g. Var/Race for race)
2.4 Type in a string, which will be displayed, when doing a script call (called "station owner race" in the following example)

So now you can call a script like this:

= [THIS] call script a.myscript: station owner race = <Var/Race>

For <Var/Race> you will of course have to choose the race or a variable.

The reply window called up via a question function needs to have both the station managers name and the credit total gathered from the first script.
For this purpose you don't even need script arguments, as described above.
You have to prepare a text to be displayed.

So something like this:

$text = sprintf: fmt='[author]%s[/author]station manager "%s" will sell for "%s"', $name, $name, $total, null, null

[author] and [/author] define the author of the incoming message. " %s " marks that there is a variable to be put in. So the first two "%s" is assigned to $name, the third to %total.


If I undestand correctly you want to assign the stations owner's name to each station, which should be the same, if you ask the station owner multiple times.
I would do this via local variables.

These are variables which are "saved" on the RefObj and can be "read" by every script. So it would work like this (if you already found a name):

$station -> set local variable: name= 'angelofreason.owner.name' value=$name

You can "read" the local variables like this:

$name = $station get local variable: name='angelofreason.owner.name'

The variable's name is a string and has to be unique. It would be best to choose something meaningful.

Global Variables work the same, they are just missing the RefObj - part.

Also do you it be a good idea for me to invest in some xml training to help me better understand X3TC scripting?
XML does not have much to do which the X3 script language. I learned by looking at other people's scripts and asking in the forum.
XML is however of interest, if you want to write you own missions via MD.


I hope that I could answer you questions.
Greets,
ScRaT
Cycrow
Moderator (Script&Mod)
Moderator (Script&Mod)
Posts: 22432
Joined: Sun, 14. Nov 04, 23:26
x4

Post by Cycrow »

if there any reason u've decised to use an incoming question, rather than creating a menu to use ?

its difficult to pass varibles to incomming questions, especially if your not sure what your doing. So they are not called like normal scripts, and use callbacks instead. You have to embed your varibles into the text.

when you define your questions, you can create them like this

Code: Select all

[select value="yes,%s,%s"]Yes[/no]
[select value="no,%s,%s"]No[/no]

Code: Select all

$message = sprintf: read text....$price, $name, $price, $name
this will create the text like this

Code: Select all

[select value="yes,$price,$name]Yes[/no]
[select value="no,$price,$name]No[/no]
the callback script will then need to have 3 arguments, the data in each one will be passed to the argument. Ie, Yes or No will be passed to the first, then what ever u put in the %s will be passed to the 2nd and 3rd


another way is to use a global varible, declare it before sending the message. Then the callback script can get these varibles to use them.

Global varibles are defined by a unique text name

Code: Select all

set global varible: 'my.varible.price' value = $price
set global varible: 'my.varible.name' value = $name
then in the callback script you need to retreive these

Code: Select all

$price = get global varible: 'my.varible.price'
$name = get global varible: 'my.varible.name'
a menu is much easier as you dont need to pass any arguments between scripts.

I've been messing around with using a global variable for the station manager's name but I think I might be misunderstanding how it works. I've use the set and get global variable functions and got it to kind of work at one point but it broke again when I attempted to set a second global variable (one to hold the total cost value). Eventually it got stuck with one value that it returned to all get global variable requests no matter what script I ran them from. I have no idea what that was about.
for something like that, it would be better to use local varibles, these are the same as global varibles, but instead, are attached to objects, like ships and stations.

Code: Select all

$station -> set local varible 'my.varible.name' value = $name
and getting them is the same

Code: Select all

$price = $station -> get local varible 'my.varible.name
this means you can set different names on each station.
User avatar
Nividium
Posts: 800
Joined: Tue, 21. Aug 07, 01:31

Post by Nividium »

Read the bottom of page 40 and the top of page 41 of the MSCI handbook for a description of Global and Local Variables.

You would be better off using a "Local Variable" to store both the station manager's name and the selling price of the station in one go, using an array. The Local Variable can point to this array and retrieve it at any time over and over again. The script shown below will indicate the type of code you need to write to create this local variable and the array to hold the station data. Arguments are used to "pass" the values from the source script to this example script. You can also run it by itself, but you would need to type in the values for the arguments (that normally would be passed by the data gathering source script). Good for testing and to see how it works though.

Code: Select all

Script a.a.a.temp
Version: 0
for Script Engine Version: 42

Description
Create a Local Variable to point at an array and return values.
Arguments
1: station , Var/Station , 'station' 
2: station.manager.name , String , 'name' 
3: selling.price , Number , 'selling.price' 
Source Text

001   $station.array =  array alloc: size=2
002   $station.array[0] = $station.manager.name
003   $station.array[1] = $selling.price
004   $station -> set local variable: name='station.details' value=$station.array
005   
006   
007   * Test the Local Variable ie the array's data.
008   $data.array = $station -> get local variable: name='station.details'
009   $manager.name = $data.array[0]
010   $price = $data.array[1]
011   write to player logbook: printf: fmt='Station Manager Name = %s, Selling Price = %s', $manager.name, $price, null, null, null
012   
013   return null
Arbitrary_Notion
Posts: 38
Joined: Fri, 24. Dec 04, 00:58
x4

Post by Arbitrary_Notion »

You guys are truly awesome to offer such a quick and detailed reply. :D

Ok, I'll give a full report about how it goes after I get more time to mess around in the SE. But for the moment, though I've got the global variables working, I can't seem to get the local variable to return a value.

It seems like it's not attaching the script to the station. I read in the MSCI that local variables are stored on the object on which the script is running. So how to I tell the script to run on the station? Do I need to reference it somehow? I tried doing a get player tracking aim to get the station id and use that variable as the start of a set local variable command and I still got null.

I appreciate you taking the time to help me.
Education is a progressive discovery of our own ignorance.
-Will Durant
asdrubale
Posts: 48
Joined: Wed, 22. Apr 09, 17:35
x4

Post by asdrubale »

Local variables are associated with an object. When you use the instruction

Code: Select all

[THIS] -> set local variable: name = 'foo' value = 'bar'
you are saying "I want to store the value 'bar' in the object [THIS] and I shall call it 'foo'.

[THIS] is a reference to the object the script is running on. If you want to store or retrieve local variables on the object $station you just have to use $station instead of [THIS].
Arbitrary_Notion
Posts: 38
Joined: Fri, 24. Dec 04, 00:58
x4

Post by Arbitrary_Notion »

Ah. I think I got it.
The set and get local variable lines had parts defined as being where you enter the RefObj so I fed a variable with the player tracking aim into it and that seems to have done the trick. :D
Education is a progressive discovery of our own ignorance.
-Will Durant
User avatar
Nividium
Posts: 800
Joined: Tue, 21. Aug 07, 01:31

Post by Nividium »

angelofreason wrote:...I fed a variable with the player tracking aim into it and that seems to have done the trick. :D
You are activating the main "buy a station" command from some script, right ie you have bound your custom command into a button ie under the main ship commands sections of [Custom] or [General] etc. Well, instead of using the player tracking aim to assign the value of the Variable, use an Argument as the first argument in the activation script, which asks for what station do you want to buy. This will give you the variable of $station. Because the first thing your user will have to do when executing your script is to identify the station they want to buy. Easy, problem solved.
Arbitrary_Notion
Posts: 38
Joined: Fri, 24. Dec 04, 00:58
x4

Post by Arbitrary_Notion »

Ok, next up on the list of snags.
I've got my local variables working nicely but I'm having a pretty hard time figuring out how to get it to only assign a name the first time.
I figured I would just ask for the value of the local var before it was created in the script so that it would return a null and then make an if statement that assigns the random name only in that case but I can't seem to get it to work. It either always returns null or always randomly generates a new name. I assumed it would read nul the first time through and then see the assigned name every time after, never assinging a new name again.

How would you guys have a script check to see if a local variable has a value and then only assign it one if it came up null?


@Cycrow
Thanks for your help. I'm a big fan of your scripts. :)
And I chose the incoming question because I just like the look of the window it brings up. From my understanding a menu would be a box with a series of buttons like the custom menu interface. The idea behind my variation of the property baron script is that you send a message to the owner to let him know that you're willing to lay out some real credits to take his factory off his hands. He thinks about it and get back to you after several seconds to give you his answer. So I wanted the message window because it gives the feel of a PM or something of the like. *shrugs*

I wanted to put some real complexity in the script to make the experience interesting and seem more like what you're expect in spur of the moment offer involving lots of credits. So I set up a shotcut key to send the request to the owner. (I might later try to add in a menu option too. not sure.) the text window show's up at the bottom of the screen stating:
" -place name here- at -station name here- has received your offer. please wait...".
About 6 seconds later you get an incoming message that reads something to the effect of:
author: -place name here- - Station Owner
title: - place station name here-
So your're interested in buying my station, eh?
Well it set me back -place price here- back when I set it up.
Not sure if it'd be in my best interest to part with it just yet.
hmm..
Tell you what, throw in another -price modifier here- and you're got a deal.
That comes to -place total here-.
What do you say?

The initial price he states is an random number between the max and min of the station value, the modifier is a fraction of that based on a random number and the total is both added together.

I needed to know how to pass the value to the answer message so that he could reply something like:
The -place total here- have been wire to my account.
pleasure doing business with you.
-place name here-

Ultimately, I want to have the messages typed out in a way that is appropriate for the way that the race in question speaks and maybe even have several answers that could be picked at random so they don't repeat themselves too often. And I was also thinking about making a button to tell him he's asking too much at which point the total might be reworked to come out higher or lower and stay stuck at that. A bit of gamble to make things fun. :D

@Nividium
I've rather enjoyed your scripts too. :)
I hope you don't mind me taking one of your ideas and running with it. I'm not sure if it's anything I'll end up wanting to upload but if I ever get that far I'll still give you credit for the initial idea. :wink:
And thanks for the advise on using an array. I definitely plan to give it a try once I'm got a handle on local variables.

Thanks again guys for helping me out.
Education is a progressive discovery of our own ignorance.
-Will Durant
pelador
Posts: 1399
Joined: Wed, 6. Nov 02, 20:31
x3tc

Post by pelador »

To examine nulls you can set the variable to examine it specifically.

Code: Select all

e.g. if $var == null
However you can use short notation as a result:

Code: Select all

if $var , if not $var, while $var etc.
This is because the logic for bollean operations is as follows:

[TRUE] is integer 1
[FALSE] is null

but the above can be used to see if any value is set in the above operations and is useful in array useage for example.

But in most cases it is best to use the literal operators (respecting nulls can be helpfull) this is to not be forgetfull that sometimes values can be zero or blank. So you need to think about the data your examining really as to when to best apply.

so best in most cases to use:

Code: Select all

if $var == null , if $var != null, while $var != null, while $var  ... etc 
(The null value can be found in the environment variable list when using the SE)

------------------------------------------------------------------------------------


So for your example you could use:

Code: Select all

$var = $obj -> get local variable: name='angel.var.store'

if $var == null

  "..do something.. to get/assign variable $new.value"

  $obj -> set local variable: name='angel.var.store' value=$new.value
end
jlehtone
Posts: 22500
Joined: Sat, 23. Apr 05, 21:42
x4

Post by jlehtone »

[url=http://forum.egosoft.com/viewtopic.php?t=216693]TC Tutorials[/url] now points to this thread too.
User avatar
Nividium
Posts: 800
Joined: Tue, 21. Aug 07, 01:31

Post by Nividium »

ARGUMENTS:

An argument is a parameter. It can be used in 2 ways. To pass an established variable's value to another script or to ask for user input. (Read the top of page 12 in MSCI handbook for a brief description of the 3 pieces of info which comprise each argument).

1) To pass the established variables value to another script the other script must have the variable defined as an argument. Then when the current running script "calls" the other script the "call script" command will show the argument's description and indicate that a variable needs to be placed into the "call script" command line to complete the command and pass the variable's value over to the other script for processing.

2) To ask for user input a command script is used and is the very first script that is processed from the ship or stations main command ie: you have bound a script to a ship's command console showing up under [General] or [Custom] etc. This first script is then executued first and if it has arguments defined or set up, then these arguments will prompt for user input (ie: select a ship or a station or object or number etc (based upon the type of variable being defined by the argument)) and the value will be placed into new variables as defined by the argument. These new variables and their values have now become established and can now be used throughout the command script and also passed when using a "call script" command as discussed above in 1).
Arbitrary_Notion
Posts: 38
Joined: Fri, 24. Dec 04, 00:58
x4

Post by Arbitrary_Notion »

Just to report back what solutions worked for me:

There were two main problems I ran into which, thanks to the examples and advice I got here, I got worked out.
First was the problem I was having with global variables. I had gone through numerous other scripts to see how they were used and I was pretty sure I had the idea but what I had missed was that the title of the global variable has to be a string. The ones that I had seen using variables for names had actually assigned a string to that variable at some point. So once I changed the names to strings they started working as expected.
And Second my local variables weren't working until I tried changing the names from something complicated like 'station.owner.loc.var' to something simple like 'owner'. I assume I had made a typo somewhere since they started working fine after I reworked them to have simple names.

I've got more questions to ask but they are off the topic of globals and arguments so I'll make a new post.

Thanks again for all of your help, guys. :)
Things are coming together nicely with my scripts.
Education is a progressive discovery of our own ignorance.
-Will Durant

Return to “X³: Terran Conflict / Albion Prelude - Scripts and Modding”