Jump to content

MOOSE - Mission Object Oriented Scripting Framework


Recommended Posts

G'day everyone, I am trying to make a mission with infinitely respawing air and ground units, but I am unable to even get MOOSE to load instead I am presented with a mission script error informing me that a nil value was uncovered whilst trying to index global, I am using a standard version of Moose with the Beta branch of DCS, is this possible the problem?

Link to comment
Share on other sites

you did not include the moose.lua that Hardcad provided. Just open your miz file with e.g. winrar and check l10n/DEFAULT/ folder the moose.lua in there is the dynamic version thats used for development.

 

simply delete the trigger in your mission file in the mission editor that loads moose, and re-add the trigger pointing to the file that Hardcard linked and it will work. Verify the correct file directly in your mission file.

Link to comment
Share on other sites

  A2ADispatcher:SetSquadron( "Stennis","unit name of the carrier in ME", { "ALERT 5" }, 20 )   

 

Hardcard,

 

This worked like a champ! Thanks for the help!

[sIGPIC][/sIGPIC]

Primary Computer

ASUS Z390-P, i7-9700K CPU @ 5.0Ghz, 32GB Patriot Viper Steel DDR4 @ 3200Mhz, ZOTAC GeForce 1070 Ti AMP Extreme, Samsung 970 EVO M.2 NVMe drives (1Tb & 500 Gb), Windows 10 Professional, Thrustmaster Warthog HOTAS, Thrustmaster Warthog Stick, Thrustmaster Cougar Throttle, Cougar MFDs x3, Saitek Combat Rudder Pedals and TrackIR 5.

 

-={TAC}=-DCS Server

Gigabyte GA-Z68XP-UD3, i7-3770K CPU @ 3.90GHz, 32GB G.SKILL Ripjaws DDR3 @ 1600Mhz, ZOTAC GeForce® GTX 970.

Link to comment
Share on other sites

@Cyclonictank

 

Aside from what EntropySG said, I don't recommend writing your scripts directly in ME.

Use either Notepad++ or LDT to write your scripts for DCS (I recommend LDT because it has intellisense).

 

explaining how to set yourself up.

 

 

As for the script itself, you could do this for each group you want to respawn in your mission (these groups must be set to late activation in ME. Modify coloured fields according to your mission needs):

 

 

local SpawnGroup = SPAWN:New("Name of the late activated group in ME"):InitLimit(maximum number of units in the group allowed to exist at any one time , total number of times the group will be spawned)

:SpawnScheduled(spawn scheduler interval in seconds , 1 )

 

 

The script will spawn the units in the group (up to the specified maximum number and provided they aren't already present on the map) every time the spawn scheduler runs.

If the maximum amount of units in that group is already present on the map, none will spawn.

When all units in that group are destroyed, new ones will spawn the next time the spawn scheduler runs (this will go on as many times as you specify)


Edited by Hardcard
Link to comment
Share on other sites

That's weird :huh:

 

Did you do it like this?

 

SPAWNSET = SET_GROUP:New()
:FilterPrefixes({"GRP1-", "GRP2-", "GRP3-"})
:FilterStart()

 

Hey I tried again and it worked as you said...probably I inserted some typo in my first try.

 

this is for sure a better solution.

 

thank you again!

Link to comment
Share on other sites

Has Moose been updated to reflect final Persian Gulf Airports?

[sIGPIC][/sIGPIC]

Primary Computer

ASUS Z390-P, i7-9700K CPU @ 5.0Ghz, 32GB Patriot Viper Steel DDR4 @ 3200Mhz, ZOTAC GeForce 1070 Ti AMP Extreme, Samsung 970 EVO M.2 NVMe drives (1Tb & 500 Gb), Windows 10 Professional, Thrustmaster Warthog HOTAS, Thrustmaster Warthog Stick, Thrustmaster Cougar Throttle, Cougar MFDs x3, Saitek Combat Rudder Pedals and TrackIR 5.

 

-={TAC}=-DCS Server

Gigabyte GA-Z68XP-UD3, i7-3770K CPU @ 3.90GHz, 32GB G.SKILL Ripjaws DDR3 @ 1600Mhz, ZOTAC GeForce® GTX 970.

Link to comment
Share on other sites

I'm having a try at working with unit class but I have lot of difficulty clearly understanding the classes documentation when there are limited examples...

 

 

I'd like a client be able to call the carrier via F10 command and get its BRC...

here's my script so far:

 

carrier = Unit.getByName("Stennis")

local function getCarrierPosition()
 carrierPos = carrier:getPosition()
 posMessage = MESSAGE:New(carrierPos,25,nil,true):ToAll()
end

MenuTop = MENU_COALITION:New( coalition.side.BLUE, "Stennis" )
MenuPosition = MENU_COALITION_COMMAND:New( coalition.side.BLUE, "Position", MenuTop,getCarrierPosition)

 

issue #1: the script return nothing and from the logs I get a Moose error...I also tried with calling a single value of the "carrierPos" table as "carrierPos[0]" but it doesn't work...

It is clear I don't understand how the position structure works...

 

issue #2: I'd like to address the message only to the client actually asking for it but I don't know how to do it and I'd like to keep it free of specific group naming criteria if possible (due to the fact the mission will be used for multiplayer)

 

for the moment thanks in advance...I will probably need help to understand how getting the orientation of the carrier (heading) from the Position table...

Link to comment
Share on other sites

@Mano

 

At first glance, there's a clear problem in the following part:

 

carrierPos = carrier:getPosition()
posMessage = MESSAGE:New([color="Red"]carrierPos[/color],25,nil,true):ToAll() 

 

MESSAGE:New() requires a string as first parameter, but you're giving it :getPosition() instead.

 

:getPosition() doesn't return a string, it returns a table which contains a position + orientation tables:

 

Position3 = {
p = {x = number, y = number, z = number}, [color="blue"]-- Position subtable[/color]
x = {x = number, y = number, z = number}, [color="blue"]-- X axis orientation subtable[/color]
y = {x = number, y = number, z = number}, [color="blue"]-- Y axis orientation subtable[/color]
z = {x = number, y = number, z = number} [color="Blue"]-- Z axis orientation subtable[/color]
}

 

Now, if you want to get the x y z coordinates of your unit relative to the map's origin, then you'll need to access the x y z values within the p subtable, like this:

 

 

carrierPos = carrier:getPosition()

posMessage = MESSAGE:New("Carrier X = ".. carrierPos.p.x .."\nCarrier Y = ".. carrierPos.p.y .."\nCarrier Z = ".. carrierPos.p.z ,25,nil,true):ToAll()

 

 

If you want to get the carrier's orientation instead, you'll need to access the x y z subtable values by navigating through the indices using single dots, as shown in the spoiler code

(Ignore the double dots .. , those are used for concatenation of strings and variables within the body of the message)

 

 

Regarding the message recipient, DCS doesn't allow for messages to be sent to individual units/clients. The best you can do is send the message to the client's group (I think there are ways of making it work even in multiplayer).

 

 

As for getting the heading of the carrier, you can use :GetHeading(), no need to mess with the position + orientation tables (they won't tell you the carrier's heading anyway).


Edited by Hardcard
Link to comment
Share on other sites

@Mano

 

If you want to get the carrier's orientation instead, you'll need to access the x y z subtable values by navigating through the indices using single dots, as shown in the spoiler code

(Ignore the double dots .. , those are used for concatenation of strings and variables within the body of the message)

 

As for getting the heading of the carrier, you can use :GetHeading(), no need to mess with the position + orientation tables (they won't tell you the carrier's heading anyway).

 

Thank you again Hardcard for your unvaluable help.

 

So, the first hint works and I get the p.x, p.y and p.z . But as you commented they are quite useless for my scope.

 

I tried the GetHeading() method but apparently it doesn't work. Maybe is required a very recent version of Moose? I'm running with the 2.4.13. Indeed I don't have any suggestion for that method from intellisense...

 

My code is:

local function getCarrierPosition()
 -- carrierPos = carrier:GetHeading()
 posMessage = MESSAGE:New(carrier:GetHeading(),25,nil,true):ToAll()
end

 

However I get this error from the logs:

2019-04-19 22:48:09.753 INFO SCRIPTING: MOOSE error in MENU COMMAND function: [string "C:\Users\Mano\AppData\Local\Temp\DCS.openbeta\/~mis0000768D.lua"]:7: attempt to call method 'GetHeading' (a nil value)

2019-04-19 22:48:09.753 INFO SCRIPTING: stack traceback:

[string "C:\Users\Mano\AppData\Local\Temp\DCS.openbeta\/~mis00005001.lua"]:7602: in function 'GetHeading'

[string "C:\Users\Mano\AppData\Local\Temp\DCS.openbeta\/~mis0000768D.lua"]:7: in function <[string "C:\Users\Mano\AppData\Local\Temp\DCS.openbeta\/~mis0000768D.lua"]:5>

(tail call): ?

[C]: in function 'xpcall'

[string "C:\Users\Mano\AppData\Local\Temp\DCS.openbeta\/~mis00005001.lua"]:7613: in function <[string "C:\Users\Mano\AppData\Local\Temp\DCS.openbeta\/~mis00005001.lua"]:7609>

2019-04-19 22:48:12.972 INFO Lua: Lua CPU usage: metric: average mission execution: 3.5589 %


Edited by Mano
Link to comment
Share on other sites

Hi Mano, many things to fix here,

 

 

First when grabbing object from Moose Wrapper (eg UNIT, GROUP, AIRBASE +++) classes you will use the FindByName(). For Unit that will be units name in Mission Editor (ME)

 

 

So to grab carrier your call:

carrier = UNIT:FindByName("Stennis")

So now you have the carrier as a Wrapper.Unit#UNIT object which you can use.

 

 

Next you have built a function which will be called from a menu object, fine. However you are using the GetPosition (with lower G which prob will return nothing) which will return a table with x,y,z values which is probably not what you want.

 

 

 

However Moose provides a CLASS called point which is very handy. If you rather call for it coordinates, you can us

 carrierPos = carrier:GetCoordinate()

Now when you look into docs for Core.Point, you see you have many option. the COORDINATE object which you now have can give you useful text, if you look at function starts with ToString (See).

 

As I understand your issue, you want BRC text, and I assume that is Bearing, Range and Course, from the user. So when generating a text like that you need to know the players location as well. However, I will not go into that now. So since this is called colation wide, it makes more sense to give position in BULLS with

carrierPos = carrier:GetCoordinate():ToStringBULLS(coalition.side.BLUE)

, which returns a string.

 

 

So get carriers heading in string format

arrierHeading = string.format ("Heading: %i", carrier:GetHeading())

Concatenate the two string to something like

Message = carrierPos .. " " .. carrierHeading

And now you have a string you can wrap into a message like

 posMessage = MESSAGE:New(Message,25,nil,true):ToAll()

You can try this as code, and see if that gets your further:

 

 

carrier = UNIT:FindByName("Stennis")

local function getCarrierPosition()
 local carrierPos = carrier:GetCoordinate():ToStringBULLS(coalition.side.BLUE)
 local carrierHeading = string.format ("Heading: %i", carrier:GetHeading())
 local Message = carrierPos .. " " .. carrierHeading
 posMessage = MESSAGE:New(Message,25,nil,true):ToAll()
end

MenuTop = MENU_COALITION:New( coalition.side.BLUE, "Stennis" )
MenuPosition = MENU_COALITION_COMMAND:New( coalition.side.BLUE, "Position", MenuTop,getCarrierPosition)

But again if you want Bearing and Range stuff you need to grab players location, then perhaps better use MENU_GROUP and send group (sender) as argument to function. Then you can calculate BRC text.

 

 

Hope this help. I have NOT TESTED the code though. Also plz join our Discord channel for further help

 

 

Regards

 

 

Wingthor

Link to comment
Share on other sites

@Mano

 

Sorry, I focused so much on the Position3 table explanation that I forgot to mention what Wingthor pointed out at the beginning.

 

:GetHeading() is a MOOSE method, only compatible with certain MOOSE classes (in this case, UNIT class), whereas Unit.getByName() is a DCS class + method which returns an incompatible DCS object.

 

Always pay attention to the kind of classes and methods you're using.

 

DCS classes require DCS methods (and vice versa), MOOSE classes require MOOSE methods (and vice versa):

 

Unit.getByName() -- DCS class + DCS method :thumbup:

 

UNIT:FindByName() -- MOOSE class + MOOSE method :thumbup:

 

Unit:FindByName() -- DCS class + MOOSE method :mad:

 

UNIT.getByName() -- MOOSE class + DCS method :mad:

 

 

 

You can still mix standard DCS code with MOOSE code, of course, but only if you observe class-method compatibility.

 

Here's a quick way of getting the DCS unit from a MOOSE unit (it also works for GROUP class):

UNIT:FindByName("name in ME"):GetDCSObject()

 

The opposite operation isn't even worth trying, since it's quicker and simpler to get the MOOSE object directly:

[color="Blue"]-- Instead of this:[/color]
DCS_Unit = Unit.getByName("name in ME")
MOOSE_Unit = UNIT:FindByName( DCS_Unit:getName() )

[color="blue"]-- Simply do this:[/color]
MOOSE_Unit = UNIT:FindByName("name in ME")

[color="Blue"]-- And once you have the MOOSE object, you can do this:[/color]
Heading = MOOSE_Unit:GetHeading() 

 

 

Now, by BRC I'm guessing that you're referring to the Base Recovery Course of the carrier, right?

 

In that case, I believe that the carrier's heading is all you need:

carrier = UNIT:FindByName("carrier's unit name in ME")
BRC = carrier:GetHeading()

 

 

As for the "client-specific" F10 commands, I think I'll be able to help with that (like Wingthor said, it's a matter of passing the group object as argument when you call the function)

 

 

Finally, as Wingthor mentioned, you should join the MOOSE Discord channel, it's a great place to get all sorts of help.


Edited by Hardcard
Link to comment
Share on other sites

 

:GetHeading() is a MOOSE method, only compatible with certain MOOSE classes (in this case, UNIT class), whereas Unit.getByName() is a DCS class + method which returns an incompatible DCS object.

 

Always pay attention to the kind of classes and methods you're using.

 

DCS classes require DCS methods (and vice versa), MOOSE classes require MOOSE methods (and vice versa):

 

Unit.getByName() -- DCS class + DCS method :thumbup:

 

UNIT:FindByName() -- MOOSE class + MOOSE method :thumbup:

 

Unit:FindByName() -- DCS class + MOOSE method :mad:

 

UNIT.getByName() -- MOOSE class + DCS method :mad:

 

 

 

oh now it is really clear! I didn't have idea of this difference and was having hard time reffering to objects in my scripts! that's great.

 

 

 

 

local carrierHeading = string.format ("Heading: %i", carrier:GetHeading())

 

this is another thing I was looking for, how to format text messages.

 

Hope this help. I have NOT TESTED the code though. Also plz join our Discord channel for further help

 

The script works perfectly and is exactly what I wanted.

 

Guys, thank you so much for your help and infinite patience with noobs like me...Now I think I have some things clearer that should ease my study.

 

(Discord joined! :thumbup: )

Link to comment
Share on other sites

When MOOSE is spawning aircraft their (unit)names will be some expressionless numbers. Is there a way to change this? E.g. when I use the ai-a2a-dispatcher I want the spawned aircraft to have the original names from the mission editor plus a #number as a suffix to distinguish them.

Link to comment
Share on other sites

When MOOSE is spawning aircraft their (unit)names will be some expressionless numbers. Is there a way to change this? E.g. when I use the ai-a2a-dispatcher I want the spawned aircraft to have the original names from the mission editor plus a #number as a suffix to distinguish them.

 

 

You need to specify? Does the Moose spawn change unit names? or do you mean Groups name. When regular spawning and also with the ai-a2a-dispatcher Groups name have the original names from the mission editor plus a #number as a suffix If spawning with warehouse class name might change.

 

 

You can have a look at this docs from Spawn class.

 

 

 

Regards :)

 

 

 

Wingthor


Edited by Wingthor
Link to comment
Share on other sites

Is there an updated link for the range script?

 

VCAW-99_sig_ED_BD-3.png

 

Alienware New Aurora R15 | Windows® 11 Home Premium | 64bit, 13thGen Intel(R) Core(TM) i9 13900KF(24-Core, 68MB|  NVIDIA(R) GeForce RTX(TM) 4090, 24GB GDDR6X | 1 X 2TB SSD, 1X 1TB SSD | 64GB, 2x32GB, DDR5, 4800MHz | 1350W PSU, Alienware Cryo-tech (TM) Edition CPU Liquid Cooling  power supply | G2 Rverb VR

Link to comment
Share on other sites

Disregard. I've got a range script working with MIST.

 

VCAW-99_sig_ED_BD-3.png

 

Alienware New Aurora R15 | Windows® 11 Home Premium | 64bit, 13thGen Intel(R) Core(TM) i9 13900KF(24-Core, 68MB|  NVIDIA(R) GeForce RTX(TM) 4090, 24GB GDDR6X | 1 X 2TB SSD, 1X 1TB SSD | 64GB, 2x32GB, DDR5, 4800MHz | 1350W PSU, Alienware Cryo-tech (TM) Edition CPU Liquid Cooling  power supply | G2 Rverb VR

Link to comment
Share on other sites

Any thoughts why I'm getting this error

 

2019-04-29 17:20:35.647 ERROR DCS: Mission script error: : [string "C:\Users\name\AppData\Local\Temp\DCS.openbeta\/~mis00002C06.lua"]:91: attempt to index global 'A2ADispatcher' (a nil value)

stack traceback:

[C]: ?

[string "C:\Users\name\AppData\Local\Temp\DCS.openbeta\/~mis00002C06.lua"]:91: in main chunk

 

Does the 91 mean the line number of the script?

A2ADispatcher:SetBorderZone( IrBorderZone )

 

cheers

 

VCAW-99_sig_ED_BD-3.png

 

Alienware New Aurora R15 | Windows® 11 Home Premium | 64bit, 13thGen Intel(R) Core(TM) i9 13900KF(24-Core, 68MB|  NVIDIA(R) GeForce RTX(TM) 4090, 24GB GDDR6X | 1 X 2TB SSD, 1X 1TB SSD | 64GB, 2x32GB, DDR5, 4800MHz | 1350W PSU, Alienware Cryo-tech (TM) Edition CPU Liquid Cooling  power supply | G2 Rverb VR

Link to comment
Share on other sites

In your script have you defined the “IrBorder Zone” ?

 

 

 

Sent from my iPhone using Tapatalk

 

Yes sir I believe the border is set properly. This script was working but quit about 2 OB updates ago.

 

Script

 

_SETTINGS:SetImperial()

-- SET DYNAMIC GROUP LISTING

clients = SET_CLIENT:New()
:FilterActive()
:FilterStart()

MiG_21_active = SET_GROUP:New()
:FilterPrefixes("MiG_21")
:FilterActive()
:FilterStart()

MiG_21_1_active = SET_GROUP:New()
:FilterPrefixes("MiG_21_1")
:FilterActive()
:FilterStart()

MiG_29_active = SET_GROUP:New()
:FilterPrefixes("MiG_29")
:FilterActive()
:FilterStart()

MiG_29_1_active = SET_GROUP:New()
:FilterPrefixes("MiG_29_1")
:FilterActive()
:FilterStart()

-- SET SPAWN GROUP DEFINITIONS
MiG_21 = SPAWN:New("MiG_21")
MiG_21_1 = SPAWN:New("MiG_21_1")
MiG_29 = SPAWN:New("MiG_29")
MiG_29_1 = SPAWN:New("MiG_29_1")

-- SET THE NUMBER OF BANDIT TO CLIENTS
CountScheduler = SCHEDULER:New( nil, function()

num_clients = clients:Count()
num_21 = MiG_21_active:Count()
num_21_1 = MiG_21_1_active:Count()
num_29 = MiG_29_active:Count()
num_29_1 = MiG_29_1_active:Count()
env.info("Count of clients is " .. num_clients)

local msgClients = {}
msgClients.text = num_clients..' Clients Active \n'..
num_21..' MiG 21 Groups Active \n'..
num_21_1..' MiG 21 Groups Active \n'..
num_29..' MiG 29 Groups Active \n'..
num_29_1..' MiG 29 Groups Active \n'..
msgClients.displayTime(5)
msgClients.msgFor = { coa = {'all'}}
mist.message.add(msgClients)

if num_21 < num_clients then
for k = 1, (num_clients - num_21*2) do
MiG_21:Spawn()
end
end

if num_21_1 < num_clients then
for k = 1, (num_clients - num_21_1*2) do
MiG_21_1:Spawn()
end
end

if (num_29*2) < num_clients then
for k = 1, (num_clients - num_29*2) do
MiG_29:Spawn()
end
end

if (num_29_1*2) < num_clients then
for k = 1, (num_clients - num_29_1*2) do
MiG_29_1:Spawn()
end
end

end, {}, 240, 240, 0.1) 

-- Setup the detection zone. 
-- In this case the zone is any group with EWR and or SAM, 
-- Any enemy crossing this border will be engaged.
DetectionSetGroup = SET_GROUP:New()
DetectionSetGroup:FilterPrefixes( { "EWR", "SAM" } )
DetectionSetGroup:FilterStart()
A2ADispatcher = AI_A2A_DISPATCHER:New( EWR_Red )
Detection = DETECTION_AREAS:New( DetectionSetGroup, 100000 )
A2ADispatcher:SetEngageRadius( 80000 )

-- Setup the squadrons.

A2ADispatcher:SetSquadron( "Tunb", AIRBASE.PersianGulf.Tunb_Island_AFB, { "MIG_29_1" } )
A2ADispatcher:SetSquadronTakeoffFromParkingHot( "Tunb" )
A2ADispatcher:SetSquadronLandingNearAirbase( "Tunb" )

A2ADispatcher:SetSquadron( "Bandar", AIRBASE.PersianGulf.Bandar_Abbas_Intl, { "MiG_29" } )
A2ADispatcher:SetSquadronTakeoffFromParkingHot( "Bandar" )
A2ADispatcher:SetSquadronLandingNearAirbase( "Bandar" )

A2ADispatcher:SetSquadron( "Lavan", AIRBASE.PersianGulf.Lavan_Island_Airport, { "MIG_21_1" } )
A2ADispatcher:SetSquadronTakeoffFromParkingHot( "Lavan" )
A2ADispatcher:SetSquadronLandingNearAirbase( "Lavan" )

A2ADispatcher:SetSquadron( "Lar", AIRBASE.PersianGulf.Lar_Airbase, { "MIG_21" } )
A2ADispatcher:SetSquadronTakeoffFromParkingHot( "Lar" )
A2ADispatcher:SetSquadronLandingNearAirbase( "Lar" )

-- Set CAP
A2ADispatcher:SetSquadronCap("Bandar",IrCapZone,1000,15000,150,230,230,320,"BARO")
A2ADispatcher:SetSquadronCapInterval("Bandar",2,120,300)
A2ADispatcher:SetSquadronGrouping( "Bandar", 2 )


A2ADispatcher:SetSquadronCap("Tunb",IrCapZone,1000,15000,150,230,230,320,"BARO")
A2ADispatcher:SetSquadronCapInterval("Tunb",2,10,30)
A2ADispatcher:SetSquadronGrouping( "Tunb", 2 )


A2ADispatcher:SetSquadronCap("Lavan",IrCapZone,1000,15000,150,230,230,320,"BARO")
A2ADispatcher:SetSquadronCapInterval("Lavan",2,20,1)
A2ADispatcher:SetSquadronGrouping( "Lavan", 2 )


A2ADispatcher:SetSquadronCap("Lar",IrCapZone,1000,15000,150,230,230,320,"BARO")
A2ADispatcher:SetSquadronCapInterval("Lar",2,120,300)
A2ADispatcher:SetSquadronGrouping( "Lar", 2 )

-- End Iran Air Defense Code

 

VCAW-99_sig_ED_BD-3.png

 

Alienware New Aurora R15 | Windows® 11 Home Premium | 64bit, 13thGen Intel(R) Core(TM) i9 13900KF(24-Core, 68MB|  NVIDIA(R) GeForce RTX(TM) 4090, 24GB GDDR6X | 1 X 2TB SSD, 1X 1TB SSD | 64GB, 2x32GB, DDR5, 4800MHz | 1350W PSU, Alienware Cryo-tech (TM) Edition CPU Liquid Cooling  power supply | G2 Rverb VR

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...