Jump to content

Tutorial: Introduction to Lua scripting


Recommended Posts

I understand what you are trying to do, but every event handler you create will receive every, all, and the same events. You don't get to choose that this event handler only receives events from say UnitA and that event handler from UnitB.


Edited by ajax
Link to comment
Share on other sites

Let's say eventhandler1 checks "world.event.S_EVENT_HIT" if group A (initiator) shot at group B (target). Then eventhandler2 checks "world.event.S_EVENT_HIT" if group C shot at group D. No reason that those can't run concurrently right?

 

My desire is to simply make the number at the end of "eventhandler" dynamic based on a variable passed through the defining function. The groups defined in each event handler are defined within separate functions, thus the desire to not jam all the variables into a single event handler.

Link to comment
Share on other sites

You can do that in one event handler -

local eHandler = {}
local groupAhit = {}
local groupDhit = {}

function eHandler:onEvent(e)
if e.id == world.event.S_EVENT_HIT and Object.getCategory(e.initiator) == Object.Category.UNIT then
 local Igroup = e.initiator:getGroup()
 local IgroupName = Igroup:getName()
 local Tgroup = e.target:getGroup()
 local TgroupName = Tgroup:getName()
 if IgroupName = "groupA" and TgroupName = "groupB" then
  groupAhit[#groupAhit + 1] = TgroupName
 elseif IgroupName = "groupC" and TgroupName = "groupD" then
  groupDhit[#groupDhit +1] = TgroupName
 end
end
end


world.addEventHandler(eHandler)

 

 

 

I've just written this quickly, there must be better ways but this code will do what you wanted with one event handler and put the hit group name into 2 different tables which you can use later to do whatever.


Edited by xcom
Link to comment
Share on other sites

Thanks guys. I might find a way to make it work that way, but will easily have 50+ if-thens in one function to cover all variations, if not more. Thus the desire for dynamic naming of the function. I also want the group variations to be automatically added if I add more to the miz (drag/drop a single function to cover all this) rather than now having multiple functions to edit when I do.

Link to comment
Share on other sites

"Mine is not to reason why..."

This code builds a function on-the-fly with a programmatically generated name:

 

[font=Courier New]-- build the name
local i = 1
local fname = "BlueHandler"..i

-- define function as string, making substitutions into string
local funcStr = fname..[[ = function(txt) ]]..[[ env.info("function name = ]]..fname..[[ passed text = "..txt) end ]]

f = loadstring(funcStr)
f()
if f then
   env.info("f is loaded")
   _G[fname]("called function") -- call the new function
else
   env.info("f did not load")
end
[/font]

Tested in DCS -- works fine.

 

DCS.log output:

 

[font=Courier New]03150.082 INFO    SCRIPTING: f is loaded
03150.082 INFO    SCRIPTING: function name = BlueHandler1 passed text = called function[/font]

Here is a test mission with the script.

 

Edit:

 

Added a little bit more to prove it accepts "BlueHandler1":

 

Inserted this line:

[font=Courier New]if f then
   env.info("f is loaded")
   _G[fname]("called function")
[color=Red]    _G["BlueHandler1"]("part 2")[/color]
else
   env.info("not f")
end
[/font]

Log output:

[font=Courier New]06016.399 INFO    SCRIPTING: f is loaded
06016.399 INFO    SCRIPTING: function name = BlueHandler1 passed text = called function
06016.399 INFO    SCRIPTING: function name = BlueHandler1 passed text = part 2
[/font]

Edit2:

The f() statement should be moved into the if block. And additional error checking should be done.

[font=Courier New]f = loadstring(funcStr)
if f then
   [/font][font=Courier New][font=Courier New][color=Red]f()[/color]
[/font]    env.info("f is loaded")
   _G[fname]("called function") -- call the new function
else
   env.info("f did not load")
end
[/font]

dynFunctionNameTest.miz


Edited by ajax
Link to comment
Share on other sites

Even though it is technically possible to do what you want to do (see previous post), I have to say that I think you're setting yourself up for some major headaches.

 

If you really want to be able to reference functions programmatically, I think I would try something like this:

 

[font=Courier New]-- define your event-handler functions, the names can be 'dummy' names
function dummyFunction1(eventdata) ... end
function dummyFunction2(eventdata) ... end, etc.

-- then set up a table of functions using meaningful names as table indexes
eventFunctions = {}
eventFunctions["blueHandler1"] = dummyFunction1
eventFunctions["blueHandler2"] = dummyFunction2, etc.

-- then in your code build a function reference string as you indicated you wanted to do
-- the end result needs to match one of the function table indexes
local functionIndex = 2
local functionCoalition = 'blue'
local functionToCall = functionCoalition.."Handler"..functionIndex

-- then call the function if needed, not that you would ever do this with an event handler, just showing how it would be done if it were a regular function.
eventFunctions[functionToCall](args)

-- or assign as eventHandler
[/font][font=Courier New]world.addEventHandler(eventFunctions[functionToCall])

[/font]

Edit:

I think the functions used for event handlers will require a slightly different form, i.e. dummyFunction1:onEvent() but the concept is the same.


Edited by ajax
Link to comment
Share on other sites

Going back to a single event handler, you could make things cleaner by subdividing the tasks into logical groups and do something like:

 

[font=Courier New]eventHandler:onEvent(eventdata)
   if checkBlueShoot(eventdata) then return end
   if checkRedShoot(eventdata) then return end
[/font][font=Courier New][font=Courier New]    if checkBlueHit(eventdata) then return end
[/font][/font][font=Courier New][font=Courier New][font=Courier New]    if checkRedHit(eventdata) then return end
   -- etc.
[/font][/font]end
[/font]

 

Each of those functions would return either true or false depending on whether the event applies to it or not. If the event does not apply, the function wouldn't do anything, just return false and the event handler continues to the next check. If true then the function would do your tasks, then return true and the event handler terminates.

Link to comment
Share on other sites

  • 3 weeks later...

Trying to select an element of a table and then remove that element so it can't be selected again. Trying to do this by key and not position, as position within the table is irrelevant. So I've read that I need to set the key to "= nil", which is the same as removing it...but not working.

 

When I run the function below repeatedly, the selected element is not removed nor does the total # reduce. Any tips? As a work-around, I suppose I could use "table.remove" but would need to know the position of a key within the table, which I don't know how to get either. :D

 

test = {'T1', 'T2', 'T3', 'T4', 'T5'}

function PickOne()
local Total = #test
local TestFlag = test[math.random(Total)]
trigger.action.setUserFlag(TestFlag, true)
trigger.action.outText('Selected = ' .. TestFlag .. ',    ' .. Total .. ' are remaining', 5)
test['' .. TestFlag .. ''] = nil
end

Link to comment
Share on other sites

test = {'T1', 'T2', 'T3', 'T4', 'T5'}  

function PickOne()   
       local theFamousIndexUWant2know = math.random(#test)
       local TestFlag = test[theFamousIndexUWant2know]
       trigger.action.setUserFlag(TestFlag, true)
       trigger.action.outText('Selected = ' .. TestFlag .. ',    ' .. Total .. ' are remaining', 5)
      test['' .. TestFlag .. ''] = nil --  remove item at theFamousIndexUWant2know instead
end


Edited by galevsky06
Link to comment
Share on other sites

  • 3 months later...

Mhh...a question jump into my brain.....in the script above I rea several built-in functions...like trigger.action.outText or trigger.action.setText...the question is:

is there a list of all in-game buil-in function?

Thanks

Link to comment
Share on other sites

Mhh...a question jump into my brain.....in the script above I rea several built-in functions...like trigger.action.outText or trigger.action.setText...the question is:

is there a list of all in-game buil-in function?

 

There's one in the ED Wiki and a more up-to-date version in the Hoggit Wiki: http://wiki.hoggit.us/view/Simulator_Scripting_Engine_Documentation :thumbup:

 

I don't know how comprehensive those lists are, but I think they're the most complete ones available to us.

Link to comment
Share on other sites

  • 4 months later...

Professor-Farnsworth.png

 

Just like to pop in and let ya guys know that I've finally gotten around to a massive re-organizing of the scripting engine wiki. I was kinda sick of everything being in two unwieldy pages. So I split it up into a lot of smaller ones. There is still plenty left to do, but I hope to get basic pages for all functions and other necessary documentation completed over the next few days. That said there is lots of smaller data that needs to get updated. Namely code examples and returned values examples. So if anyone wants to add some examples, that would be really helpful.

 

The link is the same as before. Thats one thing you gotta love about wikis. :)

 

http://wiki.hoggit.us/view/Simulator_Scripting_Engine_Documentation

  • Like 1

The right man in the wrong place makes all the difference in the world.

Current Projects:  Grayflag ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Link to comment
Share on other sites

Thanks a lot!

ChromiumDis.png

Author of DSMC, mod to enable scenario persistency and save updated miz file

Stable version & site: https://dsmcfordcs.wordpress.com/

Openbeta: https://github.com/Chromium18/DSMC

 

The thing is, helicopters are different from planes. An airplane by it's nature wants to fly, and if not interfered with too strongly by unusual events or by a deliberately incompetent pilot, it will fly. A helicopter does not want to fly. It is maintained in the air by a variety of forces in opposition to each other, and if there is any disturbance in this delicate balance the helicopter stops flying; immediately and disastrously.

Link to comment
Share on other sites

  • 3 weeks later...

Ok, all basic pages are added now. Also expanded the mission editor specific stuff.

 

Trigger Conditions

Trigger Actions

 

Please Please Please add examples. Its an area that I only added content for when it was straight forward enough to do so or I already had readily available. The goal was to create all of the pages with details matching what was on the two master pages created by Saint and organize them accordingly. Stuff like examples will get added in due time. In the mean time I'm gonna take a bit of a break from heavy editing.

 

Two useful links:

List of Functions

List of Tasks

List of Events

  • Like 1

The right man in the wrong place makes all the difference in the world.

Current Projects:  Grayflag ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Link to comment
Share on other sites

  • 3 months later...

Quick performance related question, had an idle moment at work and thinking about CAPGCI improvements that I might be sufficiently lua skilled to do went googling after running the code inspection part of pycharm over the script. One of the thing it flagged was the large numbers of global variables and google info seemed to agree that because the global vars are stored in some sort of high level hash table the script performance is reduced because it has to access the hash table before using the variable.

 

My question is - would this generate decent performance returns for not too much effort other than some analysis to determine which variables really need to be global? It sounds like it might but wondered if some lua guru's would tender some helpful feedback if they have time?

 

Thanks,

Stonehouse

Link to comment
Share on other sites

My question is - would this generate decent performance returns for not too much effort other than some analysis to determine which variables really need to be global? It sounds like it might but wondered if some lua guru's would tender some helpful feedback if they have time?

 

Obviously depends on what all is being processed and how its processed, but local variables can help out a TON. It even helps to make a local reference of a global variable if you reference it more than once. Mist does this in a few spots, most notable is updating the alive units table.

 

My rule of thumb is to only have what is absolutely necessary to be global. Everything else is local, even if its just local to the whole script. That way if you need to access it globally, just have a global function at the same level as the local variable.

The right man in the wrong place makes all the difference in the world.

Current Projects:  Grayflag ServerScripting Wiki

Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread)

 SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...