Compare commits

...

185 Commits

Author SHA1 Message Date
David Pierron 82e87bf866 v1.6.1 - ASC C-130 2025-12-12 16:22:41 +01:00
David Pierron e59bc50e6c version pushed to 1.6.0-alpha (for testing) 2025-11-22 11:53:11 +01:00
FullGas1 c12c0b242d Work by Fullgas on multiple issues and new features
* Indicate obligation to use MIST delivered with CTLD

* update ctld.dynamicCargoUnits table

* Indicate obligation to use MIST delivered with CTLD

* MIST madatory in red

* MIST mandatory in red

* fix mist.utils.getHeadingPoints calls

* commit

* fix #164 Issue-wrong12oclock msg

* commit ctld.tools.getRelativeBearing()

* commit
2025-11-22 11:50:10 +01:00
David Pierron 659268d3f5 Merge branch 'master' into develop 2025-09-27 18:53:23 +02:00
David Pierron c9270a0fd2 changed the code that looks for nearby units (#163) 2025-09-10 14:39:58 +02:00
David Pierron def40f440c added coff.ee information to the readme 2025-07-31 08:47:54 +02:00
David Pierron 417c57f97c Bump version to 1.5.1 for release 2025-07-31 08:16:42 +02:00
David Pierron dec5bf02b4 Stop autosmoke being the default for JTAC and drones 2025-07-31 08:16:25 +02:00
David Pierron 68693300dc By default, recon is disabled 2025-07-31 08:15:57 +02:00
David Pierron f7f603c486 Added checks to avoind nil errors in ctld.adjustRoute 2025-07-31 08:15:31 +02:00
David Pierron 290950a16b updated README 2025-07-22 16:24:08 +02:00
David Pierron 041a9ab6af small corrections to PR153 2025-07-22 15:24:20 +02:00
David Pierron 8d73c966db PR153 - multiple changes from FullGas1
Issue #137: Repack vehicles in crates
Issue #139: MQ9 autolase follow a moving target
Issue #151: Patriot Crate spawning into Chinook rear rotor
Issue #131: Limit Number of Troops in the game
2025-07-22 15:18:30 +02:00
FullGas1 af3e4fab17 commit 2025-05-20 17:46:02 +02:00
FullGas1 97e7c72144 fix "es" dictionary 2025-05-16 14:34:11 +02:00
FullGas1 65336fdab8 Final commit 2025-05-10 15:30:25 +02:00
FullGas1 61db3e9f93 Commit 2025-05-10 12:04:46 +02:00
FullGas1 a1da0ea1c4 Last fix commit !? 2025-05-10 12:04:18 +02:00
FullGas1 782940265d commit 2025-05-10 01:33:15 +02:00
FullGas1 b5cd8929f3 commit 2025-05-09 15:25:34 +02:00
FullGas1 1826d28a86 commit 2025-05-09 14:33:54 +02:00
FullGas1 359bf1418d commit 2025-05-09 11:54:54 +02:00
FullGas1 e3424c6af5 commit 2025-05-09 11:01:38 +02:00
FullGas1 1ac3b3f8a9 Merge branch 'Issues-#137-Repack-Vehicles-In-Crates' of https://github.com/FullGas1/DCS-CTLD_FG into Issues-#137-Repack-Vehicles-In-Crates 2025-05-09 10:15:41 +02:00
FullGas1 e13e630830 commit 2025-05-09 10:07:00 +02:00
FullGas1 7bfed7ef55 bommit fix 2025-05-08 19:30:19 +02:00
FullGas1 8bfaba399f bugs fix 2025-05-04 23:46:00 +02:00
FullGas1 4dada3d24d Merge branch 'Issues-#137-Repack-Vehicles-In-Crates' of https://github.com/FullGas1/DCS-CTLD_FG into Issues-#137-Repack-Vehicles-In-Crates 2025-05-03 16:10:34 +02:00
FullGas1 74b40fe3cb fix bug 2025-05-03 16:10:22 +02:00
FullGas1 aa8bc78b27 #131 test.miz 2025-04-26 13:50:01 +02:00
FullGas1 7286a6a010 Issue #131-Limit-Number-of-Troops 2025-04-26 13:45:31 +02:00
FullGas1 c8bb41648c Issue #131-Limit-Number-of-Troops 2025-04-26 13:44:25 +02:00
FullGas1 08635622b0 load temporary test .miz 2025-04-21 22:49:33 +02:00
FullGas1 42e8549649 commit 2025-04-21 22:48:32 +02:00
FullGas1 5c48a9d756 commit 2025-04-21 21:27:07 +02:00
FullGas1 f3983c6a90 Merge branch 'Issues-#137-Repack-Vehicles-In-Crates' of https://github.com/FullGas1/DCS-CTLD_FG into Issues-#137-Repack-Vehicles-In-Crates 2025-04-21 21:04:19 +02:00
FullGas1 1c66408127 Readme update 2025-04-21 21:04:17 +02:00
FullGas1 3ac2b3b22c commit 2025-04-21 16:49:55 +02:00
FullGas1 c576268d87 commit 2025-04-21 14:10:41 +02:00
FullGas1 35f52d543a commit 2025-04-21 14:09:18 +02:00
FullGas1 c608d00d15 commit #137 2025-04-21 13:29:31 +02:00
FullGas1 d2789f554a debug #137 2025-04-21 02:51:14 +02:00
FullGas1 fcef6a66d1 debug #137 2025-04-21 01:44:55 +02:00
FullGas1 dd71451194 debug #137 Repack 2025-04-20 22:55:49 +02:00
FullGas1 807e81e389 debug #137 2025-04-20 14:51:25 +02:00
FullGas1 33d8810ebb commit #149 drone follow target 2025-04-20 14:13:32 +02:00
FullGas1 87e8a31f31 debug 2025-04-20 14:06:58 +02:00
FullGas1 e4a0fff931 debug 2025-04-20 12:38:18 +02:00
FullGas1 ca5bf76c78 debug 2025-04-20 00:55:26 +02:00
FullGas1 f8659c5de6 debug 2025-04-19 01:49:10 +02:00
FullGas1 9a0cc8eeee debug 2025-04-17 23:48:58 +02:00
FullGas1 a706890cb6 debug 2025-04-17 23:48:37 +02:00
FullGas1 815684dd77 commit 2025-04-17 00:04:22 +02:00
FullGas1 0ccb2ba7bb debug 2025-04-13 23:14:21 +02:00
FullGas1 1e471df264 debug #159 jtac autoorbiting 2025-04-13 22:07:53 +02:00
FullGas1 cc8b916870 debug 2025-04-09 00:54:01 +02:00
FullGas1 cd62d0c60a Merge branch 'Issues-#137-Repack-Vehicles-In-Crates' of https://github.com/FullGas1/DCS-CTLD_FG into Issues-#137-Repack-Vehicles-In-Crates 2025-04-07 23:46:41 +02:00
FullGas1 a35e023752 #149 Flying JTAC orbit on target 2025-04-07 23:46:37 +02:00
FullGas1 f71e7f3213 commit 2025-04-06 22:31:37 +02:00
FullGas1 a468faefec commit 2025-04-06 21:53:15 +02:00
FullGas1 99f2c7aec0 commit 2025-04-06 19:26:06 +02:00
FullGas1 7db8e2d772 commit 2025-04-06 19:19:57 +02:00
FullGas1 026099bd12 commit 2025-04-06 19:19:45 +02:00
FullGas1 82a330e61a commit 2025-04-06 19:04:35 +02:00
FullGas1 b3470250e4 commit 2025-04-06 17:28:54 +02:00
FullGas1 bbde4ae62b comiit 2025-04-06 17:16:28 +02:00
FullGas1 540a316754 commit 2025-04-06 17:12:44 +02:00
FullGas1 574217d931 commit 2025-04-06 17:02:08 +02:00
FullGas1 1fce52088d commit 2025-04-06 11:15:16 +02:00
FullGas1 4d704a489e commit 2025-04-06 11:13:50 +02:00
FullGas1 da80f9ea06 commit 2025-04-06 11:09:38 +02:00
FullGas1 93260908c4 debug 2025-04-05 19:39:42 +02:00
FullGas1 3c261e8dc2 debug 2025-04-04 21:52:40 +02:00
FullGas1 7b7eb62bf0 debug 2025-04-03 23:48:00 +02:00
FullGas1 951ee37903 debbug 2025-04-03 21:45:46 +02:00
FullGas1 3a7ab50834 debug 2025-04-03 20:36:50 +02:00
FullGas1 9a69d4b52c debug 2025-04-03 16:32:55 +02:00
FullGas1 0345d16150 debug 2025-04-03 02:02:41 +02:00
FullGas1 d071fba20f debug 2025-04-03 01:10:03 +02:00
FullGas1 1a32ce6b57 debug 2025-04-03 00:50:30 +02:00
FullGas1 85275ad84b debug 2025-04-03 00:50:19 +02:00
FullGas1 819ba2de53 debug 2025-04-02 22:54:17 +02:00
FullGas1 8f34ad3902 debug 2025-04-02 22:19:34 +02:00
FullGas1 16f366d039 debug 2025-04-01 19:43:24 +02:00
FullGas1 2524320096 debug 2025-04-01 17:49:52 +02:00
FullGas1 e6b8c9ba14 ebug 2025-04-01 17:34:00 +02:00
FullGas1 a5b47503be Merge branch 'Issues-#137-Repack-Vehicles-In-Crates' of https://github.com/FullGas1/DCS-CTLD_FG into Issues-#137-Repack-Vehicles-In-Crates 2025-04-01 16:37:11 +02:00
FullGas1 aaa25dcd41 commit 2025-04-01 16:28:50 +02:00
FullGas1 e834dd1395 debug 2025-04-01 03:04:26 +02:00
FullGas1 774e499759 commit 2025-04-01 02:48:10 +02:00
FullGas1 0a1f4de471 commit 2025-04-01 02:22:35 +02:00
FullGas1 f9cd8b8b51 commit 2025-03-31 18:05:13 +02:00
FullGas1 3eef8d9a5d ctld.getNearbyUnits : sort by distance 2025-03-31 12:22:39 +02:00
FullGas1 e1b9e1d7d8 commit 2025-03-31 12:19:41 +02:00
FullGas1 ca976f4387 commit 2025-03-30 23:42:53 +02:00
FullGas1 91f74b73ed commit 2025-03-30 16:25:31 +02:00
FullGas1 f8df243043 commit 2025-03-30 15:42:07 +02:00
FullGas1 29b19d5262 commit 2025-03-30 15:24:20 +02:00
FullGas1 48aca9d488 commit 2025-03-30 15:07:49 +02:00
FullGas1 12741d0532 commit 2025-03-30 12:55:22 +02:00
FullGas1 6df583b9f1 commit 2025-03-30 12:23:40 +02:00
FullGas1 ca99c58f98 commit 2025-03-30 12:21:43 +02:00
FullGas1 879272a2e8 debug 2025-03-30 00:31:35 +01:00
FullGas1 267156e04e debug 2025-03-30 00:00:34 +01:00
FullGas1 6fa12ca46f debug 2025-03-29 23:49:50 +01:00
FullGas1 eb22f5dc67 debug 2025-03-29 23:20:10 +01:00
FullGas1 601805abb0 debug 2025-03-29 23:06:27 +01:00
FullGas1 e0e4279f20 debug 2025-03-29 23:00:17 +01:00
FullGas1 9023c571ba debug 2025-03-29 22:54:18 +01:00
FullGas1 72aab26e43 debug 2025-03-29 22:39:04 +01:00
FullGas1 aef146a6d8 debug 2025-03-29 22:16:48 +01:00
FullGas1 d8db662dc5 debug 2025-03-29 22:07:45 +01:00
FullGas1 e4f13f98b1 commit 2025-03-29 19:36:58 +01:00
FullGas1 c1aba95b6f for debug 2025-03-29 16:24:36 +01:00
FullGas1 d50bcfccd9 commit 2025-03-29 16:18:08 +01:00
FullGas1 f0f095e274 commit 2025-03-29 11:07:52 +01:00
FullGas1 69f04dfd57 commit 2025-03-29 10:53:37 +01:00
FullGas1 546f3feaae commit 2025-03-29 10:53:04 +01:00
FullGas1 23e83bf53a commit 2025-03-29 10:32:31 +01:00
FullGas1 ee07423588 Merge branch 'Issues-#137-Repack-Vehicles-In-Crates' of https://github.com/FullGas1/DCS-CTLD_FG into Issues-#137-Repack-Vehicles-In-Crates 2025-03-29 10:19:30 +01:00
FullGas1 96d801c342 commit 2025-03-29 10:19:27 +01:00
FullGas1 b1818d9fb3 update en dict version number 2025-03-29 09:57:57 +01:00
FullGas1 2bc6e76516 update fr & es dict version number 2025-03-29 09:57:33 +01:00
FullGas1 61a1fd42ee update dict versionnumber 2025-03-29 09:54:52 +01:00
FullGas1 954a6b0fad update dictionary 2025-03-29 09:48:35 +01:00
FullGas1 159915a6ac commit 2025-03-26 18:51:16 +01:00
FullGas1 d029e2479b commit 2025-03-26 18:43:54 +01:00
FullGas1 251467fee4 update dictionary 2025-03-26 18:39:35 +01:00
FullGas1 f3a9b44388 commit 2025-03-26 18:22:20 +01:00
FullGas1 f0adb72c49 comiit 2025-03-26 17:36:56 +01:00
FullGas1 ecc47bb247 fixes 2025-03-26 10:32:35 +01:00
FullGas1 0c74729837 fixes ctld.getSecureDistanceFromUnit 2025-03-26 10:32:10 +01:00
FullGas1 ef1d3d57e5 add ctld.getSecureDistanceFromUnit 2025-03-26 01:49:45 +01:00
FullGas1 b69f20eb6b add ctld.getSecureDistanceFromUnit fct 2025-03-26 01:31:53 +01:00
FullGas1 d80a70c0ee readme update 2025-03-26 01:18:09 +01:00
FullGas1 80fe5d59b0 readme update for repack 2025-03-26 01:00:37 +01:00
FullGas1 3eaa08b74e fixes 2025-03-26 00:01:15 +01:00
FullGas1 f83365ec63 fixes 2025-03-25 23:59:26 +01:00
FullGas1 0b3b1ea1f8 fixes 2025-03-25 23:59:06 +01:00
FullGas1 888d949234 fixes 2025-03-25 23:39:25 +01:00
FullGas1 75c9d0bf68 fixes 2025-03-25 18:10:39 +01:00
FullGas1 7517eaf188 fixes 2025-03-25 17:39:58 +01:00
FullGas1 1181fcfff7 fixes 2025-03-25 17:22:18 +01:00
FullGas1 9def2f1a3a fixes 2025-03-25 17:00:17 +01:00
FullGas1 9c25240c43 fixes 2025-03-25 16:33:09 +01:00
FullGas1 8a17ff52aa fixes 2025-03-25 15:24:12 +01:00
FullGas1 d125cdbe80 fixes 2025-03-25 15:14:03 +01:00
FullGas1 8dcaa3e0bb fixes 2025-03-25 15:05:28 +01:00
FullGas1 baf1231141 fixes 2025-03-25 14:57:32 +01:00
FullGas1 d1d9b55769 fixes 2025-03-25 14:55:10 +01:00
FullGas1 ff06dcecf7 fixes 2025-03-25 12:50:41 +01:00
FullGas1 dcdf6438a1 fixes 2025-03-25 12:29:25 +01:00
FullGas1 4d0062dee3 fixes 2025-03-25 11:37:16 +01:00
FullGas1 c618f4b282 fixes 2025-03-25 11:33:15 +01:00
FullGas1 b390d5dabf fixes 2025-03-25 11:22:57 +01:00
FullGas1 f4b81fd101 fixes 2025-03-25 11:20:40 +01:00
FullGas1 78aa8a010e fixes 2025-03-25 11:10:13 +01:00
FullGas1 6996769cec fixes 2025-03-25 11:04:00 +01:00
FullGas1 0d9c01283c fixes 2025-03-25 11:02:40 +01:00
FullGas1 fa1553a83e fixes 2025-03-24 16:09:58 +01:00
FullGas1 4db3c71728 fixes 2025-03-24 00:49:58 +01:00
FullGas1 0180cf33d2 fixes 2025-03-24 00:37:19 +01:00
FullGas1 c51a3d80ca fixes 2025-03-23 22:26:51 +01:00
FullGas1 9eb4fc66b5 fixes 2025-03-23 22:25:28 +01:00
FullGas1 8f2a335609 fixes 2025-03-23 22:12:19 +01:00
FullGas1 c5bae34ed1 fixes 2025-03-23 19:31:30 +01:00
FullGas1 6fc9f146ae fixes 2025-03-23 17:38:24 +01:00
FullGas1 b6232d3c15 fixes 2025-03-23 17:09:35 +01:00
FullGas1 111fd73b94 fixes 2025-03-23 17:03:37 +01:00
FullGas1 61d9e206b2 fixes 2025-03-23 16:58:32 +01:00
FullGas1 08ebd7e82d fixes 2025-03-23 16:54:27 +01:00
FullGas1 f152f58a97 fixes 2025-03-23 16:49:29 +01:00
FullGas1 38e86bead3 fixes 2025-03-23 16:37:30 +01:00
FullGas1 b0d8f8b5c7 fixes 2025-03-23 16:36:31 +01:00
FullGas1 a58efad985 fixes 2025-03-23 00:09:30 +01:00
FullGas1 0793d3bda5 fixes 2025-03-22 23:47:06 +01:00
FullGas1 c397bad107 fixes 2025-03-22 23:30:53 +01:00
FullGas1 791ee4e63e fixes 2025-03-22 23:02:57 +01:00
FullGas1 5aa37c52a4 fixes 2025-03-22 21:42:46 +01:00
FullGas1 fb26645996 add ctld.updateDynamicLogisticUnitsZones 2025-02-26 21:27:21 +01:00
FullGas1 3a3bcaf568 wip 2025-02-26 15:13:25 +01:00
FullGas1 fb804b4a22 1rst ok version 2025-02-26 15:05:22 +01:00
FullGas1 665bdddbdd wip 2025-02-26 03:34:05 +01:00
FullGas1 6beaedb79a ctld.getUnitsInRepackRadius(_PlayerTransportUnitName, _radius) added 2025-02-22 04:35:25 +01:00
FullGas1 9c2f982d03 ctld.getNearbyUnits 2025-02-21 23:48:02 +01:00
7 changed files with 398 additions and 277 deletions
+5
View File
@@ -0,0 +1,5 @@
{
"Lua.diagnostics.globals": [
"ctld"
]
}
+354 -252
View File
@@ -1,4 +1,5 @@
--[[
--[[ ! IMPORTANT : You must must use the version of MIST supplied in the CTLD pack to correctly manage dynamic spwans
Combat Troop and Logistics Drop
Allows Huey, Mi-8 and C130 to transport troops internally and Helicopters to transport Logistic / Vehicle units to the field via sling-loads
@@ -11,6 +12,9 @@
See https://github.com/ciribob/DCS-CTLD for a user manual and the latest version
Contributors:
- FullGas1 - https://github.com/FullGas1 (i18n concept, FR and SP translations)
- Rex (VEAF) - https://github.com/RexAttaque (code, testing, JTAC)
- Zip (VEAF) - https://github.com/davidp57 (project management, code, testing)
- Steggles - https://github.com/Bob7heBuilder
- mvee - https://github.com/mvee
- jmontleon - https://github.com/jmontleon
@@ -20,7 +24,6 @@
- Proxy404 - https://github.com/Proxy404
- atcz - https://github.com/atcz
- marcos2221- https://github.com/marcos2221
- FullGas1 - https://github.com/FullGas1 (i18n concept, FR and SP translations)
Add [issues](https://github.com/ciribob/DCS-CTLD/issues) to the GitHub repository if you want to report a bug or suggest a new feature.
@@ -40,7 +43,7 @@ end
ctld.Id = "CTLD - "
--- Version.
ctld.Version = "1.5.0"
ctld.Version = "1.6.1"
-- To add debugging messages to dcs.log, change the following log levels to `true`; `Debug` is less detailed than `Trace`
ctld.Debug = false
@@ -491,8 +494,8 @@ ctld.JTAC_LIMIT_RED = 10 -- max number of JTAC Crates for the RED Si
ctld.JTAC_LIMIT_BLUE = 10 -- max number of JTAC Crates for the BLUE Side
ctld.JTAC_dropEnabled = true -- allow JTAC Crate spawn from F10 menu
ctld.JTAC_maxDistance = 10000 -- How far a JTAC can "see" in meters (with Line of Sight)
ctld.JTAC_smokeOn_RED = true -- enables marking of target with smoke for RED forces
ctld.JTAC_smokeOn_BLUE = true -- enables marking of target with smoke for BLUE forces
ctld.JTAC_smokeOn_RED = false -- enables marking of target with smoke for RED forces
ctld.JTAC_smokeOn_BLUE = false -- enables marking of target with smoke for BLUE forces
ctld.JTAC_smokeColour_RED = 4 -- RED side smoke colour -- Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4
ctld.JTAC_smokeColour_BLUE = 1 -- BLUE side smoke colour -- Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4
ctld.JTAC_smokeMarginOfError = 50 -- error that the JTAC is allowed to make when popping a smoke (in meters)
@@ -611,6 +614,7 @@ ctld.aircraftTypeTable = {
--"Mirage-F1DDA",
--"Su-25T",
--"Yak-52",
"C-130J-30",
--%%%%% WARBIRDS %%%%%
--"Bf-109K-4",
@@ -808,6 +812,7 @@ ctld.logisticUnits = {
ctld.vehicleTransportEnabled = {
"76MD", -- the il-76 mod doesnt use a normal - sign so il-76md wont match... !!!! GRR
"Hercules",
"C-130J-30",
--"CH-47Fbl1",
}
@@ -817,7 +822,10 @@ ctld.vehicleTransportEnabled = {
-- We will also use this to make modifications to the menu and other checks and messages
ctld.dynamicCargoUnits = {
"CH-47Fbl1",
--"UH-1H",
"UH-1H",
"Mi-8MT",
"Mi-24P",
"C-130J-30"
}
-- ************** Maximum Units SETUP for UNITS ******************
@@ -866,6 +874,7 @@ ctld.unitLoadLimits = {
--["Mirage-F1DDA"] = 1,
--["Su-25T"] = 1,
--["Yak-52"] = 1,
["C-130J-30"] = 80
--%%%%% WARBIRDS %%%%%
--["Bf-109K-4"] = 1,
@@ -888,6 +897,7 @@ ctld.internalCargoLimits = {
-- Remove the -- below to turn on options
["Mi-8MT"] = 2,
["CH-47Fbl1"] = 8,
["C-130J-30"] = 20
}
@@ -916,6 +926,7 @@ ctld.unitActions = {
["Hercules"] = { crates = true, troops = true },
["SK-60"] = { crates = true, troops = true },
["UH-60L"] = { crates = true, troops = true },
["C-130J-30"] = { crates = true, troops = true },
--["T-45"] = {crates=true, troops=true},
--%%%%% CHOPPERS %%%%%
@@ -1924,19 +1935,24 @@ function ctld.spawnCrateAtPoint(_side, _weight, _point, _hdg)
end
-- ***************************************************************
function ctld.getSecureDistanceFromUnit(_unitName) -- return a distance between the center of unitName, to be sure not touch the unitName
local rotorDiameter = 0 --19 -- meters -- õk for UH & CH47
if Unit.getByName(_unitName) then
local unitUserBox = Unit.getByName(_unitName):getDesc().box
local SecureDistanceFromUnit = 0
function ctld.getSecureDistanceFromUnit(_unitOrName) -- return a distance between the center of unitName, to be sure not touch the unitName
local rotorDiameter = 19 -- meters -- ok for UH & CH47
local unit = _unitOrName
if type(unit) == "string" then
unit = Unit.getByName(_unitOrName)
end
local secureDistanceFromUnit = rotorDiameter
if unit then
local unitUserBox = unit:getDesc().box
if unitUserBox then
if math.abs(unitUserBox.max.x) >= math.abs(unitUserBox.min.x) then
SecureDistanceFromUnit = math.abs(unitUserBox.max.x) + (rotorDiameter/2)
secureDistanceFromUnit = math.abs(unitUserBox.max.x) + (rotorDiameter/2)
else
SecureDistanceFromUnit = math.abs(unitUserBox.min.x) + (rotorDiameter/2)
secureDistanceFromUnit = math.abs(unitUserBox.min.x) + (rotorDiameter/2)
end
return SecureDistanceFromUnit
end
return nil
end
return secureDistanceFromUnit
end
-- ***************************************************************
@@ -1977,7 +1993,7 @@ function ctld.getUnitsInRepackRadius(_PlayerTransportUnitName, _radius)
end
local unitsNamesList = ctld.getNearbyUnits(unit:getPoint(), _radius, unit:getCoalition())
local repackableUnits = {}
for i = 1, #unitsNamesList do
local unitObject = Unit.getByName(unitsNamesList[i])
@@ -1998,11 +2014,13 @@ function ctld.getNearbyUnits(_point, _radius, _coalition)
local unitsByDistance = {}
local cpt = 1
local _units = {}
local _unitList = mist.DBs.unitsByName
for _unitName, _unit in pairs(mist.DBs.unitsByName) do
for _unitName, _ in pairs(mist.DBs.unitsByName) do
local u = Unit.getByName(_unitName)
if u and u:isExist() and (_coalition == 4 or u:getCoalition() == _coalition) then
--local _dist = ctld.getDistance(u:getPoint(), _point)
local e = (u and u:isExist()) or false
-- pcall is needed because getCoalition() fails if the unit is an object without coalition (like a smoke effect)
local c = nil
pcall(function() c = (u and e and u:getCoalition()) or nil end)
if u and e and (_coalition == 4 or c == _coalition) then
local _dist = mist.utils.get2DDist(u:getPoint(), _point)
if _dist <= _radius then
unitsByDistance[cpt] = {id =cpt, dist = _dist, unit = _unitName, typeName = u:getTypeName()}
@@ -2010,7 +2028,7 @@ function ctld.getNearbyUnits(_point, _radius, _coalition)
end
end
end
--table.sort(unitsByDistance, function(a,b) return a.dist < b.dist end) -- sort the table by distance (the nearest first)
table.sort(unitsByDistance, function(a,b) return a.typeName < b.typeName end) -- sort the table by typeNAme
for i, v in ipairs(unitsByDistance) do
@@ -2092,7 +2110,7 @@ function ctld.repackVehicle(_params, t) -- scan rrs table 'repackRequestsStack'
local _name = string.format("%s_%i", v.desc, _unitId)
local secureDistance = ctld.getSecureDistanceFromUnit(playerUnitName) or 10
local relativePoint = ctld.getRelativePoint(playerPoint, secureDistance + (i * offset), randomHeading) -- 7 meters from the transport unit
if ctld.unitDynamicCargoCapable(PlayerTransportUnit) == false then
ctld.spawnCrateStatic(refCountry, _unitId, relativePoint, _name, crateWeight, playerCoa, playerHeading, nil)
else
@@ -2105,8 +2123,8 @@ function ctld.repackVehicle(_params, t) -- scan rrs table 'repackRequestsStack'
ctld.repackRequestsStack[ii] = nil -- remove the processed request from the stacking table
end
if ctld.enableRepackingVehicles == true then
return t + 3 -- reschedule the function in 3 seconds
else
@@ -2601,7 +2619,7 @@ function ctld.spawnCrate(_arguments, bypassCrateWaitTime)
if ctld.unitDynamicCargoCapable(_heli) then
_model_type = "dynamic"
_point = ctld.getPointAt6Oclock(_heli, 15)
_point = ctld.getPointAt6Oclock(_heli, ctld.getSecureDistanceFromUnit(_heli))
_position = "6"
end
@@ -2615,10 +2633,19 @@ function ctld.spawnCrate(_arguments, bypassCrateWaitTime)
-- add to move table
ctld.crateMove[_name] = _name
local refPoint = _heli:getPoint()
local refLat, refLon = coord.LOtoLL(refPoint)
local unitPos = _heli:getPosition()
local refHeading = math.deg(math.atan2(unitPos.x.z, unitPos.x.x))
local destLat, destLon, destAlt = coord.LOtoLL(_point)
local relativePos, forma = ctld.tools.getRelativeBearing(refLat, refLon, refHeading, destLat, destLon, 'clock')
ctld.displayMessageToGroup(_heli,
ctld.i18n_translate("A %1 crate weighing %2 kg has been brought out and is at your %3 o'clock ",
_crateType.desc, _crateType.weight, _position), 20)
_crateType.desc, _crateType.weight, relativePos), 20)
else
env.info("Couldn't find crate item to spawn")
end
@@ -3169,7 +3196,7 @@ function ctld.updateTroopsInGame(params, t) -- return count of troops in game b
for index, unitObj in pairs(v:getUnits()) do -- for each unit in group
if unitObj:getDesc().attributes.Infantry then
ctld.InfantryInGameCount[coalitionId] = ctld.InfantryInGameCount[coalitionId] + 1
end
end
end
end
end
@@ -3227,7 +3254,7 @@ function ctld.loadTroopsFromZone(_args)
ctld.logTrace("FG_ ctld.InfantryInGameCount[heloCoa] = %s", ctld.p(ctld.InfantryInGameCount[heloCoa]))
ctld.logTrace("FG_ _groupTemplate.total = %s", ctld.p(_groupTemplate.total))
ctld.logTrace("FG_ ctld.nbLimitSpawnedTroops[%s].total = %s", ctld.p(heloCoa), ctld.p(ctld.nbLimitSpawnedTroops[heloCoa]))
local limitReached = true
if (ctld.nbLimitSpawnedTroops[1]~=0 or ctld.nbLimitSpawnedTroops[2]~=0) and (ctld.InfantryInGameCount[heloCoa] + _groupTemplate.total > ctld.nbLimitSpawnedTroops[heloCoa]) then -- load troops only if Coa limit not reached
ctld.displayMessageToGroup(_heli, ctld.i18n_translate("Count Infantries limit in the mission reached, you can't load more troops"), 10)
@@ -3892,7 +3919,7 @@ function ctld.getClosestCrate(_heli, _crates, _type)
local _shortestDistance = -1
local _distance = 0
local _minimumDistance = 5 -- prevents dynamic cargo crates from unpacking while in cargo hold
local _maxDistance = 20 -- prevents onboard dynamic cargo crates from unpacking requested by other helo
local _maxDistance = 75 -- prevents onboard dynamic cargo crates from unpacking requested by other helo
for _, _crate in pairs(_crates) do
if (_crate.details.unit == _type or _type == nil) then
_distance = _crate.dist
@@ -3960,7 +3987,7 @@ function ctld.unpackCrates(_arguments)
local _crates = ctld.getCratesAndDistance(_heli)
local _crate = ctld.getClosestCrate(_heli, _crates)
ctld.logTrace("FG_ ctld.unpackCrates._crate = %s", ctld.p(_crate))
if ctld.inLogisticsZone(_heli) == true or ctld.farEnoughFromLogisticZone(_heli) == false then
ctld.displayMessageToGroup(_heli,
ctld.i18n_translate("You can't unpack that here! Take it to where it's needed!"), 20)
@@ -4015,7 +4042,7 @@ function ctld.unpackCrates(_arguments)
ctld.logTrace("_crate = %s", ctld.p(_crate))
local _spawnedGroups = ctld.spawnCrateGroup(_heli, { _point }, { _crate.details.unit }, { _crateHdg })
ctld.logTrace("_spawnedGroups = %s", ctld.p(_spawnedGroups))
if _heli:getCoalition() == 1 then
ctld.spawnedCratesRED[_crateName] = nil
else
@@ -4217,12 +4244,11 @@ function ctld.dropSlingCrate(_args)
local _position = "12"
if ctld.unitDynamicCargoCapable(_heli) then
_model_type = "dynamic"
_point = ctld.getPointAt6Oclock(_heli, 15)
_point = ctld.getPointAt6Oclock(_heli, ctld.getSecureDistanceFromUnit(_heli))
_position = "6"
end
ctld.displayMessageToGroup(_heli,
ctld.i18n_translate("%1 crate has been safely unhooked and is at your %2 o'clock", _crate.desc,
_position), 10)
ctld.i18n_translate("%1 crate has been safely unhooked and is at your %2 o'clock", _crate.desc, _position), 10)
elseif _heightDiff > 7.5 and _heightDiff <= 40.0 then
ctld.displayMessageToGroup(_heli,
ctld.i18n_translate("%1 crate has been safely dropped below you", _crate.desc), 10)
@@ -5026,7 +5052,7 @@ function ctld.unpackMultiCrate(_heli, _nearestCrate, _nearbyCrates)
if ctld.unitDynamicCargoCapable(_heli) == true then
_point = ctld.getPointInRearSector(_heli, ctld.getSecureDistanceFromUnit(_heli:getName()))
end
local _crateHdg = mist.getHeading(_nearestCrate.crateUnit, true)
-- destroy crates
@@ -5744,7 +5770,7 @@ function ctld.unitDynamicCargoCapable(_unit)
--ctld.logDebug("ctld.unitDynamicCargoCapable(_type=[%s])", ctld.p(_type))
for _, _name in ipairs(ctld.dynamicCargoUnits) do
local _nameLower = string.lower(_name)
if string.find(_type, _nameLower, 1, true) then --string.match does not work with patterns containing '-' as it is a magic character
if string.find(_type, _nameLower, 1, true) then --string.match does not work with patterns containing '-' as it is a magic character
result = true
break
end
@@ -5864,208 +5890,201 @@ end
-- Adds menuitem to a human unit
function ctld.addTransportF10MenuOptions(_unitName)
ctld.logDebug("ctld.addTransportF10MenuOptions(_unitName=[%s])", ctld.p(_unitName))
local status, error = pcall(function()
local _unit = ctld.getTransportUnit(_unitName)
ctld.logTrace("_unit = %s", ctld.p(_unit))
local _unit = ctld.getTransportUnit(_unitName)
ctld.logTrace("_unit = %s", ctld.p(_unit))
if _unit then
local _unitTypename = _unit:getTypeName()
local _groupId = ctld.getGroupId(_unit)
if _groupId then
-- ctld.logTrace("_groupId = %s", ctld.p(_groupId))
-- ctld.logTrace("ctld.addedTo = %s", ctld.p(ctld.addedTo[tostring(_groupId)]))
if ctld.addedTo[tostring(_groupId)] == nil then
ctld.logTrace("adding CTLD menu for _groupId = %s", ctld.p(_groupId))
local _rootPath = missionCommands.addSubMenuForGroup(_groupId, ctld.i18n_translate("CTLD"))
local _unitActions = ctld.getUnitActions(_unitTypename)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Check Cargo"), _rootPath, ctld.checkTroopStatus, { _unitName })
if _unitActions.troops then
local _troopCommandsPath = missionCommands.addSubMenuForGroup(_groupId,ctld.i18n_translate("Troop Transport"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Unload / Extract Troops"),
_troopCommandsPath, ctld.unloadExtractTroops, { _unitName })
if _unit then
local _unitTypename = _unit:getTypeName()
local _groupId = ctld.getGroupId(_unit)
if _groupId then
-- ctld.logTrace("_groupId = %s", ctld.p(_groupId))
-- ctld.logTrace("ctld.addedTo = %s", ctld.p(ctld.addedTo[tostring(_groupId)]))
if ctld.addedTo[tostring(_groupId)] == nil then
ctld.logTrace("adding CTLD menu for _groupId = %s", ctld.p(_groupId))
local _rootPath = missionCommands.addSubMenuForGroup(_groupId, ctld.i18n_translate("CTLD"))
local _unitActions = ctld.getUnitActions(_unitTypename)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Check Cargo"), _rootPath, ctld.checkTroopStatus, { _unitName })
if _unitActions.troops then
local _troopCommandsPath = missionCommands.addSubMenuForGroup(_groupId,ctld.i18n_translate("Troop Transport"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Unload / Extract Troops"),
_troopCommandsPath, ctld.unloadExtractTroops, { _unitName })
-- local _loadPath = missionCommands.addSubMenuForGroup(_groupId, "Load From Zone", _troopCommandsPath)
local _transportLimit = ctld.getTransportLimit(_unitTypename)
local itemNb = 0
local menuEntries = {}
local menuPath = _troopCommandsPath
for _, _loadGroup in pairs(ctld.loadableGroups) do
if not _loadGroup.side or _loadGroup.side == _unit:getCoalition() then
-- check size & unit
if _transportLimit >= _loadGroup.total then
table.insert(menuEntries,
{ text = ctld.i18n_translate("Load ") .. _loadGroup.name, group = _loadGroup })
end
-- local _loadPath = missionCommands.addSubMenuForGroup(_groupId, "Load From Zone", _troopCommandsPath)
local _transportLimit = ctld.getTransportLimit(_unitTypename)
local itemNb = 0
local menuEntries = {}
local menuPath = _troopCommandsPath
for _, _loadGroup in pairs(ctld.loadableGroups) do
if not _loadGroup.side or _loadGroup.side == _unit:getCoalition() then
-- check size & unit
if _transportLimit >= _loadGroup.total then
table.insert(menuEntries,
{ text = ctld.i18n_translate("Load ") .. _loadGroup.name, group = _loadGroup })
end
end
for _i, _menu in ipairs(menuEntries) do
-- add the menu item
itemNb = itemNb + 1
if itemNb == 9 and _i < #menuEntries then -- page limit reached (first item is "unload")
menuPath = missionCommands.addSubMenuForGroup(_groupId, ctld.i18n_translate("Next page"),
menuPath)
itemNb = 1
end
missionCommands.addCommandForGroup(_groupId, _menu.text, menuPath, ctld.loadTroopsFromZone,
{ _unitName, true, _menu.group, false })
end
if ctld.unitCanCarryVehicles(_unit) then
local _vehicleCommandsPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Vehicle / FOB Transport"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Unload Vehicles"),
_vehicleCommandsPath, ctld.unloadTroops, { _unitName, false })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Load / Extract Vehicles"),
_vehicleCommandsPath, ctld.loadTroopsFromZone, { _unitName, false, "", true })
if ctld.enabledFOBBuilding and ctld.staticBugWorkaround == false then
missionCommands.addCommandForGroup(_groupId,
ctld.i18n_translate("Load / Unload FOB Crate"), _vehicleCommandsPath,
ctld.loadUnloadFOBCrate, { _unitName, false })
end
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Check Cargo"),
_vehicleCommandsPath, ctld.checkTroopStatus, { _unitName })
end
end
for _i, _menu in ipairs(menuEntries) do
-- add the menu item
itemNb = itemNb + 1
if itemNb == 9 and _i < #menuEntries then -- page limit reached (first item is "unload")
menuPath = missionCommands.addSubMenuForGroup(_groupId, ctld.i18n_translate("Next page"),
menuPath)
itemNb = 1
end
missionCommands.addCommandForGroup(_groupId, _menu.text, menuPath, ctld.loadTroopsFromZone,
{ _unitName, true, _menu.group, false })
end
if ctld.unitCanCarryVehicles(_unit) then
local _vehicleCommandsPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Vehicle / FOB Transport"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Unload Vehicles"),
_vehicleCommandsPath, ctld.unloadTroops, { _unitName, false })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Load / Extract Vehicles"),
_vehicleCommandsPath, ctld.loadTroopsFromZone, { _unitName, false, "", true })
if ctld.enableCrates and _unitActions.crates then
if ctld.unitCanCarryVehicles(_unit) == false then
-- sort the crate categories alphabetically
local crateCategories = {}
for category, _ in pairs(ctld.spawnableCrates) do
table.insert(crateCategories, category)
if ctld.enabledFOBBuilding and ctld.staticBugWorkaround == false then
missionCommands.addCommandForGroup(_groupId,
ctld.i18n_translate("Load / Unload FOB Crate"), _vehicleCommandsPath,
ctld.loadUnloadFOBCrate, { _unitName, false })
end
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Check Cargo"),
_vehicleCommandsPath, ctld.checkTroopStatus, { _unitName })
end
end
if ctld.enableCrates and _unitActions.crates then
-- sort the crate categories alphabetically
local crateCategories = {}
for category, _ in pairs(ctld.spawnableCrates) do
table.insert(crateCategories, category)
end
table.sort(crateCategories)
--ctld.logTrace("crateCategories = [%s]", ctld.p(crateCategories))
-- add menu for spawning crates
local itemNbMain = 0
local _cratesMenuPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Crates: Vehicle / FOB / Drone"), _rootPath)
for _i, _category in ipairs(crateCategories) do
local _subMenuName = _category
local _crates = ctld.spawnableCrates[_subMenuName]
-- add the submenu item
itemNbMain = itemNbMain + 1
if itemNbMain == 10 and _i < #crateCategories then -- page limit reached
_cratesMenuPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Next page"), _cratesMenuPath)
itemNbMain = 1
end
table.sort(crateCategories)
--ctld.logTrace("crateCategories = [%s]", ctld.p(crateCategories))
-- add menu for spawning crates
local itemNbMain = 0
local _cratesMenuPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Crates: Vehicle / FOB / Drone"), _rootPath)
for _i, _category in ipairs(crateCategories) do
local _subMenuName = _category
local _crates = ctld.spawnableCrates[_subMenuName]
-- add the submenu item
itemNbMain = itemNbMain + 1
if itemNbMain == 10 and _i < #crateCategories then -- page limit reached
_cratesMenuPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Next page"), _cratesMenuPath)
itemNbMain = 1
end
local itemNbSubmenu = 0
local menuEntries = {}
local _subMenuPath = missionCommands.addSubMenuForGroup(_groupId, _subMenuName, _cratesMenuPath)
for _, _crate in pairs(_crates) do
--ctld.logTrace("_crate = [%s]", ctld.p(_crate))
if not (_crate.multiple) or ctld.enableAllCrates then
local isJTAC = ctld.isJTACUnitType(_crate.unit)
--ctld.logTrace("isJTAC = [%s]", ctld.p(isJTAC))
if not isJTAC or (isJTAC and ctld.JTAC_dropEnabled) then
if _crate.side == nil or (_crate.side == _unit:getCoalition()) then
local _crateRadioMsg = _crate.desc
--add in the number of crates required to build something
if _crate.cratesRequired ~= nil and _crate.cratesRequired > 1 then
_crateRadioMsg = _crateRadioMsg .. " (" .. _crate.cratesRequired ..
")"
end
if _crate.multiple then
_crateRadioMsg = "* " .. _crateRadioMsg
end
local _menuEntry = { text = _crateRadioMsg, crate = _crate }
--ctld.logTrace("_menuEntry = [%s]", ctld.p(_menuEntry))
table.insert(menuEntries, _menuEntry)
local itemNbSubmenu = 0
local menuEntries = {}
local _subMenuPath = missionCommands.addSubMenuForGroup(_groupId, _subMenuName, _cratesMenuPath)
for _, _crate in pairs(_crates) do
--ctld.logTrace("_crate = [%s]", ctld.p(_crate))
if not (_crate.multiple) or ctld.enableAllCrates then
local isJTAC = ctld.isJTACUnitType(_crate.unit)
--ctld.logTrace("isJTAC = [%s]", ctld.p(isJTAC))
if not isJTAC or (isJTAC and ctld.JTAC_dropEnabled) then
if _crate.side == nil or (_crate.side == _unit:getCoalition()) then
local _crateRadioMsg = _crate.desc
--add in the number of crates required to build something
if _crate.cratesRequired ~= nil and _crate.cratesRequired > 1 then
_crateRadioMsg = _crateRadioMsg .. " (" .. _crate.cratesRequired ..
")"
end
if _crate.multiple then
_crateRadioMsg = "* " .. _crateRadioMsg
end
local _menuEntry = { text = _crateRadioMsg, crate = _crate }
--ctld.logTrace("_menuEntry = [%s]", ctld.p(_menuEntry))
table.insert(menuEntries, _menuEntry)
end
end
end
for _i, _menu in ipairs(menuEntries) do
--ctld.logTrace("_menu = [%s]", ctld.p(_menu))
-- add the submenu item
itemNbSubmenu = itemNbSubmenu + 1
if itemNbSubmenu == 10 and _i < #menuEntries then -- page limit reached
_subMenuPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Next page"), _subMenuPath)
itemNbSubmenu = 1
end
missionCommands.addCommandForGroup(_groupId, _menu.text, _subMenuPath,
ctld.spawnCrate, { _unitName, _menu.crate.weight })
end
for _i, _menu in ipairs(menuEntries) do
--ctld.logTrace("_menu = [%s]", ctld.p(_menu))
-- add the submenu item
itemNbSubmenu = itemNbSubmenu + 1
if itemNbSubmenu == 10 and _i < #menuEntries then -- page limit reached
_subMenuPath = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Next page"), _subMenuPath)
itemNbSubmenu = 1
end
end
missionCommands.addCommandForGroup(_groupId, _menu.text, _subMenuPath,
ctld.spawnCrate, { _unitName, _menu.crate.weight })
end
end
if (ctld.enabledFOBBuilding or ctld.enableCrates) and _unitActions.crates then
local _crateCommands = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("CTLD Commands"), _rootPath)
if ctld.vehicleCommandsPath[_unitName] == nil then
ctld.vehicleCommandsPath[_unitName] = mist.utils.deepCopy(_crateCommands)
end
if ctld.hoverPickup == false or ctld.loadCrateFromMenu == true then
if ctld.loadCrateFromMenu then
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Load Nearby Crate(s)"),
_crateCommands, ctld.loadNearbyCrate, _unitName)
end
end
if ctld.loadCrateFromMenu or ctld.hoverPickup then
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Crate(s)"),
_crateCommands, ctld.dropSlingCrate, { _unitName })
end
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Unpack Any Crate"),
_crateCommands, ctld.unpackCrates, { _unitName })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List Nearby Crates"),
_crateCommands, ctld.listNearbyCrates, { _unitName })
if ctld.enabledFOBBuilding then
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List FOBs"), _crateCommands,
ctld.listFOBS, { _unitName })
end
if ctld.enableRepackingVehicles == true then
ctld.updateRepackMenu( _unitName ) -- add repack menu
end
end
if ctld.enableSmokeDrop then
local _smokeMenu = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Smoke Markers"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Red Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Red })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Blue Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Blue })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Orange Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Orange })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Green Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Green })
end
if ctld.enabledRadioBeaconDrop then
local _radioCommands = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Radio Beacons"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List Beacons"), _radioCommands,
ctld.listRadioBeacons, { _unitName })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Beacon"), _radioCommands,
ctld.dropRadioBeacon, { _unitName })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Remove Closest Beacon"),
_radioCommands, ctld.removeRadioBeacon, { _unitName })
elseif ctld.deployedRadioBeacons ~= {} then
local _radioCommands = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Radio Beacons"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List Beacons"), _radioCommands,
ctld.listRadioBeacons, { _unitName })
end
ctld.addedTo[tostring(_groupId)] = true
ctld.logTrace("ctld.addedTo = %s", ctld.p(ctld.addedTo))
ctld.logTrace("done adding CTLD menu for _groupId = %s", ctld.p(_groupId))
end
if (ctld.enabledFOBBuilding or ctld.enableCrates) and _unitActions.crates then
local _crateCommands = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("CTLD Commands"), _rootPath)
if ctld.vehicleCommandsPath[_unitName] == nil then
ctld.vehicleCommandsPath[_unitName] = mist.utils.deepCopy(_crateCommands)
end
if ctld.hoverPickup == false or ctld.loadCrateFromMenu == true then
if ctld.loadCrateFromMenu then
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Load Nearby Crate(s)"),
_crateCommands, ctld.loadNearbyCrate, _unitName)
end
end
if ctld.loadCrateFromMenu or ctld.hoverPickup then
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Crate(s)"),
_crateCommands, ctld.dropSlingCrate, { _unitName })
end
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Unpack Any Crate"),
_crateCommands, ctld.unpackCrates, { _unitName })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List Nearby Crates"),
_crateCommands, ctld.listNearbyCrates, { _unitName })
if ctld.enabledFOBBuilding then
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List FOBs"), _crateCommands,
ctld.listFOBS, { _unitName })
end
if ctld.enableRepackingVehicles == true then
ctld.updateRepackMenu( _unitName ) -- add repack menu
end
end
if ctld.enableSmokeDrop then
local _smokeMenu = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Smoke Markers"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Red Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Red })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Blue Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Blue })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Orange Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Orange })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Green Smoke"), _smokeMenu,
ctld.dropSmoke, { _unitName, trigger.smokeColor.Green })
end
if ctld.enabledRadioBeaconDrop then
local _radioCommands = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Radio Beacons"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List Beacons"), _radioCommands,
ctld.listRadioBeacons, { _unitName })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Drop Beacon"), _radioCommands,
ctld.dropRadioBeacon, { _unitName })
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("Remove Closest Beacon"),
_radioCommands, ctld.removeRadioBeacon, { _unitName })
elseif ctld.deployedRadioBeacons ~= {} then
local _radioCommands = missionCommands.addSubMenuForGroup(_groupId,
ctld.i18n_translate("Radio Beacons"), _rootPath)
missionCommands.addCommandForGroup(_groupId, ctld.i18n_translate("List Beacons"), _radioCommands,
ctld.listRadioBeacons, { _unitName })
end
ctld.addedTo[tostring(_groupId)] = true
ctld.logTrace("ctld.addedTo = %s", ctld.p(ctld.addedTo))
ctld.logTrace("done adding CTLD menu for _groupId = %s", ctld.p(_groupId))
end
end
end)
if (not status) then
ctld.logError(string.format("Error adding f10 to transport: %s", error))
end
end
@@ -7773,7 +7792,7 @@ function ctld.TreatOrbitJTAC(params, t)
if ctld.JTACInRoute[k] == nil and ctld.OrbitInUse[k] == nil then -- if JTAC is in route
ctld.JTACInRoute[k] = timer.getTime() -- update time of the last run
end
if ctld.jtacCurrentTargets[k] ~= nil then -- if target lased by JTAC
local droneAlti = Unit.getByName(k):getPoint().y
if ctld.OrbitInUse[k] == nil then -- if JTAC is not in orbit => start orbiting and update start time
@@ -7784,7 +7803,7 @@ function ctld.TreatOrbitJTAC(params, t)
if timer.getTime() > (ctld.OrbitInUse[k] + 60) then -- each 60" update orbit coord
ctld.StartOrbitGroup(k, ctld.jtacCurrentTargets[k].name, droneAlti, 100) -- do orbit JTAC
ctld.OrbitInUse[k] = timer.getTime() -- update time of the last orbit run
end
end
end
else -- if JTAC have no target
if ctld.InOrbitList(k) == true then -- JTAC orbiting, without target => stop orbit
@@ -7802,12 +7821,12 @@ end
-- Make orbit the group "_grpName", on target "_unitTargetName". _alti in meters, speed in km/h
function ctld.StartOrbitGroup(_jtacUnitName, _unitTargetName, _alti, _speed)
if (Unit.getByName(_unitTargetName) ~= nil) and (Unit.getByName(_jtacUnitName) ~= nil) then -- si target unit and JTAC group exist
local orbit = { id = 'Orbit',
local orbit = { id = 'Orbit',
params = {pattern = 'Circle',
point = mist.utils.makeVec2(mist.getAvgPos(mist.makeUnitTable({_unitTargetName}))),
speed = _speed,
altitude = _alti
}
}
}
local jtacGroupName = Unit.getByName(_jtacUnitName):getGroup():getName()
Unit.getByName(_jtacUnitName):getController():popTask() -- stop current Task
@@ -7818,10 +7837,10 @@ end
-- test if one unitName already is targeted by a JTAC
function ctld.InOrbitList(_grpName)
for k, v in pairs(ctld.OrbitInUse) do -- for each orbit in use
if k == _grpName then
if k == _grpName then
return true
end
end
end
return false
end
-------------------------------------------------------------------------------------------
@@ -7853,10 +7872,10 @@ function ctld.backToRoute(_jtacUnitName)
local jtacGroupName = Unit.getByName(_jtacUnitName):getGroup():getName()
--local JTACRoute = mist.getGroupRoute(jtacGroupName, true) -- get the initial editor route of the current group
local JTACRoute = mist.utils.deepCopy(mist.getGroupRoute(jtacGroupName, true)) -- get the initial editor route of the current group
local newJTACRoute = ctld.adjustRoute(JTACRoute, ctld.getNearestWP(_jtacUnitName))
local newJTACRoute = ctld.adjustRoute(JTACRoute, ctld.getNearestWP(_jtacUnitName))
local Mission = {}
Mission = { id = 'Mission', params = {route = {points = newJTACRoute}}}
local Mission = {}
Mission = { id = 'Mission', params = {route = {points = newJTACRoute}}}
-- unactive orbit mode if it's on
if ctld.InOrbitList(_jtacUnitName) == true then -- if JTAC orbiting => stop it
@@ -7887,26 +7906,56 @@ function ctld.adjustRoute(_initialRouteTable, _firstWpOfNewRoute) -- create a r
-- apply offset (_firstWpOfNewRoute) to SwitchWaypoint tasks
local lastWpAsAlreadySwitchWaypoint = false
for idx = 1, #adjustedRoute do
for j=1, #adjustedRoute[idx].task.params.tasks do
if adjustedRoute[idx].task.params.tasks[j].id ~= "ControlledTask" then
if adjustedRoute[idx].task.params.tasks[j].params.action.id == "SwitchWaypoint" then
local goToWaypointIndex = adjustedRoute[idx].task.params.tasks[j].params.action.params.goToWaypointIndex
adjustedRoute[idx].task.params.tasks[j].params.action.params.fromWaypointIndex = idx
adjustedRoute[idx].task.params.tasks[j].params.action.params.goToWaypointIndex = mappingWP[goToWaypointIndex]
if idx == #adjustedRoute then
lastWpAsAlreadySwitchWaypoint = true
for idx2 = 1, #adjustedRoute do
if #adjustedRoute[idx2] and
#adjustedRoute[idx2].task and
#adjustedRoute[idx2].task.params and
#adjustedRoute[idx2].task.params.tasks then
for j=1, #adjustedRoute[idx2].task.params.tasks do
if adjustedRoute[idx2].task.params.tasks[j].id and
adjustedRoute[idx2].task.params.tasks[j].id ~= "ControlledTask" then
if adjustedRoute[idx2].task.params.tasks[j].params and
adjustedRoute[idx2].task.params.tasks[j].params.action and
adjustedRoute[idx2].task.params.tasks[j].params.action.id and
adjustedRoute[idx2].task.params.tasks[j].params.action.id == "SwitchWaypoint" then
if adjustedRoute[idx2].task.params.tasks[j].params.action.params then
local goToWaypointIndex = adjustedRoute[idx2].task.params.tasks[j].params.action.params.goToWaypointIndex
adjustedRoute[idx2].task.params.tasks[j].params.action.params.fromWaypointIndex = idx2
adjustedRoute[idx2].task.params.tasks[j].params.action.params.goToWaypointIndex = mappingWP[goToWaypointIndex]
if idx2 == #adjustedRoute then
lastWpAsAlreadySwitchWaypoint = true
end
end
end
end
else -- for "ControlledTask"
if adjustedRoute[idx].task.params.tasks[j].params.task.params.action.id == "SwitchWaypoint" then
local goToWaypointIndex = adjustedRoute[idx].task.params.tasks[j].params.task.params.action.params.goToWaypointIndex
adjustedRoute[idx].task.params.tasks[j].params.task.params.action.params.fromWaypointIndex = idx
adjustedRoute[idx].task.params.tasks[j].params.task.params.action.params.goToWaypointIndex = mappingWP[goToWaypointIndex]
if idx == #adjustedRoute then
lastWpAsAlreadySwitchWaypoint = true
else -- for "ControlledTask"
if adjustedRoute[idx2].task.params.tasks[j].params and
adjustedRoute[idx2].task.params.tasks[j].params.task and
adjustedRoute[idx2].task.params.tasks[j].params.task.params and
adjustedRoute[idx2].task.params.tasks[j].params.task.params.action and
adjustedRoute[idx2].task.params.tasks[j].params.task.params.action.id and
adjustedRoute[idx2].task.params.tasks[j].params.task.params.action.id == "SwitchWaypoint" then
if adjustedRoute[idx2].task.params.tasks[j].params.task.params.action.params then
local goToWaypointIndex = adjustedRoute[idx2].task.params.tasks[j].params.task.params.action.params.goToWaypointIndex
adjustedRoute[idx2].task.params.tasks[j].params.task.params.action.params.fromWaypointIndex = idx2
adjustedRoute[idx2].task.params.tasks[j].params.task.params.action.params.goToWaypointIndex = mappingWP[goToWaypointIndex]
if idx2 == #adjustedRoute then
lastWpAsAlreadySwitchWaypoint = true
end
end
end
end
end
end
end
@@ -7957,7 +8006,7 @@ ctld.reconMenuName = ctld.i18n_translate("RECON") --name of the
ctld.reconRadioAdded = {} --stores the groups that have had the radio menu added
ctld.reconLosSearchRadius = 2000 -- search radius in meters
ctld.reconLosMarkRadius = 100 -- mark radius dimension in meters
ctld.reconAutoRefreshLosTargetMarks = true -- if true recon LOS marks are automaticaly refreshed on F10 map
ctld.reconAutoRefreshLosTargetMarks = false -- if true recon LOS marks are automaticaly refreshed on F10 map
ctld.reconLastScheduleIdAutoRefresh = 0
---- F10 RECON Menus ------------------------------------------------------------------
@@ -8465,7 +8514,7 @@ end
--- Handle world events.
ctld.eventHandler = {}
function ctld.eventHandler:onEvent(event)
ctld.logTrace("ctld.eventHandler:onEvent()")
--ctld.logTrace("ctld.eventHandler:onEvent()")
if event == nil then
ctld.logError("Event handler was called with a nil event!")
return
@@ -8478,7 +8527,7 @@ function ctld.eventHandler:onEvent(event)
elseif event.id == world.event.S_EVENT_BIRTH then
eventName = "S_EVENT_BIRTH"
else
ctld.logTrace("Ignoring event %s", ctld.p(event))
--ctld.logTrace("Ignoring event %s", ctld.p(event))
return
end
ctld.logDebug("caught event %s: %s", ctld.p(eventName), ctld.p(event))
@@ -8513,7 +8562,7 @@ function ctld.eventHandler:onEvent(event)
for _, aircraftType in pairs(ctld.aircraftTypeTable) do
if aircraftType == playerTypeName then
ctld.logTrace("adding by aircraft type, unitName = %s", ctld.p(unitName))
if ctld.isValueInIpairTable(ctld.transportPilotNames, unitName) == false then
if ctld.tools.isValueInIpairTable(ctld.transportPilotNames, unitName) == false then
table.insert(ctld.transportPilotNames, unitName) -- add transport unit to the list
end
if ctld.addedTo[tostring(_groupId)] == nil then -- only if menu not already set up
@@ -8591,7 +8640,8 @@ function ctld.RandomReal(mini, maxi)
end
-- Tools
function ctld.isValueInIpairTable(tab, value)
ctld.tools = {}
function ctld.tools.isValueInIpairTable(tab, value)
for i, v in ipairs(tab) do
if v == value then
return true -- La valeur existe
@@ -8599,6 +8649,58 @@ function ctld.isValueInIpairTable(tab, value)
end
return false -- La valeur n'existe pas
end
------------------------------------------------------------------------------------
--- Calculates the orientation of an end point relative to a reference point.
--- The calculation takes into account the current orientation of the reference point.
---
--- @param refLat number Latitude of the reference point in degrees.
--- @param refLon number Longitude of the reference point in degrees.
--- @param refHeading number Current orientation of the reference point in degrees (0 = North, 90 = East).
--- @param destLat number Latitude of the arrival point in degrees.
--- @param destLon number Longitude of the arrival point in degrees.
--- @param resultFormat string The desired output format: "radian", "degree" or "clock".
--- @return number The relative orientation in the specified resultFormat.
function ctld.tools.getRelativeBearing(refLat, refLon, refHeading, destLat, destLon, resultFormat)
-- Converting degrees to radians for geometric calculations
local radrefLat = math.rad(refLat)
local raddestLat = math.rad(destLat)
local radrefLon = math.rad(refLon)
local raddestLon = math.rad(destLon)
local radrefHeading = math.rad(refHeading)
-- Calculating the longitude difference between the two points
local deltaLon = raddestLon - radrefLon
-- Using the great circle formula for azimuth (bearing)
-- This formula is based on spherical trigonometry and uses atan2
-- to correctly handle all quadrants.
local y = math.sin(deltaLon) * math.cos(raddestLat)
local x = math.cos(radrefLat) * math.sin(raddestLat) - math.sin(radrefLat) * math.cos(raddestLat) * math.cos(deltaLon)
local absoluteBearingRad = math.atan2(y, x)
-- Calculate relative orientation by subtracting the reference refHeading
local relativeBearingRad = absoluteBearingRad - radrefHeading
-- Normalizes the angle to be in the range [-pi, pi]
-- This ensures a consistent angle, whether positive or negative.
local normalizedRad = (relativeBearingRad + math.pi) % (2 * math.pi) - math.pi
-- Returns the value in the requested resultFormat
if resultFormat == "radian" then
return normalizedRad, resultFormat
elseif resultFormat == "clock" then
-- Convert to clock position (12h = front, 3h = right, 6h = back, etc..)
local bearingDeg = math.deg(normalizedRad)
local clockPosition = ((bearingDeg + 360) % 360) / 30
clockPosition = clockPosition >= 0 and math.floor(clockPosition + 0.5) or math.ceil(clockPosition - 0.5), resultFormat -- rounded clockPosition
if clockPosition == 0 then clockPosition = 12 end
return clockPosition, resultFormat
else -- By default, the resultFormat is "degree"
resultFormat = "degree"
local bearingDeg = math.deg(normalizedRad)
return (bearingDeg + 360) % 360, resultFormat
end
end
--- Enable/Disable error boxes displayed on screen.
env.setErrorMessageBoxEnabled(false)
+18 -12
View File
@@ -11,6 +11,8 @@ It's open-source and free as in free beer (you don't have to pay to use it), and
We're always looking for help, please reach out to [Zip on Discord](https://discordapp.com/users/421317390807203850) if you want to participate in maintenance or development.
And if you'd like to support our work, you can [buy me a coffee](https://coff.ee/veaf_zip)!
## Contents
This script is a rewrite of some of the functionality of the original Complete Combat Troop Transport Script (CTTS) by Geloxo (http://forums.eagle.ru/showthread.php?t=108523), as well as adding new features.
@@ -130,7 +132,7 @@ Optionaly, you can disable the STTS (text to speech over SRS) feature (4).
![dynamic_loading]
### Script Setup
**This script requires MIST version 4.0.57 or above: https://github.com/mrSkortch/MissionScriptingTools**
🔴IMPORTANT: This script requires MIST supplied in the CTLD zipped pack to correctly manage dynamic spwans.
First make sure MIST is loaded, either as an Initialization Script for the mission or the first DO SCRIPT with a "TIME MORE" of 1. "TIME MORE" means run the actions after X seconds into the mission.
@@ -865,10 +867,11 @@ For example, if the laser code is *1688*, the frequency will be *40.40Mhz*.
JTAC frequency is available through the "JTAC Status" radio menu
#### Jtac-automatic-orbiting-over-lased-target
By setting parameter ctld.enableAutoOrbitingFlyingJtacOnTarget = true, a script
dedicated script puts in orbit each flying JTAC over his detected target.
Associated with CTLD/JTAC functions, you can assign a fly route to the JTAC drone,
this one follow it, and start orbiting when he detects a target.
By setting parameter ctld.enableAutoOrbitingFlyingJtacOnTarget = true, a script dedicated script puts in orbit each flying JTAC over his detected target.
Associated with CTLD/JTAC functions, you can assign a fly route to the JTAC drone, this one follow it, and start orbiting when he detects a target.
As soon as it don't detect a target, it restart following its initial route at the nearest waypoint
# In Game
@@ -927,11 +930,13 @@ ctld.JTAC_WEIGHT = 15 -- kg
```
## Limit troop Loading
The number of Infantries units in mission can be limited by setting the table below :
ctld.nbLimitSpwanedTroops = {0, 0} -- {redLimitInfantryCount, blueLimitInfantryCount}
`ctld.nbLimitSpawnedTroops = {0, 0} -- {redLimitInfantryCount, blueLimitInfantryCount}`
When this cumulative number of troops is reached for a coalition, no more troops can be loaded onboard, and a message is sent to player.
If ctld.nbLimitSpwanedTroops = {0, 0} (both values at 0) the limit control is disabled.
If set to `ctld.nbLimitSpawnedTroops = {0, 0}` (both values at 0) the limit control is disabled. This is the default.
If either value is non-zero, limit control becomes active for both coalitions.
## Cargo Spawning and Sling Loading
@@ -1024,13 +1029,14 @@ Rearming:
You can also repair a partially destroyed HAWK / BUK or KUB system by dropping a repair crate next to it and unpacking. A repair crate will also re-arm the system.
## Crate Repacking
The F10 menu allows you to repack units having associated crate types in the "ctld.spawnableCrates" table.
Simply land near the unit you wish to repack and select it from the list presented by the "CTLD//Vehicle/FOB transport...//Repack Vehicles" menu.
The defined radius of vehicles detection is specified by the parameter
ctld.maximumDistanceRepackableUnitsSearch = 200 -- max distance from transportUnit to search force repackable units in meters
The F10 menu allows you to repack units having associated crate types in the "ctld.spawnableCrates" table.
Simply land near the unit you wish to repack and select it from the list presented by the "CTLD//Vehicle/FOB transport...//Repack Vehicles" menu.
The defined radius of vehicles detection is specified by the parameter `ctld.maximumDistanceRepackableUnitsSearch` (default 200 meters).
WARNING: Due to technical reasons related to the refresh time of the F10 menus, there may be inconsistencies between the type of vehicles requested and those provided. It is recommended to wait 5 to 10 seconds without moving after landing and opening the F10 menu for a packaging order.
*WARNING*: Due to technical reasons related to the refresh time of the F10 menus, there may be inconsistencies between the type of vehicles requested and those provided. It is recommended to wait 5 to 10 seconds without moving after landing and opening the F10 menu for a packaging order.
## Forward Operating Base (FOB) Construction
FOBs can be built by loading special FOB crates from a **Logistics** unit into a C-130 or other large aircraft configured in the script. To load the crate use the F10 - Troop Commands Menu. The idea behind FOBs is to make player vs player missions even more dynamic as these can be deployed in most locations. Once destroyed the FOB can no longer be used.
+21 -13
View File
@@ -35,7 +35,7 @@ mist = {}
-- don't change these
mist.majorVersion = 4
mist.minorVersion = 5
mist.build = "128-DYNSLOTS-01"
mist.build = "128-DYNSLOTS-02"
-- forward declaration of log shorthand
local log
@@ -826,11 +826,11 @@ do -- the main scope
if zone.verticies then
local offset = {}
for i = 1, #zone.verticies do
table.insert(offset, {dist = mist.utils.get2DDist(uRef.point, zone.verticies[i]), heading = mist.getHeadingPoints(uRef.point, zone.verticies[i]) + uRef.heading})
table.insert(offset, {dist = mist.utils.get2DDist(uRef.point, zone.verticies[i]), heading = mist.utils.getHeadingPoints(uRef.point, zone.verticies[i]) + uRef.heading})
end
zone.offset = offset
else
zone.offset = {dist = mist.utils.get2DDist(uRef.point, zone.point), heading = mist.getHeadingPoints(uRef.point, zone.point) + uRef.heading}
zone.offset = {dist = mist.utils.get2DDist(uRef.point, zone.point), heading = mist.utils.getHeadingPoints(uRef.point, zone.point) + uRef.heading}
end
end
end
@@ -1481,19 +1481,27 @@ do -- the main scope
-- dont need to add units spawned in at the start of the mission if mist is loaded in init line
if event.id == world.event.S_EVENT_BIRTH and timer.getTime0() < timer.getAbsTime() then
if Object.getCategory(event.initiator) == 1 then
if Object.getCategory(event.initiator) == 1 then
--log:info('Object is a Unit')
local g = Unit.getGroup(event.initiator)
if g and event.initiator:getPlayerName() ~= "" and not mist.DBs.MEunitsByName[event.initiator:getName()] then
if not g then
log:error('groupSpawned event handler: cannot get hold of Group via Unit. This is a DCS bug')
return
end
if event.initiator:getPlayerName() == "" then
log:error('groupSpawned event handler: cannot get initiator playerName. This is a DCS bug')
return
end
if not mist.DBs.MEunitsByName[event.initiator:getName()] then
log:error('groupSpawned event handler: cannot find initiator unit in MiST tables. This is a DCS bug')
return
end
-- log:info(Unit.getGroup(event.initiator):getName())
local gName = g:getName()
if not tempSpawnedGroups[gName] then
--log:warn('addedTo tempSpawnedGroups: $1', gName)
tempSpawnedGroups[gName] = {type = 'group', gp = g}
tempSpawnGroupsCounter = tempSpawnGroupsCounter + 1
end
else
log:error('Group not accessible by unit in event handler. This is a DCS bug')
local gName = g:getName()
if not tempSpawnedGroups[gName] then
--log:warn('addedTo tempSpawnedGroups: $1', gName)
tempSpawnedGroups[gName] = {type = 'group', gp = g}
tempSpawnGroupsCounter = tempSpawnGroupsCounter + 1
end
elseif Object.getCategory(event.initiator) == 3 or Object.getCategory(event.initiator) == 6 then
--log:info('staticSpawnEvent')
Binary file not shown.
Binary file not shown.
Binary file not shown.