Hard Light Productions Forums

Modding, Mission Design, and Coding => The Scripting Workshop => Topic started by: Aginor on July 04, 2012, 01:35:23 pm

Title: scripting.html
Post by: Aginor on July 04, 2012, 01:35:23 pm
Hi guys!
Since the link in this thread http://www.hard-light.net/forums/index.php?topic=45554.0
to the scripting.html is dead, could one of you please create a scripting.html from a current build (doesn't have to be the newest one) and post it here?
I only have the WCS build and want to do a little bit of scripting, and unfortunately that build doesn't support the -output_scripting command line parameter it seems.
I know some of the newer features won't work but that doesn't matter, I suppose I'll only need some that are quite old for the scripts I want to test.

Thanks in advance!
Title: Re: scripting.html
Post by: Zacam on July 04, 2012, 01:52:10 pm
You'll have to ask this in the WCS thread.

Further, the command line can be run by anybody on any build, so the recent RC's for 3.6.14 can output one.
Title: Re: scripting.html
Post by: The E on July 04, 2012, 01:52:55 pm
This is scripting.html as of July 2nd

http://blueplanet.fsmods.net/E/scripting.html

btw, you _do_ know that there's nothing preventing you from downloading an FSO build and running it?
Title: Re: scripting.html
Post by: Aginor on July 04, 2012, 02:10:12 pm
Thanks a lot, E!

About the FSO build... can it run without all the files? I don't have FS2 on my PC, just WCS (I can't even find my FS2 disks at the moment tbh).
Title: Re: scripting.html
Post by: The E on July 04, 2012, 02:13:58 pm
It _should_ be able to run long enough to spit out scripting.html, anyway.
Title: Re: scripting.html
Post by: Dragon on July 04, 2012, 06:21:51 pm
You can always try running an FSO build on TBP (if you want to download it, that is. It's quite huge).
Title: Re: scripting.html
Post by: jr2 on July 05, 2012, 12:11:16 am
How about BtRL?  :)
Title: Re: scripting.html
Post by: Dragon on July 05, 2012, 03:49:28 am
It's too hard to find, I doubt any of the original download locations still has it.
Title: Re: scripting.html
Post by: Aginor on July 05, 2012, 04:56:39 am
Thanks to you guys I have now created my first scripts. :)
What I'm working on at the moment are two scripts to help me with the Strakha cloaking.

I already managed to read the player's ship class and I also can read and write HUD colors. I need that because I want to create the Wing Commander 3  cloaking thing as a script. I already managed to make most of the HUD black and white (except the colors of ships on the radar and the targeting brackets), and next I'll try if it is possible to make the rest happen.

Having some experience with programming/script languages helped me a lot, LUA really isn't hard. It is also quite pleasant sometimes, the syntax is quite easy.
But... I don't like that they decided to call an array "table", that confuses the hell out of me since I work with databases all day :D
And most important: WHO THE F*** thought it was a good idea to let arrays start with one? Fortran was that way and it sucked.

Whatever. It works and I'm now learning about all the objects and how they work.

What I don't understand yet is the hook structure, despite reading the tutorial.
I already got a scripting table that looks like this:
Code: [Select]
$Global hooks:

$GameInit
[
..  some methods that are used by Saga's HUD scripting
....
]

$HUD:
[
... triggers that use the functions defined above, for making the cool weapons display,
.....

....here I put my stuff that changes the color of all gauges depending on the ship type of the player (if playerShip.class == "Strakha#Inv") etc.

]
#End



Now I want to have that Conditional Hook thingie that triggers when there is a ship collision involving the player. Where do I put it? Everything I tried produced and error saying something like "#End expected" or just did nothing.
Title: Re: scripting.html
Post by: Nuke on July 05, 2012, 05:23:57 am
tables are different from arrays in that elements need not all be the same type. and the indexing starting at 1 is kind of an oddball thing, but you get used to it.
Title: Re: scripting.html
Post by: m!m on July 05, 2012, 06:05:04 am
Now I want to have that Conditional Hook thingie that triggers when there is a ship collision involving the player. Where do I put it? Everything I tried produced and error saying something like "#End expected" or just did nothing.

If you want to know of collisions involving the player you can use this as a template:
Code: [Select]
#Conditional Hooks

$On Ship Collision:
[
if (hv.Self == hv.Player) then
    -- Add code that should be executed
end
]

#End

Inside that hook you have hv.Self as one ship that collided and hv.Ship as the other. I hope that helps.
Title: Re: scripting.html
Post by: Aginor on July 05, 2012, 06:13:21 am
Thanks m!m, but I already figured that out so far. As far as I have seen the object structure is pretty logical when you are used to OOP. What I don't get is where to put that block (starting with #Conditional Hooks and ending with #End).
Does it go into the same file (scripting.tbl), below the "#End" tag from the Global Hooks? I think I already tried that and the parser said something like "expecting <eof>, found Conditional Hooks".

tables are different from arrays in that elements need not all be the same type.
That's the same as PHP arrays.
Title: Re: scripting.html
Post by: m!m on July 05, 2012, 06:35:45 am
The #Conditional Hooks part should be located after the #End of the #Global Hooks part but you should consider switching to #Conditional Hooks entirely as that will give you much better control over when the hooks are executed and will make your live easier later.

tables are different from arrays in that elements need not all be the same type.
That's the same as PHP arrays.
I think the goal here is that lua "tables" aren't plain C arrays but can also be used as maps (like PHP arrays) so the term "array" could have been misleading.
Title: Re: scripting.html
Post by: Nuke on July 05, 2012, 06:55:06 am
lua tables are pretty versatile. you can do named keys, use indexes, they can contain sub-tables or any of the other lua data types (including userdata and functions). so a table can do the job of arrays, structs, even objects if your lua fu is strong. note i come from a c/++ background (sort of), so i mean those terms from the perspective of those languages.
Title: Re: scripting.html
Post by: Aginor on July 05, 2012, 07:11:44 am
Yeah, it's really versatile, comparable to PHP. Of course it also shares its weaknesses it seems.
I am not a c or c++ expert (I use mainly script languages and Java) but I understand what you mean, those are also the terms I'm used to most.
A language that isn't strict with datatypes can be quite a shock when you come from a Java- or c background.
It certainly was my impression when I first used PHP. :D
But since I have experience using a couple of such languages already I'm fairly confident I'll get along with LUA quite well, provided a bit of training.
I just couldn't believe it when I saw that they used arrays starting with one. I thought that bad habit had finally died out. :D
Title: Re: scripting.html
Post by: Aginor on July 05, 2012, 01:46:58 pm
Found it.

I had to add

$Application: FS2_Open
$State: GS_STATE_GAME_PLAY

before the "$On Ship Collision:[]" block. I don't know exactly why but I read it in one of the examples and it worked :D
Title: Re: scripting.html
Post by: Nuke on July 05, 2012, 07:24:50 pm
both of those are conditions that have to be met before the actions below them are executed. i dont know why we need the $application: condition at all since i doubt it would be anything but fs2_open unless they had decided to extend the scripting system to fred or whatever. but i find that ommitting it can lead to stuff not working. essentially what that says is:

if were running fs2_open and the state is GS_STATE_GAME_PLAY then run the following action scripts.

you can stack as many conditions as you want but they all have to be true before the actions are run. all available conditions and actions are listed in the scripting.html right at the top of the file. should probibly say that you probibly shouldnt use global or state hooks. global hooks can only run once, so if you are using modular scripting tables only the one from the first (or last, im not sure) *-sct.tbm will run. i guess they can be useful in tcs and whatnot where youre just using a scripting.tbl. as for state hooks they've mostly been deprecated, i think they were kind of an experimental feature that didnt pan out.

i kinda think the wiki entry for this needs work, i think what we have is left over from 3.6.9/10. its confusing and has a lot of useless or misleading information in it and is kinda vague where it matters.
Title: Re: scripting.html
Post by: The_Force on July 06, 2012, 06:07:46 am
There scripting.html form saga build

[attachment deleted by ninja]
Title: Re: scripting.html
Post by: Aginor on July 06, 2012, 07:35:34 am
?? How did you get that? When I added the command line option nothing happened at all...
Title: Re: scripting.html
Post by: The_Force on July 06, 2012, 07:53:34 am
were you running through the saga launcher? because the launcher removes all flags, also make sure you are adding it to the file in the user documents/Violation/data folder.
Title: Re: scripting.html
Post by: Dragon on July 06, 2012, 08:53:03 am
Volition, not Violation. :)
Title: Re: scripting.html
Post by: The_Force on July 06, 2012, 09:18:34 am
 :nervous: Oops
Title: Re: scripting.html
Post by: Aginor on July 06, 2012, 10:19:59 am
No, I added it directly to the file.
but... ...actually I think I should check my PC later, maybe the file is there and I just didn't see it, or the exe wasn't able to save the file because of some strange WinXP Professional 64 (I still curse the day I bought that one) rights issue or something.
Title: Re: scripting.html
Post by: The_Force on July 06, 2012, 10:24:58 am
It's in the directory before the file you modify.
Title: Re: scripting.html
Post by: Aginor on July 06, 2012, 02:29:56 pm
Oh man.... turns out it was there all the time, I just never looked in that folder. I somehow assumed it would be in the same folder as the exe, which it of course isn't.
Sorry for stirring everyone up!
<-- feels really stupid now


But while I'm here I got a question:
Is there a possibility to trigger a script even whenever a certain event in the mission becomes true? Maybe by monitoring a SEXP variable?

My problem is the following:
My player cloaking events are working and all, but since I change the player ship's model to another one to have animated cloaking the secondaries reset to the standard missile type and the maximum number.
Until now I just limited the player to that one missile type and stored the number of missiles in a variable. As soon as the event has changed the model it sets the secondary ammo to the stored value.
But since there is no SEXP to set the type of secondary (I think there is one in other builds but not here it seems) I thought I could maybe do it by scripting.

Here's what I tried so far:

Code: [Select]

      -- Mission starts and player flies the Strakha, I read the type of secondary weapon from bank 1 (there is only one)
      -- edited it, first version was even worse, didn't work as intended.

misTime = mn.getMissionTime()
if (misTime == 1 and playerShip.Class.Name == "Strakha" and Weapinit == 0) then
orgWeapClass = playerShip.SecondaryBanks[1].WeaponClass.Name
Weapinit = 1
end




      -- When the player is cloaking or cloaked  OR has just finished decloaking,
      -- set the secondary type to the one he is supposed to have

       if (
(     playerShip.Class.Name == "Strakha#Inv"
   or playerShip.Class.Name == "Strakha#Cloak"
   or playerShip.Class.Name == "Strakha#Decloak"
)
or
(
      playerShip.Class.Name == "Strakha"
  and Weapinit == 1
)
) then

playerShip.SecondaryBanks[1].WeaponClass = tb.WeaponClasses[orgWeapClass]
end


I know that code is far from perfect. But worse is: I do that "On Frame" at the moment, which sucks of course. I want to only do that when the player just triggered the cloaking.
Also there is the problem that if the player carries missiles that are smaller than the standard WCS missiles (those are all of the same size) the number is set to the maximum number of standard missiles the ship can carry. That's because when changing the ship model the number of missiles is set to the default number for a short moment before the script changes the type.

Any ideas?


EDIT: Ok, found another error.
Title: Re: scripting.html
Post by: Admiral MS on July 06, 2012, 02:48:56 pm
Quote
Is there a possibility to trigger a script even whenever a certain event in the mission becomes true? Maybe by monitoring a SEXP variable?

Create a function in LUA after
$On Mission Start:
or
$On Gameplay Start:
or whatever you want
Code: [Select]
$Application: FS2_Open
$On Mission Start:
[
function = changestuff(x)
if x=1 then
<do stuff>
...

and call that function in fred with the script-eval sexp like script-eval "changestuff(1)"

You can do it via a changing sexp-variable in Fred but that one would still require $On Frame so I think a function call out of Fred is way better.

Title: Re: scripting.html
Post by: Aginor on July 06, 2012, 02:57:11 pm
Ah thanks!

Maybe I can even change some more things in the script so I have to do less in the events. That way mission designers that want to use the Strakha don't have to include six events that have a horrible number of SEXPs in them.
Title: Re: scripting.html
Post by: Admiral MS on July 06, 2012, 03:06:29 pm
Everything you can change by using Fred events can be done within the scripting system as well. It allows you to call every possible SEXP.

And for your missile number problem:

Code: [Select]
playership.Class = tb.ShipClasses["name"]
playership.SecondaryBanks[x].WeaponClass = tb.WeaponClasses["name"]
playership.SecondaryBanks[x].AmmoLeft = number
in this order

and if it still fails you can add:
Code: [Select]
playership.SecondaryBanks[x].AmmoMax = number2
before AmmoLeft to overwrite the table setting.

If this doesn't work... in the BtA Demo and my test missions it definetly works.
Title: Re: scripting.html
Post by: Aginor on July 06, 2012, 03:16:17 pm
The problem is that I have to determine the number of missiles just before switching the models, but at the moment my script runs when the ship class has already changed (so there is already the wrong number of missiles - the maximum number - in the bank)

But maybe I have the solution for that already. I'll try that. And if it works I think I will put all the stuff into the script instead of the events. Let's see....
Title: Re: scripting.html
Post by: Admiral MS on July 06, 2012, 03:21:04 pm
Change the shipclass within the script instead of FRED and save AmmoLeft before doing that would be the obvious solution.

Code: [Select]
number = playership.SecondaryBanks[x].AmmoLeft
number2 = playership.SecondaryBanks[x].AmmoMax

playership.Class = tb.ShipClasses["name"]
playership.SecondaryBanks[x].WeaponClass = tb.WeaponClasses["name"]
playership.SecondaryBanks[x].AmmoMax = number2
playership.SecondaryBanks[x].AmmoLeft = number

And if you need a delay between the events do it in 2 different functions sharing the variables or with a delay function in LUA.
Title: Re: scripting.html
Post by: Aginor on July 06, 2012, 04:20:57 pm
Yeah, I guess I'll do that.
But first I'll have to fix my script. I somehow destroyed it during one of my last changes :D
Title: Re: scripting.html
Post by: Aginor on July 07, 2012, 08:30:40 am
Ok, most stuff is working now. I had a bit of trouble running SEXPs but the forum search helped me. I never would have guesses it is the "!". The exclamation mark is hardcoded in my brain as a negation already because it is the same in almost every programming language. And of course it isn't the negation in LUA as I had to learn.... :D

Anyway, here's my next question: Admiral MS, you were talking about a LUA delay function or something.
I searched for "delay", "sleep", and "wait" (those are the most common names for such a function in script languages) in the LUA documentation but couldn't find it yet. Can anyone point me to an example?

For those interested in my cloaking script here it is how it looks now:

in the mission there are four events that trigger the "p_CloakOrder" function and keep track of the cloaking status. The player can't cloak or decloak more often than every 5 seconds (because the cloaking and decloaking animations take three seconds), that is done by the events at the moment. The whole other stuff is done by the script below.

I'm using a ghost named cloak_ghost in the mission to store the player's damage. Is there a more elegant way?

Code: [Select]
-- ------------------------ Cloaking -----------------------------


p_CloakOrder = function(par_order)
playerShip = hv.Player

if (par_order == 1) then
p_Cloaking(0)
end

if (par_order == 2) then
p_Cloaked(0)
end

if (par_order == 3) then
p_Decloaking(0)
end

if (par_order == 0) then
p_Decloaked(0)
end

return 0
end


p_Cloaking = function(x)
mn.runSEXP("play-sound-from-table !0 !0 !0 !144")
orgWeapClass = playerShip.SecondaryBanks[1].WeaponClass.Name
orgAmmo = playerShip.SecondaryBanks[1].AmmoLeft
orgEnergy = playerShip.WeaponEnergyLeft
mn.runSEXP("ship-copy-damage !" .. tostring(playerShip.Name) .. "! !cloak_ghost!")
mn.runSEXP("change-ship-class !Strakha#Cloak! !".. tostring(playerShip.Name) .. "!")
mn.runSEXP("ship-copy-damage !cloak_ghost! !" .. tostring(playerShip.Name) .. "!")
playerShip.SecondaryBanks[1].WeaponClass = tb.WeaponClasses[orgWeapClass]
playerShip.SecondaryBanks[1].AmmoLeft = orgAmmo
playerShip.WeaponEnergyLeft = orgEnergy
mn.runSEXP("lock-primary-weapon !" .. tostring(playerShip.Name) .. "!")
mn.runSEXP("lock-secondary-weapon !" .. tostring(playerShip.Name) .. "!")
mn.runSEXP("hud-set-text !Cinfo! !    Cloaking!")
return 0
end


p_Cloaked = function(x)
orgWeapClass = playerShip.SecondaryBanks[1].WeaponClass.Name
orgAmmo = playerShip.SecondaryBanks[1].AmmoLeft
orgEnergy = playerShip.WeaponEnergyLeft
mn.runSEXP("ship-copy-damage !" .. tostring(playerShip.Name) .. "! !cloak_ghost!")
mn.runSEXP("change-ship-class !Strakha#Inv! !".. tostring(playerShip.Name) .. "!")
mn.runSEXP("ship-copy-damage !cloak_ghost! !" .. tostring(playerShip.Name) .. "!")
playerShip.SecondaryBanks[1].WeaponClass = tb.WeaponClasses[orgWeapClass]
playerShip.SecondaryBanks[1].AmmoLeft = orgAmmo
playerShip.WeaponEnergyLeft = orgEnergy
mn.runSEXP("protect-ship !" .. tostring(playerShip.Name) .. "!")
mn.runSEXP("hud-set-text !Cinfo! !    Cloaked!")
return 0
end


p_Decloaking = function(x)
mn.runSEXP("play-sound-from-table !0 !0 !0 !145")
orgWeapClass = playerShip.SecondaryBanks[1].WeaponClass.Name
orgAmmo = playerShip.SecondaryBanks[1].AmmoLeft
orgEnergy = playerShip.WeaponEnergyLeft
mn.runSEXP("ship-copy-damage !" .. tostring(playerShip.Name) .. "! !cloak_ghost!")
mn.runSEXP("change-ship-class !Strakha#Decloak! !".. tostring(playerShip.Name) .. "!")
mn.runSEXP("ship-copy-damage !cloak_ghost! !" .. tostring(playerShip.Name) .. "!")
playerShip.SecondaryBanks[1].WeaponClass = tb.WeaponClasses[orgWeapClass]
playerShip.SecondaryBanks[1].AmmoLeft = orgAmmo
playerShip.WeaponEnergyLeft = orgEnergy
mn.runSEXP("hud-set-text !Cinfo! !   Decloaking!")
return 0
end


p_Decloaked = function(x)
orgWeapClass = playerShip.SecondaryBanks[1].WeaponClass.Name
orgAmmo = playerShip.SecondaryBanks[1].AmmoLeft
orgEnergy = playerShip.WeaponEnergyLeft
mn.runSEXP("ship-copy-damage !" .. tostring(playerShip.Name) .. "! !cloak_ghost!")
mn.runSEXP("change-ship-class !Strakha! !".. tostring(playerShip.Name) .. "!")
mn.runSEXP("ship-copy-damage !cloak_ghost! !" .. tostring(playerShip.Name) .. "!")
playerShip.SecondaryBanks[1].WeaponClass = tb.WeaponClasses[orgWeapClass]
playerShip.SecondaryBanks[1].AmmoLeft = orgAmmo
playerShip.WeaponEnergyLeft = orgEnergy
mn.runSEXP("unlock-primary-weapon !" .. tostring(playerShip.Name) .. "!")
mn.runSEXP("unlock-secondary-weapon !" .. tostring(playerShip.Name) .. "!")
mn.runSEXP("unprotect-ship !" .. tostring(playerShip.Name) .. "!")
mn.runSEXP("hud-set-text !Cinfo! !    Visible!")
return 0
end
-- ---------------------------------------------------------------
Title: Re: scripting.html
Post by: m!m on July 07, 2012, 08:39:15 am
You can access and change the hitpoints of the player object using the HitpointsLeft field.

I'm not aware of any functions in LUA (which could be used in the way FSO handles lua scripts) that would work like the sleep functions in other languages.
Title: Re: scripting.html
Post by: Admiral MS on July 07, 2012, 10:32:17 am
Anyway, here's my next question: Admiral MS, you were talking about a LUA delay function or something.
I searched for "delay", "sleep", and "wait" (those are the most common names for such a function in script languages) in the LUA documentation but couldn't find it yet. Can anyone point me to an example?
I'm not aware of any functions in LUA (which could be used in the way FSO handles lua scripts) that would work like the sleep functions in other languages.
Right - there is no integrated LUA function (as far as I know it would cause the interpreter stop doing things and freeze FSO). So no easy way to delay something.

What I called a "delay function" is a workaround several scripts use. It's a function that checks how much time has passed and activates when time passed is larger than the specified delay.
Code: [Select]
$Application: FS2_Open
$On Gameplay Start: [
ammodelay = {}
delay = 1

bla = function()
...
AmmoLeft = ...
ammodelay.AmmoLeft = AmmoLeft
ammodelay.starttime = mn.getMissionTime()
end
]

$On Frame:[
if (mn.getMissionTime() - ammodelay.starttime) > delay then
    playerShip.SecondaryBanks[1].AmmoLeft = ammodelay.AmmoLeft
end
]
You can use such a delay so set some boolean variables after 5 seconds that enable or disable the cloaking functions.

Quote
I'm using a ghost named cloak_ghost in the mission to store the player's damage. Is there a more elegant way?
If you want to copy damage only it's m!m's solution with HitpointsLeft and possibly a loop through the subsystems to get their hitpoints as well. In case you want everything out of shipdata down to Shields, Energy and whatever you can get these values as well and store them - the functions might get a bit longer and complicated though.
Title: Re: scripting.html
Post by: Aginor on July 07, 2012, 12:43:32 pm
Quote
What I called a "delay function" is a workaround several scripts use. It's a function that checks how much time has passed and activates when time passed is larger than the specified delay.

Ah, ok. It is basically a state machine.
I did it similarly and now I need only two events for player cloaking.


Quote
want everything out of shipdata down to Shields, Energy and whatever you can get these values as well and store them - the functions might get a bit longer and complicated though.

I'm doing that at the moment.

Btw: Is there any possibility to get and set the energy management bars? Those are one of the things that reset when changing models. Most of the rest is already in my script now.
Title: Re: scripting.html
Post by: Nuke on July 07, 2012, 07:26:55 pm
for delays just use timestamps. some pseudocode:

timestamp = current time + how long you want it to last

if timestamp is more than current time
 do stuff
 --if we want to do this again at some interval
 timestamp = current time + how long you want it to last
end

the timestamp will be handled on the next frame that the if returns true. note that this may result in some lost time, because it will be very unlikely the code will be evaluated exactly when the timestamp expires. so if you need to do something at a regular interval, you need to subtract the current time from the timestamp right after the timestamp expires to get the overtime, then subtract this from the next timestamp.
 
Title: Re: scripting.html
Post by: Aginor on July 11, 2012, 05:21:35 pm

Hi guys!

I have another two questions:
Is there a difference between evaluateSEXP() and runSEXP() ? It is not documented but I _think_ the return values are different. Any information about that?

The other thing is this:
I want to check whether the ship in the variable "nship" has been destroyed or not and act accordingly. So I wrote
Code: [Select]
destr = mn.evaluateSEXP("is-destroyed-delay !0! !".. tostring(nship.Name) .. "!")

if (not destr) then
-- stuff --
end
But I get only an error: "can't find operator in operator list"

What am I doing wrong?
Title: Re: scripting.html
Post by: Admiral MS on July 11, 2012, 11:53:28 pm
As far as I know runSEXP() just returns whether it was able to do what it should or not.
evaluateSEXP() returns the result of the check like the name indicates  but has a slightly different syntax than runSEXP() for some reason:
Code: [Select]
result = mn.evaluateSEXP("(is-destroyed-delay !0! !"..shipname.."!)")
These functions are a good example of really bad/nonexisting documentation...
Title: Re: scripting.html
Post by: Aginor on July 12, 2012, 04:34:41 am
AH! Thanks a lot, I'll try that once I'm home.
Maybe we should really take a scripting.html from a recent build and comment all the functions, including examples, like you just did, plus common errors or things that look like they were possible with a function but aren't.

Because at the moment a scripting newbie doesn't have it easy. And I am a software developer, I can't even imagine how someone who has no programming/scripting experience yet could do scripts in FS2 based on what documentation we have.

The most useful stuff is in the wiki tutorials and (even more useful) the scripting examples, but the tutorials are very basic and you quickly reach the point where you just don't know how to actually use the functions the scripting.html tells you about. I figured most of it out after a while, but there are many people who don't even understand the error texts or the syntax description. (ok, they could be worse. At least they are not BNF :D )
Title: Re: scripting.html
Post by: Nuke on July 12, 2012, 04:48:49 am
you can edit the function descriptions in lua.cpp so that the game generates more useful instructions automatically. not sure if there is any string length limits there. you might be able to include a couple paragraphs of commentary on a thing and do a way with one liner documentation which seems to plague scripting.html (and much of the wiki). details are important. i tend to fix up any bad documentation every time i screw around in that piece of code. but i make sure i understand how something works before i start spewing out potentially wrong information. events <-> scripting interfaces are kind of a grey area for me since i really never learned how the events system works. think after over a decade of freespace modding this would have been a skill id have picked up by now. :D
Title: Re: scripting.html
Post by: Admiral MS on July 12, 2012, 02:06:01 pm
Maybe we should really take a scripting.html from a recent build and comment all the functions, including examples, like you just did, plus common errors or things that look like they were possible with a function but aren't.

Because at the moment a scripting newbie doesn't have it easy. And I am a software developer, I can't even imagine how someone who has no programming/scripting experience yet could do scripts in FS2 based on what documentation we have.

Guess what my programming experience was before starting with LUA maybe one and a half year ago :rolleyes: Don't know how many LUA functions I had to test with the good old trial and error method to see how their input syntax has to be and what they actually return or (should) do. When a forum search didn't help I had to ask like in the case of evaluateSEXP(). No one without access to and knowledge about FSO code could have figured out how it works.

So if you say
Quote
you can edit the function descriptions in lua.cpp so that the game generates more useful instructions automatically.
I start thinking something like: Huh what's this?? Where do I get this .cpp thing and how the heck do I even edit it, not break it and commit changes?

So if I could I would edit the function descriptions with a better description and even example uses for the functions that lack documentation. But as you said - how can I make sure I understand how it really works without checking the actual code and some decent C knowledge?


Complete lack of documentation gets me to another question: What the hell are hook variables, which do exist and what's the difference to normal objects/variables?
Title: Re: scripting.html
Post by: Nuke on July 12, 2012, 02:23:04 pm
that was more of a comment for the c coders in here. when somone wants a new function in scripting what you do is get the game source and edit that cpp file and add a function to fetch/write the data from c/lua to lua/c. easiest way is to copy something that does something similar and edit it to operate on the data you need. one of the arguments in this function is, go figure, the documentation that comes out in the scripting.html file. i was basicly stating that when programmers add stuff to it, that they put more than a cryptic line of information into this string. and the same goes for wiki editors who are mostly modders with a minimalist usage of words, or coders without a lot of spare time on their hands.

to be fair scripting.html seems to have pretty good reference info in it. so most of the coders have been making use of the auto-documentation feature there. and through various patches to scripting over the years it seems fairly solid. if your engine is based off of a very old branch then a lot of those scripting functions and documentation fixups just wont be there.
Title: Re: scripting.html
Post by: Aginor on July 12, 2012, 02:37:09 pm
I think we should do it this way, it ensures that everybody can help:

We take the scripting.html the E posted on page 1 of this thread (http://blueplanet.fsmods.net/E/scripting.html)
and put it into a wiki article (tbh I never worked with a wiki so I don't know how to create or edit a page, but this is a good reason to learn it I guess)
Then we can edit around in it, discuss, and when we have some descriptions someone (meaning someone who knows how not to break the CPP file) has to just take the stuff and put it into the file.
That's not much work but a huge improvement of the documentation.

Any objections? If not: Someone has to tell me how creating a wiki account works. Now!
Title: Re: scripting.html
Post by: Nuke on July 12, 2012, 03:05:13 pm
at least that way you dont have to be a coder to fix documentation shortcomings. so long as our documentation quality is smack dab in between totally vague and outright wankery (like linux man pages).
Title: Re: scripting.html
Post by: Admiral MS on July 12, 2012, 03:28:42 pm
Taking the scripting.html to Wiki and edit it there sounds like a good idea. I guess I should create an account there as well and learn how a wiki works.

Quote
to be fair scripting.html seems to have pretty good reference info in it. so most of the coders have been making use of the auto-documentation feature there. and through various patches to scripting over the years it seems fairly solid. if your engine is based off of a very old branch then a lot of those scripting functions and documentation fixups just wont be there.
Without scripting.html it would have been impossible for me to create any useful script and fortunately a lot of functions (especially newer ones or ones that have been edited recently) do have a proper description in there.
Title: Re: scripting.html
Post by: Aginor on July 12, 2012, 03:36:42 pm
Ok, then let's do this!
(and hey, Linux man pages are cool!)


Another question related to my scripting problems:
When a ship is destroyed, does it get erased from the Ships[] array or does it stay in? If it is erased: Do the rest of the indices stay the same? Same goes for a ship that is spawned later. Is it in the array all the time (like in the mission file where it has an index already of course) or is mn.Ships[] only an array of ships that are active in the mission at the moment?

I'm asking because I did a loop through the Ships array and use the ship name at the index i for my other array. And somehow my function doesn't work anymore as soon as one ship in the mission is destroyed...
Title: Re: scripting.html
Post by: Admiral MS on July 12, 2012, 05:00:27 pm
It gets removed a bit later or I wouldn't have to do this one:
Code: [Select]
if (ship:isValid() and (ship:hasShipExploded() == 0)) then It is still within Ships[] during most of the explosion part.

When it is done exploding, has warped out or is vanished it gets removed from Ships[] and all the other ships may get a different index number. Same may happen when new ships arrive.
So mn.Ships[] is only an array of what is currently active in the mission and every index number up to the number of ships in mission represents one of them. If you need a specific ship save its name rather than its index number and use mn.Ships[shipname].
Title: Re: scripting.html
Post by: Nuke on July 12, 2012, 05:39:34 pm
i should also point out that therews
Ok, then let's do this!
(and hey, Linux man pages are cool!)

the idea is cool, the writing talen of those that fill them in, not so much. linux documentation i find is an atrocious read at best.

Quote
Another question related to my scripting problems:
When a ship is destroyed, does it get erased from the Ships[] array or does it stay in? If it is erased: Do the rest of the indices stay the same? Same goes for a ship that is spawned later. Is it in the array all the time (like in the mission file where it has an index already of course) or is mn.Ships[] only an array of ships that are active in the mission at the moment?

I'm asking because I did a loop through the Ships array and use the ship name at the index i for my other array. And somehow my function doesn't work anymore as soon as one ship in the mission is destroyed...

use the ship:isValid() function to determine if the handle is still good. i think when a ship is destroyed the handle is marked as invalid. i could be mistaken though. almost all the object handles have this feature so use it when you cant be sure about the validity of something.
Title: Re: scripting.html
Post by: Aginor on July 12, 2012, 06:11:03 pm
Ah thanks, that makes it a bit more clear.

...but it seems like I have destroyed my script completely now :D
I'll need some precise help on the following topic:  (I guess I didn't get the meta thing completely after all)


I want to create a list (table? array?) of ships that are capable of cloaking. I'll trigger a function that creates that list based on the ship class at the start of the mission.
I also need the information when the ship last cloaked, when it last decloaked, and what its cloaking state is now (visible =0, cloaking=1, cloaked = 2, decloaking=3)

Then I want to loop through those ships every frame to check whether each ship was cloaking for three seconds and set it to cloaked.
The same goes for decloaking. three seconds later it is cloaked.

I had that working already with single variables for each ship (so you could only have 4 cloakable ships you knew the names of) but I just don't get it to work now.

Take your time, I'll go to bed now. It is 01:00h here and my boss wants me to work tomorrow :D
Title: Re: scripting.html
Post by: Nuke on July 12, 2012, 06:38:05 pm
you can call ship:getSignature() to get a unique neumeric identifier for that ship. id suggest iterating through the ships. get the signature and then look inside a table to see if it has a key with that value, if it doesnt, then create it (init your list, set default values for sutt, etc) and add it to the table, otherwise pull up the data which was saved on a previous loop. it does help to clean up the table periodically. iterate through it (use a k,v in pairs() loop because the values probibly wont be in sequential order and there will be gaps) look up the objects the table key with mn.getObjectFromSignature(), test if its valid, if it is skip it, otherwise set that table key to nil, this will allow it to be garbage collected. i tend to do this every 10 or so seconds.
Title: Re: scripting.html
Post by: Alan Bolte on July 12, 2012, 09:54:32 pm
I think we should do it this way, it ensures that everybody can help:

We take the scripting.html the E posted on page 1 of this thread (http://blueplanet.fsmods.net/E/scripting.html)
and put it into a wiki article (tbh I never worked with a wiki so I don't know how to create or edit a page, but this is a good reason to learn it I guess)
Then we can edit around in it, discuss, and when we have some descriptions someone (meaning someone who knows how not to break the CPP file) has to just take the stuff and put it into the file.
That's not much work but a huge improvement of the documentation.

Any objections? If not: Someone has to tell me how creating a wiki account works. Now!
Go to the Freespace Wiki. Click sign in in the upper right. Create an account. Go to, e.g., the scripting.tbl page (http://www.hard-light.net/wiki/index.php/Scripting.tbl). Click 'edit' at the top of the page. The syntax should be easy enough to learn if you can learn lua. To create a new page, your best bet would be to create a link from an established page like that one to a page that doesn't yet exist, then follow that link.

I'd be very grateful if those in-the-know could expand on the existing hook descriptions and improve upon scripting.html. For example, I see that in January zookeeper listed 'on turret fired' as a 3.6.15 feature, but it shows up in the scripting.html posted above, which identifies itself as produced by a 3.6.13 build. Does that mean the feature exists, but isn't yet ready? Or is the wiki page out of date? Furthermore, while i see a hook variable for the ship as a whole, I'm not clear on whether I can use that to tell which turret was fired. I suppose I could run through the whole ship using hasFired() but I don't know if  that would fit for every use case I might come up with.

Anyway, I don't mean to derail Aginor's thread with my questions, I just wanted to give an example of what another scripting noob would find helpful.
Title: Re: scripting.html
Post by: Aginor on July 13, 2012, 05:47:04 am
Thanks for your explanation, Nuke!
it does help to clean up the table periodically. iterate through it (use a k,v in pairs() loop because the values probibly wont be in sequential order and there will be gaps)
Ah! I think that's what I did wrong. At least it would explain the errors.


@Alan Bolte:
Ok, thanks. I think we should call the page "scripting functions" and also redirect to it if someone searches for scripting.html, because the page will basically look like a scripting.html (but hopefully better documented :D )
Title: Re: scripting.html
Post by: Nuke on July 13, 2012, 07:36:21 am
thats why the generic loop format exists. to accomidate the potentially wonkyness that comes with non-sequential use of indices, named keys get iterated through as well. you also can define your own iterator function here to make your loop smarter, but most of the time pairs() just works fine.
Title: Re: scripting.html
Post by: Aginor on July 13, 2012, 07:54:52 am
Ok guys, I just created a page in the wiki. It is called "Scripting functions" and one page already links to it (scripting.tbl)

And before you read it: YES, it looks like crap. And YES, it is only a scripting.html C&P'd into the wiki. And YES, I don't have any clue how work on a wiki normally goes. Free feel to correct me.
EDIT: Also I'm not a design guy. So I would be happy if someone else did that kind of stuff with hierarchy and hints in pretty green boxes and warnings in red and such stuff. Also I think the hierarchy is broken. There are suddenly boxes randomly around stuff in the page. I think it is because of the empty lines or something....

I just wanted to have a point where we could start from. To prove I'm not only talking but actually doing something. Now we can start editing the hell out of this thing.

Here it is:
http://www.hard-light.net/wiki/index.php/Scripting_functions
preparing for edit war / ****storm now :D
Title: Re: scripting.html
Post by: Aginor on July 13, 2012, 01:22:42 pm
Ok, sorry for asking again, but I'm stuck somehow. Here's my code:

at mission start a event calls the following function:
Code: [Select]
p_InitCloakTimers = function(x)

-- set everything to null
naCloakableShips = {} -- table that contains cloakable ships. Index is the Signature, value is the name
naCloakingTimers = {} -- cloaking timer table. Index is the Signature, value the time when the ship cloaked
naDecloakingTimers = {} -- decloaking timer table. Index is the Signature, value the time when the ship decloaked
naCloakStatus = {} -- Status. 0=visible, 1=cloaking, 2=cloaked, 3=decloaking

--loop through ships, get their names and signatures
for i=1, #mn.Ships do
i_ship = mn.Ships[i]
ishipName = tostring(i_ship.Name)
nshipSig = i_ship:getSignature()
-- if they are cloakable (only Strakha for now) set their status and add them to the CloakableShips list
if (i_ship.Class.Name == "Strakha") then
naCloakableShips[nshipSig] = ishipName
naCloakingTimers[nshipSig] = 0
naDecloakingTimers[nshipSig] = 0
naCloakStatus[nshipSig] = 0
end
end

PlayerCloakable = 1 -- I should rename this variable, it has nothing to do with the player

-- HUD color for player cloaking
orgHUDR, orgHUDG, orgHUDB = hu.getHUDGaugeColor(9) -- get HUD colors on mission start
end



The CloakOrder function triggers the cloaking functions based on the first parameter,
the ship name is the second one. Orders 1 and 3 are called by key-pressed events, and they work.
The other two are triggered OnFrame (see code further below)
Code: [Select]
p_CloakOrder = function(par_order, nship)
destr = mn.evaluateSEXP("(is-destroyed-delay !0! !".. nship .. "!)")
nshipSig = mn.Ships[nship]:getSignature()

if (not destr) then

if (par_order == 1) then
p_Cloaking(nship)
naCloakingTimers[nshipSig] = mn.getMissionTime()
naCloakStatus[nshipSig]  = 1
end

if (par_order == 2) then
p_Cloaked(nship)
naCloakStatus[nshipSig]  = 2
end

if (par_order == 3) then
p_Decloaking(nship)
naDecloakingTimers[nshipSig] = mn.getMissionTime()
naCloakStatus[nshipSig]  = 3
end

if (par_order == 0) then
p_Decloaked(nship)
naCloakStatus[nshipSig]  = 0
end
end

return 0
end



The following function should check whether a ship is cloaking or decloaking for 3 seconds,
change the status to cloaked and trigger the cloak functions 2 and 0. The cloak functions themselves work

Code: [Select]
$On Frame:
[
if PlayerCloakable == 1 then
-- here I loop through my table of cloakable ships to see whether the cloaking or decloaking timers have reached 3 already
for i_shipSig,i_shipName in pairs(naCloakableShips) do
o_ship = mn.getObjectFromSignature(i_shipSig)
if ((i_shipname ~= nil) and (o_ship:isValid()) and (o_ship:hasShipExploded() == 0)) then
if ((mn.getMissionTime() - naCloakingTimers[i_shipSig]) == 3 and naCloakStatus[i_shipSig] == 1) then
p_CloakOrder(2, i_shipName)
elseif ((mn.getMissionTime() - naDecloakingTimers[i_shipSig]) == 3 and naCloakStatus[i_shipSig] == 3) then
p_CloakOrder(0, i_shipName)
else
end

end
end
end
]



I can't find the error. The ships start cloaking when I press the key, and go to decloaking when I press it again,
but they are never cloaked or decloaked. So they newer reach CloakStatus 0 or 2 again.
So I think the first or last block I posted is the problem.

Take your time, I'll work on my campaign missions in the meantime. :)
Title: Re: scripting.html
Post by: Admiral MS on July 13, 2012, 03:39:43 pm
Code: [Select]
mn.getMissionTime() - naCloakingTimers[i_shipSig]) == 3Well this one will never get true unless you are really lucky. Mission time is exact down to a lot of decimal places.
Do it like this:
Code: [Select]
mn.getMissionTime() - naCloakingTimers[i_shipSig]) > 3and add a true/false variable that is true after the initial cloaking/decloaking and is set false when the second event is activated to prevent repeated activation.
Title: Re: scripting.html
Post by: Aginor on July 13, 2012, 05:57:42 pm
Ah, ok. I thought missionTime was like in FRED, an integer value. This part of the code is a remnant of the time when I did the whole thing by events.
The repeated activation should be no problem I think, since the CloakStatus is immediately set by the function p_Cloak order when it is activated.

I'll try it tomorrow, though. Gotta go to bed now.
Thanks for your help!
Title: Re: scripting.html
Post by: Nuke on July 13, 2012, 06:16:31 pm
lua doesnt understand integers unfortunately
Title: Re: scripting.html
Post by: Aginor on July 14, 2012, 06:26:58 am
I changed the time thing. But it didn't change the bahaviour. But then I corrected a wrong-case variable name and now it works better.
...better meaning I was back to the situation where everything worked until a ship in the mission is destroyed. As soon as that happens the cloaking was broken.


...and then I realized I am indeed an idiot. Maybe I should read what I write for a change. It happens every time a ship dies. MAYBE it has something to do with what I do OnDeath!
I have a small script that checks OnDeath if it is the player who dies. If he is the script sets the HUD color back to the original one (otherwise it could happen that when a player dies while cloaked the black&white HUD color I use as a cloaking indicator stays.
In that part of the script I used a variable in the wrong IF block. It was set to zero everytime some ship was killed. I corrected it and now the script seems to work :)

I still have a bug though, maybe there is a scripting way to do this:
When the player is using the afterburner and then hits the cloaking button the afterburner sound loops until the player hits the afterburner again. I assume this is a sound thing since there is also a cloaking sound. Maybe they interfere with each other. Does anyone know a solution for that? (except locking the afterburner of course.)