mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Compare commits
209 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c6efed995 | ||
|
|
68a31b1eb7 | ||
|
|
f46f755327 | ||
|
|
5d4f870a1d | ||
|
|
08c5c38c7b | ||
|
|
0c9238651a | ||
|
|
10a9b062b6 | ||
|
|
53c6a17ccb | ||
|
|
c10617e1b0 | ||
|
|
be01567a1b | ||
|
|
88fc501c24 | ||
|
|
e93bb5ceba | ||
|
|
7983621f8e | ||
|
|
6c79d6b01f | ||
|
|
b2a351e67d | ||
|
|
574fa8abf4 | ||
|
|
c4f4af5e5a | ||
|
|
1da0792ed7 | ||
|
|
7d37acb1cd | ||
|
|
fd230701e9 | ||
|
|
91d492c579 | ||
|
|
5eabe7e644 | ||
|
|
368e720cab | ||
|
|
cba156b3dc | ||
|
|
676bc0fef0 | ||
|
|
7455c63716 | ||
|
|
81818705df | ||
|
|
61ea484614 | ||
|
|
d5e8de4d74 | ||
|
|
b7d5144c91 | ||
|
|
7bba5ec69e | ||
|
|
0441acf101 | ||
|
|
89f0909a8f | ||
|
|
ff0f1c4c24 | ||
|
|
3a6c52ae73 | ||
|
|
7ec18ebf00 | ||
|
|
66f52d41eb | ||
|
|
1172cf0ae7 | ||
|
|
1d296d1cf4 | ||
|
|
a6bddc5aca | ||
|
|
bdd40fdf7d | ||
|
|
c84e153ff2 | ||
|
|
ab4c83d284 | ||
|
|
cd99c053df | ||
|
|
3434ef47d9 | ||
|
|
c5145a38e2 | ||
|
|
38b9778e9a | ||
|
|
2ca6168f47 | ||
|
|
0da2299472 | ||
|
|
bf2ce3c4af | ||
|
|
c0f82eabb2 | ||
|
|
30aba1258d | ||
|
|
f2ed920214 | ||
|
|
2fc7139f6b | ||
|
|
e8ace49e8b | ||
|
|
dddb9ff713 | ||
|
|
f582f7df7c | ||
|
|
14c6d1be9b | ||
|
|
0731e15385 | ||
|
|
9eb82060a5 | ||
|
|
9f232ab5ec | ||
|
|
ec0d164619 | ||
|
|
e804ab9254 | ||
|
|
25cb12a81a | ||
|
|
231acc7363 | ||
|
|
d8bdf6a8d3 | ||
|
|
d506067c72 | ||
|
|
4483d3231a | ||
|
|
481ee186aa | ||
|
|
8820b8a41c | ||
|
|
0971f8ffa7 | ||
|
|
9739f94428 | ||
|
|
450f4eaec0 | ||
|
|
b5186fa328 | ||
|
|
526dc8363d | ||
|
|
242d735d8c | ||
|
|
9fedd32e78 | ||
|
|
a146003a6a | ||
|
|
d17df74191 | ||
|
|
d23403383f | ||
|
|
877b36f8a8 | ||
|
|
299820162b | ||
|
|
5d20a59d92 | ||
|
|
c1ab3b5476 | ||
|
|
0076130483 | ||
|
|
a5194b1999 | ||
|
|
b53b1f083f | ||
|
|
994a36001f | ||
|
|
26b91e3f66 | ||
|
|
f42aedd485 | ||
|
|
a73818a615 | ||
|
|
7c22e9fe69 | ||
|
|
c58e91b956 | ||
|
|
a61059242c | ||
|
|
cea9437e66 | ||
|
|
3f052ef1da | ||
|
|
c137a4b06d | ||
|
|
6c46dafc59 | ||
|
|
1207417894 | ||
|
|
7c717c219c | ||
|
|
a9fad53255 | ||
|
|
372cc021bd | ||
|
|
6820774266 | ||
|
|
a0c189a349 | ||
|
|
1060ff16d8 | ||
|
|
1255f48645 | ||
|
|
7ef69208d4 | ||
|
|
5277cca4e1 | ||
|
|
aaf77815ca | ||
|
|
3f488cc091 | ||
|
|
bdbbdfe60e | ||
|
|
d15c2be2d0 | ||
|
|
73994914eb | ||
|
|
63b0dae794 | ||
|
|
003e865ff7 | ||
|
|
e3c03287b7 | ||
|
|
73493c3a23 | ||
|
|
562a3f6208 | ||
|
|
3c5f3d6c37 | ||
|
|
a37d4214c0 | ||
|
|
636d6ce324 | ||
|
|
eef8b362d2 | ||
|
|
4ae586ebaa | ||
|
|
f6e673c2bb | ||
|
|
183a60159c | ||
|
|
1fdf4f371d | ||
|
|
f50c374d04 | ||
|
|
d59fc331f6 | ||
|
|
b83f478294 | ||
|
|
d5636f4a19 | ||
|
|
196bcf39cf | ||
|
|
afec1c3a5b | ||
|
|
6025339b46 | ||
|
|
40c6cc59d3 | ||
|
|
514e568e04 | ||
|
|
2f34b0a5ed | ||
|
|
708c076885 | ||
|
|
f0e0b918af | ||
|
|
e45f5e1122 | ||
|
|
932015668b | ||
|
|
4011bc3fe6 | ||
|
|
1dcccdc434 | ||
|
|
3380ed9360 | ||
|
|
ed9c14e63d | ||
|
|
4762793adc | ||
|
|
7df3946189 | ||
|
|
d5fb75fe43 | ||
|
|
c0b32a5584 | ||
|
|
e2b1276d7b | ||
|
|
f6aea13fae | ||
|
|
646b113c55 | ||
|
|
58074f499f | ||
|
|
1483ffd7ff | ||
|
|
cdaef851a0 | ||
|
|
04068d7117 | ||
|
|
41e8ddea8c | ||
|
|
cc49791997 | ||
|
|
ba4a8050ba | ||
|
|
7c5067a59a | ||
|
|
69eb920173 | ||
|
|
07d761941a | ||
|
|
ca52585759 | ||
|
|
decc9d09f8 | ||
|
|
466a18447c | ||
|
|
27902ee107 | ||
|
|
8a8b806362 | ||
|
|
40bb181c78 | ||
|
|
8099847e29 | ||
|
|
6e8edd95ec | ||
|
|
5112c9598b | ||
|
|
749158c086 | ||
|
|
b3d4024f21 | ||
|
|
c283b66c1d | ||
|
|
3209843318 | ||
|
|
d35e5cc0f7 | ||
|
|
e5eeb592a2 | ||
|
|
3d38f4d17a | ||
|
|
2d91647e0b | ||
|
|
cac0f30673 | ||
|
|
c5ecba3389 | ||
|
|
e0397dff47 | ||
|
|
e08fb2e972 | ||
|
|
c02ae82003 | ||
|
|
e6fc301b0d | ||
|
|
a385ed57fb | ||
|
|
09dafe4b1d | ||
|
|
ba8505c983 | ||
|
|
fba359d389 | ||
|
|
c56763b68f | ||
|
|
03c2943545 | ||
|
|
98039b9048 | ||
|
|
5065d3b068 | ||
|
|
6828f7e262 | ||
|
|
a685f3ffbd | ||
|
|
e84156d2e9 | ||
|
|
0ce1c31e1c | ||
|
|
f7e14bb60c | ||
|
|
7b907df816 | ||
|
|
7f5be2829c | ||
|
|
fa5afae783 | ||
|
|
b17507d0fa | ||
|
|
5ed43a3190 | ||
|
|
d2a5144a23 | ||
|
|
fb2031d7ca | ||
|
|
4a42571925 | ||
|
|
38413625c2 | ||
|
|
2d544b7a98 | ||
|
|
b1e5e1840e | ||
|
|
e6f9b4a125 |
10
.vs/VSWorkspaceState.json
Normal file
10
.vs/VSWorkspaceState.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"ExpandedNodes": [
|
||||||
|
"",
|
||||||
|
"\\Moose Development",
|
||||||
|
"\\Moose Development\\Moose",
|
||||||
|
"\\Moose Development\\Moose\\Ops"
|
||||||
|
],
|
||||||
|
"SelectedNode": "\\Moose Development\\Moose\\Ops\\Airboss.lua",
|
||||||
|
"PreviewInSolutionExplorer": false
|
||||||
|
}
|
||||||
BIN
.vs/slnx.sqlite
Normal file
BIN
.vs/slnx.sqlite
Normal file
Binary file not shown.
166
Moose Development/Moose/.editorconfig
Normal file
166
Moose Development/Moose/.editorconfig
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# Repository: https://github.com/CppCXY/EmmyLuaCodeStyle
|
||||||
|
# English documentation: https://github.com/CppCXY/EmmyLuaCodeStyle/blob/master/README_EN.md
|
||||||
|
[*.lua]
|
||||||
|
# [basic]
|
||||||
|
|
||||||
|
# optional space/tab
|
||||||
|
indent_style = space
|
||||||
|
# if indent_style is space, this is valid
|
||||||
|
indent_size = 4
|
||||||
|
# if indent_style is tab, this is valid
|
||||||
|
tab_width = 4
|
||||||
|
# none/single/double
|
||||||
|
quote_style = none
|
||||||
|
|
||||||
|
# only support number
|
||||||
|
continuation_indent_size = 0
|
||||||
|
|
||||||
|
# optional crlf/lf/cr/auto, if it is 'auto', in windows it is crlf other platforms are lf
|
||||||
|
end_of_line = auto
|
||||||
|
|
||||||
|
detect_end_of_line = false
|
||||||
|
|
||||||
|
# this mean utf8 length , if this is 'unset' then the line width is no longer checked
|
||||||
|
# this option decides when to chopdown the code
|
||||||
|
max_line_length = 9999
|
||||||
|
|
||||||
|
# this will check text end with new line
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# [function]
|
||||||
|
|
||||||
|
# function call expression's args will align to first arg
|
||||||
|
# optional true/false/only_after_more_indention_statement/only_not_exist_cross_row_expression
|
||||||
|
align_call_args = false
|
||||||
|
|
||||||
|
# if true, all function define params will align to first param
|
||||||
|
align_function_define_params = true
|
||||||
|
|
||||||
|
remove_expression_list_finish_comma = true
|
||||||
|
|
||||||
|
# keep/remove/remove_table_only/remove_string_only/unambiguous_remove_string_only
|
||||||
|
call_arg_parentheses = keep
|
||||||
|
|
||||||
|
# [table]
|
||||||
|
|
||||||
|
#optional none/comma/semicolon
|
||||||
|
table_separator_style = none
|
||||||
|
|
||||||
|
#optional keep/never/always/smart
|
||||||
|
trailing_table_separator = keep
|
||||||
|
|
||||||
|
# see document for detail
|
||||||
|
continuous_assign_table_field_align_to_equal_sign = true
|
||||||
|
|
||||||
|
# if true, format like this "local t = { 1, 2, 3 }"
|
||||||
|
keep_one_space_between_table_and_bracket = true
|
||||||
|
|
||||||
|
# if indent_style is tab, this option is invalid
|
||||||
|
align_table_field_to_first_field = true
|
||||||
|
|
||||||
|
# [statement]
|
||||||
|
|
||||||
|
align_chained_expression_statement = false
|
||||||
|
|
||||||
|
# continous line distance
|
||||||
|
max_continuous_line_distance = 1
|
||||||
|
|
||||||
|
# see document for detail
|
||||||
|
continuous_assign_statement_align_to_equal_sign = true
|
||||||
|
|
||||||
|
# if statement will align like switch case
|
||||||
|
if_condition_align_with_each_other = false
|
||||||
|
|
||||||
|
# if true, continuation_indent_size for local or assign statement is invalid
|
||||||
|
# however, if the expression list has cross row expression, it will not be aligned to the first expression
|
||||||
|
local_assign_continuation_align_to_first_expression = false
|
||||||
|
|
||||||
|
statement_inline_comment_space = 1
|
||||||
|
|
||||||
|
# [indentation]
|
||||||
|
|
||||||
|
# if true, the label loses its current indentation
|
||||||
|
label_no_indent = false
|
||||||
|
# if true, there will be no indentation in the do statement
|
||||||
|
do_statement_no_indent = false
|
||||||
|
# if true, the conditional expression of the if statement will not be a continuation line indent
|
||||||
|
if_condition_no_continuation_indent = false
|
||||||
|
|
||||||
|
if_branch_comments_after_block_no_indent = false
|
||||||
|
|
||||||
|
# [space]
|
||||||
|
|
||||||
|
# if true, t[#t+1] will not space wrapper '+'
|
||||||
|
table_append_expression_no_space = false
|
||||||
|
|
||||||
|
long_chain_expression_allow_one_space_after_colon = false
|
||||||
|
|
||||||
|
remove_empty_header_and_footer_lines_in_function = true
|
||||||
|
|
||||||
|
space_before_function_open_parenthesis = false
|
||||||
|
|
||||||
|
space_inside_function_call_parentheses = false
|
||||||
|
|
||||||
|
space_inside_function_param_list_parentheses = false
|
||||||
|
|
||||||
|
space_before_open_square_bracket = false
|
||||||
|
|
||||||
|
space_inside_square_brackets = false
|
||||||
|
|
||||||
|
# if true, ormat like this "local t <const> = 1"
|
||||||
|
keep_one_space_between_namedef_and_attribute = true
|
||||||
|
|
||||||
|
# [row_layout]
|
||||||
|
# The following configuration supports four expressions
|
||||||
|
# minLine:${n}
|
||||||
|
# keepLine
|
||||||
|
# keepLine:${n}
|
||||||
|
# maxLine:${n}
|
||||||
|
|
||||||
|
keep_line_after_if_statement = minLine:0
|
||||||
|
|
||||||
|
keep_line_after_do_statement = minLine:0
|
||||||
|
|
||||||
|
keep_line_after_while_statement = minLine:0
|
||||||
|
|
||||||
|
keep_line_after_repeat_statement = minLine:0
|
||||||
|
|
||||||
|
keep_line_after_for_statement = minLine:0
|
||||||
|
|
||||||
|
keep_line_after_local_or_assign_statement = keepLine
|
||||||
|
|
||||||
|
keep_line_after_function_define_statement = keepLine:1
|
||||||
|
|
||||||
|
keep_line_after_expression_statement = keepLine
|
||||||
|
|
||||||
|
# [diagnostic]
|
||||||
|
|
||||||
|
# the following is code diagnostic options
|
||||||
|
enable_check_codestyle = true
|
||||||
|
|
||||||
|
# [diagnostic.name_style]
|
||||||
|
enable_name_style_check = false
|
||||||
|
# the following is name style check rule
|
||||||
|
# base option off/camel_case/snake_case/upper_snake_case/pascal_case/same(filename/first_param/'<const string>', snake_case/pascal_case/camel_case)
|
||||||
|
# all option can use '|' represent or
|
||||||
|
# for example:
|
||||||
|
# snake_case | upper_snake_case
|
||||||
|
# same(first_param, snake_case)
|
||||||
|
# same('m')
|
||||||
|
local_name_define_style = snake_case
|
||||||
|
|
||||||
|
function_param_name_style = snake_case
|
||||||
|
|
||||||
|
function_name_define_style = snake_case
|
||||||
|
|
||||||
|
local_function_name_define_style = snake_case
|
||||||
|
|
||||||
|
table_field_name_define_style = snake_case
|
||||||
|
|
||||||
|
global_variable_name_define_style = snake_case|upper_snake_case
|
||||||
|
|
||||||
|
module_name_define_style = same('m')|same(filename, snake_case)
|
||||||
|
|
||||||
|
require_module_name_style = same(first_param, snake_case)
|
||||||
|
|
||||||
|
class_name_define_style = same(filename, snake_case)
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# See https://github.com/Koihik/LuaFormatter
|
|
||||||
# Use '-- LuaFormatter off' and '-- LuaFormatter on' around code blocks to inhibit formatting
|
|
||||||
|
|
||||||
column_limit: 500
|
|
||||||
indent_width: 2
|
|
||||||
use_tab: false
|
|
||||||
continuation_indent_width: 2
|
|
||||||
keep_simple_control_block_one_line: false
|
|
||||||
keep_simple_function_one_line: false
|
|
||||||
align_args: true
|
|
||||||
break_after_functioncall_lp: false
|
|
||||||
break_before_functioncall_rp: false
|
|
||||||
align_parameter: true
|
|
||||||
chop_down_parameter: true
|
|
||||||
break_after_functiondef_lp: false
|
|
||||||
break_before_functiondef_rp: false
|
|
||||||
align_table_field: true
|
|
||||||
break_after_table_lb: true
|
|
||||||
break_before_table_rb: true
|
|
||||||
chop_down_table: true
|
|
||||||
chop_down_kv_table: true
|
|
||||||
column_table_limit: 500
|
|
||||||
table_sep: ','
|
|
||||||
extra_sep_at_table_end: true
|
|
||||||
break_after_operator: true
|
|
||||||
single_quote_to_double_quote: false
|
|
||||||
double_quote_to_single_quote: false
|
|
||||||
spaces_before_call: 1
|
|
||||||
spaces_inside_functiondef_parens: true
|
|
||||||
spaces_inside_functioncall_parens: true
|
|
||||||
spaces_inside_table_braces: true
|
|
||||||
spaces_around_equals_in_field: true
|
|
||||||
line_breaks_after_function_body: 1
|
|
||||||
17
Moose Development/Moose/.vscode/settings.json
vendored
Normal file
17
Moose Development/Moose/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"Lua.workspace.preloadFileSize": 1000,
|
||||||
|
"Lua.diagnostics.disable": [
|
||||||
|
"undefined-doc-name"
|
||||||
|
],
|
||||||
|
"Lua.diagnostics.globals": [
|
||||||
|
"BASE",
|
||||||
|
"lfs",
|
||||||
|
"__Moose",
|
||||||
|
"trigger",
|
||||||
|
"coord",
|
||||||
|
"missionCommands"
|
||||||
|
],
|
||||||
|
"Lua.completion.displayContext": 5,
|
||||||
|
"Lua.runtime.version": "Lua 5.1",
|
||||||
|
"Lua.completion.callSnippet": "Both"
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
--- **AI** -- (R2.2) - Models the process of Combat Air Patrol (CAP) for airplanes.
|
--- **AI** - Models the process of Combat Air Patrol (CAP) for airplanes.
|
||||||
|
--
|
||||||
|
-- This is a class used in the @{AI.AI_A2A_Dispatcher}.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -13,8 +15,7 @@
|
|||||||
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
-- @extends AI.AI_Air_Patrol#AI_AIR_PATROL
|
||||||
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
-- @extends AI.AI_Air_Engage#AI_AIR_ENGAGE
|
||||||
|
|
||||||
|
--- The AI_A2A_CAP class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
||||||
--- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -81,15 +82,15 @@
|
|||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||||
-- The range is applied at the position of the AI.
|
-- The range is applied at the position of the AI.
|
||||||
-- Use the method @{AI.AI_CAP#AI_A2A_CAP.SetEngageRange}() to define that range.
|
-- Use the method @{#AI_A2A_CAP.SetEngageRange}() to define that range.
|
||||||
--
|
--
|
||||||
-- ## 4. Set the Zone of Engagement
|
-- ## 4. Set the Zone of Engagement
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Core.Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI.AI_Cap#AI_A2A_CAP.SetEngageZone}() to define that Zone.
|
-- Use the method @{#AI_A2A_CAP.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -106,7 +107,7 @@ AI_A2A_CAP = {
|
|||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
@@ -132,7 +133,7 @@ end
|
|||||||
--- Creates a new AI_A2A_CAP object
|
--- Creates a new AI_A2A_CAP object
|
||||||
-- @param #AI_A2A_CAP self
|
-- @param #AI_A2A_CAP self
|
||||||
-- @param Wrapper.Group#GROUP AICap
|
-- @param Wrapper.Group#GROUP AICap
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -191,7 +192,7 @@ end
|
|||||||
--- Evaluate the attack and create an AttackUnitTask list.
|
--- Evaluate the attack and create an AttackUnitTask list.
|
||||||
-- @param #AI_A2A_CAP self
|
-- @param #AI_A2A_CAP self
|
||||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||||
-- @return #AI_A2A_CAP self
|
-- @return #AI_A2A_CAP self
|
||||||
function AI_A2A_CAP:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
function AI_A2A_CAP:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** - (R2.2) - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
--- **AI** - Manages the process of an automatic A2A defense system based on an EWR network targets and coordinating CAP and GCI.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -57,8 +57,8 @@
|
|||||||
--
|
--
|
||||||
-- ## 2. Which type of EWR will I setup? Grouping based per AREA, per TYPE or per UNIT? (Later others will follow).
|
-- ## 2. Which type of EWR will I setup? Grouping based per AREA, per TYPE or per UNIT? (Later others will follow).
|
||||||
--
|
--
|
||||||
-- The MOOSE framework leverages the @{Detection} classes to perform the EWR detection.
|
-- The MOOSE framework leverages the @{Functional.Detection} classes to perform the EWR detection.
|
||||||
-- Several types of @{Detection} classes exist, and the most common characteristics of these classes is that they:
|
-- Several types of @{Functional.Detection} classes exist, and the most common characteristics of these classes is that they:
|
||||||
--
|
--
|
||||||
-- * Perform detections from multiple FACs as one co-operating entity.
|
-- * Perform detections from multiple FACs as one co-operating entity.
|
||||||
-- * Communicate with a Head Quarters, which consolidates each detection.
|
-- * Communicate with a Head Quarters, which consolidates each detection.
|
||||||
@@ -126,7 +126,7 @@
|
|||||||
-- * polygon zones
|
-- * polygon zones
|
||||||
-- * moving zones
|
-- * moving zones
|
||||||
--
|
--
|
||||||
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
|
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
|
||||||
--
|
--
|
||||||
-- ## 14. For each Squadron doing CAP, what are the time intervals and CAP amounts to be performed?
|
-- ## 14. For each Squadron doing CAP, what are the time intervals and CAP amounts to be performed?
|
||||||
--
|
--
|
||||||
@@ -356,7 +356,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}.
|
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}.
|
||||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than
|
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than
|
||||||
-- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are.
|
-- it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are.
|
||||||
-- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition.
|
-- In a hot war the borders are effectively defined by the ground based radar coverage of a coalition.
|
||||||
@@ -425,7 +425,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromParkingHot}() will spawn new aircraft in with running engines at a parking spot at the airfield.
|
-- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromParkingHot}() will spawn new aircraft in with running engines at a parking spot at the airfield.
|
||||||
-- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromRunway}() will spawn new aircraft at the runway at the airfield.
|
-- * @{#AI_A2A_DISPATCHER.SetSquadronTakeoffFromRunway}() will spawn new aircraft at the runway at the airfield.
|
||||||
--
|
--
|
||||||
-- **The default landing method is to spawn new aircraft directly in the air.**
|
-- **The default take-off method is to spawn new aircraft directly in the air.**
|
||||||
--
|
--
|
||||||
-- Use these methods to fine-tune for specific airfields that are known to create bottlenecks, or have reduced airbase efficiency.
|
-- Use these methods to fine-tune for specific airfields that are known to create bottlenecks, or have reduced airbase efficiency.
|
||||||
-- The more and the longer aircraft need to taxi at an airfield, the more risk there is that:
|
-- The more and the longer aircraft need to taxi at an airfield, the more risk there is that:
|
||||||
@@ -592,7 +592,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- A2ADispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" )
|
-- A2ADispatcher:SetSquadronCap( "Maykop", CAPZoneMiddle, 4000, 8000, 600, 800, 800, 1200, "RADIO" )
|
||||||
-- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
-- A2ADispatcher:SetSquadronCapInterval( "Sochi", 2, 30, 120, 1 )
|
||||||
--
|
--
|
||||||
-- Note the different @{Zone} MOOSE classes being used to create zones of different types. Please click the @{Zone} link for more information about the different zone types.
|
-- Note the different @{Core.Zone} MOOSE classes being used to create zones of different types. Please click the @{Core.Zone} link for more information about the different zone types.
|
||||||
-- Zones can be circles, can be setup in the mission editor using trigger zones, but can also be setup in the mission editor as polygons and in this case GROUP objects are being used!
|
-- Zones can be circles, can be setup in the mission editor using trigger zones, but can also be setup in the mission editor as polygons and in this case GROUP objects are being used!
|
||||||
--
|
--
|
||||||
-- ## 7.2. Set the squadron to execute CAP:
|
-- ## 7.2. Set the squadron to execute CAP:
|
||||||
@@ -881,8 +881,9 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Enumerator for spawns at airbases
|
--- Enumerator for spawns at airbases
|
||||||
-- @type AI_A2A_DISPATCHER.Takeoff
|
-- @type AI_A2A_DISPATCHER.Takeoff
|
||||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
-- @extends Wrapper.Group#GROUP.Takeoff
|
||||||
|
|
||||||
--- @field #AI_A2A_DISPATCHER.Takeoff Takeoff
|
---
|
||||||
|
-- @field #AI_A2A_DISPATCHER.Takeoff Takeoff
|
||||||
AI_A2A_DISPATCHER.Takeoff = GROUP.Takeoff
|
AI_A2A_DISPATCHER.Takeoff = GROUP.Takeoff
|
||||||
|
|
||||||
--- Defines Landing type/location.
|
--- Defines Landing type/location.
|
||||||
@@ -928,6 +929,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self.DefenderTasks = {} -- The Defenders Tasks.
|
self.DefenderTasks = {} -- The Defenders Tasks.
|
||||||
self.DefenderDefault = {} -- The Defender Default Settings over all Squadrons.
|
self.DefenderDefault = {} -- The Defender Default Settings over all Squadrons.
|
||||||
|
|
||||||
|
self.SetSendPlayerMessages = false --#boolean Flash messages to player
|
||||||
|
|
||||||
-- TODO: Check detection through radar.
|
-- TODO: Check detection through radar.
|
||||||
self.Detection:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
|
self.Detection:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
|
||||||
-- self.Detection:InitDetectRadar( true )
|
-- self.Detection:InitDetectRadar( true )
|
||||||
@@ -1145,7 +1148,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
|
|
||||||
self:I( "Captured " .. AirbaseName )
|
self:I( "Captured " .. AirbaseName )
|
||||||
|
|
||||||
-- Now search for all squadrons located at the airbase, and sanatize them.
|
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||||
if Squadron.AirbaseName == AirbaseName then
|
if Squadron.AirbaseName == AirbaseName then
|
||||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||||
@@ -1301,7 +1304,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Define a border area to simulate a **cold war** scenario.
|
--- Define a border area to simulate a **cold war** scenario.
|
||||||
-- A **cold war** is one where CAP aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
-- A **cold war** is one where CAP aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||||
-- A **hot war** is one where CAP aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send CAP and GCI aircraft to attack it.
|
-- A **hot war** is one where CAP aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send CAP and GCI aircraft to attack it.
|
||||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
||||||
@@ -1710,7 +1713,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- Get free parking for fighter aircraft.
|
-- Get free parking for fighter aircraft.
|
||||||
local nfreeparking = DefenderSquadron.Airbase:GetFreeParkingSpotsNumber( AIRBASE.TerminalType.FighterAircraft, true )
|
local nfreeparking = DefenderSquadron.Airbase:GetFreeParkingSpotsNumber( AIRBASE.TerminalType.FighterAircraft, true )
|
||||||
|
|
||||||
-- Take number of free parking spots if no resource count was specifed.
|
-- Take number of free parking spots if no resource count was specified.
|
||||||
DefenderSquadron.ResourceCount = DefenderSquadron.ResourceCount or nfreeparking
|
DefenderSquadron.ResourceCount = DefenderSquadron.ResourceCount or nfreeparking
|
||||||
|
|
||||||
-- Check that resource count is not larger than free parking spots.
|
-- Check that resource count is not larger than free parking spots.
|
||||||
@@ -1755,7 +1758,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param #number EngageAltType The altitude type to engage, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
|
-- @param #number EngageAltType The altitude type to engage, which is a string "BARO" defining Barometric or "RADIO" defining radio controlled altitude.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
||||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
|
-- @param #number PatrolMaxSpeed The maximum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
|
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
|
||||||
@@ -1822,7 +1825,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
--- Set a CAP for a Squadron.
|
--- Set a CAP for a Squadron.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the CAP will be executed.
|
||||||
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
|
-- @param #number PatrolFloorAltitude The minimum altitude at which the cap can be executed.
|
||||||
-- @param #number PatrolCeilingAltitude the maximum altitude at which the cap can be executed.
|
-- @param #number PatrolCeilingAltitude the maximum altitude at which the cap can be executed.
|
||||||
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed The minimum speed at which the cap can be executed.
|
||||||
@@ -2319,6 +2322,13 @@ do -- AI_A2A_DISPATCHER
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set flashing player messages on or off
|
||||||
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
|
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||||
|
function AI_A2A_DISPATCHER:SetSendMessages( onoff )
|
||||||
|
self.SetSendPlayerMessages = onoff
|
||||||
|
end
|
||||||
|
|
||||||
--- Sets flights to take-off in the air, as part of the defense system.
|
--- Sets flights to take-off in the air, as part of the defense system.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string SquadronName The name of the squadron.
|
-- @param #string SquadronName The name of the squadron.
|
||||||
@@ -2971,7 +2981,20 @@ do -- AI_A2A_DISPATCHER
|
|||||||
for FriendlyDistance, AIFriendly in UTILS.spairs( DefenderFriendlies or {} ) do
|
for FriendlyDistance, AIFriendly in UTILS.spairs( DefenderFriendlies or {} ) do
|
||||||
-- We only allow to ENGAGE targets as long as the Units on both sides are balanced.
|
-- We only allow to ENGAGE targets as long as the Units on both sides are balanced.
|
||||||
if AttackerCount > DefenderCount then
|
if AttackerCount > DefenderCount then
|
||||||
local Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP
|
--self:I("***** AI_A2A_DISPATCHER:CountDefendersToBeEngaged() *****\nThis is supposed to be a UNIT:")
|
||||||
|
if AIFriendly then
|
||||||
|
local classname = AIFriendly.ClassName or "No Class Name"
|
||||||
|
local unitname = AIFriendly.IdentifiableName or "No Unit Name"
|
||||||
|
--self:I("Class Name: " .. classname)
|
||||||
|
--self:I("Unit Name: " .. unitname)
|
||||||
|
--self:I({AIFriendly})
|
||||||
|
end
|
||||||
|
local Friendly = nil
|
||||||
|
if AIFriendly and AIFriendly:IsAlive() then
|
||||||
|
--self:I("AIFriendly alive, getting GROUP")
|
||||||
|
Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP
|
||||||
|
end
|
||||||
|
|
||||||
if Friendly and Friendly:IsAlive() then
|
if Friendly and Friendly:IsAlive() then
|
||||||
-- Ok, so we have a friendly near the potential target.
|
-- Ok, so we have a friendly near the potential target.
|
||||||
-- Now we need to check if the AIGroup has a Task.
|
-- Now we need to check if the AIGroup has a Task.
|
||||||
@@ -3175,7 +3198,9 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron then
|
if Squadron then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " Wheels up.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " Wheels up.", DefenderGroup )
|
||||||
|
end
|
||||||
AI_A2A_Fsm:__Patrol( 2 ) -- Start Patrolling
|
AI_A2A_Fsm:__Patrol( 2 ) -- Start Patrolling
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3187,10 +3212,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self:GetParent( self ).onafterPatrolRoute( self, DefenderGroup, From, Event, To )
|
self:GetParent( self ).onafterPatrolRoute( self, DefenderGroup, From, Event, To )
|
||||||
|
|
||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
if Squadron then
|
if Squadron and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
@@ -3206,8 +3231,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
if Squadron then
|
if Squadron and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
||||||
end
|
end
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
end
|
end
|
||||||
@@ -3391,10 +3416,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local DefenderTarget = Dispatcher:GetDefenderTaskTarget( DefenderGroup )
|
local DefenderTarget = Dispatcher:GetDefenderTaskTarget( DefenderGroup )
|
||||||
|
|
||||||
if DefenderTarget then
|
if DefenderTarget then
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " wheels up.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " wheels up.", DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " колеса вверх.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " колёса вверх.", DefenderGroup )
|
||||||
end
|
end
|
||||||
-- Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
-- Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
||||||
Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
||||||
@@ -3412,12 +3437,12 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", intercepting bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", intercepting bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", перехват самолетов в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", перехватывая боги в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
elseif Squadron.Language == "DE" then
|
elseif Squadron.Language == "DE" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", Eindringlinge abfangen bei" .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", Eindringlinge abfangen bei" .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:GetParent( Fsm ).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
self:GetParent( Fsm ).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
@@ -3434,10 +3459,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", захватывающие самолеты в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", задействуя боги в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:GetParent( Fsm ).onafterEngage( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
self:GetParent( Fsm ).onafterEngage( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
@@ -3452,10 +3477,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron then
|
if Squadron then
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", возвращаясь на базу.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", возвращение на базу.", DefenderGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
@@ -3483,11 +3508,11 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " landing at base.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " landing at base.", DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", захватывающие самолеты в посадка на базу.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", посадка на базу.", DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
if Action and Action == "Destroy" then
|
if Action and Action == "Destroy" then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
@@ -3570,7 +3595,7 @@ do -- AI_A2A_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Assigns A2G AI Tasks in relation to the detected items.
|
--- Assigns A2G AI Tasks in relation to the detected items.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
function AI_A2A_DISPATCHER:Order( DetectedItem )
|
function AI_A2A_DISPATCHER:Order( DetectedItem )
|
||||||
|
|
||||||
local detection = self.Detection -- Functional.Detection#DETECTION_AREAS
|
local detection = self.Detection -- Functional.Detection#DETECTION_AREAS
|
||||||
@@ -3877,7 +3902,7 @@ do
|
|||||||
self:CAP( SquadronName )
|
self:CAP( SquadronName )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add resources to a Squadron
|
--- Add resources to a Squadron
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string Squadron The squadron name.
|
-- @param #string Squadron The squadron name.
|
||||||
-- @param #number Amount Number of resources to add.
|
-- @param #number Amount Number of resources to add.
|
||||||
@@ -3900,7 +3925,7 @@ do
|
|||||||
end
|
end
|
||||||
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -4471,5 +4496,5 @@ do
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **AI** -- (R2.2) - Models the process of Ground Controlled Interception (GCI) for airplanes.
|
--- **AI** - Models the process of Ground Controlled Interception (GCI) for airplanes.
|
||||||
--
|
--
|
||||||
-- This is a class used in the @{AI_A2A_Dispatcher}.
|
-- This is a class used in the @{AI.AI_A2A_Dispatcher}.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_A2A_GCI
|
-- @module AI.AI_A2A_Gci
|
||||||
-- @image AI_Ground_Control_Intercept.JPG
|
-- @image AI_Ground_Control_Intercept.JPG
|
||||||
|
|
||||||
|
|
||||||
@@ -89,9 +89,9 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Core.Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI.AI_Cap#AI_A2A_GCI.SetEngageZone}() to define that Zone.
|
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -153,7 +153,7 @@ end
|
|||||||
--- Evaluate the attack and create an AttackUnitTask list.
|
--- Evaluate the attack and create an AttackUnitTask list.
|
||||||
-- @param #AI_A2A_GCI self
|
-- @param #AI_A2A_GCI self
|
||||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||||
-- @return #AI_A2A_GCI self
|
-- @return #AI_A2A_GCI self
|
||||||
function AI_A2A_GCI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
function AI_A2A_GCI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.2) - Models the process of air patrol of airplanes.
|
--- **AI** - Models the process of air patrol of airplanes.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
--- @type AI_A2A_PATROL
|
--- @type AI_A2A_PATROL
|
||||||
-- @extends AI.AI_A2A#AI_A2A
|
-- @extends AI.AI_A2A#AI_A2A
|
||||||
|
|
||||||
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
||||||
-- while a new AI is targetted to the AI_A2A_PATROL.
|
-- while a new AI is targeted to the AI_A2A_PATROL.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place.
|
-- Use the method @{#AI_A2A_PATROL.ManageFuel}() to have this proces in place.
|
||||||
--
|
--
|
||||||
@@ -122,7 +122,7 @@ AI_A2A_PATROL = {
|
|||||||
--- Creates a new AI_A2A_PATROL object
|
--- Creates a new AI_A2A_PATROL object
|
||||||
-- @param #AI_A2A_PATROL self
|
-- @param #AI_A2A_PATROL self
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol The patrol group object.
|
-- @param Wrapper.Group#GROUP AIPatrol The patrol group object.
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -264,7 +264,7 @@ function AI_A2A_PATROL:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||||
-- @param #AI_A2A_PATROL self
|
-- @param #AI_A2A_PATROL self
|
||||||
-- @return #AI_A2A_PATROL self
|
-- @return #AI_A2A_PATROL self
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||||
@@ -287,7 +287,7 @@ function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
--- This static method is called from the route path within the last task at the last waypoint of the AIPatrol.
|
||||||
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
||||||
-- @param #AI_A2A_PATROL Fsm The FSM.
|
-- @param #AI_A2A_PATROL Fsm The FSM.
|
||||||
@@ -302,7 +302,7 @@ function AI_A2A_PATROL.PatrolRoute( AIPatrol, Fsm )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||||
-- @param #AI_A2A_PATROL self
|
-- @param #AI_A2A_PATROL self
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
|
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **AI** -- Models the process of air to ground BAI engagement for airplanes and helicopters.
|
--- **AI** - Models the process of air to ground BAI engagement for airplanes and helicopters.
|
||||||
--
|
--
|
||||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -11,11 +11,8 @@
|
|||||||
-- @module AI.AI_A2G_BAI
|
-- @module AI.AI_A2G_BAI
|
||||||
-- @image AI_Air_To_Ground_Engage.JPG
|
-- @image AI_Air_To_Ground_Engage.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_A2G_BAI
|
--- @type AI_A2G_BAI
|
||||||
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage
|
-- @extends AI.AI_A2A_Engage#AI_A2A_Engage -- TODO: Documentation. This class does not exist, unable to determine what it extends.
|
||||||
|
|
||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
@@ -26,8 +23,6 @@ AI_A2G_BAI = {
|
|||||||
ClassName = "AI_A2G_BAI",
|
ClassName = "AI_A2G_BAI",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new AI_A2G_BAI object
|
--- Creates a new AI_A2G_BAI object
|
||||||
-- @param #AI_A2G_BAI self
|
-- @param #AI_A2G_BAI self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
@@ -36,7 +31,7 @@ AI_A2G_BAI = {
|
|||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -53,7 +48,6 @@ function AI_A2G_BAI:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAl
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new AI_A2G_BAI object
|
--- Creates a new AI_A2G_BAI object
|
||||||
-- @param #AI_A2G_BAI self
|
-- @param #AI_A2G_BAI self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
@@ -61,7 +55,7 @@ end
|
|||||||
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -76,7 +70,7 @@ end
|
|||||||
--- Evaluate the attack and create an AttackUnitTask list.
|
--- Evaluate the attack and create an AttackUnitTask list.
|
||||||
-- @param #AI_A2G_BAI self
|
-- @param #AI_A2G_BAI self
|
||||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||||
-- @return #AI_A2G_BAI self
|
-- @return #AI_A2G_BAI self
|
||||||
function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||||
@@ -92,8 +86,6 @@ function AI_A2G_BAI:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageA
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return AttackUnitTasks
|
return AttackUnitTasks
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
|
--- **AI** - Models the process of air to ground engagement for airplanes and helicopters.
|
||||||
--
|
--
|
||||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -11,11 +11,8 @@
|
|||||||
-- @module AI.AI_A2G_CAS
|
-- @module AI.AI_A2G_CAS
|
||||||
-- @image AI_Air_To_Ground_Engage.JPG
|
-- @image AI_Air_To_Ground_Engage.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_A2G_CAS
|
--- @type AI_A2G_CAS
|
||||||
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL
|
-- @extends AI.AI_A2G_Patrol#AI_AIR_PATROL TODO: Documentation. This class does not exist, unable to determine what it extends.
|
||||||
|
|
||||||
|
|
||||||
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
--- Implements the core functions to intercept intruders. Use the Engage trigger to intercept intruders.
|
||||||
--
|
--
|
||||||
@@ -26,8 +23,6 @@ AI_A2G_CAS = {
|
|||||||
ClassName = "AI_A2G_CAS",
|
ClassName = "AI_A2G_CAS",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new AI_A2G_CAS object
|
--- Creates a new AI_A2G_CAS object
|
||||||
-- @param #AI_A2G_CAS self
|
-- @param #AI_A2G_CAS self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
@@ -36,7 +31,7 @@ AI_A2G_CAS = {
|
|||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -53,7 +48,6 @@ function AI_A2G_CAS:New2( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloorAl
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new AI_A2G_CAS object
|
--- Creates a new AI_A2G_CAS object
|
||||||
-- @param #AI_A2G_CAS self
|
-- @param #AI_A2G_CAS self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
@@ -61,7 +55,7 @@ end
|
|||||||
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -76,7 +70,7 @@ end
|
|||||||
--- Evaluate the attack and create an AttackUnitTask list.
|
--- Evaluate the attack and create an AttackUnitTask list.
|
||||||
-- @param #AI_A2G_CAS self
|
-- @param #AI_A2G_CAS self
|
||||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||||
-- @return #AI_A2G_CAS self
|
-- @return #AI_A2G_CAS self
|
||||||
function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||||
@@ -92,9 +86,6 @@ function AI_A2G_CAS:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageA
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return AttackUnitTasks
|
return AttackUnitTasks
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,7 @@
|
|||||||
-- * polygon zones
|
-- * polygon zones
|
||||||
-- * moving zones
|
-- * moving zones
|
||||||
--
|
--
|
||||||
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
|
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## 12. Are moving defense coordinates possible?
|
-- ## 12. Are moving defense coordinates possible?
|
||||||
@@ -999,7 +999,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- self.Detection:InitDetectRadar( false )
|
-- self.Detection:InitDetectRadar( false )
|
||||||
-- self.Detection:InitDetectVisual( true )
|
-- self.Detection:InitDetectVisual( true )
|
||||||
-- self.Detection:SetRefreshTimeInterval( 30 )
|
-- self.Detection:SetRefreshTimeInterval( 30 )
|
||||||
|
|
||||||
|
self.SetSendPlayerMessages = false --flash messages to players
|
||||||
|
|
||||||
self:SetDefenseRadius()
|
self:SetDefenseRadius()
|
||||||
self:SetDefenseLimit( nil )
|
self:SetDefenseLimit( nil )
|
||||||
self:SetDefenseApproach( AI_A2G_DISPATCHER.DefenseApproach.Random )
|
self:SetDefenseApproach( AI_A2G_DISPATCHER.DefenseApproach.Random )
|
||||||
@@ -1387,7 +1389,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
--- Define a border area to simulate a **cold war** scenario.
|
--- Define a border area to simulate a **cold war** scenario.
|
||||||
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||||
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
|
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
|
||||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
||||||
@@ -2183,7 +2185,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||||
@@ -2232,7 +2234,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
-- The Sead patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||||
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||||
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
||||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||||
@@ -2334,7 +2336,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||||
@@ -2383,7 +2385,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
-- The Cas patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||||
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||||
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
||||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||||
@@ -2485,7 +2487,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
-- @param #number PatrolMaxSpeed (optional, default = 75% of max speed) The maximum speed at which the cap can be executed.
|
||||||
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
-- @param #number PatrolFloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||||
@@ -2534,7 +2536,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
-- The Bai patrol will start a patrol of the aircraft at a specified zone, and will engage when commanded.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string SquadronName The squadron name.
|
-- @param #string SquadronName The squadron name.
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The @{Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
-- @param Core.Zone#ZONE_BASE Zone The @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE} that defines the zone wherein the Patrol will be executed.
|
||||||
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
-- @param #number FloorAltitude (optional, default = 1000m ) The minimum altitude at which the cap can be executed.
|
||||||
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
-- @param #number CeilingAltitude (optional, default = 1500m ) The maximum altitude at which the cap can be executed.
|
||||||
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
-- @param #number PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed at which the cap can be executed.
|
||||||
@@ -3718,7 +3720,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron then
|
if Squadron then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
||||||
|
end
|
||||||
AI_A2G_Fsm:Patrol() -- Engage on the TargetSetUnit
|
AI_A2G_Fsm:Patrol() -- Engage on the TargetSetUnit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3730,7 +3734,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
if Squadron then
|
if Squadron and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3749,8 +3753,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
if Squadron and AttackSetUnit:Count() > 0 then
|
if Squadron and AttackSetUnit:Count() > 0 then
|
||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", moving on to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", moving on to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3764,8 +3769,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
if FirstUnit then
|
if FirstUnit then
|
||||||
local Coordinate = FirstUnit:GetCoordinate()
|
local Coordinate = FirstUnit:GetCoordinate()
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3776,8 +3782,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
||||||
|
end
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3789,7 +3796,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", lost control." )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", lost control." )
|
||||||
|
end
|
||||||
if DefenderGroup:IsAboveRunway() then
|
if DefenderGroup:IsAboveRunway() then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3804,8 +3813,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
||||||
|
end
|
||||||
if Action and Action == "Destroy" then
|
if Action and Action == "Destroy" then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3861,7 +3871,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
self:F( { DefenderTarget = DefenderTarget } )
|
self:F( { DefenderTarget = DefenderTarget } )
|
||||||
|
|
||||||
if DefenderTarget then
|
if DefenderTarget then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
||||||
|
end
|
||||||
AI_A2G_Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
AI_A2G_Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3876,8 +3888,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
if Squadron then
|
if Squadron then
|
||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
end
|
end
|
||||||
@@ -3892,8 +3905,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
if FirstUnit then
|
if FirstUnit then
|
||||||
local Coordinate = FirstUnit:GetCoordinate()
|
local Coordinate = FirstUnit:GetCoordinate()
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3903,8 +3917,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
||||||
|
end
|
||||||
self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To )
|
self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To )
|
||||||
|
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
@@ -3918,8 +3933,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
--Dispatcher:MessageToPlayers( Squadron, "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." )
|
||||||
|
end
|
||||||
if DefenderGroup:IsAboveRunway() then
|
if DefenderGroup:IsAboveRunway() then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3934,8 +3950,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
||||||
|
end
|
||||||
if Action and Action == "Destroy" then
|
if Action and Action == "Destroy" then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3975,7 +3992,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
|
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
|
||||||
|
|
||||||
-- Now check if this coordinate is not in a danger zone, meaning, that the attack line is not crossing other coordinates.
|
-- Now check if this coordinate is not in a danger zone, meaning, that the attack line is not crossing other coordinates.
|
||||||
-- (y1 – y2)x + (x2 – x1)y + (x1y2 – x2y1) = 0
|
-- (y1 - y2)x + (x2 - x1)y + (x1y2 - x2y1) = 0
|
||||||
|
|
||||||
local c1 = DefenseCoordinate
|
local c1 = DefenseCoordinate
|
||||||
local c2 = AttackCoordinate
|
local c2 = AttackCoordinate
|
||||||
@@ -4036,7 +4053,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
for DefenderID, DefenderGroup in pairs( DefenderFriendlies or {} ) do
|
for DefenderID, DefenderGroup in pairs( DefenderFriendlies or {} ) do
|
||||||
|
|
||||||
-- Here we check if the defenders have a defense line to the attackers.
|
-- Here we check if the defenders have a defense line to the attackers.
|
||||||
-- If the attackers are behind enemy lines or too close to an other defense line; then don´t engage.
|
-- If the attackers are behind enemy lines or too close to an other defense line; then don't engage.
|
||||||
local DefenseCoordinate = DefenderGroup:GetCoordinate()
|
local DefenseCoordinate = DefenderGroup:GetCoordinate()
|
||||||
local HasDefenseLine = self:HasDefenseLine( DefenseCoordinate, DetectedItem )
|
local HasDefenseLine = self:HasDefenseLine( DefenseCoordinate, DetectedItem )
|
||||||
|
|
||||||
@@ -4341,7 +4358,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
-- Show tactical situation
|
-- Show tactical situation
|
||||||
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
||||||
Report:Add( string.format( " - %1s%s ( %04s ): ( #%02d - %-4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
Report:Add( string.format( " - %1s%s ( %04s ): ( #%02d - %-4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
||||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||||
local Defender = Defender -- Wrapper.Group#GROUP
|
local Defender = Defender -- Wrapper.Group#GROUP
|
||||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||||
@@ -4559,7 +4576,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
if self.TacticalDisplay then
|
if self.TacticalDisplay then
|
||||||
-- Show tactical situation
|
-- Show tactical situation
|
||||||
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
||||||
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
||||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||||
local Defender = Defender -- Wrapper.Group#GROUP
|
local Defender = Defender -- Wrapper.Group#GROUP
|
||||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||||
@@ -4729,7 +4746,15 @@ do
|
|||||||
self:Patrol( SquadronName, PatrolTaskType )
|
self:Patrol( SquadronName, PatrolTaskType )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add resources to a Squadron
|
--- Set flashing player messages on or off
|
||||||
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
|
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||||
|
function AI_A2G_DISPATCHER:SetSendMessages( onoff )
|
||||||
|
self.SetSendPlayerMessages = onoff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add resources to a Squadron
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string Squadron The squadron name.
|
-- @param #string Squadron The squadron name.
|
||||||
-- @param #number Amount Number of resources to add.
|
-- @param #number Amount Number of resources to add.
|
||||||
@@ -4751,7 +4776,4 @@ do
|
|||||||
Squadron.ResourceCount = Squadron.ResourceCount - Amount
|
Squadron.ResourceCount = Squadron.ResourceCount - Amount
|
||||||
end
|
end
|
||||||
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **AI** -- Models the process of air to ground SEAD engagement for airplanes and helicopters.
|
--- **AI** - Models the process of air to ground SEAD engagement for airplanes and helicopters.
|
||||||
--
|
--
|
||||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -65,9 +65,9 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Core.Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI.AI_Cap#AI_A2G_SEAD.SetEngageZone}() to define that Zone.
|
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageZone}() to define that Zone. -- TODO: Documentation. Check that this is actually correct. The originally referenced class does not exist.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -76,8 +76,6 @@ AI_A2G_SEAD = {
|
|||||||
ClassName = "AI_A2G_SEAD",
|
ClassName = "AI_A2G_SEAD",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new AI_A2G_SEAD object
|
--- Creates a new AI_A2G_SEAD object
|
||||||
-- @param #AI_A2G_SEAD self
|
-- @param #AI_A2G_SEAD self
|
||||||
-- @param Wrapper.Group#GROUP AIGroup
|
-- @param Wrapper.Group#GROUP AIGroup
|
||||||
@@ -86,7 +84,7 @@ AI_A2G_SEAD = {
|
|||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
-- @param DCS#AltitudeType EngageAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to "RADIO".
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -111,7 +109,7 @@ end
|
|||||||
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
-- @param DCS#Speed EngageMaxSpeed The maximum speed of the @{Wrapper.Group} in km/h when engaging a target.
|
||||||
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageFloorAltitude The lowest altitude in meters where to execute the engagement.
|
||||||
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
-- @param DCS#Altitude EngageCeilingAltitude The highest altitude in meters where to execute the engagement.
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -127,7 +125,7 @@ end
|
|||||||
--- Evaluate the attack and create an AttackUnitTask list.
|
--- Evaluate the attack and create an AttackUnitTask list.
|
||||||
-- @param #AI_A2G_SEAD self
|
-- @param #AI_A2G_SEAD self
|
||||||
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
-- @param Core.Set#SET_UNIT AttackSetUnit The set of units to attack.
|
||||||
-- @param Wrappper.Group#GROUP DefenderGroup The group of defenders.
|
-- @param Wrapper.Group#GROUP DefenderGroup The group of defenders.
|
||||||
-- @param #number EngageAltitude The altitude to engage the targets.
|
-- @param #number EngageAltitude The altitude to engage the targets.
|
||||||
-- @return #AI_A2G_SEAD self
|
-- @return #AI_A2G_SEAD self
|
||||||
function AI_A2G_SEAD:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
function AI_A2G_SEAD:CreateAttackUnitTasks( AttackSetUnit, DefenderGroup, EngageAltitude )
|
||||||
|
|||||||
@@ -253,6 +253,9 @@ function AI_AIR:New( AIGroup )
|
|||||||
|
|
||||||
self.IdleCount = 0
|
self.IdleCount = 0
|
||||||
|
|
||||||
|
self.RTBSpeedMaxFactor = 0.6
|
||||||
|
self.RTBSpeedMinFactor = 0.5
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -371,7 +374,7 @@ end
|
|||||||
|
|
||||||
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_AIR.
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targeted to the AI_AIR.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @param #number FuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
-- @param #number FuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||||
@@ -406,7 +409,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||||
-- @param #AI_AIR self
|
-- @param #AI_AIR self
|
||||||
-- @return #AI_AIR self
|
-- @return #AI_AIR self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||||
@@ -470,27 +473,27 @@ function AI_AIR:onafterStatus()
|
|||||||
-- self:Home( "Destroy" )
|
-- self:Home( "Destroy" )
|
||||||
-- end
|
-- end
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
|
|
||||||
if not self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" )then
|
if not self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" )then
|
||||||
|
|
||||||
local Fuel = self.Controllable:GetFuelMin()
|
local Fuel = self.Controllable:GetFuelMin()
|
||||||
|
|
||||||
-- If the fuel in the controllable is below the threshold percentage,
|
-- If the fuel in the controllable is below the threshold percentage,
|
||||||
-- then send for refuel in case of a tanker, otherwise RTB.
|
-- then send for refuel in case of a tanker, otherwise RTB.
|
||||||
if Fuel < self.FuelThresholdPercentage then
|
if Fuel < self.FuelThresholdPercentage then
|
||||||
|
|
||||||
if self.TankerName then
|
if self.TankerName then
|
||||||
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
||||||
self:Refuel()
|
self:Refuel()
|
||||||
else
|
else
|
||||||
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
||||||
local OldAIControllable = self.Controllable
|
local OldAIControllable = self.Controllable
|
||||||
|
|
||||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||||
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.OutOfFuelOrbitTime,nil ) )
|
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.OutOfFuelOrbitTime,nil ) )
|
||||||
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
||||||
|
|
||||||
self:Fuel()
|
self:Fuel()
|
||||||
RTB = true
|
RTB = true
|
||||||
end
|
end
|
||||||
@@ -501,11 +504,11 @@ function AI_AIR:onafterStatus()
|
|||||||
if self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" ) then
|
if self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" ) then
|
||||||
RTB = true
|
RTB = true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: Check GROUP damage function.
|
-- TODO: Check GROUP damage function.
|
||||||
local Damage = self.Controllable:GetLife()
|
local Damage = self.Controllable:GetLife()
|
||||||
local InitialLife = self.Controllable:GetLife0()
|
local InitialLife = self.Controllable:GetLife0()
|
||||||
|
|
||||||
-- If the group is damaged, then RTB.
|
-- If the group is damaged, then RTB.
|
||||||
-- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue.
|
-- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue.
|
||||||
-- The damaged unit will RTB due to DCS logic, and the others will continue to engage.
|
-- The damaged unit will RTB due to DCS logic, and the others will continue to engage.
|
||||||
@@ -515,7 +518,7 @@ function AI_AIR:onafterStatus()
|
|||||||
RTB = true
|
RTB = true
|
||||||
self:SetStatusOff()
|
self:SetStatusOff()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if planes went RTB and are out of control.
|
-- Check if planes went RTB and are out of control.
|
||||||
-- We only check if planes are out of control, when they are in duty.
|
-- We only check if planes are out of control, when they are in duty.
|
||||||
if self.Controllable:HasTask() == false then
|
if self.Controllable:HasTask() == false then
|
||||||
@@ -529,7 +532,7 @@ function AI_AIR:onafterStatus()
|
|||||||
self:Damaged()
|
self:Damaged()
|
||||||
else
|
else
|
||||||
self:I( self.Controllable:GetName() .. " control lost! " )
|
self:I( self.Controllable:GetName() .. " control lost! " )
|
||||||
|
|
||||||
self:LostControl()
|
self:LostControl()
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -547,7 +550,7 @@ function AI_AIR:onafterStatus()
|
|||||||
if not self:Is("Home") then
|
if not self:Is("Home") then
|
||||||
self:__Status( 10 )
|
self:__Status( 10 )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -556,11 +559,11 @@ end
|
|||||||
function AI_AIR.RTBRoute( AIGroup, Fsm )
|
function AI_AIR.RTBRoute( AIGroup, Fsm )
|
||||||
|
|
||||||
AIGroup:F( { "AI_AIR.RTBRoute:", AIGroup:GetName() } )
|
AIGroup:F( { "AI_AIR.RTBRoute:", AIGroup:GetName() } )
|
||||||
|
|
||||||
if AIGroup:IsAlive() then
|
if AIGroup:IsAlive() then
|
||||||
Fsm:RTB()
|
Fsm:RTB()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIGroup
|
--- @param Wrapper.Group#GROUP AIGroup
|
||||||
@@ -573,7 +576,20 @@ function AI_AIR.RTBHold( AIGroup, Fsm )
|
|||||||
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
|
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
|
||||||
AIGroup:SetTask( Task )
|
AIGroup:SetTask( Task )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the min and max factors on RTB speed. Use this, if your planes are heading back to base too fast. Default values are 0.5 and 0.6.
|
||||||
|
-- The RTB speed is calculated as the max speed of the unit multiplied by MinFactor (lower bracket) and multiplied by MaxFactor (upper bracket).
|
||||||
|
-- A random value in this bracket is then applied in the waypoint routing generation.
|
||||||
|
-- @param #AI_AIR self
|
||||||
|
-- @param #number MinFactor Lower bracket factor. Defaults to 0.5.
|
||||||
|
-- @param #number MaxFactor Upper bracket factor. Defaults to 0.6.
|
||||||
|
-- @return #AI_AIR self
|
||||||
|
function AI_AIR:SetRTBSpeedFactors(MinFactor,MaxFactor)
|
||||||
|
self.RTBSpeedMaxFactor = MaxFactor or 0.6
|
||||||
|
self.RTBSpeedMinFactor = MinFactor or 0.5
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -582,50 +598,53 @@ end
|
|||||||
function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
||||||
self:F( { AIGroup, From, Event, To } )
|
self:F( { AIGroup, From, Event, To } )
|
||||||
|
|
||||||
|
if AIGroup and AIGroup:IsAlive() then
|
||||||
if AIGroup and AIGroup:IsAlive() then
|
|
||||||
|
|
||||||
self:T( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
|
self:T( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
|
||||||
|
|
||||||
self:ClearTargetDistance()
|
self:ClearTargetDistance()
|
||||||
--AIGroup:ClearTasks()
|
--AIGroup:ClearTasks()
|
||||||
|
|
||||||
|
AIGroup:OptionProhibitAfterburner(true)
|
||||||
|
|
||||||
local EngageRoute = {}
|
local EngageRoute = {}
|
||||||
|
|
||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
|
|
||||||
local FromCoord = AIGroup:GetCoordinate()
|
local FromCoord = AIGroup:GetCoordinate()
|
||||||
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
local ToTargetCoord = self.HomeAirbase:GetCoordinate() -- coordinate is on land height(!)
|
||||||
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
local ToTargetVec3 = ToTargetCoord:GetVec3()
|
||||||
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+1000 -- let's set this 1000m/3000 feet above ground
|
ToTargetVec3.y = ToTargetCoord:GetLandHeight()+3000 -- let's set this 1000m/3000 feet above ground
|
||||||
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
local ToTargetCoord2 = COORDINATE:NewFromVec3( ToTargetVec3 )
|
||||||
|
|
||||||
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
|
if not self.RTBMinSpeed or not self.RTBMaxSpeed then
|
||||||
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
local RTBSpeedMax = AIGroup:GetSpeedMax()
|
||||||
self:SetRTBSpeed( RTBSpeedMax * 0.5, RTBSpeedMax * 0.6 )
|
local RTBSpeedMaxFactor = self.RTBSpeedMaxFactor or 0.6
|
||||||
|
local RTBSpeedMinFactor = self.RTBSpeedMinFactor or 0.5
|
||||||
|
self:SetRTBSpeed( RTBSpeedMax * RTBSpeedMinFactor, RTBSpeedMax * RTBSpeedMaxFactor)
|
||||||
end
|
end
|
||||||
|
|
||||||
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
local RTBSpeed = math.random( self.RTBMinSpeed, self.RTBMaxSpeed )
|
||||||
--local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord2 ) )
|
--local ToAirbaseAngle = FromCoord:GetAngleDegrees( FromCoord:GetDirectionVec3( ToTargetCoord2 ) )
|
||||||
|
|
||||||
local Distance = FromCoord:Get2DDistance( ToTargetCoord2 )
|
local Distance = FromCoord:Get2DDistance( ToTargetCoord2 )
|
||||||
|
|
||||||
--local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
|
--local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
|
||||||
local ToAirbaseCoord = ToTargetCoord2
|
local ToAirbaseCoord = ToTargetCoord2
|
||||||
|
|
||||||
if Distance < 5000 then
|
if Distance < 5000 then
|
||||||
self:I( "RTB and near the airbase!" )
|
self:I( "RTB and near the airbase!" )
|
||||||
self:Home()
|
self:Home()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not AIGroup:InAir() == true then
|
if not AIGroup:InAir() == true then
|
||||||
self:I( "Not anymore in the air, considered Home." )
|
self:I( "Not anymore in the air, considered Home." )
|
||||||
self:Home()
|
self:Home()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local FromRTBRoutePoint = FromCoord:WaypointAir(
|
local FromRTBRoutePoint = FromCoord:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
@@ -646,10 +665,10 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
|
|
||||||
EngageRoute[#EngageRoute+1] = FromRTBRoutePoint
|
EngageRoute[#EngageRoute+1] = FromRTBRoutePoint
|
||||||
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
|
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
Tasks[#Tasks+1] = AIGroup:TaskFunction( "AI_AIR.RTBRoute", self )
|
Tasks[#Tasks+1] = AIGroup:TaskFunction( "AI_AIR.RTBRoute", self )
|
||||||
|
|
||||||
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
|
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
|
||||||
|
|
||||||
AIGroup:OptionROEHoldFire()
|
AIGroup:OptionROEHoldFire()
|
||||||
@@ -657,9 +676,9 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
|
|||||||
|
|
||||||
--- NOW ROUTE THE GROUP!
|
--- NOW ROUTE THE GROUP!
|
||||||
AIGroup:Route( EngageRoute, self.TaskDelay )
|
AIGroup:Route( EngageRoute, self.TaskDelay )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param #AI_AIR self
|
--- @param #AI_AIR self
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** - Create an automated AIR defense system based on a detection network of reconnaissance vehicles and air units, coordinating SEAD, BAI and CAP operations.
|
--- **AI** - Create an automated AIR defense system with reconnaissance units, coordinating SEAD, BAI and CAP operations.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
-- * Setup quickly an AIR defense system for a coalition.
|
-- * Setup quickly an AIR defense system for a coalition.
|
||||||
-- * Setup multiple defense zones to defend specific coordinates in your battlefield.
|
-- * Setup multiple defense zones to defend specific coordinates in your battlefield.
|
||||||
-- * Setup (SEAD) Suppression of Air Defense squadrons, to gain control in the air of enemy grounds.
|
-- * Setup (SEAD) Suppression of Air Defense squadrons, to gain control in the air of enemy grounds.
|
||||||
-- * Setup (CAS) Controlled Air Support squadrons, to attack closeby enemy ground units near friendly installations.
|
-- * Setup (CAS) Controlled Air Support squadrons, to attack close by enemy ground units near friendly installations.
|
||||||
-- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets.
|
-- * Setup (BAI) Battleground Air Interdiction squadrons to attack remote enemy ground units and targets.
|
||||||
-- * Define and use a detection network controlled by recce.
|
-- * Define and use a detection network controlled by recce.
|
||||||
-- * Define AIR defense squadrons at airbases, FARPs and carriers.
|
-- * Define AIR defense squadrons at airbases, FARPs and carriers.
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Missions:
|
-- ## Missions:
|
||||||
--
|
--
|
||||||
-- [AID-AIR - AI AIR Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching/AID-AIR%20-%20AI%20AIR%20Dispatching)
|
-- [AID-AIR - AI AIR Dispatching](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AID%20-%20AI%20Dispatching)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
--
|
--
|
||||||
-- ## 4. How do the defenses decide **when and where to engage** on approaching enemy units?
|
-- ## 4. How do the defenses decide **when and where to engage** on approaching enemy units?
|
||||||
--
|
--
|
||||||
-- The AIR dispacher needs you to setup (various) defense coordinates, which are strategic positions in the battle field to be defended.
|
-- The AIR dispatcher needs you to setup (various) defense coordinates, which are strategic positions in the battle field to be defended.
|
||||||
-- Any ground based enemy approaching within the proximity of such a defense point, may trigger for a defensive action by friendly air units.
|
-- Any ground based enemy approaching within the proximity of such a defense point, may trigger for a defensive action by friendly air units.
|
||||||
--
|
--
|
||||||
-- There are 2 important parameters that play a role in the defensive decision making: defensiveness and reactivity.
|
-- There are 2 important parameters that play a role in the defensive decision making: defensiveness and reactivity.
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
-- ## 5. Are defense coordinates and defense reactivity the only parameters?
|
-- ## 5. Are defense coordinates and defense reactivity the only parameters?
|
||||||
--
|
--
|
||||||
-- No, depending on the target type, and the threat level of the target, the probability of defense will be higher.
|
-- No, depending on the target type, and the threat level of the target, the probability of defense will be higher.
|
||||||
-- In other words, when a SAM-10 radar emitter is detected, its probabilty for defense will be much higher than when a BMP-1 vehicle is
|
-- In other words, when a SAM-10 radar emitter is detected, its probability for defense will be much higher than when a BMP-1 vehicle is
|
||||||
-- detected, even when both enemies are at the same distance from a defense coordinate.
|
-- detected, even when both enemies are at the same distance from a defense coordinate.
|
||||||
-- This will ensure optimal defenses, SEAD tasks will be launched much more quicker against engaging radar emitters, to ensure air superiority.
|
-- This will ensure optimal defenses, SEAD tasks will be launched much more quicker against engaging radar emitters, to ensure air superiority.
|
||||||
-- Approaching main battle tanks will be engaged much faster, than a group of approaching trucks.
|
-- Approaching main battle tanks will be engaged much faster, than a group of approaching trucks.
|
||||||
@@ -117,12 +117,12 @@
|
|||||||
-- ## 6. Which Squadrons will I create and which name will I give each Squadron?
|
-- ## 6. Which Squadrons will I create and which name will I give each Squadron?
|
||||||
--
|
--
|
||||||
-- The AIR defense system works with **Squadrons**. Each Squadron must be given a unique name, that forms the **key** to the squadron.
|
-- The AIR defense system works with **Squadrons**. Each Squadron must be given a unique name, that forms the **key** to the squadron.
|
||||||
-- Several options and activities can be set per Squadron. A free format name can be given, but always ensure that the name is meaningfull
|
-- Several options and activities can be set per Squadron. A free format name can be given, but always ensure that the name is meaningful
|
||||||
-- for your mission, and remember that squadron names are used for communication to the players of your mission.
|
-- for your mission, and remember that squadron names are used for communication to the players of your mission.
|
||||||
--
|
--
|
||||||
-- There are mainly 3 types of defenses: **SEAD**, **CAS** and **BAI**.
|
-- There are mainly 3 types of defenses: **SEAD**, **CAS** and **BAI**.
|
||||||
--
|
--
|
||||||
-- Suppression of Air Defenses (SEAD) are effective agains radar emitters. Close Air Support (CAS) is launched when the enemy is close near friendly units.
|
-- Suppression of Air Defenses (SEAD) are effective against radar emitters. Close Air Support (CAS) is launched when the enemy is close near friendly units.
|
||||||
-- Battleground Air Interdiction (BAI) tasks are launched when there are no friendlies around.
|
-- Battleground Air Interdiction (BAI) tasks are launched when there are no friendlies around.
|
||||||
--
|
--
|
||||||
-- Depending on the defense type, different payloads will be needed. See further points on squadron definition.
|
-- Depending on the defense type, different payloads will be needed. See further points on squadron definition.
|
||||||
@@ -174,13 +174,13 @@
|
|||||||
-- * polygon zones
|
-- * polygon zones
|
||||||
-- * moving zones
|
-- * moving zones
|
||||||
--
|
--
|
||||||
-- Depending on the type of zone selected, a different @{Zone} object needs to be created from a ZONE_ class.
|
-- Depending on the type of zone selected, a different @{Core.Zone} object needs to be created from a ZONE_ class.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## 12. Are moving defense coordinates possible?
|
-- ## 12. Are moving defense coordinates possible?
|
||||||
--
|
--
|
||||||
-- Yes, different COORDINATE types are possible to be used.
|
-- Yes, different COORDINATE types are possible to be used.
|
||||||
-- The COORDINATE_UNIT will help you to specify a defense coodinate that is attached to a moving unit.
|
-- The COORDINATE_UNIT will help you to specify a defense coordinate that is attached to a moving unit.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## 13. How much defense coordinates do I need to create?
|
-- ## 13. How much defense coordinates do I need to create?
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
-- * From a parking spot with running engines
|
-- * From a parking spot with running engines
|
||||||
-- * From a parking spot with cold engines
|
-- * From a parking spot with cold engines
|
||||||
--
|
--
|
||||||
-- **The default takeoff method is staight in the air.**
|
-- **The default takeoff method is straight in the air.**
|
||||||
-- This takeoff method is the most useful if you want to avoid airplane clutter at airbases!
|
-- This takeoff method is the most useful if you want to avoid airplane clutter at airbases!
|
||||||
-- But it is the least realistic one!
|
-- But it is the least realistic one!
|
||||||
--
|
--
|
||||||
@@ -236,10 +236,10 @@
|
|||||||
--
|
--
|
||||||
-- For each Squadron, depending on the helicopter or airplane type (modern, old) and payload, which overhead is required to provide any defense?
|
-- For each Squadron, depending on the helicopter or airplane type (modern, old) and payload, which overhead is required to provide any defense?
|
||||||
--
|
--
|
||||||
-- In other words, if **X** enemy ground units are detected, how many **Y** defense helicpters or airplanes need to engage (per squadron)?
|
-- In other words, if **X** enemy ground units are detected, how many **Y** defense helicopters or airplanes need to engage (per squadron)?
|
||||||
-- The **Y** is dependent on the type of airplane (era), payload, fuel levels, skills etc.
|
-- The **Y** is dependent on the type of airplane (era), payload, fuel levels, skills etc.
|
||||||
-- But the most important factor is the payload, which is the amount of AIR weapons the defense can carry to attack the enemy ground units.
|
-- But the most important factor is the payload, which is the amount of AIR weapons the defense can carry to attack the enemy ground units.
|
||||||
-- For example, a Ka-50 can carry 16 vikrs, that means, that it potentially can destroy at least 8 ground units without a reload of ammunication.
|
-- For example, a Ka-50 can carry 16 vikrs, that means, that it potentially can destroy at least 8 ground units without a reload of ammunition.
|
||||||
-- That means, that one defender can destroy more enemy ground units.
|
-- That means, that one defender can destroy more enemy ground units.
|
||||||
-- Thus, the overhead is a **factor** that will calculate dynamically how many **Y** defenses will be required based on **X** attackers detected.
|
-- Thus, the overhead is a **factor** that will calculate dynamically how many **Y** defenses will be required based on **X** attackers detected.
|
||||||
--
|
--
|
||||||
@@ -259,7 +259,7 @@
|
|||||||
--
|
--
|
||||||
-- ### Author: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
-- ### Author: **FlightControl** rework of GCICAP + introduction of new concepts (squadrons).
|
||||||
--
|
--
|
||||||
-- @module AI.AI_AIR_Dispatcher
|
-- @module AI.AI_Air_Dispatcher
|
||||||
-- @image AI_Air_To_Ground_Dispatching.JPG
|
-- @image AI_Air_To_Ground_Dispatching.JPG
|
||||||
|
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- Multiple defense coordinates can be setup. Defense coordinates can be strategic or tactical positions or references to strategic units or scenery.
|
-- Multiple defense coordinates can be setup. Defense coordinates can be strategic or tactical positions or references to strategic units or scenery.
|
||||||
-- The AIR dispatcher will evaluate every x seconds the tactical situation around each defense coordinate. When a defense coordinate
|
-- The AIR dispatcher will evaluate every x seconds the tactical situation around each defense coordinate. When a defense coordinate
|
||||||
-- is under threat, it will communicate through the command center that defensive actions need to be taken and will launch groups of air units for defense.
|
-- is under threat, it will communicate through the command center that defensive actions need to be taken and will launch groups of air units for defense.
|
||||||
-- The level of threat to the defense coordinate varyies upon the strength and types of the enemy units, the distance to the defense point, and the defensiveness parameters.
|
-- The level of threat to the defense coordinate varies upon the strength and types of the enemy units, the distance to the defense point, and the defensiveness parameters.
|
||||||
-- Defensive actions are taken through probability, but the closer and the more threat the enemy poses to the defense coordinate, the faster it will be attacked by friendly AIR units.
|
-- Defensive actions are taken through probability, but the closer and the more threat the enemy poses to the defense coordinate, the faster it will be attacked by friendly AIR units.
|
||||||
--
|
--
|
||||||
-- Please study carefully the underlying explanations how to setup and use this module, as it has many features.
|
-- Please study carefully the underlying explanations how to setup and use this module, as it has many features.
|
||||||
@@ -328,7 +328,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- By spawning in dynamically additional recce, you can ensure that there is sufficient reconnaissance coverage so the defense mechanism is continuously
|
-- By spawning in dynamically additional recce, you can ensure that there is sufficient reconnaissance coverage so the defense mechanism is continuously
|
||||||
-- alerted of new enemy ground targets.
|
-- alerted of new enemy ground targets.
|
||||||
--
|
--
|
||||||
-- The following example defens a new reconnaissance network using a @{Functional.Detection#DETECTION_AREAS} object.
|
-- The following example defense a new reconnaissance network using a @{Functional.Detection#DETECTION_AREAS} object.
|
||||||
--
|
--
|
||||||
-- -- Define a SET_GROUP object that builds a collection of groups that define the recce network.
|
-- -- Define a SET_GROUP object that builds a collection of groups that define the recce network.
|
||||||
-- -- Here we build the network with all the groups that have a name starting with CCCP Recce.
|
-- -- Here we build the network with all the groups that have a name starting with CCCP Recce.
|
||||||
@@ -473,7 +473,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- the mission designer can choose to increase or reduce the amount of planes spawned.
|
-- the mission designer can choose to increase or reduce the amount of planes spawned.
|
||||||
--
|
--
|
||||||
-- The method @{#AI_AIR_DISPATCHER.SetSquadron}() defines for you a new squadron.
|
-- The method @{#AI_AIR_DISPATCHER.SetSquadron}() defines for you a new squadron.
|
||||||
-- The provided parameters are the squadron name, airbase name and a list of template prefixe, and a number that indicates the amount of resources.
|
-- The provided parameters are the squadron name, airbase name and a list of template prefixes, and a number that indicates the amount of resources.
|
||||||
--
|
--
|
||||||
-- For example, this defines 3 new squadrons:
|
-- For example, this defines 3 new squadrons:
|
||||||
--
|
--
|
||||||
@@ -619,7 +619,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- Depending on the demand of requested takeoffs by the AIR dispatcher, an airfield can become overloaded. Too many aircraft need to be taken
|
-- Depending on the demand of requested takeoffs by the AIR dispatcher, an airfield can become overloaded. Too many aircraft need to be taken
|
||||||
-- off at the same time, which will result in clutter as described above. In order to better control this behaviour, a takeoff scheduler is implemented,
|
-- off at the same time, which will result in clutter as described above. In order to better control this behaviour, a takeoff scheduler is implemented,
|
||||||
-- which can be used to control how many aircraft are ordered for takeoff between specific time intervals.
|
-- which can be used to control how many aircraft are ordered for takeoff between specific time intervals.
|
||||||
-- The takeff intervals can be specified per squadron, which make sense, as each squadron have a "home" airfield.
|
-- The takeoff intervals can be specified per squadron, which make sense, as each squadron have a "home" airfield.
|
||||||
--
|
--
|
||||||
-- For this purpose, the method @{#AI_AIR_DISPATCHER.SetSquadronTakeOffInterval}() can be used to specify the takeoff intervals of
|
-- For this purpose, the method @{#AI_AIR_DISPATCHER.SetSquadronTakeOffInterval}() can be used to specify the takeoff intervals of
|
||||||
-- aircraft groups per squadron to avoid cluttering of aircraft at airbases.
|
-- aircraft groups per squadron to avoid cluttering of aircraft at airbases.
|
||||||
@@ -1021,7 +1021,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @param Tasking.Task_AIR#AI_AIR Task
|
-- @param AI.AI_Air#AI_AIR Task
|
||||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||||
-- @param #string PlayerName
|
-- @param #string PlayerName
|
||||||
|
|
||||||
@@ -1224,7 +1224,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
|
|
||||||
self:I( "Captured " .. AirbaseName )
|
self:I( "Captured " .. AirbaseName )
|
||||||
|
|
||||||
-- Now search for all squadrons located at the airbase, and sanatize them.
|
-- Now search for all squadrons located at the airbase, and sanitize them.
|
||||||
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
for SquadronName, Squadron in pairs( self.DefenderSquadrons ) do
|
||||||
if Squadron.AirbaseName == AirbaseName then
|
if Squadron.AirbaseName == AirbaseName then
|
||||||
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
Squadron.ResourceCount = -999 -- The base has been captured, and the resources are eliminated. No more spawning.
|
||||||
@@ -1376,7 +1376,7 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--- Define a border area to simulate a **cold war** scenario.
|
--- Define a border area to simulate a **cold war** scenario.
|
||||||
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
-- A **cold war** is one where Patrol aircraft patrol their territory but will not attack enemy aircraft or launch GCI aircraft unless enemy aircraft enter their territory. In other words the EWR may detect an enemy aircraft but will only send aircraft to attack it if it crosses the border.
|
||||||
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
|
-- A **hot war** is one where Patrol aircraft will intercept any detected enemy aircraft and GCI aircraft will launch against detected enemy aircraft without regard for territory. In other words if the ground radar can detect the enemy aircraft then it will send Patrol and GCI aircraft to attack it.
|
||||||
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
-- If it's a cold war then the **borders of red and blue territory** need to be defined using a @{Core.Zone} object derived from @{Core.Zone#ZONE_BASE}. This method needs to be used for this.
|
||||||
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
-- If a hot war is chosen then **no borders** actually need to be defined using the helicopter units other than it makes it easier sometimes for the mission maker to envisage where the red and blue territories roughly are. In a hot war the borders are effectively defined by the ground based radar coverage of a coalition. Set the noborders parameter to 1
|
||||||
-- @param #AI_AIR_DISPATCHER self
|
-- @param #AI_AIR_DISPATCHER self
|
||||||
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
-- @param Core.Zone#ZONE_BASE BorderZone An object derived from ZONE_BASE, or a list of objects derived from ZONE_BASE.
|
||||||
@@ -1796,12 +1796,12 @@ do -- AI_AIR_DISPATCHER
|
|||||||
--
|
--
|
||||||
-- @return #AI_AIR_DISPATCHER
|
-- @return #AI_AIR_DISPATCHER
|
||||||
function AI_AIR_DISPATCHER:SetSquadron2( Squadron )
|
function AI_AIR_DISPATCHER:SetSquadron2( Squadron )
|
||||||
|
|
||||||
local SquadronName = Squadron:GetName() -- Retrieves the Squadron Name.
|
local SquadronName = Squadron:GetName() -- Retrieves the Squadron Name.
|
||||||
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
|
||||||
|
|
||||||
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
|
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1812,15 +1812,15 @@ do -- AI_AIR_DISPATCHER
|
|||||||
function AI_AIR_DISPATCHER:GetSquadron( SquadronName )
|
function AI_AIR_DISPATCHER:GetSquadron( SquadronName )
|
||||||
|
|
||||||
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
|
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
|
||||||
|
|
||||||
if not DefenderSquadron then
|
if not DefenderSquadron then
|
||||||
error( "Unknown Squadron for Dispatcher:" .. SquadronName )
|
error( "Unknown Squadron for Dispatcher:" .. SquadronName )
|
||||||
end
|
end
|
||||||
|
|
||||||
return DefenderSquadron
|
return DefenderSquadron
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the Squadron visible before startup of the dispatcher.
|
--- Set the Squadron visible before startup of the dispatcher.
|
||||||
-- All planes will be spawned as uncontrolled on the parking spot.
|
-- All planes will be spawned as uncontrolled on the parking spot.
|
||||||
-- They will lock the parking spot.
|
-- They will lock the parking spot.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **AI** -- Models the process of air to ground engagement for airplanes and helicopters.
|
--- **AI** - Models the process of air to ground engagement for airplanes and helicopters.
|
||||||
--
|
--
|
||||||
-- This is a class used in the @{AI_A2G_Dispatcher}.
|
-- This is a class used in the @{AI.AI_A2G_Dispatcher}.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -65,9 +65,9 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Core.Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI.AI_Cap#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone.
|
-- Use the method @{AI.AI_CAP#AI_AIR_ENGAGE.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -533,6 +533,10 @@ function AI_AIR_ENGAGE:onafterEngage( DefenderGroup, From, Event, To, AttackSetU
|
|||||||
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
DefenderCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||||
|
|
||||||
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
local TargetCoord = AttackSetUnit:GetFirst():GetPointVec3()
|
||||||
|
if not TargetCoord then
|
||||||
|
self:Return()
|
||||||
|
return
|
||||||
|
end
|
||||||
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
TargetCoord:SetY( EngageAltitude ) -- Ground targets don't have an altitude.
|
||||||
|
|
||||||
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
local TargetDistance = DefenderCoord:Get2DDistance( TargetCoord )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
|
--- **AI** - Models the process of A2G patrolling and engaging ground targets for airplanes and helicopters.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -12,8 +12,7 @@
|
|||||||
--- @type AI_AIR_PATROL
|
--- @type AI_AIR_PATROL
|
||||||
-- @extends AI.AI_Air#AI_AIR
|
-- @extends AI.AI_Air#AI_AIR
|
||||||
|
|
||||||
|
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Group}
|
||||||
--- The AI_AIR_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Group} or @{Wrapper.Group}
|
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -86,9 +85,9 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Core.Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI.AI_Cap#AI_AIR_PATROL.SetEngageZone}() to define that Zone.
|
-- Use the method @{AI.AI_CAP#AI_AIR_PATROL.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -101,7 +100,7 @@ AI_AIR_PATROL = {
|
|||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
-- @param AI.AI_Air#AI_AIR AI_Air The AI_AIR FSM.
|
-- @param AI.AI_Air#AI_AIR AI_Air The AI_AIR FSM.
|
||||||
-- @param Wrapper.Group#GROUP AIGroup The AI group.
|
-- @param Wrapper.Group#GROUP AIGroup The AI group.
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude (optional, default = 1000m ) The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude (optional, default = 1500m ) The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed (optional, default = 50% of max speed) The minimum speed of the @{Wrapper.Group} in km/h.
|
||||||
@@ -114,17 +113,17 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
|||||||
local self = BASE:Inherit( self, AI_Air ) -- #AI_AIR_PATROL
|
local self = BASE:Inherit( self, AI_Air ) -- #AI_AIR_PATROL
|
||||||
|
|
||||||
local SpeedMax = AIGroup:GetSpeedMax()
|
local SpeedMax = AIGroup:GetSpeedMax()
|
||||||
|
|
||||||
self.PatrolZone = PatrolZone
|
self.PatrolZone = PatrolZone
|
||||||
|
|
||||||
self.PatrolFloorAltitude = PatrolFloorAltitude or 1000
|
self.PatrolFloorAltitude = PatrolFloorAltitude or 1000
|
||||||
self.PatrolCeilingAltitude = PatrolCeilingAltitude or 1500
|
self.PatrolCeilingAltitude = PatrolCeilingAltitude or 1500
|
||||||
self.PatrolMinSpeed = PatrolMinSpeed or SpeedMax * 0.5
|
self.PatrolMinSpeed = PatrolMinSpeed or SpeedMax * 0.5
|
||||||
self.PatrolMaxSpeed = PatrolMaxSpeed or SpeedMax * 0.75
|
self.PatrolMaxSpeed = PatrolMaxSpeed or SpeedMax * 0.75
|
||||||
|
|
||||||
-- defafult PatrolAltType to "RADIO" if not specified
|
-- defafult PatrolAltType to "RADIO" if not specified
|
||||||
self.PatrolAltType = PatrolAltType or "RADIO"
|
self.PatrolAltType = PatrolAltType or "RADIO"
|
||||||
|
|
||||||
self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" )
|
self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" )
|
||||||
|
|
||||||
--- OnBefore Transition Handler for Event Patrol.
|
--- OnBefore Transition Handler for Event Patrol.
|
||||||
@@ -135,7 +134,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Patrol.
|
--- OnAfter Transition Handler for Event Patrol.
|
||||||
-- @function [parent=#AI_AIR_PATROL] OnAfterPatrol
|
-- @function [parent=#AI_AIR_PATROL] OnAfterPatrol
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
@@ -143,16 +142,16 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Patrol.
|
--- Synchronous Event Trigger for Event Patrol.
|
||||||
-- @function [parent=#AI_AIR_PATROL] Patrol
|
-- @function [parent=#AI_AIR_PATROL] Patrol
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Patrol.
|
--- Asynchronous Event Trigger for Event Patrol.
|
||||||
-- @function [parent=#AI_AIR_PATROL] __Patrol
|
-- @function [parent=#AI_AIR_PATROL] __Patrol
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
-- @param #number Delay The delay in seconds.
|
-- @param #number Delay The delay in seconds.
|
||||||
|
|
||||||
--- OnLeave Transition Handler for State Patrolling.
|
--- OnLeave Transition Handler for State Patrolling.
|
||||||
-- @function [parent=#AI_AIR_PATROL] OnLeavePatrolling
|
-- @function [parent=#AI_AIR_PATROL] OnLeavePatrolling
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
@@ -161,7 +160,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnEnter Transition Handler for State Patrolling.
|
--- OnEnter Transition Handler for State Patrolling.
|
||||||
-- @function [parent=#AI_AIR_PATROL] OnEnterPatrolling
|
-- @function [parent=#AI_AIR_PATROL] OnEnterPatrolling
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
@@ -169,9 +168,9 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
self:AddTransition( "Patrolling", "PatrolRoute", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
|
self:AddTransition( "Patrolling", "PatrolRoute", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
|
||||||
|
|
||||||
--- OnBefore Transition Handler for Event PatrolRoute.
|
--- OnBefore Transition Handler for Event PatrolRoute.
|
||||||
-- @function [parent=#AI_AIR_PATROL] OnBeforePatrolRoute
|
-- @function [parent=#AI_AIR_PATROL] OnBeforePatrolRoute
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
@@ -180,7 +179,7 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event PatrolRoute.
|
--- OnAfter Transition Handler for Event PatrolRoute.
|
||||||
-- @function [parent=#AI_AIR_PATROL] OnAfterPatrolRoute
|
-- @function [parent=#AI_AIR_PATROL] OnAfterPatrolRoute
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
@@ -188,23 +187,21 @@ function AI_AIR_PATROL:New( AI_Air, AIGroup, PatrolZone, PatrolFloorAltitude, Pa
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event PatrolRoute.
|
--- Synchronous Event Trigger for Event PatrolRoute.
|
||||||
-- @function [parent=#AI_AIR_PATROL] PatrolRoute
|
-- @function [parent=#AI_AIR_PATROL] PatrolRoute
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event PatrolRoute.
|
--- Asynchronous Event Trigger for Event PatrolRoute.
|
||||||
-- @function [parent=#AI_AIR_PATROL] __PatrolRoute
|
-- @function [parent=#AI_AIR_PATROL] __PatrolRoute
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
-- @param #number Delay The delay in seconds.
|
-- @param #number Delay The delay in seconds.
|
||||||
|
|
||||||
|
|
||||||
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
|
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_AIR_PATROL.
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the Engage Range when the AI will engage with airborne enemies.
|
--- Set the Engage Range when the AI will engage with airborne enemies.
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
-- @param #number EngageRange The Engage Range.
|
-- @param #number EngageRange The Engage Range.
|
||||||
@@ -230,7 +227,7 @@ end
|
|||||||
-- @param #table CapCoordinates Table of coordinates of first race track point. Second point is determined by leg length and heading.
|
-- @param #table CapCoordinates Table of coordinates of first race track point. Second point is determined by leg length and heading.
|
||||||
-- @return #AI_AIR_PATROL self
|
-- @return #AI_AIR_PATROL self
|
||||||
function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMax, DurationMin, DurationMax, CapCoordinates)
|
function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMax, DurationMin, DurationMax, CapCoordinates)
|
||||||
|
|
||||||
self.racetrack=true
|
self.racetrack=true
|
||||||
self.racetracklegmin=LegMin or 10000
|
self.racetracklegmin=LegMin or 10000
|
||||||
self.racetracklegmax=LegMax or 15000
|
self.racetracklegmax=LegMax or 15000
|
||||||
@@ -238,18 +235,16 @@ function AI_AIR_PATROL:SetRaceTrackPattern(LegMin, LegMax, HeadingMin, HeadingMa
|
|||||||
self.racetrackheadingmax=HeadingMax or 180
|
self.racetrackheadingmax=HeadingMax or 180
|
||||||
self.racetrackdurationmin=DurationMin
|
self.racetrackdurationmin=DurationMin
|
||||||
self.racetrackdurationmax=DurationMax
|
self.racetrackdurationmax=DurationMax
|
||||||
|
|
||||||
if self.racetrackdurationmax and not self.racetrackdurationmin then
|
if self.racetrackdurationmax and not self.racetrackdurationmin then
|
||||||
self.racetrackdurationmin=self.racetrackdurationmax
|
self.racetrackdurationmin=self.racetrackdurationmax
|
||||||
end
|
end
|
||||||
|
|
||||||
self.racetrackcapcoordinates=CapCoordinates
|
self.racetrackcapcoordinates=CapCoordinates
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
-- @return #AI_AIR_PATROL self
|
-- @return #AI_AIR_PATROL self
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||||
@@ -262,7 +257,7 @@ function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
|||||||
self:ClearTargetDistance()
|
self:ClearTargetDistance()
|
||||||
|
|
||||||
self:__PatrolRoute( self.TaskDelay )
|
self:__PatrolRoute( self.TaskDelay )
|
||||||
|
|
||||||
AIPatrol:OnReSpawn(
|
AIPatrol:OnReSpawn(
|
||||||
function( PatrolGroup )
|
function( PatrolGroup )
|
||||||
self:__Reset( self.TaskDelay )
|
self:__Reset( self.TaskDelay )
|
||||||
@@ -271,7 +266,7 @@ function AI_AIR_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
--- This static method is called from the route path within the last task at the last waypoint of the AIPatrol.
|
||||||
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
-- @param Wrapper.Group#GROUP AIPatrol The AI group.
|
||||||
-- @param #AI_AIR_PATROL Fsm The FSM.
|
-- @param #AI_AIR_PATROL Fsm The FSM.
|
||||||
@@ -282,10 +277,10 @@ function AI_AIR_PATROL.___PatrolRoute( AIPatrol, Fsm )
|
|||||||
if AIPatrol and AIPatrol:IsAlive() then
|
if AIPatrol and AIPatrol:IsAlive() then
|
||||||
Fsm:PatrolRoute()
|
Fsm:PatrolRoute()
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
--- Defines a new patrol route using the @{AI.AI_Patrol#AI_PATROL_ZONE} parameters and settings.
|
||||||
-- @param #AI_AIR_PATROL self
|
-- @param #AI_AIR_PATROL self
|
||||||
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
|
-- @param Wrapper.Group#GROUP AIPatrol The Group managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
@@ -300,21 +295,20 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if AIPatrol and AIPatrol:IsAlive() then
|
if AIPatrol and AIPatrol:IsAlive() then
|
||||||
|
|
||||||
local PatrolRoute = {}
|
local PatrolRoute = {}
|
||||||
|
|
||||||
--- Calculate the target route point.
|
--- Calculate the target route point.
|
||||||
|
|
||||||
local CurrentCoord = AIPatrol:GetCoordinate()
|
local CurrentCoord = AIPatrol:GetCoordinate()
|
||||||
|
|
||||||
local altitude= math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude )
|
local altitude= math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude )
|
||||||
|
|
||||||
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
|
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
|
||||||
ToTargetCoord:SetAlt( altitude )
|
ToTargetCoord:SetAlt( altitude )
|
||||||
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
|
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
|
||||||
|
|
||||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||||
local speedkmh=ToTargetSpeed
|
local speedkmh=ToTargetSpeed
|
||||||
|
|
||||||
@@ -322,31 +316,31 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
|||||||
PatrolRoute[#PatrolRoute+1] = FromWP
|
PatrolRoute[#PatrolRoute+1] = FromWP
|
||||||
|
|
||||||
if self.racetrack then
|
if self.racetrack then
|
||||||
|
|
||||||
-- Random heading.
|
-- Random heading.
|
||||||
local heading = math.random(self.racetrackheadingmin, self.racetrackheadingmax)
|
local heading = math.random(self.racetrackheadingmin, self.racetrackheadingmax)
|
||||||
|
|
||||||
-- Random leg length.
|
-- Random leg length.
|
||||||
local leg=math.random(self.racetracklegmin, self.racetracklegmax)
|
local leg=math.random(self.racetracklegmin, self.racetracklegmax)
|
||||||
|
|
||||||
-- Random duration if any.
|
-- Random duration if any.
|
||||||
local duration = self.racetrackdurationmin
|
local duration = self.racetrackdurationmin
|
||||||
if self.racetrackdurationmax then
|
if self.racetrackdurationmax then
|
||||||
duration=math.random(self.racetrackdurationmin, self.racetrackdurationmax)
|
duration=math.random(self.racetrackdurationmin, self.racetrackdurationmax)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- CAP coordinate.
|
-- CAP coordinate.
|
||||||
local c0=self.PatrolZone:GetRandomCoordinate()
|
local c0=self.PatrolZone:GetRandomCoordinate()
|
||||||
if self.racetrackcapcoordinates and #self.racetrackcapcoordinates>0 then
|
if self.racetrackcapcoordinates and #self.racetrackcapcoordinates>0 then
|
||||||
c0=self.racetrackcapcoordinates[math.random(#self.racetrackcapcoordinates)]
|
c0=self.racetrackcapcoordinates[math.random(#self.racetrackcapcoordinates)]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Race track points.
|
-- Race track points.
|
||||||
local c1=c0:SetAltitude(altitude) --Core.Point#COORDINATE
|
local c1=c0:SetAltitude(altitude) --Core.Point#COORDINATE
|
||||||
local c2=c1:Translate(leg, heading):SetAltitude(altitude)
|
local c2=c1:Translate(leg, heading):SetAltitude(altitude)
|
||||||
|
|
||||||
self:SetTargetDistance(c0) -- For RTB status check
|
self:SetTargetDistance(c0) -- For RTB status check
|
||||||
|
|
||||||
-- Debug:
|
-- Debug:
|
||||||
self:T(string.format("Patrol zone race track: v=%.1f knots, h=%.1f ft, heading=%03d, leg=%d m, t=%s sec", UTILS.KmphToKnots(speedkmh), UTILS.MetersToFeet(altitude), heading, leg, tostring(duration)))
|
self:T(string.format("Patrol zone race track: v=%.1f knots, h=%.1f ft, heading=%03d, leg=%d m, t=%s sec", UTILS.KmphToKnots(speedkmh), UTILS.MetersToFeet(altitude), heading, leg, tostring(duration)))
|
||||||
--c1:MarkToAll("Race track c1")
|
--c1:MarkToAll("Race track c1")
|
||||||
@@ -354,39 +348,41 @@ function AI_AIR_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
|
|||||||
|
|
||||||
-- Task to orbit.
|
-- Task to orbit.
|
||||||
local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2)
|
local taskOrbit=AIPatrol:TaskOrbit(c1, altitude, UTILS.KmphToMps(speedkmh), c2)
|
||||||
|
|
||||||
-- Task function to redo the patrol at other random position.
|
-- Task function to redo the patrol at other random position.
|
||||||
local taskPatrol=AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
local taskPatrol=AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||||
|
|
||||||
-- Controlled task with task condition.
|
-- Controlled task with task condition.
|
||||||
local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil)
|
local taskCond=AIPatrol:TaskCondition(nil, nil, nil, nil, duration, nil)
|
||||||
local taskCont=AIPatrol:TaskControlled(taskOrbit, taskCond)
|
local taskCont=AIPatrol:TaskControlled(taskOrbit, taskCond)
|
||||||
|
|
||||||
-- Second waypoint
|
-- Second waypoint
|
||||||
PatrolRoute[2]=c1:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskCont, taskPatrol}, "CAP Orbit")
|
PatrolRoute[2]=c1:WaypointAirTurningPoint(self.PatrolAltType, speedkmh, {taskCont, taskPatrol}, "CAP Orbit")
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToWP = ToTargetCoord:WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
local ToWP = ToTargetCoord:WaypointAir(self.PatrolAltType, POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint, ToTargetSpeed, true)
|
||||||
PatrolRoute[#PatrolRoute+1] = ToWP
|
PatrolRoute[#PatrolRoute+1] = ToWP
|
||||||
|
|
||||||
local Tasks = {}
|
local Tasks = {}
|
||||||
Tasks[#Tasks+1] = AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
Tasks[#Tasks+1] = AIPatrol:TaskFunction("AI_AIR_PATROL.___PatrolRoute", self)
|
||||||
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
AIPatrol:OptionROEReturnFire()
|
AIPatrol:OptionROEReturnFire()
|
||||||
AIPatrol:OptionROTEvadeFire()
|
AIPatrol:OptionROTEvadeFire()
|
||||||
|
|
||||||
AIPatrol:Route( PatrolRoute, self.TaskDelay )
|
AIPatrol:Route( PatrolRoute, self.TaskDelay )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Group#GROUP AIPatrol
|
--- Resumes the AIPatrol
|
||||||
|
-- @param Wrapper.Group#GROUP AIPatrol
|
||||||
|
-- @param Core.Fsm#FSM Fsm
|
||||||
function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
|
function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
|
||||||
|
|
||||||
AIPatrol:F( { "AI_AIR_PATROL.Resume:", AIPatrol:GetName() } )
|
AIPatrol:F( { "AI_AIR_PATROL.Resume:", AIPatrol:GetName() } )
|
||||||
@@ -394,5 +390,5 @@ function AI_AIR_PATROL.Resume( AIPatrol, Fsm )
|
|||||||
Fsm:__Reset( Fsm.TaskDelay )
|
Fsm:__Reset( Fsm.TaskDelay )
|
||||||
Fsm:__PatrolRoute( Fsm.TaskDelay )
|
Fsm:__PatrolRoute( Fsm.TaskDelay )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
--- **AI** - Models squadrons for airplanes and helicopters.
|
--- **AI** - Models squadrons for airplanes and helicopters.
|
||||||
--
|
--
|
||||||
-- This is a class used in the @{AI_Air_Dispatcher} and derived dispatcher classes.
|
-- This is a class used in the @{AI.AI_Air_Dispatcher} and derived dispatcher classes.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- Peform Battlefield Area Interdiction (BAI) within an engagement zone.
|
--- **AI** - Peform Battlefield Area Interdiction (BAI) within an engagement zone.
|
||||||
--
|
--
|
||||||
-- **Features:**
|
-- **Features:**
|
||||||
--
|
--
|
||||||
@@ -26,17 +26,17 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Bai
|
-- @module AI.AI_BAI
|
||||||
-- @image AI_Battlefield_Air_Interdiction.JPG
|
-- @image AI_Battlefield_Air_Interdiction.JPG
|
||||||
|
|
||||||
|
|
||||||
--- AI_BAI_ZONE class
|
--- AI_BAI_ZONE class
|
||||||
-- @type AI_BAI_ZONE
|
-- @type AI_BAI_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
|
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to provide BattleGround Air Interdiction in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_BAI_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
@@ -142,7 +142,7 @@ AI_BAI_ZONE = {
|
|||||||
|
|
||||||
--- Creates a new AI_BAI_ZONE object
|
--- Creates a new AI_BAI_ZONE object
|
||||||
-- @param #AI_BAI_ZONE self
|
-- @param #AI_BAI_ZONE self
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
@@ -515,8 +515,8 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -566,7 +566,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
|
|
||||||
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
|
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
|
||||||
|
|
||||||
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
|
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
|
||||||
|
|
||||||
--- Find a random 2D point in EngageZone.
|
--- Find a random 2D point in EngageZone.
|
||||||
local ToTargetVec2 = self.EngageZone:GetRandomVec2()
|
local ToTargetVec2 = self.EngageZone:GetRandomVec2()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
|
--- **AI** - Balance player slots with AI to create an engaging simulation environment, independent of the amount of players.
|
||||||
--
|
--
|
||||||
-- **Features:**
|
-- **Features:**
|
||||||
--
|
--
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/AIB%20-%20AI%20Balancing)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/AIB%20-%20AI%20Balancing)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- Perform Combat Air Patrolling (CAP) for airplanes.
|
--- **AI** - Perform Combat Air Patrolling (CAP) for airplanes.
|
||||||
--
|
--
|
||||||
-- **Features:**
|
-- **Features:**
|
||||||
--
|
--
|
||||||
@@ -6,11 +6,10 @@
|
|||||||
-- * Trigger detected events when enemy airplanes are detected.
|
-- * Trigger detected events when enemy airplanes are detected.
|
||||||
-- * Manage a fuel threshold to RTB on time.
|
-- * Manage a fuel threshold to RTB on time.
|
||||||
-- * Engage the enemy when detected.
|
-- * Engage the enemy when detected.
|
||||||
--
|
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAP%20-%20Combat%20Air%20Patrol)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAP%20-%20Combat%20Air%20Patrol)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -19,27 +18,25 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
-- * **[Quax](https://forums.eagle.ru/member.php?u=90530)**: Concept, Advice & Testing.
|
||||||
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
|
-- * **[Pikey](https://forums.eagle.ru/member.php?u=62835)**: Concept, Advice & Testing.
|
||||||
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
-- * **[Gunterlund](http://forums.eagle.ru:8080/member.php?u=75036)**: Test case revision.
|
||||||
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
|
-- * **[Whisper](http://forums.eagle.ru/member.php?u=3829): Testing.
|
||||||
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
|
-- * **[Delta99](https://forums.eagle.ru/member.php?u=125166): Testing.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Cap
|
-- @module AI.AI_CAP
|
||||||
-- @image AI_Combat_Air_Patrol.JPG
|
-- @image AI_Combat_Air_Patrol.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type AI_CAP_ZONE
|
--- @type AI_CAP_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
|
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
||||||
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}
|
|
||||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -106,15 +103,15 @@
|
|||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
-- The range can be beyond or smaller than the range of the Patrol Zone.
|
||||||
-- The range is applied at the position of the AI.
|
-- The range is applied at the position of the AI.
|
||||||
-- Use the method @{AI.AI_CAP#AI_CAP_ZONE.SetEngageRange}() to define that range.
|
-- Use the method @{#AI_CAP_ZONE.SetEngageRange}() to define that range.
|
||||||
--
|
--
|
||||||
-- ## 4. Set the Zone of Engagement
|
-- ## 4. Set the Zone of Engagement
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- An optional @{Zone} can be set,
|
-- An optional @{Core.Zone} can be set,
|
||||||
-- that will define when the AI will engage with the detected airborne enemy targets.
|
-- that will define when the AI will engage with the detected airborne enemy targets.
|
||||||
-- Use the method @{AI.AI_Cap#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
-- Use the method @{#AI_CAP_ZONE.SetEngageZone}() to define that Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -123,11 +120,9 @@ AI_CAP_ZONE = {
|
|||||||
ClassName = "AI_CAP_ZONE",
|
ClassName = "AI_CAP_ZONE",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new AI_CAP_ZONE object
|
--- Creates a new AI_CAP_ZONE object
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
@@ -141,7 +136,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
|
|
||||||
self.Accomplished = false
|
self.Accomplished = false
|
||||||
self.Engaging = false
|
self.Engaging = false
|
||||||
|
|
||||||
self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
self:AddTransition( { "Patrolling", "Engaging" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
||||||
|
|
||||||
--- OnBefore Transition Handler for Event Engage.
|
--- OnBefore Transition Handler for Event Engage.
|
||||||
@@ -152,7 +147,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Engage.
|
--- OnAfter Transition Handler for Event Engage.
|
||||||
-- @function [parent=#AI_CAP_ZONE] OnAfterEngage
|
-- @function [parent=#AI_CAP_ZONE] OnAfterEngage
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -160,11 +155,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Engage.
|
--- Synchronous Event Trigger for Event Engage.
|
||||||
-- @function [parent=#AI_CAP_ZONE] Engage
|
-- @function [parent=#AI_CAP_ZONE] Engage
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Engage.
|
--- Asynchronous Event Trigger for Event Engage.
|
||||||
-- @function [parent=#AI_CAP_ZONE] __Engage
|
-- @function [parent=#AI_CAP_ZONE] __Engage
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -188,7 +183,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
self:AddTransition( "Engaging", "Fired", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
||||||
|
|
||||||
--- OnBefore Transition Handler for Event Fired.
|
--- OnBefore Transition Handler for Event Fired.
|
||||||
-- @function [parent=#AI_CAP_ZONE] OnBeforeFired
|
-- @function [parent=#AI_CAP_ZONE] OnBeforeFired
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -197,7 +192,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Fired.
|
--- OnAfter Transition Handler for Event Fired.
|
||||||
-- @function [parent=#AI_CAP_ZONE] OnAfterFired
|
-- @function [parent=#AI_CAP_ZONE] OnAfterFired
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -205,11 +200,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Fired.
|
--- Synchronous Event Trigger for Event Fired.
|
||||||
-- @function [parent=#AI_CAP_ZONE] Fired
|
-- @function [parent=#AI_CAP_ZONE] Fired
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Fired.
|
--- Asynchronous Event Trigger for Event Fired.
|
||||||
-- @function [parent=#AI_CAP_ZONE] __Fired
|
-- @function [parent=#AI_CAP_ZONE] __Fired
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -225,7 +220,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Destroy.
|
--- OnAfter Transition Handler for Event Destroy.
|
||||||
-- @function [parent=#AI_CAP_ZONE] OnAfterDestroy
|
-- @function [parent=#AI_CAP_ZONE] OnAfterDestroy
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -233,17 +228,16 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Destroy.
|
--- Synchronous Event Trigger for Event Destroy.
|
||||||
-- @function [parent=#AI_CAP_ZONE] Destroy
|
-- @function [parent=#AI_CAP_ZONE] Destroy
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Destroy.
|
--- Asynchronous Event Trigger for Event Destroy.
|
||||||
-- @function [parent=#AI_CAP_ZONE] __Destroy
|
-- @function [parent=#AI_CAP_ZONE] __Destroy
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
-- @param #number Delay The delay in seconds.
|
-- @param #number Delay The delay in seconds.
|
||||||
|
|
||||||
|
|
||||||
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
self:AddTransition( "Engaging", "Abort", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_CAP_ZONE.
|
||||||
|
|
||||||
--- OnBefore Transition Handler for Event Abort.
|
--- OnBefore Transition Handler for Event Abort.
|
||||||
@@ -254,7 +248,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Abort.
|
--- OnAfter Transition Handler for Event Abort.
|
||||||
-- @function [parent=#AI_CAP_ZONE] OnAfterAbort
|
-- @function [parent=#AI_CAP_ZONE] OnAfterAbort
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -262,11 +256,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Abort.
|
--- Synchronous Event Trigger for Event Abort.
|
||||||
-- @function [parent=#AI_CAP_ZONE] Abort
|
-- @function [parent=#AI_CAP_ZONE] Abort
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Abort.
|
--- Asynchronous Event Trigger for Event Abort.
|
||||||
-- @function [parent=#AI_CAP_ZONE] __Abort
|
-- @function [parent=#AI_CAP_ZONE] __Abort
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -282,7 +276,7 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @return #boolean Return false to cancel Transition.
|
-- @return #boolean Return false to cancel Transition.
|
||||||
|
|
||||||
--- OnAfter Transition Handler for Event Accomplish.
|
--- OnAfter Transition Handler for Event Accomplish.
|
||||||
-- @function [parent=#AI_CAP_ZONE] OnAfterAccomplish
|
-- @function [parent=#AI_CAP_ZONE] OnAfterAccomplish
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -290,11 +284,11 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Accomplish.
|
--- Synchronous Event Trigger for Event Accomplish.
|
||||||
-- @function [parent=#AI_CAP_ZONE] Accomplish
|
-- @function [parent=#AI_CAP_ZONE] Accomplish
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
|
|
||||||
--- Asynchronous Event Trigger for Event Accomplish.
|
--- Asynchronous Event Trigger for Event Accomplish.
|
||||||
-- @function [parent=#AI_CAP_ZONE] __Accomplish
|
-- @function [parent=#AI_CAP_ZONE] __Accomplish
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
@@ -303,7 +297,6 @@ function AI_CAP_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the Engage Zone which defines where the AI will engage bogies.
|
--- Set the Engage Zone which defines where the AI will engage bogies.
|
||||||
-- @param #AI_CAP_ZONE self
|
-- @param #AI_CAP_ZONE self
|
||||||
-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP.
|
-- @param Core.Zone#ZONE EngageZone The zone where the AI is performing CAP.
|
||||||
@@ -311,7 +304,7 @@ end
|
|||||||
function AI_CAP_ZONE:SetEngageZone( EngageZone )
|
function AI_CAP_ZONE:SetEngageZone( EngageZone )
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
if EngageZone then
|
if EngageZone then
|
||||||
self.EngageZone = EngageZone
|
self.EngageZone = EngageZone
|
||||||
else
|
else
|
||||||
self.EngageZone = nil
|
self.EngageZone = nil
|
||||||
@@ -346,7 +339,6 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param AI.AI_CAP#AI_CAP_ZONE
|
--- @param AI.AI_CAP#AI_CAP_ZONE
|
||||||
-- @param Wrapper.Group#GROUP EngageGroup
|
-- @param Wrapper.Group#GROUP EngageGroup
|
||||||
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
|
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
|
||||||
@@ -358,8 +350,6 @@ function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_CAP_ZONE self
|
--- @param #AI_CAP_ZONE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
@@ -380,11 +370,11 @@ end
|
|||||||
function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
||||||
|
|
||||||
if From ~= "Engaging" then
|
if From ~= "Engaging" then
|
||||||
|
|
||||||
local Engage = false
|
local Engage = false
|
||||||
|
|
||||||
for DetectedUnit, Detected in pairs( self.DetectedUnits ) do
|
for DetectedUnit, Detected in pairs( self.DetectedUnits ) do
|
||||||
|
|
||||||
local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT
|
local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT
|
||||||
self:T( DetectedUnit )
|
self:T( DetectedUnit )
|
||||||
if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then
|
if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then
|
||||||
@@ -392,7 +382,7 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if Engage == true then
|
if Engage == true then
|
||||||
self:F( 'Detected -> Engaging' )
|
self:F( 'Detected -> Engaging' )
|
||||||
self:__Engage( 1 )
|
self:__Engage( 1 )
|
||||||
@@ -400,7 +390,6 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_CAP_ZONE self
|
--- @param #AI_CAP_ZONE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
@@ -411,9 +400,6 @@ function AI_CAP_ZONE:onafterAbort( Controllable, From, Event, To )
|
|||||||
self:__Route( 1 )
|
self:__Route( 1 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- @param #AI_CAP_ZONE self
|
--- @param #AI_CAP_ZONE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
@@ -427,22 +413,23 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
|
|
||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
if not CurrentVec2 then return self end
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
|
||||||
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
ToEngageZoneSpeed,
|
ToEngageZoneSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
EngageRoute[#EngageRoute+1] = CurrentRoutePoint
|
EngageRoute[#EngageRoute+1] = CurrentRoutePoint
|
||||||
|
|
||||||
|
|
||||||
--- Find a random 2D point in PatrolZone.
|
--- Find a random 2D point in PatrolZone.
|
||||||
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
|
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
|
||||||
self:T2( ToTargetVec2 )
|
self:T2( ToTargetVec2 )
|
||||||
@@ -451,17 +438,17 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude )
|
local ToTargetAltitude = math.random( self.EngageFloorAltitude, self.EngageCeilingAltitude )
|
||||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||||
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
self:T2( { self.PatrolMinSpeed, self.PatrolMaxSpeed, ToTargetSpeed } )
|
||||||
|
|
||||||
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
--- Obtain a 3D @{Point} from the 2D point + altitude.
|
||||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||||
|
|
||||||
--- Create a route point of type air.
|
--- Create a route point of type air.
|
||||||
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||||
self.PatrolAltType,
|
self.PatrolAltType,
|
||||||
POINT_VEC3.RoutePointType.TurningPoint,
|
POINT_VEC3.RoutePointType.TurningPoint,
|
||||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||||
ToTargetSpeed,
|
ToTargetSpeed,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||||
@@ -480,7 +467,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
self:F( {"Within Zone and Engaging ", DetectedUnit } )
|
self:F( {"Within Zone and Engaging ", DetectedUnit } )
|
||||||
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
|
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if self.EngageRange then
|
if self.EngageRange then
|
||||||
if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then
|
if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then
|
||||||
self:F( {"Within Range and Engaging", DetectedUnit } )
|
self:F( {"Within Range and Engaging", DetectedUnit } )
|
||||||
@@ -504,12 +491,12 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
|
|
||||||
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self )
|
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self )
|
||||||
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
|
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
|
||||||
|
|
||||||
self:SetDetectionDeactivated()
|
self:SetDetectionDeactivated()
|
||||||
end
|
end
|
||||||
|
|
||||||
Controllable:Route( EngageRoute, 0.5 )
|
Controllable:Route( EngageRoute, 0.5 )
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- Perform Close Air Support (CAS) near friendlies.
|
--- **AI** - Perform Close Air Support (CAS) near friendlies.
|
||||||
--
|
--
|
||||||
-- **Features:**
|
-- **Features:**
|
||||||
--
|
--
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CAS%20-%20Close%20Air%20Support)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CAS%20-%20Close%20Air%20Support)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -28,16 +28,16 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Cas
|
-- @module AI.AI_CAS
|
||||||
-- @image AI_Close_Air_Support.JPG
|
-- @image AI_Close_Air_Support.JPG
|
||||||
|
|
||||||
--- AI_CAS_ZONE class
|
--- AI_CAS_ZONE class
|
||||||
-- @type AI_CAS_ZONE
|
-- @type AI_CAS_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||||
-- @field Core.Zone#ZONE_BASE TargetZone The @{Zone} where the patrol needs to be executed.
|
-- @field Core.Zone#ZONE_BASE TargetZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
-- @extends AI.AI_Patrol#AI_PATROL_ZONE
|
||||||
|
|
||||||
--- Implements the core functions to provide Close Air Support in an Engage @{Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to provide Close Air Support in an Engage @{Core.Zone} by an AIR @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
-- The AI_CAS_ZONE runs a process. It holds an AI in a Patrol Zone and when the AI is commanded to engage, it will fly to an Engage Zone.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -130,7 +130,7 @@ AI_CAS_ZONE = {
|
|||||||
|
|
||||||
--- Creates a new AI_CAS_ZONE object
|
--- Creates a new AI_CAS_ZONE object
|
||||||
-- @param #AI_CAS_ZONE self
|
-- @param #AI_CAS_ZONE self
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
@@ -459,8 +459,8 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -496,7 +496,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAS_ZONE.EngageRoute", self )
|
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAS_ZONE.EngageRoute", self )
|
||||||
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
|
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
|
||||||
|
|
||||||
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
|
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
|
||||||
|
|
||||||
--- Find a random 2D point in EngageZone.
|
--- Find a random 2D point in EngageZone.
|
||||||
local ToTargetVec2 = self.EngageZone:GetRandomVec2()
|
local ToTargetVec2 = self.EngageZone:GetRandomVec2()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.4) - Models the intelligent transportation of infantry and other cargo using Planes.
|
--- **AI** - Models the intelligent transportation of infantry and other cargo using Planes.
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (2.4) - Models the intelligent transportation of infantry and other cargo using Helicopters.
|
--- **AI** - Models the intelligent transportation of infantry and other cargo using Helicopters.
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
@@ -174,8 +174,8 @@ function AI_CARGO_DISPATCHER_HELICOPTER:New( HelicopterSet, CargoSet, PickupZone
|
|||||||
self:SetPickupSpeed( 350, 150 )
|
self:SetPickupSpeed( 350, 150 )
|
||||||
self:SetDeploySpeed( 350, 150 )
|
self:SetDeploySpeed( 350, 150 )
|
||||||
|
|
||||||
self:SetPickupRadius( 0, 0 )
|
self:SetPickupRadius( 40, 12 )
|
||||||
self:SetDeployRadius( 0, 0 )
|
self:SetDeployRadius( 40, 12 )
|
||||||
|
|
||||||
self:SetPickupHeight( 500, 200 )
|
self:SetPickupHeight( 500, 200 )
|
||||||
self:SetDeployHeight( 500, 200 )
|
self:SetDeployHeight( 500, 200 )
|
||||||
@@ -186,6 +186,9 @@ end
|
|||||||
|
|
||||||
function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, CargoSet )
|
function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, CargoSet )
|
||||||
|
|
||||||
return AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
local dispatcher = AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
||||||
|
dispatcher:SetLandingSpeedAndHeight(27, 6)
|
||||||
|
return dispatcher
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (2.5.1) - Models the intelligent transportation of infantry and other cargo using Ships
|
--- **AI** - Models the intelligent transportation of infantry and other cargo using Ships.
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Cargo_Dispatcher_Ship
|
-- @module AI.AI_Cargo_Dispatcher_Ship
|
||||||
-- @image AI_Cargo_Dispatching_For_Ship.JPG
|
-- @image AI_Cargo_Dispatcher.JPG
|
||||||
|
|
||||||
--- @type AI_CARGO_DISPATCHER_SHIP
|
--- @type AI_CARGO_DISPATCHER_SHIP
|
||||||
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
||||||
@@ -37,14 +37,14 @@
|
|||||||
--
|
--
|
||||||
-- This will be particularly helpful in order to determine how to **Tailor the different cargo handling events**.
|
-- This will be particularly helpful in order to determine how to **Tailor the different cargo handling events**.
|
||||||
--
|
--
|
||||||
-- The AI_CARGO_DISPATCHER_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framwork.
|
-- The AI_CARGO_DISPATCHER_SHIP class uses the @{Cargo.Cargo} capabilities within the MOOSE framework.
|
||||||
-- Also ensure that you fully understand how to declare and setup Cargo objects within the MOOSE framework before using this class.
|
-- Also ensure that you fully understand how to declare and setup Cargo objects within the MOOSE framework before using this class.
|
||||||
-- CARGO derived objects must generally be declared within the mission to make the AI_CARGO_DISPATCHER_SHIP object recognize the cargo.
|
-- CARGO derived objects must generally be declared within the mission to make the AI_CARGO_DISPATCHER_SHIP object recognize the cargo.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- # 1) AI_CARGO_DISPATCHER_SHIP constructor.
|
-- # 1) AI_CARGO_DISPATCHER_SHIP constructor.
|
||||||
--
|
--
|
||||||
-- * @{AI_CARGO_DISPATCHER_SHIP.New}(): Creates a new AI_CARGO_DISPATCHER_SHIP object.
|
-- * @{#AI_CARGO_DISPATCHER_SHIP.New}(): Creates a new AI_CARGO_DISPATCHER_SHIP object.
|
||||||
--
|
--
|
||||||
-- ---
|
-- ---
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- (R2.5.1) - Models the intelligent transportation of infantry and other cargo.
|
--- **AI** - Models the intelligent transportation of infantry and other cargo.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Cargo_Ship
|
-- @module AI.AI_Cargo_Ship
|
||||||
-- @image AI_Cargo_Dispatching_For_Ship.JPG
|
-- @image AI_Cargo_Dispatcher.JPG
|
||||||
|
|
||||||
--- @type AI_CARGO_SHIP
|
--- @type AI_CARGO_SHIP
|
||||||
-- @extends AI.AI_Cargo#AI_CARGO
|
-- @extends AI.AI_Cargo#AI_CARGO
|
||||||
@@ -46,12 +46,12 @@
|
|||||||
--
|
--
|
||||||
-- ## Cargo deployment.
|
-- ## Cargo deployment.
|
||||||
--
|
--
|
||||||
-- Using the @{AI_CARGO_SHIP.Deploy}() method, you are able to direct the Ship towards a Deploy zone to unboard/unload the cargo at the
|
-- Using the @{#AI_CARGO_SHIP.Deploy}() method, you are able to direct the Ship towards a Deploy zone to unboard/unload the cargo at the
|
||||||
-- specified coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
-- specified coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
||||||
--
|
--
|
||||||
-- ## Cargo pickup.
|
-- ## Cargo pickup.
|
||||||
--
|
--
|
||||||
-- Using the @{AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
|
-- Using the @{#AI_CARGO_SHIP.Pickup}() method, you are able to direct the Ship towards a Pickup zone to board/load the cargo at the specified
|
||||||
-- coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
-- coordinate. The Ship will follow the Shipping Lane to ensure consistent cargo transportation within the simulation environment.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Taking the lead of AI escorting your flight or of other AI.
|
--- **AI** - Taking the lead of AI escorting your flight or of other AI.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_ESCORT_DISPATCHER_REQUEST
|
-- @module AI.AI_Escort_Dispatcher_Request
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Taking the lead of AI escorting your flight or of other AI, upon request using the menu.
|
--- **AI** - Taking the lead of AI escorting your flight or of other AI, upon request using the menu.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Escort
|
-- @module AI.AI_Escort_Request
|
||||||
-- @image Escorting.JPG
|
-- @image Escorting.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- Build large airborne formations of aircraft.
|
--- **AI** - Build large airborne formations of aircraft.
|
||||||
--
|
--
|
||||||
-- **Features:**
|
-- **Features:**
|
||||||
--
|
--
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
--- Build large formations, make AI follow a @{Wrapper.Client#CLIENT} (player) leader or a @{Wrapper.Unit#UNIT} (AI) leader.
|
||||||
--
|
--
|
||||||
-- AI_FORMATION makes AI @{GROUP}s fly in formation of various compositions.
|
-- AI_FORMATION makes AI @{Wrapper.Group#GROUP}s fly in formation of various compositions.
|
||||||
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
-- The AI_FORMATION class models formations in a different manner than the internal DCS formation logic!!!
|
||||||
-- The purpose of the class is to:
|
-- The purpose of the class is to:
|
||||||
--
|
--
|
||||||
@@ -1140,8 +1140,8 @@ end
|
|||||||
-- @param DCS#Vec3 CV2 Vec3
|
-- @param DCS#Vec3 CV2 Vec3
|
||||||
function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
|
function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
|
||||||
|
|
||||||
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then
|
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation and not self:Is("Stopped") then
|
||||||
|
|
||||||
self:T({Mode=FollowGroup:GetState( FollowGroup, "Mode" )})
|
self:T({Mode=FollowGroup:GetState( FollowGroup, "Mode" )})
|
||||||
|
|
||||||
FollowGroup:OptionROTEvadeFire()
|
FollowGroup:OptionROTEvadeFire()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **AI** -- Perform Air Patrolling for airplanes.
|
--- **AI** - Perform Air Patrolling for airplanes.
|
||||||
--
|
--
|
||||||
-- **Features:**
|
-- **Features:**
|
||||||
--
|
--
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/PAT%20-%20Patrolling)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/PAT%20-%20Patrolling)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
--- AI_PATROL_ZONE class
|
--- AI_PATROL_ZONE class
|
||||||
-- @type AI_PATROL_ZONE
|
-- @type AI_PATROL_ZONE
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
-- @field Wrapper.Controllable#CONTROLLABLE AIControllable The @{Wrapper.Controllable} patrolling.
|
||||||
-- @field Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @field Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @field DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @field DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @field DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @field DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @field DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
-- @field DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
-- @field Core.Spawn#SPAWN CoordTest
|
-- @field Core.Spawn#SPAWN CoordTest
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
--- Implements the core functions to patrol a @{Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
--- Implements the core functions to patrol a @{Core.Zone} by an AI @{Wrapper.Controllable} or @{Wrapper.Group}.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -135,15 +135,15 @@
|
|||||||
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
-- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit,
|
||||||
-- while a new AI is targetted to the AI_PATROL_ZONE.
|
-- while a new AI is targeted to the AI_PATROL_ZONE.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this proces in place.
|
-- Use the method @{#AI_PATROL_ZONE.ManageFuel}() to have this process in place.
|
||||||
--
|
--
|
||||||
-- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE
|
-- ## 7. Manage "damage" behaviour of the AI in the AI_PATROL_ZONE
|
||||||
--
|
--
|
||||||
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
|
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
|
||||||
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
-- Therefore, when the damage threshold is reached, the AI will return immediately to the home base (RTB).
|
||||||
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this proces in place.
|
-- Use the method @{#AI_PATROL_ZONE.ManageDamage}() to have this process in place.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -154,7 +154,7 @@ AI_PATROL_ZONE = {
|
|||||||
|
|
||||||
--- Creates a new AI_PATROL_ZONE object
|
--- Creates a new AI_PATROL_ZONE object
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Core.Zone} where the patrol needs to be executed.
|
||||||
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
-- @param DCS#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||||
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
-- @param DCS#Speed PatrolMinSpeed The minimum speed of the @{Wrapper.Controllable} in km/h.
|
||||||
@@ -170,27 +170,27 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
|||||||
|
|
||||||
-- Inherits from BASE
|
-- Inherits from BASE
|
||||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_PATROL_ZONE
|
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_PATROL_ZONE
|
||||||
|
|
||||||
|
|
||||||
self.PatrolZone = PatrolZone
|
self.PatrolZone = PatrolZone
|
||||||
self.PatrolFloorAltitude = PatrolFloorAltitude
|
self.PatrolFloorAltitude = PatrolFloorAltitude
|
||||||
self.PatrolCeilingAltitude = PatrolCeilingAltitude
|
self.PatrolCeilingAltitude = PatrolCeilingAltitude
|
||||||
self.PatrolMinSpeed = PatrolMinSpeed
|
self.PatrolMinSpeed = PatrolMinSpeed
|
||||||
self.PatrolMaxSpeed = PatrolMaxSpeed
|
self.PatrolMaxSpeed = PatrolMaxSpeed
|
||||||
|
|
||||||
-- defafult PatrolAltType to "BARO" if not specified
|
-- defafult PatrolAltType to "BARO" if not specified
|
||||||
self.PatrolAltType = PatrolAltType or "BARO"
|
self.PatrolAltType = PatrolAltType or "BARO"
|
||||||
|
|
||||||
self:SetRefreshTimeInterval( 30 )
|
self:SetRefreshTimeInterval( 30 )
|
||||||
|
|
||||||
self.CheckStatus = true
|
self.CheckStatus = true
|
||||||
|
|
||||||
self:ManageFuel( .2, 60 )
|
self:ManageFuel( .2, 60 )
|
||||||
self:ManageDamage( 1 )
|
self:ManageDamage( 1 )
|
||||||
|
|
||||||
|
|
||||||
self.DetectedUnits = {} -- This table contains the targets detected during patrol.
|
self.DetectedUnits = {} -- This table contains the targets detected during patrol.
|
||||||
|
|
||||||
self:SetStartState( "None" )
|
self:SetStartState( "None" )
|
||||||
|
|
||||||
self:AddTransition( "*", "Stop", "Stopped" )
|
self:AddTransition( "*", "Stop", "Stopped" )
|
||||||
@@ -228,7 +228,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Stop.
|
--- Synchronous Event Trigger for Event Stop.
|
||||||
-- @function [parent=#AI_PATROL_ZONE] Stop
|
-- @function [parent=#AI_PATROL_ZONE] Stop
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
@@ -256,7 +256,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Start.
|
--- Synchronous Event Trigger for Event Start.
|
||||||
-- @function [parent=#AI_PATROL_ZONE] Start
|
-- @function [parent=#AI_PATROL_ZONE] Start
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
@@ -329,7 +329,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event Status.
|
--- Synchronous Event Trigger for Event Status.
|
||||||
-- @function [parent=#AI_PATROL_ZONE] Status
|
-- @function [parent=#AI_PATROL_ZONE] Status
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
@@ -413,7 +413,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
--- Synchronous Event Trigger for Event RTB.
|
--- Synchronous Event Trigger for Event RTB.
|
||||||
-- @function [parent=#AI_PATROL_ZONE] RTB
|
-- @function [parent=#AI_PATROL_ZONE] RTB
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
@@ -441,11 +441,11 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
|||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
|
||||||
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE.
|
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_PATROL_ZONE.
|
||||||
|
|
||||||
self:AddTransition( "*", "Eject", "*" )
|
self:AddTransition( "*", "Eject", "*" )
|
||||||
self:AddTransition( "*", "Crash", "Crashed" )
|
self:AddTransition( "*", "Crash", "Crashed" )
|
||||||
self:AddTransition( "*", "PilotDead", "*" )
|
self:AddTransition( "*", "PilotDead", "*" )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -459,7 +459,7 @@ end
|
|||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
function AI_PATROL_ZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
||||||
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
||||||
|
|
||||||
self.PatrolMinSpeed = PatrolMinSpeed
|
self.PatrolMinSpeed = PatrolMinSpeed
|
||||||
self.PatrolMaxSpeed = PatrolMaxSpeed
|
self.PatrolMaxSpeed = PatrolMaxSpeed
|
||||||
end
|
end
|
||||||
@@ -473,7 +473,7 @@ end
|
|||||||
-- @return #AI_PATROL_ZONE self
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
function AI_PATROL_ZONE:SetAltitude( PatrolFloorAltitude, PatrolCeilingAltitude )
|
||||||
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
self:F2( { PatrolFloorAltitude, PatrolCeilingAltitude } )
|
||||||
|
|
||||||
self.PatrolFloorAltitude = PatrolFloorAltitude
|
self.PatrolFloorAltitude = PatrolFloorAltitude
|
||||||
self.PatrolCeilingAltitude = PatrolCeilingAltitude
|
self.PatrolCeilingAltitude = PatrolCeilingAltitude
|
||||||
end
|
end
|
||||||
@@ -582,7 +582,7 @@ end
|
|||||||
|
|
||||||
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
--- When the AI is out of fuel, it is required that a new AI is started, before the old AI can return to the home base.
|
||||||
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel threshold is calculated.
|
||||||
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
|
-- When the fuel threshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targeted to the AI_PATROL_ZONE.
|
||||||
-- Once the time is finished, the old AI will return to the base.
|
-- Once the time is finished, the old AI will return to the base.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param #number PatrolFuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
-- @param #number PatrolFuelThresholdPercentage The threshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||||
@@ -592,7 +592,7 @@ function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFu
|
|||||||
|
|
||||||
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
||||||
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -609,28 +609,28 @@ function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
|
|||||||
|
|
||||||
self.PatrolManageDamage = true
|
self.PatrolManageDamage = true
|
||||||
self.PatrolDamageThreshold = PatrolDamageThreshold
|
self.PatrolDamageThreshold = PatrolDamageThreshold
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
--- Defines a new patrol route using the @{#AI_PATROL_ZONE} parameters and settings.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @return #AI_PATROL_ZONE self
|
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
|
-- @return #AI_PATROL_ZONE self
|
||||||
function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To )
|
function AI_PATROL_ZONE:onafterStart( Controllable, From, Event, To )
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
self:__Route( 1 ) -- Route to the patrol point. The asynchronous trigger is important, because a spawned group and units takes at least one second to come live.
|
self:__Route( 1 ) -- Route to the patrol point. The asynchronous trigger is important, because a spawned group and units takes at least one second to come live.
|
||||||
self:__Status( 60 ) -- Check status status every 30 seconds.
|
self:__Status( 60 ) -- Check status status every 30 seconds.
|
||||||
self:SetDetectionActivated()
|
self:SetDetectionActivated()
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.PilotDead, self.OnPilotDead )
|
self:HandleEvent( EVENTS.PilotDead, self.OnPilotDead )
|
||||||
self:HandleEvent( EVENTS.Crash, self.OnCrash )
|
self:HandleEvent( EVENTS.Crash, self.OnCrash )
|
||||||
self:HandleEvent( EVENTS.Ejection, self.OnEjection )
|
self:HandleEvent( EVENTS.Ejection, self.OnEjection )
|
||||||
|
|
||||||
Controllable:OptionROEHoldFire()
|
Controllable:OptionROEHoldFire()
|
||||||
Controllable:OptionROTVertical()
|
Controllable:OptionROTVertical()
|
||||||
|
|
||||||
@@ -667,12 +667,12 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
|||||||
if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then
|
if TargetObject and TargetObject:isExist() and TargetObject.id_ < 50000000 then
|
||||||
|
|
||||||
local TargetUnit = UNIT:Find( TargetObject )
|
local TargetUnit = UNIT:Find( TargetObject )
|
||||||
|
|
||||||
-- Check that target is alive due to issue https://github.com/FlightControl-Master/MOOSE/issues/1234
|
-- Check that target is alive due to issue https://github.com/FlightControl-Master/MOOSE/issues/1234
|
||||||
if TargetUnit and TargetUnit:IsAlive() then
|
if TargetUnit and TargetUnit:IsAlive() then
|
||||||
|
|
||||||
local TargetUnitName = TargetUnit:GetName()
|
local TargetUnitName = TargetUnit:GetName()
|
||||||
|
|
||||||
if self.DetectionZone then
|
if self.DetectionZone then
|
||||||
if TargetUnit:IsInZone( self.DetectionZone ) then
|
if TargetUnit:IsInZone( self.DetectionZone ) then
|
||||||
self:T( {"Detected ", TargetUnit } )
|
self:T( {"Detected ", TargetUnit } )
|
||||||
@@ -687,13 +687,13 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
|||||||
end
|
end
|
||||||
Detected = true
|
Detected = true
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:__Detect( -self.DetectInterval )
|
self:__Detect( -self.DetectInterval )
|
||||||
|
|
||||||
if Detected == true then
|
if Detected == true then
|
||||||
self:__Detected( 1.5 )
|
self:__Detected( 1.5 )
|
||||||
end
|
end
|
||||||
@@ -701,7 +701,7 @@ function AI_PATROL_ZONE:onafterDetect( Controllable, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
||||||
-- This statis method is called from the route path within the last task at the last waaypoint of the Controllable.
|
-- This static method is called from the route path within the last task at the last waypoint of the Controllable.
|
||||||
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
|
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
|
||||||
function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
|
function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
|
||||||
|
|
||||||
@@ -710,7 +710,7 @@ function AI_PATROL_ZONE:_NewPatrolRoute( AIControllable )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
--- Defines a new patrol route using the @{#AI_PATROL_ZONE} parameters and settings.
|
||||||
-- @param #AI_PATROL_ZONE self
|
-- @param #AI_PATROL_ZONE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
@@ -725,11 +725,11 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local life = self.Controllable:GetLife() or 0
|
||||||
if self.Controllable:IsAlive() then
|
if self.Controllable:IsAlive() and life > 1 then
|
||||||
-- Determine if the AIControllable is within the PatrolZone.
|
-- Determine if the AIControllable is within the PatrolZone.
|
||||||
-- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point.
|
-- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point.
|
||||||
|
|
||||||
local PatrolRoute = {}
|
local PatrolRoute = {}
|
||||||
|
|
||||||
-- Calculate the current route point of the controllable as the start point of the route.
|
-- Calculate the current route point of the controllable as the start point of the route.
|
||||||
@@ -743,8 +743,9 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
if self.Controllable:InAir() == false then
|
if self.Controllable:InAir() == false then
|
||||||
self:T( "Not in the air, finding route path within PatrolZone" )
|
self:T( "Not in the air, finding route path within PatrolZone" )
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
if not CurrentVec2 then return end
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
--Done: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -758,8 +759,9 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
else
|
else
|
||||||
self:T( "In the air, finding route path within PatrolZone" )
|
self:T( "In the air, finding route path within PatrolZone" )
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
if not CurrentVec2 then return end
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
@@ -773,7 +775,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
|
--- Define a random point in the @{Core.Zone}. The AI will fly to that point within the zone.
|
||||||
|
|
||||||
--- Find a random 2D point in PatrolZone.
|
--- Find a random 2D point in PatrolZone.
|
||||||
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
|
local ToTargetVec2 = self.PatrolZone:GetRandomVec2()
|
||||||
@@ -870,9 +872,10 @@ function AI_PATROL_ZONE:onafterRTB()
|
|||||||
|
|
||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
if not CurrentVec2 then return end
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
--local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||||
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occuring on @{Wrapper.Unit}s.
|
--- **Actions** - ACT_ACCOUNT_ classes **account for** (detect, count & report) various DCS events occurring on UNITs.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Actions.Account
|
-- @module Actions.Act_Account
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
do -- ACT_ACCOUNT
|
do -- ACT_ACCOUNT
|
||||||
@@ -20,7 +20,7 @@ do -- ACT_ACCOUNT
|
|||||||
--
|
--
|
||||||
-- ### ACT_ACCOUNT States
|
-- ### ACT_ACCOUNT States
|
||||||
--
|
--
|
||||||
-- * **Asigned**: The player is assigned.
|
-- * **Assigned**: The player is assigned.
|
||||||
-- * **Waiting**: Waiting for an event.
|
-- * **Waiting**: Waiting for an event.
|
||||||
-- * **Report**: Reporting.
|
-- * **Report**: Reporting.
|
||||||
-- * **Account**: Account for an event.
|
-- * **Account**: Account for an event.
|
||||||
@@ -104,7 +104,6 @@ do -- ACT_ACCOUNT
|
|||||||
self:__Wait( 1 )
|
self:__Wait( 1 )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- StateMachine callback function
|
--- StateMachine callback function
|
||||||
-- @param #ACT_ACCOUNT self
|
-- @param #ACT_ACCOUNT self
|
||||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||||
@@ -141,7 +140,7 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Core.Fsm.Account#ACT_ACCOUNT}
|
--- # @{#ACT_ACCOUNT_DEADS} FSM class, extends @{Core.Fsm.Account#ACT_ACCOUNT}
|
||||||
--
|
--
|
||||||
-- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units.
|
-- The ACT_ACCOUNT_DEADS class accounts (detects, counts and reports) successful kills of DCS units.
|
||||||
-- The process is given a @{Set} of units that will be tracked upon successful destruction.
|
-- The process is given a @{Core.Set} of units that will be tracked upon successful destruction.
|
||||||
-- The process will end after each target has been successfully destroyed.
|
-- The process will end after each target has been successfully destroyed.
|
||||||
-- Each successful dead will trigger an Account state transition that can be scored, modified or administered.
|
-- Each successful dead will trigger an Account state transition that can be scored, modified or administered.
|
||||||
--
|
--
|
||||||
@@ -157,7 +156,6 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
ClassName = "ACT_ACCOUNT_DEADS",
|
ClassName = "ACT_ACCOUNT_DEADS",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new DESTROY process.
|
--- Creates a new DESTROY process.
|
||||||
-- @param #ACT_ACCOUNT_DEADS self
|
-- @param #ACT_ACCOUNT_DEADS self
|
||||||
-- @param Core.Set#SET_UNIT TargetSetUnit
|
-- @param Core.Set#SET_UNIT TargetSetUnit
|
||||||
@@ -195,7 +193,6 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- StateMachine callback function
|
--- StateMachine callback function
|
||||||
-- @param #ACT_ACCOUNT_DEADS self
|
-- @param #ACT_ACCOUNT_DEADS self
|
||||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||||
@@ -270,7 +267,6 @@ do -- ACT_ACCOUNT_DEADS
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- DCS Events
|
--- DCS Events
|
||||||
|
|
||||||
--- @param #ACT_ACCOUNT_DEADS self
|
--- @param #ACT_ACCOUNT_DEADS self
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Actions.Assign
|
-- @module Actions.Act_Assign
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
--
|
--
|
||||||
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Core.Fsm.Route#ACT_ASSIST}
|
-- # 1) @{#ACT_ASSIST_SMOKE_TARGETS_ZONE} class, extends @{Core.Fsm.Route#ACT_ASSIST}
|
||||||
--
|
--
|
||||||
-- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Zone}.
|
-- The ACT_ASSIST_SMOKE_TARGETS_ZONE class implements the core functions to smoke targets in a @{Core.Zone}.
|
||||||
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
|
-- The targets are smoked within a certain range around each target, simulating a realistic smoking behaviour.
|
||||||
-- At random intervals, a new target is smoked.
|
-- At random intervals, a new target is smoked.
|
||||||
--
|
--
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Actions.Assist
|
-- @module Actions.Act_Assist
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
--
|
--
|
||||||
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE}
|
-- # 1) @{#ACT_ROUTE_ZONE} class, extends @{Core.Fsm.Route#ACT_ROUTE}
|
||||||
--
|
--
|
||||||
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Zone}.
|
-- The ACT_ROUTE_ZONE class implements the core functions to route an AIR @{Wrapper.Controllable} player @{Wrapper.Unit} to a @{Core.Zone}.
|
||||||
-- The player receives on perioding times messages with the coordinates of the route to follow.
|
-- The player receives on perioding times messages with the coordinates of the route to follow.
|
||||||
-- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended.
|
-- Upon arrival at the zone, a confirmation of arrival is sent, and the process will be ended.
|
||||||
--
|
--
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Actions.Route
|
-- @module Actions.Act_Route
|
||||||
-- @image MOOSE.JPG
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
-- you can board the cargo into the carrier `CargoCarrier`.
|
-- you can board the cargo into the carrier `CargoCarrier`.
|
||||||
-- Simple, isn't it? Told you, and this is only the beginning.
|
-- Simple, isn't it? Told you, and this is only the beginning.
|
||||||
--
|
--
|
||||||
-- The boarding, unboarding, loading, unloading of cargo is however something that is not meant to be coded manualy by mission designers.
|
-- The boarding, unboarding, loading, unloading of cargo is however something that is not meant to be coded manually by mission designers.
|
||||||
-- It would be too low-level and not end-user friendly to deal with cargo handling complexity.
|
-- It would be too low-level and not end-user friendly to deal with cargo handling complexity.
|
||||||
-- Things can become really complex if you want to make cargo being handled and behave in multiple scenarios.
|
-- Things can become really complex if you want to make cargo being handled and behave in multiple scenarios.
|
||||||
--
|
--
|
||||||
@@ -77,8 +77,8 @@
|
|||||||
--
|
--
|
||||||
-- ## 3.1) AI Cargo handlers.
|
-- ## 3.1) AI Cargo handlers.
|
||||||
--
|
--
|
||||||
-- - @{AI.AI_Cargo_APC} will create for you the capatility to make an APC group handle cargo.
|
-- - @{AI.AI_Cargo_APC} will create for you the capability to make an APC group handle cargo.
|
||||||
-- - @{AI.AI_Cargo_Helicopter} will create for you the capatility to make a Helicopter group handle cargo.
|
-- - @{AI.AI_Cargo_Helicopter} will create for you the capability to make a Helicopter group handle cargo.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## 3.2) AI Cargo transportation dispatchers.
|
-- ## 3.2) AI Cargo transportation dispatchers.
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
-- There are also dispatchers that make AI work together to transport cargo automatically!!!
|
-- There are also dispatchers that make AI work together to transport cargo automatically!!!
|
||||||
--
|
--
|
||||||
-- - @{AI.AI_Cargo_Dispatcher_APC} derived classes will create for your dynamic cargo handlers controlled by AI ground vehicle groups (APCs) to transport cargo between sites.
|
-- - @{AI.AI_Cargo_Dispatcher_APC} derived classes will create for your dynamic cargo handlers controlled by AI ground vehicle groups (APCs) to transport cargo between sites.
|
||||||
-- - @{AI.AI_Cargo_Dispatcher_Helicopters} derived classes will create for your dynamic cargo handlers controlled by AI helicpter groups to transport cargo between sites.
|
-- - @{AI.AI_Cargo_Dispatcher_Helicopters} derived classes will create for your dynamic cargo handlers controlled by AI helicopter groups to transport cargo between sites.
|
||||||
--
|
--
|
||||||
-- ## 3.3) Cargo transportation tasking.
|
-- ## 3.3) Cargo transportation tasking.
|
||||||
--
|
--
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
--
|
--
|
||||||
-- - @{Tasking.Task_CARGO} derived classes will create for you cargo transportation tasks, that allow human players to interact with MOOSE cargo objects to complete tasks.
|
-- - @{Tasking.Task_CARGO} derived classes will create for you cargo transportation tasks, that allow human players to interact with MOOSE cargo objects to complete tasks.
|
||||||
--
|
--
|
||||||
-- Please refer to the documentation reflected within these modules to understand the detailed capabilties.
|
-- Please refer to the documentation reflected within these modules to understand the detailed capabilities.
|
||||||
--
|
--
|
||||||
-- # 4) Cargo SETs.
|
-- # 4) Cargo SETs.
|
||||||
--
|
--
|
||||||
@@ -206,27 +206,29 @@
|
|||||||
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
||||||
-- Note that this option is optional, so can be omitted. The default value of the RR is 10 meters.
|
-- Note that this option is optional, so can be omitted. The default value of the RR is 10 meters.
|
||||||
--
|
--
|
||||||
-- ## 5.2) The \#CARGO tag to create CARGO_CRATE objects:
|
-- ## 5.2) The \#CARGO tag to create CARGO_CRATE or CARGO_SLINGLOAD objects:
|
||||||
--
|
--
|
||||||
-- You can also use the \#CARGO tag on **static** objects, including **static cargo** objects of the mission editor.
|
-- You can also use the \#CARGO tag on **static** objects, including **static cargo** objects of the mission editor.
|
||||||
--
|
--
|
||||||
-- For example, the following #CARGO naming in the **static name** of the object, will create a CARGO_CRATE object when the mission starts.
|
-- For example, the following #CARGO naming in the **static name** of the object, will create a CARGO_CRATE object when the mission starts.
|
||||||
--
|
--
|
||||||
-- `Static #CARGO(T=Workmaterials,RR=500,NR=25)`
|
-- `Static #CARGO(T=Workmaterials,C=CRATE,RR=500,NR=25)`
|
||||||
--
|
--
|
||||||
-- This will create a CARGO_CRATE object:
|
-- This will create a CARGO_CRATE object:
|
||||||
--
|
--
|
||||||
-- * with the group name `Static #CARGO`
|
-- * with the group name `Static #CARGO`
|
||||||
-- * is of type `Workmaterials`
|
-- * is of type `Workmaterials`
|
||||||
|
-- * is of category `CRATE` (as opposed to `SLING`)
|
||||||
-- * will report when a carrier is within 500 meters
|
-- * will report when a carrier is within 500 meters
|
||||||
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
||||||
-- * will disappear when the cargo is within 25 meters from the carrier during boarding
|
-- * will disappear when the cargo is within 25 meters from the carrier during boarding
|
||||||
--
|
--
|
||||||
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
||||||
--
|
--
|
||||||
-- `StaticName #CARGO(T=CargoTypeName,RR=Range,NR=Range)`
|
-- `StaticName #CARGO(T=CargoTypeName,C=Category,RR=Range,NR=Range)`
|
||||||
--
|
--
|
||||||
-- * **T=** Provide a text that contains the type name of the cargo object. This type name can be used to filter cargo within a SET_CARGO object.
|
-- * **T=** Provide a text that contains the type name of the cargo object. This type name can be used to filter cargo within a SET_CARGO object.
|
||||||
|
-- * **C=** Provide either `CRATE` or `SLING` to have this static created as a CARGO_CRATE or CARGO_SLINGLOAD respectively.
|
||||||
-- * **RR=** Provide the minimal range in meters when the report to the carrier, and board to the carrier.
|
-- * **RR=** Provide the minimal range in meters when the report to the carrier, and board to the carrier.
|
||||||
-- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters.
|
-- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters.
|
||||||
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
||||||
@@ -375,7 +377,7 @@ do -- CARGO
|
|||||||
-- @field #boolean Moveable This flag defines if the cargo is moveable.
|
-- @field #boolean Moveable This flag defines if the cargo is moveable.
|
||||||
-- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit.
|
-- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit.
|
||||||
-- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit.
|
-- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit.
|
||||||
|
|
||||||
--- Defines the core functions that defines a cargo object within MOOSE.
|
--- Defines the core functions that defines a cargo object within MOOSE.
|
||||||
--
|
--
|
||||||
-- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation.
|
-- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation.
|
||||||
@@ -428,8 +430,7 @@ do -- CARGO
|
|||||||
|
|
||||||
--- @type CARGO.CargoObjects
|
--- @type CARGO.CargoObjects
|
||||||
-- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo.
|
-- @map < #string, Wrapper.Positionable#POSITIONABLE > The alive POSITIONABLE objects representing the the cargo.
|
||||||
|
|
||||||
|
|
||||||
--- CARGO Constructor. This class is an abstract class and should not be instantiated.
|
--- CARGO Constructor. This class is an abstract class and should not be instantiated.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #string Type
|
-- @param #string Type
|
||||||
@@ -439,10 +440,10 @@ do -- CARGO
|
|||||||
-- @param #number NearRadius (optional)
|
-- @param #number NearRadius (optional)
|
||||||
-- @return #CARGO
|
-- @return #CARGO
|
||||||
function CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) --R2.1
|
function CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) --R2.1
|
||||||
|
|
||||||
local self = BASE:Inherit( self, FSM:New() ) -- #CARGO
|
local self = BASE:Inherit( self, FSM:New() ) -- #CARGO
|
||||||
self:F( { Type, Name, Weight, LoadRadius, NearRadius } )
|
self:F( { Type, Name, Weight, LoadRadius, NearRadius } )
|
||||||
|
|
||||||
self:SetStartState( "UnLoaded" )
|
self:SetStartState( "UnLoaded" )
|
||||||
self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" )
|
self:AddTransition( { "UnLoaded", "Boarding" }, "Board", "Boarding" )
|
||||||
self:AddTransition( "Boarding" , "Boarding", "Boarding" )
|
self:AddTransition( "Boarding" , "Boarding", "Boarding" )
|
||||||
@@ -457,7 +458,7 @@ do -- CARGO
|
|||||||
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||||
self:AddTransition( "*", "Respawn", "UnLoaded" )
|
self:AddTransition( "*", "Respawn", "UnLoaded" )
|
||||||
self:AddTransition( "*", "Reset", "UnLoaded" )
|
self:AddTransition( "*", "Reset", "UnLoaded" )
|
||||||
|
|
||||||
self.Type = Type
|
self.Type = Type
|
||||||
self.Name = Name
|
self.Name = Name
|
||||||
self.Weight = Weight or 0
|
self.Weight = Weight or 0
|
||||||
@@ -469,31 +470,29 @@ do -- CARGO
|
|||||||
self.Containable = false
|
self.Containable = false
|
||||||
|
|
||||||
self.CargoLimit = 0
|
self.CargoLimit = 0
|
||||||
|
|
||||||
self.LoadRadius = LoadRadius or 500
|
self.LoadRadius = LoadRadius or 500
|
||||||
--self.NearRadius = NearRadius or 25
|
--self.NearRadius = NearRadius or 25
|
||||||
|
|
||||||
self:SetDeployed( false )
|
self:SetDeployed( false )
|
||||||
|
|
||||||
self.CargoScheduler = SCHEDULER:New()
|
self.CargoScheduler = SCHEDULER:New()
|
||||||
|
|
||||||
CARGOS[self.Name] = self
|
CARGOS[self.Name] = self
|
||||||
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Find a CARGO in the _DATABASE.
|
--- Find a CARGO in the _DATABASE.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #string CargoName The Cargo Name.
|
-- @param #string CargoName The Cargo Name.
|
||||||
-- @return #CARGO self
|
-- @return #CARGO self
|
||||||
function CARGO:FindByName( CargoName )
|
function CARGO:FindByName( CargoName )
|
||||||
|
|
||||||
local CargoFound = _DATABASE:FindCargo( CargoName )
|
local CargoFound = _DATABASE:FindCargo( CargoName )
|
||||||
return CargoFound
|
return CargoFound
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the x position of the cargo.
|
--- Get the x position of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #number
|
-- @return #number
|
||||||
@@ -502,9 +501,9 @@ do -- CARGO
|
|||||||
return self.CargoCarrier:GetCoordinate().x
|
return self.CargoCarrier:GetCoordinate().x
|
||||||
else
|
else
|
||||||
return self.CargoObject:GetCoordinate().x
|
return self.CargoObject:GetCoordinate().x
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the y position of the cargo.
|
--- Get the y position of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #number
|
-- @return #number
|
||||||
@@ -513,9 +512,9 @@ do -- CARGO
|
|||||||
return self.CargoCarrier:GetCoordinate().z
|
return self.CargoCarrier:GetCoordinate().z
|
||||||
else
|
else
|
||||||
return self.CargoObject:GetCoordinate().z
|
return self.CargoObject:GetCoordinate().z
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the heading of the cargo.
|
--- Get the heading of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #number
|
-- @return #number
|
||||||
@@ -524,22 +523,21 @@ do -- CARGO
|
|||||||
return self.CargoCarrier:GetHeading()
|
return self.CargoCarrier:GetHeading()
|
||||||
else
|
else
|
||||||
return self.CargoObject:GetHeading()
|
return self.CargoObject:GetHeading()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check if the cargo can be Slingloaded.
|
--- Check if the cargo can be Slingloaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:CanSlingload()
|
function CARGO:CanSlingload()
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if the cargo can be Boarded.
|
--- Check if the cargo can be Boarded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:CanBoard()
|
function CARGO:CanBoard()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if the cargo can be Unboarded.
|
--- Check if the cargo can be Unboarded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:CanUnboard()
|
function CARGO:CanUnboard()
|
||||||
@@ -551,14 +549,13 @@ do -- CARGO
|
|||||||
function CARGO:CanLoad()
|
function CARGO:CanLoad()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if the cargo can be Unloaded.
|
--- Check if the cargo can be Unloaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:CanUnload()
|
function CARGO:CanUnload()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Destroy the cargo.
|
--- Destroy the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:Destroy()
|
function CARGO:Destroy()
|
||||||
@@ -567,14 +564,14 @@ do -- CARGO
|
|||||||
end
|
end
|
||||||
self:Destroyed()
|
self:Destroyed()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the name of the Cargo.
|
--- Get the name of the Cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #string The name of the Cargo.
|
-- @return #string The name of the Cargo.
|
||||||
function CARGO:GetName() --R2.1
|
function CARGO:GetName() --R2.1
|
||||||
return self.Name
|
return self.Name
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the current active object representing or being the Cargo.
|
--- Get the current active object representing or being the Cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return Wrapper.Positionable#POSITIONABLE The object representing or being the Cargo.
|
-- @return Wrapper.Positionable#POSITIONABLE The object representing or being the Cargo.
|
||||||
@@ -583,9 +580,9 @@ do -- CARGO
|
|||||||
return self.CargoCarrier
|
return self.CargoCarrier
|
||||||
else
|
else
|
||||||
return self.CargoObject
|
return self.CargoObject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the object name of the Cargo.
|
--- Get the object name of the Cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #string The object name of the Cargo.
|
-- @return #string The object name of the Cargo.
|
||||||
@@ -594,9 +591,9 @@ do -- CARGO
|
|||||||
return self.CargoCarrier:GetName()
|
return self.CargoCarrier:GetName()
|
||||||
else
|
else
|
||||||
return self.CargoObject:GetName()
|
return self.CargoObject:GetName()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the amount of Cargo.
|
--- Get the amount of Cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #number The amount of Cargo.
|
-- @return #number The amount of Cargo.
|
||||||
@@ -611,7 +608,6 @@ do -- CARGO
|
|||||||
return self.Type
|
return self.Type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the transportation method of the Cargo.
|
--- Get the transportation method of the Cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #string The transportation method of the Cargo.
|
-- @return #string The transportation method of the Cargo.
|
||||||
@@ -619,7 +615,6 @@ do -- CARGO
|
|||||||
return self.TransportationMethod
|
return self.TransportationMethod
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the coalition of the Cargo.
|
--- Get the coalition of the Cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return Coalition
|
-- @return Coalition
|
||||||
@@ -628,32 +623,30 @@ do -- CARGO
|
|||||||
return self.CargoCarrier:GetCoalition()
|
return self.CargoCarrier:GetCoalition()
|
||||||
else
|
else
|
||||||
return self.CargoObject:GetCoalition()
|
return self.CargoObject:GetCoalition()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the current coordinates of the Cargo.
|
--- Get the current coordinates of the Cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return Core.Point#COORDINATE The coordinates of the Cargo.
|
-- @return Core.Point#COORDINATE The coordinates of the Cargo.
|
||||||
function CARGO:GetCoordinate()
|
function CARGO:GetCoordinate()
|
||||||
return self.CargoObject:GetCoordinate()
|
return self.CargoObject:GetCoordinate()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if cargo is destroyed.
|
--- Check if cargo is destroyed.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #boolean true if destroyed
|
-- @return #boolean true if destroyed
|
||||||
function CARGO:IsDestroyed()
|
function CARGO:IsDestroyed()
|
||||||
return self:Is( "Destroyed" )
|
return self:Is( "Destroyed" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check if cargo is loaded.
|
--- Check if cargo is loaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #boolean true if loaded
|
-- @return #boolean true if loaded
|
||||||
function CARGO:IsLoaded()
|
function CARGO:IsLoaded()
|
||||||
return self:Is( "Loaded" )
|
return self:Is( "Loaded" )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if cargo is loaded.
|
--- Check if cargo is loaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Wrapper.Unit#UNIT Carrier
|
-- @param Wrapper.Unit#UNIT Carrier
|
||||||
@@ -661,14 +654,14 @@ do -- CARGO
|
|||||||
function CARGO:IsLoadedInCarrier( Carrier )
|
function CARGO:IsLoadedInCarrier( Carrier )
|
||||||
return self.CargoCarrier and self.CargoCarrier:GetName() == Carrier:GetName()
|
return self.CargoCarrier and self.CargoCarrier:GetName() == Carrier:GetName()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if cargo is unloaded.
|
--- Check if cargo is unloaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #boolean true if unloaded
|
-- @return #boolean true if unloaded
|
||||||
function CARGO:IsUnLoaded()
|
function CARGO:IsUnLoaded()
|
||||||
return self:Is( "UnLoaded" )
|
return self:Is( "UnLoaded" )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if cargo is boarding.
|
--- Check if cargo is boarding.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #boolean true if boarding
|
-- @return #boolean true if boarding
|
||||||
@@ -676,52 +669,47 @@ do -- CARGO
|
|||||||
return self:Is( "Boarding" )
|
return self:Is( "Boarding" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check if cargo is unboarding.
|
--- Check if cargo is unboarding.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #boolean true if unboarding
|
-- @return #boolean true if unboarding
|
||||||
function CARGO:IsUnboarding()
|
function CARGO:IsUnboarding()
|
||||||
return self:Is( "UnBoarding" )
|
return self:Is( "UnBoarding" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check if cargo is alive.
|
--- Check if cargo is alive.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #boolean true if unloaded
|
-- @return #boolean true if unloaded
|
||||||
function CARGO:IsAlive()
|
function CARGO:IsAlive()
|
||||||
|
|
||||||
if self:IsLoaded() then
|
if self:IsLoaded() then
|
||||||
return self.CargoCarrier:IsAlive()
|
return self.CargoCarrier:IsAlive()
|
||||||
else
|
else
|
||||||
return self.CargoObject:IsAlive()
|
return self.CargoObject:IsAlive()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the cargo as deployed.
|
--- Set the cargo as deployed.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #boolean Deployed true if the cargo is to be deployed. false or nil otherwise.
|
-- @param #boolean Deployed true if the cargo is to be deployed. false or nil otherwise.
|
||||||
function CARGO:SetDeployed( Deployed )
|
function CARGO:SetDeployed( Deployed )
|
||||||
self.Deployed = Deployed
|
self.Deployed = Deployed
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Is the cargo deployed
|
--- Is the cargo deployed
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
function CARGO:IsDeployed()
|
function CARGO:IsDeployed()
|
||||||
return self.Deployed
|
return self.Deployed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Template method to spawn a new representation of the CARGO in the simulator.
|
--- Template method to spawn a new representation of the CARGO in the simulator.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #CARGO
|
-- @return #CARGO
|
||||||
function CARGO:Spawn( PointVec2 )
|
function CARGO:Spawn( PointVec2 )
|
||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Signal a flare at the position of the CARGO.
|
--- Signal a flare at the position of the CARGO.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Utilities.Utils#FLARECOLOR FlareColor
|
-- @param Utilities.Utils#FLARECOLOR FlareColor
|
||||||
@@ -730,31 +718,31 @@ do -- CARGO
|
|||||||
trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 )
|
trigger.action.signalFlare( self.CargoObject:GetVec3(), FlareColor , 0 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Signal a white flare at the position of the CARGO.
|
--- Signal a white flare at the position of the CARGO.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:FlareWhite()
|
function CARGO:FlareWhite()
|
||||||
self:Flare( trigger.flareColor.White )
|
self:Flare( trigger.flareColor.White )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Signal a yellow flare at the position of the CARGO.
|
--- Signal a yellow flare at the position of the CARGO.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:FlareYellow()
|
function CARGO:FlareYellow()
|
||||||
self:Flare( trigger.flareColor.Yellow )
|
self:Flare( trigger.flareColor.Yellow )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Signal a green flare at the position of the CARGO.
|
--- Signal a green flare at the position of the CARGO.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:FlareGreen()
|
function CARGO:FlareGreen()
|
||||||
self:Flare( trigger.flareColor.Green )
|
self:Flare( trigger.flareColor.Green )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Signal a red flare at the position of the CARGO.
|
--- Signal a red flare at the position of the CARGO.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:FlareRed()
|
function CARGO:FlareRed()
|
||||||
self:Flare( trigger.flareColor.Red )
|
self:Flare( trigger.flareColor.Red )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the CARGO.
|
--- Smoke the CARGO.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke.
|
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The color of the smoke.
|
||||||
@@ -768,38 +756,37 @@ do -- CARGO
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the CARGO Green.
|
--- Smoke the CARGO Green.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:SmokeGreen()
|
function CARGO:SmokeGreen()
|
||||||
self:Smoke( trigger.smokeColor.Green, Range )
|
self:Smoke( trigger.smokeColor.Green, Range )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the CARGO Red.
|
--- Smoke the CARGO Red.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:SmokeRed()
|
function CARGO:SmokeRed()
|
||||||
self:Smoke( trigger.smokeColor.Red, Range )
|
self:Smoke( trigger.smokeColor.Red, Range )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the CARGO White.
|
--- Smoke the CARGO White.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:SmokeWhite()
|
function CARGO:SmokeWhite()
|
||||||
self:Smoke( trigger.smokeColor.White, Range )
|
self:Smoke( trigger.smokeColor.White, Range )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the CARGO Orange.
|
--- Smoke the CARGO Orange.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:SmokeOrange()
|
function CARGO:SmokeOrange()
|
||||||
self:Smoke( trigger.smokeColor.Orange, Range )
|
self:Smoke( trigger.smokeColor.Orange, Range )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Smoke the CARGO Blue.
|
--- Smoke the CARGO Blue.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
function CARGO:SmokeBlue()
|
function CARGO:SmokeBlue()
|
||||||
self:Smoke( trigger.smokeColor.Blue, Range )
|
self:Smoke( trigger.smokeColor.Blue, Range )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the Load radius, which is the radius till when the Cargo can be loaded.
|
--- Set the Load radius, which is the radius till when the Cargo can be loaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #number LoadRadius The radius till Cargo can be loaded.
|
-- @param #number LoadRadius The radius till Cargo can be loaded.
|
||||||
@@ -807,23 +794,21 @@ do -- CARGO
|
|||||||
function CARGO:SetLoadRadius( LoadRadius )
|
function CARGO:SetLoadRadius( LoadRadius )
|
||||||
self.LoadRadius = LoadRadius or 150
|
self.LoadRadius = LoadRadius or 150
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the Load radius, which is the radius till when the Cargo can be loaded.
|
--- Get the Load radius, which is the radius till when the Cargo can be loaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #number The radius till Cargo can be loaded.
|
-- @return #number The radius till Cargo can be loaded.
|
||||||
function CARGO:GetLoadRadius()
|
function CARGO:GetLoadRadius()
|
||||||
return self.LoadRadius
|
return self.LoadRadius
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded.
|
--- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Core.Point#COORDINATE Coordinate
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
-- @return #boolean true if the CargoGroup is within the loading radius.
|
-- @return #boolean true if the CargoGroup is within the loading radius.
|
||||||
function CARGO:IsInLoadRadius( Coordinate )
|
function CARGO:IsInLoadRadius( Coordinate )
|
||||||
self:F( { Coordinate, LoadRadius = self.LoadRadius } )
|
self:F( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||||
|
|
||||||
local Distance = 0
|
local Distance = 0
|
||||||
if self:IsUnLoaded() then
|
if self:IsUnLoaded() then
|
||||||
local CargoCoordinate = self.CargoObject:GetCoordinate()
|
local CargoCoordinate = self.CargoObject:GetCoordinate()
|
||||||
@@ -833,18 +818,17 @@ do -- CARGO
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check if the Cargo can report itself to be Boarded or Loaded.
|
--- Check if the Cargo can report itself to be Boarded or Loaded.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Core.Point#COORDINATE Coordinate
|
-- @param Core.Point#COORDINATE Coordinate
|
||||||
-- @return #boolean true if the Cargo can report itself.
|
-- @return #boolean true if the Cargo can report itself.
|
||||||
function CARGO:IsInReportRadius( Coordinate )
|
function CARGO:IsInReportRadius( Coordinate )
|
||||||
self:F( { Coordinate } )
|
self:F( { Coordinate } )
|
||||||
|
|
||||||
local Distance = 0
|
local Distance = 0
|
||||||
if self:IsUnLoaded() then
|
if self:IsUnLoaded() then
|
||||||
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||||
@@ -853,7 +837,7 @@ do -- CARGO
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -865,7 +849,7 @@ do -- CARGO
|
|||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
function CARGO:IsNear( Coordinate, NearRadius )
|
function CARGO:IsNear( Coordinate, NearRadius )
|
||||||
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } )
|
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } )
|
||||||
|
|
||||||
if self.CargoObject:IsAlive() then
|
if self.CargoObject:IsAlive() then
|
||||||
--local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() )
|
--local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() )
|
||||||
--self:F( { CargoObjectName = self.CargoObject:GetName() } )
|
--self:F( { CargoObjectName = self.CargoObject:GetName() } )
|
||||||
@@ -873,26 +857,24 @@ do -- CARGO
|
|||||||
--self:F( { PointVec2 = PointVec2:GetVec2() } )
|
--self:F( { PointVec2 = PointVec2:GetVec2() } )
|
||||||
local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||||
--self:F( { Distance = Distance, NearRadius = NearRadius or "nil" } )
|
--self:F( { Distance = Distance, NearRadius = NearRadius or "nil" } )
|
||||||
|
|
||||||
if Distance <= NearRadius then
|
if Distance <= NearRadius then
|
||||||
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } )
|
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = true } )
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } )
|
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius, IsNear = false } )
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if Cargo is the given @{Core.Zone}.
|
||||||
|
|
||||||
--- Check if Cargo is the given @{Zone}.
|
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Core.Zone#ZONE_BASE Zone
|
-- @param Core.Zone#ZONE_BASE Zone
|
||||||
-- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone.
|
-- @return #boolean **true** if cargo is in the Zone, **false** if cargo is not in the Zone.
|
||||||
function CARGO:IsInZone( Zone )
|
function CARGO:IsInZone( Zone )
|
||||||
--self:F( { Zone } )
|
--self:F( { Zone } )
|
||||||
|
|
||||||
if self:IsLoaded() then
|
if self:IsLoaded() then
|
||||||
return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() )
|
return Zone:IsPointVec2InZone( self.CargoCarrier:GetPointVec2() )
|
||||||
else
|
else
|
||||||
@@ -902,34 +884,33 @@ do -- CARGO
|
|||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the current PointVec2 of the cargo.
|
--- Get the current PointVec2 of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return Core.Point#POINT_VEC2
|
-- @return Core.Point#POINT_VEC2
|
||||||
function CARGO:GetPointVec2()
|
function CARGO:GetPointVec2()
|
||||||
return self.CargoObject:GetPointVec2()
|
return self.CargoObject:GetPointVec2()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the current Coordinate of the cargo.
|
--- Get the current Coordinate of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return Core.Point#COORDINATE
|
-- @return Core.Point#COORDINATE
|
||||||
function CARGO:GetCoordinate()
|
function CARGO:GetCoordinate()
|
||||||
return self.CargoObject:GetCoordinate()
|
return self.CargoObject:GetCoordinate()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the weight of the cargo.
|
--- Get the weight of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #number Weight The weight in kg.
|
-- @return #number Weight The weight in kg.
|
||||||
function CARGO:GetWeight()
|
function CARGO:GetWeight()
|
||||||
return self.Weight
|
return self.Weight
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the weight of the cargo.
|
--- Set the weight of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #number Weight The weight in kg.
|
-- @param #number Weight The weight in kg.
|
||||||
@@ -938,14 +919,14 @@ do -- CARGO
|
|||||||
self.Weight = Weight
|
self.Weight = Weight
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the volume of the cargo.
|
--- Get the volume of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @return #number Volume The volume in kg.
|
-- @return #number Volume The volume in kg.
|
||||||
function CARGO:GetVolume()
|
function CARGO:GetVolume()
|
||||||
return self.Volume
|
return self.Volume
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the volume of the cargo.
|
--- Set the volume of the cargo.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #number Volume The volume in kg.
|
-- @param #number Volume The volume in kg.
|
||||||
@@ -954,18 +935,18 @@ do -- CARGO
|
|||||||
self.Volume = Volume
|
self.Volume = Volume
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Send a CC message to a @{Wrapper.Group}.
|
--- Send a CC message to a @{Wrapper.Group}.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #string Message
|
-- @param #string Message
|
||||||
-- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group.
|
-- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group.
|
||||||
-- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
|
-- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
|
||||||
function CARGO:MessageToGroup( Message, CarrierGroup, Name )
|
function CARGO:MessageToGroup( Message, CarrierGroup, Name )
|
||||||
|
|
||||||
MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( CarrierGroup )
|
MESSAGE:New( Message, 20, "Cargo " .. self:GetName() ):ToGroup( CarrierGroup )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Report to a Carrier Group.
|
--- Report to a Carrier Group.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #string Action The string describing the action for the cargo.
|
-- @param #string Action The string describing the action for the cargo.
|
||||||
@@ -991,8 +972,7 @@ do -- CARGO
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Report to a Carrier Group with a Flaring signal.
|
--- Report to a Carrier Group with a Flaring signal.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Utils#UTILS.FlareColor FlareColor the color of the flare.
|
-- @param Utils#UTILS.FlareColor FlareColor the color of the flare.
|
||||||
@@ -1001,8 +981,7 @@ do -- CARGO
|
|||||||
|
|
||||||
self.ReportFlareColor = FlareColor
|
self.ReportFlareColor = FlareColor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Report to a Carrier Group with a Smoking signal.
|
--- Report to a Carrier Group with a Smoking signal.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Utils#UTILS.SmokeColor SmokeColor the color of the smoke.
|
-- @param Utils#UTILS.SmokeColor SmokeColor the color of the smoke.
|
||||||
@@ -1011,8 +990,7 @@ do -- CARGO
|
|||||||
|
|
||||||
self.ReportSmokeColor = SmokeColor
|
self.ReportSmokeColor = SmokeColor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Reset the reporting for a Carrier Group.
|
--- Reset the reporting for a Carrier Group.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #string Action The string describing the action for the cargo.
|
-- @param #string Action The string describing the action for the cargo.
|
||||||
@@ -1022,7 +1000,7 @@ do -- CARGO
|
|||||||
|
|
||||||
self.Reported[CarrierGroup][Action] = nil
|
self.Reported[CarrierGroup][Action] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Reset all the reporting for a Carrier Group.
|
--- Reset all the reporting for a Carrier Group.
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to.
|
-- @param Wrapper.Group#GROUP CarrierGroup The Carrier Group to send the report to.
|
||||||
@@ -1031,7 +1009,7 @@ do -- CARGO
|
|||||||
|
|
||||||
self.Reported[CarrierGroup] = nil
|
self.Reported[CarrierGroup] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Respawn the cargo when destroyed
|
--- Respawn the cargo when destroyed
|
||||||
-- @param #CARGO self
|
-- @param #CARGO self
|
||||||
-- @param #boolean RespawnDestroyed
|
-- @param #boolean RespawnDestroyed
|
||||||
@@ -1044,11 +1022,8 @@ do -- CARGO
|
|||||||
else
|
else
|
||||||
self.onenterDestroyed = nil
|
self.onenterDestroyed = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end -- CARGO
|
end -- CARGO
|
||||||
|
|
||||||
@@ -1073,7 +1048,7 @@ do -- CARGO_REPRESENTABLE
|
|||||||
-- @param #number NearRadius (optional) Radius in meters when the cargo is loaded into the carrier.
|
-- @param #number NearRadius (optional) Radius in meters when the cargo is loaded into the carrier.
|
||||||
-- @return #CARGO_REPRESENTABLE
|
-- @return #CARGO_REPRESENTABLE
|
||||||
function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius )
|
function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius )
|
||||||
|
|
||||||
-- Inherit CARGO.
|
-- Inherit CARGO.
|
||||||
local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
|
local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
|
||||||
self:F( { Type, Name, LoadRadius, NearRadius } )
|
self:F( { Type, Name, LoadRadius, NearRadius } )
|
||||||
@@ -1081,10 +1056,10 @@ do -- CARGO_REPRESENTABLE
|
|||||||
-- Descriptors.
|
-- Descriptors.
|
||||||
local Desc=CargoObject:GetDesc()
|
local Desc=CargoObject:GetDesc()
|
||||||
self:T({Desc=Desc})
|
self:T({Desc=Desc})
|
||||||
|
|
||||||
-- Weight.
|
-- Weight.
|
||||||
local Weight = math.random( 80, 120 )
|
local Weight = math.random( 80, 120 )
|
||||||
|
|
||||||
-- Adjust weight..
|
-- Adjust weight..
|
||||||
if Desc then
|
if Desc then
|
||||||
if Desc.typeName == "2B11 mortar" then
|
if Desc.typeName == "2B11 mortar" then
|
||||||
@@ -1095,8 +1070,8 @@ do -- CARGO_REPRESENTABLE
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Set weight.
|
-- Set weight.
|
||||||
self:SetWeight( Weight )
|
self:SetWeight( Weight )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1104,14 +1079,14 @@ do -- CARGO_REPRESENTABLE
|
|||||||
-- @param #CARGO_REPRESENTABLE self
|
-- @param #CARGO_REPRESENTABLE self
|
||||||
-- @return #CARGO_REPRESENTABLE
|
-- @return #CARGO_REPRESENTABLE
|
||||||
function CARGO_REPRESENTABLE:Destroy()
|
function CARGO_REPRESENTABLE:Destroy()
|
||||||
|
|
||||||
-- Cargo objects are deleted from the _DATABASE and SET_CARGO objects.
|
-- Cargo objects are deleted from the _DATABASE and SET_CARGO objects.
|
||||||
self:F( { CargoName = self:GetName() } )
|
self:F( { CargoName = self:GetName() } )
|
||||||
--_EVENTDISPATCHER:CreateEventDeleteCargo( self )
|
--_EVENTDISPATCHER:CreateEventDeleteCargo( self )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Route a cargo unit to a PointVec2.
|
--- Route a cargo unit to a PointVec2.
|
||||||
-- @param #CARGO_REPRESENTABLE self
|
-- @param #CARGO_REPRESENTABLE self
|
||||||
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
-- @param Core.Point#POINT_VEC2 ToPointVec2
|
||||||
@@ -1119,19 +1094,19 @@ do -- CARGO_REPRESENTABLE
|
|||||||
-- @return #CARGO_REPRESENTABLE
|
-- @return #CARGO_REPRESENTABLE
|
||||||
function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
|
function CARGO_REPRESENTABLE:RouteTo( ToPointVec2, Speed )
|
||||||
self:F2( ToPointVec2 )
|
self:F2( ToPointVec2 )
|
||||||
|
|
||||||
local Points = {}
|
local Points = {}
|
||||||
|
|
||||||
local PointStartVec2 = self.CargoObject:GetPointVec2()
|
local PointStartVec2 = self.CargoObject:GetPointVec2()
|
||||||
|
|
||||||
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
|
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
|
||||||
Points[#Points+1] = ToPointVec2:WaypointGround( Speed )
|
Points[#Points+1] = ToPointVec2:WaypointGround( Speed )
|
||||||
|
|
||||||
local TaskRoute = self.CargoObject:TaskRoute( Points )
|
local TaskRoute = self.CargoObject:TaskRoute( Points )
|
||||||
self.CargoObject:SetTask( TaskRoute, 2 )
|
self.CargoObject:SetTask( TaskRoute, 2 )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Send a message to a @{Wrapper.Group} through a communication channel near the cargo.
|
--- Send a message to a @{Wrapper.Group} through a communication channel near the cargo.
|
||||||
-- @param #CARGO_REPRESENTABLE self
|
-- @param #CARGO_REPRESENTABLE self
|
||||||
-- @param #string Message
|
-- @param #string Message
|
||||||
@@ -1155,20 +1130,19 @@ do -- CARGO_REPRESENTABLE
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end -- CARGO_REPRESENTABLE
|
end -- CARGO_REPRESENTABLE
|
||||||
|
|
||||||
do -- CARGO_REPORTABLE
|
do -- CARGO_REPORTABLE
|
||||||
|
|
||||||
--- @type CARGO_REPORTABLE
|
--- @type CARGO_REPORTABLE
|
||||||
-- @extends #CARGO
|
-- @extends #CARGO
|
||||||
CARGO_REPORTABLE = {
|
CARGO_REPORTABLE = {
|
||||||
ClassName = "CARGO_REPORTABLE"
|
ClassName = "CARGO_REPORTABLE"
|
||||||
}
|
}
|
||||||
|
|
||||||
--- CARGO_REPORTABLE Constructor.
|
--- CARGO_REPORTABLE Constructor.
|
||||||
-- @param #CARGO_REPORTABLE self
|
-- @param #CARGO_REPORTABLE self
|
||||||
-- @param #string Type
|
-- @param #string Type
|
||||||
@@ -1180,31 +1154,23 @@ do -- CARGO_REPORTABLE
|
|||||||
function CARGO_REPORTABLE:New( Type, Name, Weight, LoadRadius, NearRadius )
|
function CARGO_REPORTABLE:New( Type, Name, Weight, LoadRadius, NearRadius )
|
||||||
local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPORTABLE
|
local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPORTABLE
|
||||||
self:F( { Type, Name, Weight, LoadRadius, NearRadius } )
|
self:F( { Type, Name, Weight, LoadRadius, NearRadius } )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Send a CC message to a @{Wrapper.Group}.
|
--- Send a CC message to a @{Wrapper.Group}.
|
||||||
-- @param #CARGO_REPORTABLE self
|
-- @param #CARGO_REPORTABLE self
|
||||||
-- @param #string Message
|
-- @param #string Message
|
||||||
-- @param Wrapper.Group#GROUP TaskGroup
|
-- @param Wrapper.Group#GROUP TaskGroup
|
||||||
-- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
|
-- @param #string Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
|
||||||
function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name )
|
function CARGO_REPORTABLE:MessageToGroup( Message, TaskGroup, Name )
|
||||||
|
|
||||||
MESSAGE:New( Message, 20, "Cargo " .. self:GetName() .. " reporting" ):ToGroup( TaskGroup )
|
MESSAGE:New( Message, 20, "Cargo " .. self:GetName() .. " reporting" ):ToGroup( TaskGroup )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
do -- CARGO_PACKAGE
|
do -- CARGO_PACKAGE
|
||||||
|
|
||||||
--- @type CARGO_PACKAGE
|
--- @type CARGO_PACKAGE
|
||||||
@@ -1278,10 +1244,10 @@ function CARGO_PACKAGE:IsNear( CargoCarrier )
|
|||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
local CargoCarrierPoint = CargoCarrier:GetCoordinate()
|
local CargoCarrierPoint = CargoCarrier:GetCoordinate()
|
||||||
|
|
||||||
local Distance = CargoCarrierPoint:Get2DDistance( self.CargoCarrier:GetCoordinate() )
|
local Distance = CargoCarrierPoint:Get2DDistance( self.CargoCarrier:GetCoordinate() )
|
||||||
self:T( Distance )
|
self:T( Distance )
|
||||||
|
|
||||||
if Distance <= self.NearRadius then
|
if Distance <= self.NearRadius then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
@@ -1332,7 +1298,7 @@ function CARGO_PACKAGE:onafterUnBoard( From, Event, To, CargoCarrier, Speed, UnL
|
|||||||
if not self.CargoInAir then
|
if not self.CargoInAir then
|
||||||
|
|
||||||
self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle )
|
self:_Next( self.FsmP.UnLoad, UnLoadDistance, Angle )
|
||||||
|
|
||||||
local Points = {}
|
local Points = {}
|
||||||
|
|
||||||
local StartPointVec2 = CargoCarrier:GetPointVec2()
|
local StartPointVec2 = CargoCarrier:GetPointVec2()
|
||||||
@@ -1387,7 +1353,7 @@ function CARGO_PACKAGE:onafterLoad( From, Event, To, CargoCarrier, Speed, LoadDi
|
|||||||
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading )
|
local CargoDeployPointVec2 = StartPointVec2:Translate( LoadDistance, CargoDeployHeading )
|
||||||
|
|
||||||
local Points = {}
|
local Points = {}
|
||||||
Points[#Points+1] = StartPointVec2:WaypointGround( Speed )
|
Points[#Points+1] = StartPointVec2:WaypointGround( Speed )
|
||||||
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
|
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
|
||||||
@@ -1408,12 +1374,12 @@ end
|
|||||||
-- @param #number Angle
|
-- @param #number Angle
|
||||||
function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle )
|
function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle )
|
||||||
self:F()
|
self:F()
|
||||||
|
|
||||||
local StartPointVec2 = self.CargoCarrier:GetPointVec2()
|
local StartPointVec2 = self.CargoCarrier:GetPointVec2()
|
||||||
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
local CargoCarrierHeading = self.CargoCarrier:GetHeading() -- Get Heading of object in degrees.
|
||||||
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
|
||||||
local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading )
|
local CargoDeployPointVec2 = StartPointVec2:Translate( Distance, CargoDeployHeading )
|
||||||
|
|
||||||
self.CargoCarrier = CargoCarrier
|
self.CargoCarrier = CargoCarrier
|
||||||
|
|
||||||
local Points = {}
|
local Points = {}
|
||||||
@@ -1425,5 +1391,4 @@ function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Dist
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object.
|
--- **Cargo** - Management of single cargo crates, which are based on a STATIC object.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Cargo** - Management of grouped cargo logistics, which are based on a @{Wrapper.Group} object.
|
--- **Cargo** - Management of grouped cargo logistics, which are based on a GROUP object.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -47,7 +47,7 @@ do -- CARGO_GROUP
|
|||||||
|
|
||||||
--- CARGO_GROUP constructor.
|
--- CARGO_GROUP constructor.
|
||||||
-- This make a new CARGO_GROUP from a @{Wrapper.Group} object.
|
-- This make a new CARGO_GROUP from a @{Wrapper.Group} object.
|
||||||
-- It will "ungroup" the group object within the sim, and will create a @{Set} of individual Unit objects.
|
-- It will "ungroup" the group object within the sim, and will create a @{Core.Set} of individual Unit objects.
|
||||||
-- @param #CARGO_GROUP self
|
-- @param #CARGO_GROUP self
|
||||||
-- @param Wrapper.Group#GROUP CargoGroup Group to be transported as cargo.
|
-- @param Wrapper.Group#GROUP CargoGroup Group to be transported as cargo.
|
||||||
-- @param #string Type Cargo type, e.g. "Infantry". This is the type used in SET_CARGO:New():FilterTypes("Infantry") to define the valid cargo groups of the set.
|
-- @param #string Type Cargo type, e.g. "Infantry". This is the type used in SET_CARGO:New():FilterTypes("Infantry") to define the valid cargo groups of the set.
|
||||||
@@ -727,7 +727,7 @@ do -- CARGO_GROUP
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Check if the first element of the CargoGroup is the given @{Zone}.
|
--- Check if the first element of the CargoGroup is the given @{Core.Zone}.
|
||||||
-- @param #CARGO_GROUP self
|
-- @param #CARGO_GROUP self
|
||||||
-- @param Core.Zone#ZONE_BASE Zone
|
-- @param Core.Zone#ZONE_BASE Zone
|
||||||
-- @return #boolean **true** if the first element of the CargoGroup is in the Zone
|
-- @return #boolean **true** if the first element of the CargoGroup is in the Zone
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Cargo** -- Management of single cargo crates, which are based on a @{Static} object. The cargo can only be slingloaded.
|
--- **Cargo** - Management of single cargo crates, which are based on a STATIC object. The cargo can only be slingloaded.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Cargo** - Management of single cargo logistics, which are based on a @{Wrapper.Unit} object.
|
--- **Cargo** - Management of single cargo logistics, which are based on a UNIT object.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
943
Moose Development/Moose/Core/Astar.lua
Normal file
943
Moose Development/Moose/Core/Astar.lua
Normal file
@@ -0,0 +1,943 @@
|
|||||||
|
--- **Core** - A* Pathfinding.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Find path from A to B.
|
||||||
|
-- * Pre-defined as well as custom valid neighbour functions.
|
||||||
|
-- * Pre-defined as well as custom cost functions.
|
||||||
|
-- * Easy rectangular grid setup.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Core.Astar
|
||||||
|
-- @image CORE_Astar.png
|
||||||
|
|
||||||
|
|
||||||
|
--- ASTAR class.
|
||||||
|
-- @type ASTAR
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #table nodes Table of nodes.
|
||||||
|
-- @field #number counter Node counter.
|
||||||
|
-- @field #number Nnodes Number of nodes.
|
||||||
|
-- @field #number nvalid Number of nvalid calls.
|
||||||
|
-- @field #number nvalidcache Number of cached valid evals.
|
||||||
|
-- @field #number ncost Number of cost evaluations.
|
||||||
|
-- @field #number ncostcache Number of cached cost evals.
|
||||||
|
-- @field #ASTAR.Node startNode Start node.
|
||||||
|
-- @field #ASTAR.Node endNode End node.
|
||||||
|
-- @field Core.Point#COORDINATE startCoord Start coordinate.
|
||||||
|
-- @field Core.Point#COORDINATE endCoord End coordinate.
|
||||||
|
-- @field #function ValidNeighbourFunc Function to check if a node is valid.
|
||||||
|
-- @field #table ValidNeighbourArg Optional arguments passed to the valid neighbour function.
|
||||||
|
-- @field #function CostFunc Function to calculate the heuristic "cost" to go from one node to another.
|
||||||
|
-- @field #table CostArg Optional arguments passed to the cost function.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *When nothing goes right... Go left!*
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The ASTAR Concept
|
||||||
|
--
|
||||||
|
-- Pathfinding algorithm.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Start and Goal
|
||||||
|
--
|
||||||
|
-- The first thing we need to define is obviously the place where we want to start and where we want to go eventually.
|
||||||
|
--
|
||||||
|
-- ## Start
|
||||||
|
--
|
||||||
|
-- The start
|
||||||
|
--
|
||||||
|
-- ## Goal
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Nodes
|
||||||
|
--
|
||||||
|
-- ## Rectangular Grid
|
||||||
|
--
|
||||||
|
-- A rectangular grid can be created using the @{#ASTAR.CreateGrid}(*ValidSurfaceTypes, BoxHY, SpaceX, deltaX, deltaY, MarkGrid*), where
|
||||||
|
--
|
||||||
|
-- * *ValidSurfaceTypes* is a table of valid surface types. By default all surface types are valid.
|
||||||
|
-- * *BoxXY* is the width of the grid perpendicular the the line between start and end node. Default is 40,000 meters (40 km).
|
||||||
|
-- * *SpaceX* is the additional space behind the start and end nodes. Default is 20,000 meters (20 km).
|
||||||
|
-- * *deltaX* is the grid spacing between nodes in the direction of start and end node. Default is 2,000 meters (2 km).
|
||||||
|
-- * *deltaY* is the grid spacing perpendicular to the direction of start and end node. Default is the same as *deltaX*.
|
||||||
|
-- * *MarkGrid* If set to *true*, this places marker on the F10 map on each grid node. Note that this can stall DCS if too many nodes are created.
|
||||||
|
--
|
||||||
|
-- ## Valid Surfaces
|
||||||
|
--
|
||||||
|
-- Certain unit types can only travel on certain surfaces types, for example
|
||||||
|
--
|
||||||
|
-- * Naval units can only travel on water (that also excludes shallow water in DCS currently),
|
||||||
|
-- * Ground units can only traval on land.
|
||||||
|
--
|
||||||
|
-- By restricting the surface type in the grid construction, we also reduce the number of nodes, which makes the algorithm more efficient.
|
||||||
|
--
|
||||||
|
-- ## Box Width (BoxHY)
|
||||||
|
--
|
||||||
|
-- The box width needs to be large enough to capture all paths you want to consider.
|
||||||
|
--
|
||||||
|
-- ## Space in X
|
||||||
|
--
|
||||||
|
-- The space in X value is important if the algorithm needs to to backwards from the start node or needs to extend even further than the end node.
|
||||||
|
--
|
||||||
|
-- ## Grid Spacing
|
||||||
|
--
|
||||||
|
-- The grid spacing is an important factor as it determines the number of nodes and hence the performance of the algorithm. It should be as large as possible.
|
||||||
|
-- However, if the value is too large, the algorithm might fail to get a valid path.
|
||||||
|
--
|
||||||
|
-- A good estimate of the grid spacing is to set it to be smaller (~ half the size) of the smallest gap you need to path.
|
||||||
|
--
|
||||||
|
-- # Valid Neighbours
|
||||||
|
--
|
||||||
|
-- The A* algorithm needs to know if a transition from one node to another is allowed or not. By default, hopping from one node to another is always possible.
|
||||||
|
--
|
||||||
|
-- ## Line of Sight
|
||||||
|
--
|
||||||
|
-- For naval
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Heuristic Cost
|
||||||
|
--
|
||||||
|
-- In order to determine the optimal path, the pathfinding algorithm needs to know, how costly it is to go from one node to another.
|
||||||
|
-- Often, this can simply be determined by the distance between two nodes. Therefore, the default cost function is set to be the 2D distance between two nodes.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Calculate the Path
|
||||||
|
--
|
||||||
|
-- Finally, we have to calculate the path. This is done by the @{ASTAR.GetPath}(*ExcludeStart, ExcludeEnd*) function. This function returns a table of nodes, which
|
||||||
|
-- describe the optimal path from the start node to the end node.
|
||||||
|
--
|
||||||
|
-- By default, the start and end node are include in the table that is returned.
|
||||||
|
--
|
||||||
|
-- Note that a valid path must not always exist. So you should check if the function returns *nil*.
|
||||||
|
--
|
||||||
|
-- Common reasons that a path cannot be found are:
|
||||||
|
--
|
||||||
|
-- * The grid is too small ==> increase grid size, e.g. *BoxHY* and/or *SpaceX* if you use a rectangular grid.
|
||||||
|
-- * The grid spacing is too large ==> decrease *deltaX* and/or *deltaY*
|
||||||
|
-- * There simply is no valid path ==> you are screwed :(
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Examples
|
||||||
|
--
|
||||||
|
-- ## Strait of Hormuz
|
||||||
|
--
|
||||||
|
-- Carrier Group finds its way through the Stait of Hormuz.
|
||||||
|
--
|
||||||
|
-- ##
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #ASTAR
|
||||||
|
ASTAR = {
|
||||||
|
ClassName = "ASTAR",
|
||||||
|
Debug = nil,
|
||||||
|
lid = nil,
|
||||||
|
nodes = {},
|
||||||
|
counter = 1,
|
||||||
|
Nnodes = 0,
|
||||||
|
ncost = 0,
|
||||||
|
ncostcache = 0,
|
||||||
|
nvalid = 0,
|
||||||
|
nvalidcache = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Node data.
|
||||||
|
-- @type ASTAR.Node
|
||||||
|
-- @field #number id Node id.
|
||||||
|
-- @field Core.Point#COORDINATE coordinate Coordinate of the node.
|
||||||
|
-- @field #number surfacetype Surface type.
|
||||||
|
-- @field #table valid Cached valid/invalid nodes.
|
||||||
|
-- @field #table cost Cached cost.
|
||||||
|
|
||||||
|
--- ASTAR infinity.
|
||||||
|
-- @field #number INF
|
||||||
|
ASTAR.INF=1/0
|
||||||
|
|
||||||
|
--- ASTAR class version.
|
||||||
|
-- @field #string version
|
||||||
|
ASTAR.version="0.4.0"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: Add more valid neighbour functions.
|
||||||
|
-- TODO: Write docs.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new ASTAR object.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:New()
|
||||||
|
|
||||||
|
-- Inherit everything from INTEL class.
|
||||||
|
local self=BASE:Inherit(self, BASE:New()) --#ASTAR
|
||||||
|
|
||||||
|
self.lid="ASTAR | "
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set coordinate from where to start.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Start coordinate.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetStartCoordinate(Coordinate)
|
||||||
|
|
||||||
|
self.startCoord=Coordinate
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set coordinate where you want to go.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate end coordinate.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetEndCoordinate(Coordinate)
|
||||||
|
|
||||||
|
self.endCoord=Coordinate
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a node from a given coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where to create the node.
|
||||||
|
-- @return #ASTAR.Node The node.
|
||||||
|
function ASTAR:GetNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
|
local node={} --#ASTAR.Node
|
||||||
|
|
||||||
|
node.coordinate=Coordinate
|
||||||
|
node.surfacetype=Coordinate:GetSurfaceType()
|
||||||
|
node.id=self.counter
|
||||||
|
|
||||||
|
node.valid={}
|
||||||
|
node.cost={}
|
||||||
|
|
||||||
|
self.counter=self.counter+1
|
||||||
|
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a node to the table of grid nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:AddNode(Node)
|
||||||
|
|
||||||
|
self.nodes[Node.id]=Node
|
||||||
|
self.Nnodes=self.Nnodes+1
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a node to the table of grid nodes specifying its coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where the node is created.
|
||||||
|
-- @return #ASTAR.Node The node.
|
||||||
|
function ASTAR:AddNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
|
local node=self:GetNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
|
self:AddNode(node)
|
||||||
|
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the coordinate of a node has is at a valid surface type.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added.
|
||||||
|
-- @param #table SurfaceTypes Surface types, for example `{land.SurfaceType.WATER}`. By default all surface types are valid.
|
||||||
|
-- @return #boolean If true, surface type of node is valid.
|
||||||
|
function ASTAR:CheckValidSurfaceType(Node, SurfaceTypes)
|
||||||
|
|
||||||
|
if SurfaceTypes then
|
||||||
|
|
||||||
|
if type(SurfaceTypes)~="table" then
|
||||||
|
SurfaceTypes={SurfaceTypes}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _,surface in pairs(SurfaceTypes) do
|
||||||
|
if surface==Node.surfacetype then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function to determine if a neighbour of a node is valid.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #function NeighbourFunction Function that needs to return *true* for a neighbour to be valid.
|
||||||
|
-- @param ... Condition function arguments if any.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourFunction(NeighbourFunction, ...)
|
||||||
|
|
||||||
|
self.ValidNeighbourFunc=NeighbourFunction
|
||||||
|
|
||||||
|
self.ValidNeighbourArg={}
|
||||||
|
if arg then
|
||||||
|
self.ValidNeighbourArg=arg
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set valid neighbours to require line of sight between two nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #number CorridorWidth Width of LoS corridor in meters.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourLoS(CorridorWidth)
|
||||||
|
|
||||||
|
self:SetValidNeighbourFunction(ASTAR.LoS, CorridorWidth)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set valid neighbours to be in a certain distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #number MaxDistance Max distance between nodes in meters. Default is 2000 m.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourDistance(MaxDistance)
|
||||||
|
|
||||||
|
self:SetValidNeighbourFunction(ASTAR.DistMax, MaxDistance)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set valid neighbours to be in a certain distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #number MaxDistance Max distance between nodes in meters. Default is 2000 m.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourRoad(MaxDistance)
|
||||||
|
|
||||||
|
self:SetValidNeighbourFunction(ASTAR.Road, MaxDistance)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the function which calculates the "cost" to go from one to another node.
|
||||||
|
-- The first to arguments of this function are always the two nodes under consideration. But you can add optional arguments.
|
||||||
|
-- Very often the distance between nodes is a good measure for the cost.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #function CostFunction Function that returns the "cost".
|
||||||
|
-- @param ... Condition function arguments if any.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostFunction(CostFunction, ...)
|
||||||
|
|
||||||
|
self.CostFunc=CostFunction
|
||||||
|
|
||||||
|
self.CostArg={}
|
||||||
|
if arg then
|
||||||
|
self.CostArg=arg
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 2D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostDist2D()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR.Dist2D)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 3D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostDist3D()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR.Dist3D)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 3D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostRoad()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Grid functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a rectangular grid of nodes between star and end coordinate.
|
||||||
|
-- The coordinate system is oriented along the line between start and end point.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table ValidSurfaceTypes Valid surface types. By default is all surfaces are allowed.
|
||||||
|
-- @param #number BoxHY Box "height" in meters along the y-coordinate. Default 40000 meters (40 km).
|
||||||
|
-- @param #number SpaceX Additional space in meters before start and after end coordinate. Default 10000 meters (10 km).
|
||||||
|
-- @param #number deltaX Increment in the direction of start to end coordinate in meters. Default 2000 meters.
|
||||||
|
-- @param #number deltaY Increment perpendicular to the direction of start to end coordinate in meters. Default is same as deltaX.
|
||||||
|
-- @param #boolean MarkGrid If true, create F10 map markers at grid nodes.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:CreateGrid(ValidSurfaceTypes, BoxHY, SpaceX, deltaX, deltaY, MarkGrid)
|
||||||
|
|
||||||
|
-- Note that internally
|
||||||
|
-- x coordinate is z: x-->z Line from start to end
|
||||||
|
-- y coordinate is x: y-->x Perpendicular
|
||||||
|
|
||||||
|
-- Grid length and width.
|
||||||
|
local Dz=SpaceX or 10000
|
||||||
|
local Dx=BoxHY and BoxHY/2 or 20000
|
||||||
|
|
||||||
|
-- Increments.
|
||||||
|
local dz=deltaX or 2000
|
||||||
|
local dx=deltaY or dz
|
||||||
|
|
||||||
|
-- Heading from start to end coordinate.
|
||||||
|
local angle=self.startCoord:HeadingTo(self.endCoord)
|
||||||
|
|
||||||
|
--Distance between start and end.
|
||||||
|
local dist=self.startCoord:Get2DDistance(self.endCoord)+2*Dz
|
||||||
|
|
||||||
|
-- Origin of map. Needed to translate back to wanted position.
|
||||||
|
local co=COORDINATE:New(0, 0, 0)
|
||||||
|
local do1=co:Get2DDistance(self.startCoord)
|
||||||
|
local ho1=co:HeadingTo(self.startCoord)
|
||||||
|
|
||||||
|
-- Start of grid.
|
||||||
|
local xmin=-Dx
|
||||||
|
local zmin=-Dz
|
||||||
|
|
||||||
|
-- Number of grid points.
|
||||||
|
local nz=dist/dz+1
|
||||||
|
local nx=2*Dx/dx+1
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Building grid with nx=%d ny=%d => total=%d nodes", nx, nz, nx*nz)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
-- Loop over x and z coordinate to create a 2D grid.
|
||||||
|
for i=1,nx do
|
||||||
|
|
||||||
|
-- x coordinate perpendicular to z.
|
||||||
|
local x=xmin+dx*(i-1)
|
||||||
|
|
||||||
|
for j=1,nz do
|
||||||
|
|
||||||
|
-- z coordinate connecting start and end.
|
||||||
|
local z=zmin+dz*(j-1)
|
||||||
|
|
||||||
|
-- Rotate 2D.
|
||||||
|
local vec3=UTILS.Rotate2D({x=x, y=0, z=z}, angle)
|
||||||
|
|
||||||
|
-- Coordinate of the node.
|
||||||
|
local c=COORDINATE:New(vec3.z, vec3.y, vec3.x):Translate(do1, ho1, true)
|
||||||
|
|
||||||
|
-- Create a node at this coordinate.
|
||||||
|
local node=self:GetNodeFromCoordinate(c)
|
||||||
|
|
||||||
|
-- Check if node has valid surface type.
|
||||||
|
if self:CheckValidSurfaceType(node, ValidSurfaceTypes) then
|
||||||
|
|
||||||
|
if MarkGrid then
|
||||||
|
c:MarkToAll(string.format("i=%d, j=%d surface=%d", i, j, node.surfacetype))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add node to grid.
|
||||||
|
self:AddNode(node)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Done building grid!")
|
||||||
|
self:T2(self.lid..text)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Valid neighbour functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Function to check if two nodes have line of sight (LoS).
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @param #number corridor (Optional) Width of corridor in meters.
|
||||||
|
-- @return #boolean If true, two nodes have LoS.
|
||||||
|
function ASTAR.LoS(nodeA, nodeB, corridor)
|
||||||
|
|
||||||
|
local offset=1
|
||||||
|
|
||||||
|
local dx=corridor and corridor/2 or nil
|
||||||
|
local dy=dx
|
||||||
|
|
||||||
|
local cA=nodeA.coordinate:GetVec3()
|
||||||
|
local cB=nodeB.coordinate:GetVec3()
|
||||||
|
cA.y=offset
|
||||||
|
cB.y=offset
|
||||||
|
|
||||||
|
local los=land.isVisible(cA, cB)
|
||||||
|
|
||||||
|
if los and corridor then
|
||||||
|
|
||||||
|
-- Heading from A to B.
|
||||||
|
local heading=nodeA.coordinate:HeadingTo(nodeB.coordinate)
|
||||||
|
|
||||||
|
local Ap=UTILS.VecTranslate(cA, dx, heading+90)
|
||||||
|
local Bp=UTILS.VecTranslate(cB, dx, heading+90)
|
||||||
|
|
||||||
|
los=land.isVisible(Ap, Bp)
|
||||||
|
|
||||||
|
if los then
|
||||||
|
|
||||||
|
local Am=UTILS.VecTranslate(cA, dx, heading-90)
|
||||||
|
local Bm=UTILS.VecTranslate(cB, dx, heading-90)
|
||||||
|
|
||||||
|
los=land.isVisible(Am, Bm)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return los
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to check if two nodes have a road connection.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #boolean If true, two nodes are connected via a road.
|
||||||
|
function ASTAR.Road(nodeA, nodeB)
|
||||||
|
|
||||||
|
local path=land.findPathOnRoads("roads", nodeA.coordinate.x, nodeA.coordinate.z, nodeB.coordinate.x, nodeB.coordinate.z)
|
||||||
|
|
||||||
|
if path then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to check if distance between two nodes is less than a threshold distance.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @param #number distmax Max distance in meters. Default is 2000 m.
|
||||||
|
-- @return #boolean If true, distance between the two nodes is below threshold.
|
||||||
|
function ASTAR.DistMax(nodeA, nodeB, distmax)
|
||||||
|
|
||||||
|
distmax=distmax or 2000
|
||||||
|
|
||||||
|
local dist=nodeA.coordinate:Get2DDistance(nodeB.coordinate)
|
||||||
|
|
||||||
|
return dist<=distmax
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Heuristic cost functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the 2D distance between the nodes.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.Dist2D(nodeA, nodeB)
|
||||||
|
local dist=nodeA.coordinate:Get2DDistance(nodeB)
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the 3D distance between the nodes.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.Dist3D(nodeA, nodeB)
|
||||||
|
local dist=nodeA.coordinate:Get3DDistance(nodeB.coordinate)
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the distance between the nodes on road.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.DistRoad(nodeA, nodeB)
|
||||||
|
|
||||||
|
-- Get the path.
|
||||||
|
local path=land.findPathOnRoads("roads", nodeA.coordinate.x, nodeA.coordinate.z, nodeB.coordinate.x, nodeB.coordinate.z)
|
||||||
|
|
||||||
|
if path then
|
||||||
|
|
||||||
|
local dist=0
|
||||||
|
|
||||||
|
for i=2,#path do
|
||||||
|
local b=path[i] --DCS#Vec2
|
||||||
|
local a=path[i-1] --DCS#Vec2
|
||||||
|
|
||||||
|
dist=dist+UTILS.VecDist2D(a,b)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return math.huge
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Misc functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Find the closest node from a given coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate.
|
||||||
|
-- @return #ASTAR.Node Cloest node to the coordinate.
|
||||||
|
-- @return #number Distance to closest node in meters.
|
||||||
|
function ASTAR:FindClosestNode(Coordinate)
|
||||||
|
|
||||||
|
local distMin=math.huge
|
||||||
|
local closeNode=nil
|
||||||
|
|
||||||
|
for _,_node in pairs(self.nodes) do
|
||||||
|
local node=_node --#ASTAR.Node
|
||||||
|
|
||||||
|
local dist=node.coordinate:Get2DDistance(Coordinate)
|
||||||
|
|
||||||
|
if dist<distMin then
|
||||||
|
distMin=dist
|
||||||
|
closeNode=node
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return closeNode, distMin
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find the start node.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:FindStartNode()
|
||||||
|
|
||||||
|
local node, dist=self:FindClosestNode(self.startCoord)
|
||||||
|
|
||||||
|
self.startNode=node
|
||||||
|
|
||||||
|
if dist>1000 then
|
||||||
|
self:T(self.lid.."Adding start node to node grid!")
|
||||||
|
self:AddNode(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a node.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:FindEndNode()
|
||||||
|
|
||||||
|
local node, dist=self:FindClosestNode(self.endCoord)
|
||||||
|
|
||||||
|
self.endNode=node
|
||||||
|
|
||||||
|
if dist>1000 then
|
||||||
|
self:T(self.lid.."Adding end node to node grid!")
|
||||||
|
self:AddNode(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Main A* pathfinding function
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- A* pathfinding function. This seaches the path along nodes between start and end nodes/coordinates.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #boolean ExcludeStartNode If *true*, do not include start node in found path. Default is to include it.
|
||||||
|
-- @param #boolean ExcludeEndNode If *true*, do not include end node in found path. Default is to include it.
|
||||||
|
-- @return #table Table of nodes from start to finish.
|
||||||
|
function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||||
|
|
||||||
|
self:FindStartNode()
|
||||||
|
self:FindEndNode()
|
||||||
|
|
||||||
|
local nodes=self.nodes
|
||||||
|
local start=self.startNode
|
||||||
|
local goal=self.endNode
|
||||||
|
|
||||||
|
-- Sets.
|
||||||
|
local openset = {}
|
||||||
|
local closedset = {}
|
||||||
|
local came_from = {}
|
||||||
|
local g_score = {}
|
||||||
|
local f_score = {}
|
||||||
|
|
||||||
|
openset[start.id]=true
|
||||||
|
local Nopen=1
|
||||||
|
|
||||||
|
-- Initial scores.
|
||||||
|
g_score[start.id]=0
|
||||||
|
f_score[start.id]=g_score[start.id]+self:_HeuristicCost(start, goal)
|
||||||
|
|
||||||
|
-- Set start time.
|
||||||
|
local T0=timer.getAbsTime()
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("Starting A* pathfinding with %d Nodes", self.Nnodes)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
local Tstart=UTILS.GetOSTime()
|
||||||
|
|
||||||
|
-- Loop while we still have an open set.
|
||||||
|
while Nopen > 0 do
|
||||||
|
|
||||||
|
-- Get current node.
|
||||||
|
local current=self:_LowestFscore(openset, f_score)
|
||||||
|
|
||||||
|
-- Check if we are at the end node.
|
||||||
|
if current.id==goal.id then
|
||||||
|
|
||||||
|
local path=self:_UnwindPath({}, came_from, goal)
|
||||||
|
|
||||||
|
if not ExcludeEndNode then
|
||||||
|
table.insert(path, goal)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ExcludeStartNode then
|
||||||
|
table.remove(path, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local Tstop=UTILS.GetOSTime()
|
||||||
|
|
||||||
|
local dT=nil
|
||||||
|
if Tstart and Tstop then
|
||||||
|
dT=Tstop-Tstart
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("Found path with %d nodes (%d total)", #path, self.Nnodes)
|
||||||
|
if dT then
|
||||||
|
text=text..string.format(", OS Time %.6f sec", dT)
|
||||||
|
end
|
||||||
|
text=text..string.format(", Nvalid=%d [%d cached]", self.nvalid, self.nvalidcache)
|
||||||
|
text=text..string.format(", Ncost=%d [%d cached]", self.ncost, self.ncostcache)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move Node from open to closed set.
|
||||||
|
openset[current.id]=nil
|
||||||
|
Nopen=Nopen-1
|
||||||
|
closedset[current.id]=true
|
||||||
|
|
||||||
|
-- Get neighbour nodes.
|
||||||
|
local neighbors=self:_NeighbourNodes(current, nodes)
|
||||||
|
|
||||||
|
-- Loop over neighbours.
|
||||||
|
for _,neighbor in pairs(neighbors) do
|
||||||
|
|
||||||
|
if self:_NotIn(closedset, neighbor.id) then
|
||||||
|
|
||||||
|
local tentative_g_score=g_score[current.id]+self:_DistNodes(current, neighbor)
|
||||||
|
|
||||||
|
if self:_NotIn(openset, neighbor.id) or tentative_g_score < g_score[neighbor.id] then
|
||||||
|
|
||||||
|
came_from[neighbor]=current
|
||||||
|
|
||||||
|
g_score[neighbor.id]=tentative_g_score
|
||||||
|
f_score[neighbor.id]=g_score[neighbor.id]+self:_HeuristicCost(neighbor, goal)
|
||||||
|
|
||||||
|
if self:_NotIn(openset, neighbor.id) then
|
||||||
|
-- Add to open set.
|
||||||
|
openset[neighbor.id]=true
|
||||||
|
Nopen=Nopen+1
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("WARNING: Could NOT find valid path!")
|
||||||
|
self:E(self.lid..text)
|
||||||
|
MESSAGE:New(text, 60, "ASTAR"):ToAllIf(self.Debug)
|
||||||
|
|
||||||
|
return nil -- no valid path
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- A* pathfinding helper functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Heuristic "cost" function to go from node A to node B. Default is the distance between the nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node nodeA Node A.
|
||||||
|
-- @param #ASTAR.Node nodeB Node B.
|
||||||
|
-- @return #number "Cost" to go from node A to node B.
|
||||||
|
function ASTAR:_HeuristicCost(nodeA, nodeB)
|
||||||
|
|
||||||
|
-- Counter.
|
||||||
|
self.ncost=self.ncost+1
|
||||||
|
|
||||||
|
-- Get chached cost if available.
|
||||||
|
local cost=nodeA.cost[nodeB.id]
|
||||||
|
if cost~=nil then
|
||||||
|
self.ncostcache=self.ncostcache+1
|
||||||
|
return cost
|
||||||
|
end
|
||||||
|
|
||||||
|
local cost=nil
|
||||||
|
if self.CostFunc then
|
||||||
|
cost=self.CostFunc(nodeA, nodeB, unpack(self.CostArg))
|
||||||
|
else
|
||||||
|
cost=self:_DistNodes(nodeA, nodeB)
|
||||||
|
end
|
||||||
|
|
||||||
|
nodeA.cost[nodeB.id]=cost
|
||||||
|
nodeB.cost[nodeA.id]=cost -- Symmetric problem.
|
||||||
|
|
||||||
|
return cost
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if going from a node to a neighbour is possible.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node node A node.
|
||||||
|
-- @param #ASTAR.Node neighbor Neighbour node.
|
||||||
|
-- @return #boolean If true, transition between nodes is possible.
|
||||||
|
function ASTAR:_IsValidNeighbour(node, neighbor)
|
||||||
|
|
||||||
|
-- Counter.
|
||||||
|
self.nvalid=self.nvalid+1
|
||||||
|
|
||||||
|
local valid=node.valid[neighbor.id]
|
||||||
|
if valid~=nil then
|
||||||
|
--env.info(string.format("Node %d has valid=%s neighbour %d", node.id, tostring(valid), neighbor.id))
|
||||||
|
self.nvalidcache=self.nvalidcache+1
|
||||||
|
return valid
|
||||||
|
end
|
||||||
|
|
||||||
|
local valid=nil
|
||||||
|
if self.ValidNeighbourFunc then
|
||||||
|
valid=self.ValidNeighbourFunc(node, neighbor, unpack(self.ValidNeighbourArg))
|
||||||
|
else
|
||||||
|
valid=true
|
||||||
|
end
|
||||||
|
|
||||||
|
node.valid[neighbor.id]=valid
|
||||||
|
neighbor.valid[node.id]=valid -- Symmetric problem.
|
||||||
|
|
||||||
|
return valid
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculate 2D distance between two nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node nodeA Node A.
|
||||||
|
-- @param #ASTAR.Node nodeB Node B.
|
||||||
|
-- @return #number Distance between nodes in meters.
|
||||||
|
function ASTAR:_DistNodes(nodeA, nodeB)
|
||||||
|
return nodeA.coordinate:Get2DDistance(nodeB.coordinate)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function that calculates the lowest F score.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table set The set of nodes IDs.
|
||||||
|
-- @param #number f_score F score.
|
||||||
|
-- @return #ASTAR.Node Best node.
|
||||||
|
function ASTAR:_LowestFscore(set, f_score)
|
||||||
|
|
||||||
|
local lowest, bestNode = ASTAR.INF, nil
|
||||||
|
|
||||||
|
for nid,node in pairs(set) do
|
||||||
|
|
||||||
|
local score=f_score[nid]
|
||||||
|
|
||||||
|
if score<lowest then
|
||||||
|
lowest, bestNode = score, nid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.nodes[bestNode]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to get valid neighbours of a node.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node theNode The node.
|
||||||
|
-- @param #table nodes Possible neighbours.
|
||||||
|
-- @param #table Valid neighbour nodes.
|
||||||
|
function ASTAR:_NeighbourNodes(theNode, nodes)
|
||||||
|
|
||||||
|
local neighbors = {}
|
||||||
|
|
||||||
|
for _,node in pairs(nodes) do
|
||||||
|
|
||||||
|
if theNode.id~=node.id then
|
||||||
|
|
||||||
|
local isvalid=self:_IsValidNeighbour(theNode, node)
|
||||||
|
|
||||||
|
if isvalid then
|
||||||
|
table.insert(neighbors, node)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return neighbors
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to check if a node is not in a set.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table set Set of nodes.
|
||||||
|
-- @param #ASTAR.Node theNode The node to check.
|
||||||
|
-- @return #boolean If true, the node is not in the set.
|
||||||
|
function ASTAR:_NotIn(set, theNode)
|
||||||
|
return set[theNode]==nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Unwind path function.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table flat_path Flat path.
|
||||||
|
-- @param #table map Map.
|
||||||
|
-- @param #ASTAR.Node current_node The current node.
|
||||||
|
-- @return #table Unwinded path.
|
||||||
|
function ASTAR:_UnwindPath( flat_path, map, current_node )
|
||||||
|
|
||||||
|
if map [current_node] then
|
||||||
|
table.insert (flat_path, 1, map[current_node])
|
||||||
|
return self:_UnwindPath(flat_path, map, map[current_node])
|
||||||
|
else
|
||||||
|
return flat_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -157,7 +157,7 @@ local _ClassID = 0
|
|||||||
-- self:SmokeBlue()
|
-- self:SmokeBlue()
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
-- See the @{Event} module for more information about event handling.
|
-- See the @{Core.Event} module for more information about event handling.
|
||||||
--
|
--
|
||||||
-- # 4. Class identification methods.
|
-- # 4. Class identification methods.
|
||||||
--
|
--
|
||||||
@@ -229,7 +229,8 @@ FORMATION = {
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @return #BASE
|
-- @return #BASE
|
||||||
function BASE:New()
|
function BASE:New()
|
||||||
local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
--local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||||
|
local self = UTILS.DeepCopy(self)
|
||||||
|
|
||||||
_ClassID = _ClassID + 1
|
_ClassID = _ClassID + 1
|
||||||
self.ClassID = _ClassID
|
self.ClassID = _ClassID
|
||||||
@@ -411,20 +412,20 @@ do -- Event Handling
|
|||||||
return _EVENTDISPATCHER
|
return _EVENTDISPATCHER
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the Class @{Event} processing Priority.
|
--- Get the Class @{Core.Event} processing Priority.
|
||||||
-- The Event processing Priority is a number from 1 to 10,
|
-- The Event processing Priority is a number from 1 to 10,
|
||||||
-- reflecting the order of the classes subscribed to the Event to be processed.
|
-- reflecting the order of the classes subscribed to the Event to be processed.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @return #number The @{Event} processing Priority.
|
-- @return #number The @{Core.Event} processing Priority.
|
||||||
function BASE:GetEventPriority()
|
function BASE:GetEventPriority()
|
||||||
return self._.EventPriority or 5
|
return self._.EventPriority or 5
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the Class @{Event} processing Priority.
|
--- Set the Class @{Core.Event} processing Priority.
|
||||||
-- The Event processing Priority is a number from 1 to 10,
|
-- The Event processing Priority is a number from 1 to 10,
|
||||||
-- reflecting the order of the classes subscribed to the Event to be processed.
|
-- reflecting the order of the classes subscribed to the Event to be processed.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #number EventPriority The @{Event} processing Priority.
|
-- @param #number EventPriority The @{Core.Event} processing Priority.
|
||||||
-- @return #BASE self
|
-- @return #BASE self
|
||||||
function BASE:SetEventPriority( EventPriority )
|
function BASE:SetEventPriority( EventPriority )
|
||||||
self._.EventPriority = EventPriority
|
self._.EventPriority = EventPriority
|
||||||
@@ -462,132 +463,153 @@ do -- Event Handling
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Event handling function prototypes
|
-- Event handling function prototypes - Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
|
||||||
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or auto cannon based weapon, those are handled by EVENT.ShootingStart.
|
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or autocannon based weapon, those are handled by EVENT.ShootingStart.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventShot
|
-- @function [parent=#BASE] OnEventShot
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs whenever an object is hit by a weapon.
|
--- Occurs whenever an object is hit by a weapon.
|
||||||
-- initiator : The unit object the fired the weapon.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- weapon: Weapon object that hit the target.
|
-- initiator : The unit object the fired the weapon
|
||||||
-- target: The Object that was hit.
|
-- weapon: Weapon object that hit the target
|
||||||
|
-- target: The Object that was hit.
|
||||||
-- @function [parent=#BASE] OnEventHit
|
-- @function [parent=#BASE] OnEventHit
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft takes off from an airbase, farp, or ship.
|
--- Occurs when an aircraft takes off from an airbase, farp, or ship.
|
||||||
-- initiator : The unit that took off.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships.
|
-- initiator : The unit that tookoff
|
||||||
|
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships
|
||||||
-- @function [parent=#BASE] OnEventTakeoff
|
-- @function [parent=#BASE] OnEventTakeoff
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft lands at an airbase, farp or ship
|
--- Occurs when an aircraft lands at an airbase, farp or ship
|
||||||
-- initiator : The unit that has landed.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships.
|
-- initiator : The unit that has landed
|
||||||
|
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships
|
||||||
-- @function [parent=#BASE] OnEventLand
|
-- @function [parent=#BASE] OnEventLand
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any aircraft crashes into the ground and is completely destroyed.
|
--- Occurs when any aircraft crashes into the ground and is completely destroyed.
|
||||||
-- initiator : The unit that has crashed.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that has crashed
|
||||||
-- @function [parent=#BASE] OnEventCrash
|
-- @function [parent=#BASE] OnEventCrash
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a pilot ejects from an aircraft
|
--- Occurs when a pilot ejects from an aircraft
|
||||||
-- initiator : The unit that has ejected
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that has ejected
|
||||||
-- @function [parent=#BASE] OnEventEjection
|
-- @function [parent=#BASE] OnEventEjection
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft connects with a tanker and begins taking on fuel.
|
--- Occurs when an aircraft connects with a tanker and begins taking on fuel.
|
||||||
-- initiator : The unit that is receiving fuel.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that is receiving fuel.
|
||||||
-- @function [parent=#BASE] OnEventRefueling
|
-- @function [parent=#BASE] OnEventRefueling
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an object is dead.
|
--- Occurs when an object is dead.
|
||||||
-- initiator : The unit that is dead.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that is dead.
|
||||||
-- @function [parent=#BASE] OnEventDead
|
-- @function [parent=#BASE] OnEventDead
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an object is completely destroyed.
|
--- Occurs when an Event for an object is triggered.
|
||||||
-- initiator : The unit that is was destroyed.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that triggered the event.
|
||||||
-- @function [parent=#BASE] OnEvent
|
-- @function [parent=#BASE] OnEvent
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when the pilot of an aircraft is killed. Can occur either if the player is alive and crashes or if a weapon kills the pilot without completely destroying the plane.
|
--- Occurs when the pilot of an aircraft is killed. Can occur either if the player is alive and crashes or if a weapon kills the pilot without completely destroying the plane.
|
||||||
-- initiator : The unit that the pilot has died in.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that the pilot has died in.
|
||||||
-- @function [parent=#BASE] OnEventPilotDead
|
-- @function [parent=#BASE] OnEventPilotDead
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a ground unit captures either an airbase or a farp.
|
--- Occurs when a ground unit captures either an airbase or a farp.
|
||||||
-- initiator : The unit that captured the base.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
|
-- initiator : The unit that captured the base
|
||||||
|
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
|
||||||
-- @function [parent=#BASE] OnEventBaseCaptured
|
-- @function [parent=#BASE] OnEventBaseCaptured
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mission starts.
|
--- Occurs when a mission starts
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventMissionStart
|
-- @function [parent=#BASE] OnEventMissionStart
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mission ends.
|
--- Occurs when a mission ends
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventMissionEnd
|
-- @function [parent=#BASE] OnEventMissionEnd
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft is finished taking fuel.
|
--- Occurs when an aircraft is finished taking fuel.
|
||||||
-- initiator : The unit that was receiving fuel.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that was receiving fuel.
|
||||||
-- @function [parent=#BASE] OnEventRefuelingStop
|
-- @function [parent=#BASE] OnEventRefuelingStop
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any object is spawned into the mission.
|
--- Occurs when any object is spawned into the mission.
|
||||||
-- initiator : The unit that was spawned.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that was spawned
|
||||||
-- @function [parent=#BASE] OnEventBirth
|
-- @function [parent=#BASE] OnEventBirth
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any system fails on a human controlled aircraft.
|
--- Occurs when any system fails on a human controlled aircraft.
|
||||||
-- initiator : The unit that had the failure.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that had the failure
|
||||||
-- @function [parent=#BASE] OnEventHumanFailure
|
-- @function [parent=#BASE] OnEventHumanFailure
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any aircraft starts its engines.
|
--- Occurs when any aircraft starts its engines.
|
||||||
-- initiator : The unit that is starting its engines..
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that is starting its engines.
|
||||||
-- @function [parent=#BASE] OnEventEngineStartup
|
-- @function [parent=#BASE] OnEventEngineStartup
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any aircraft shuts down its engines.
|
--- Occurs when any aircraft shuts down its engines.
|
||||||
-- initiator : The unit that is stopping its engines..
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that is stopping its engines.
|
||||||
-- @function [parent=#BASE] OnEventEngineShutdown
|
-- @function [parent=#BASE] OnEventEngineShutdown
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any player assumes direct control of a unit.
|
--- Occurs when any player assumes direct control of a unit. Note - not Mulitplayer safe. Use PlayerEnterAircraft.
|
||||||
-- initiator : The unit that is being taken control of.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that is being taken control of.
|
||||||
-- @function [parent=#BASE] OnEventPlayerEnterUnit
|
-- @function [parent=#BASE] OnEventPlayerEnterUnit
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any player relieves control of a unit to the AI.
|
--- Occurs when any player relieves control of a unit to the AI.
|
||||||
-- initiator : The unit that the player left.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that the player left.
|
||||||
-- @function [parent=#BASE] OnEventPlayerLeaveUnit
|
-- @function [parent=#BASE] OnEventPlayerLeaveUnit
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), auto cannons, and machine guns.
|
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), autocannons, and machine guns.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that is doing the shooting.
|
-- initiator : The unit that is doing the shooting.
|
||||||
-- target: The unit that is being targeted.
|
-- target: The unit that is being targeted.
|
||||||
-- @function [parent=#BASE] OnEventShootingStart
|
-- @function [parent=#BASE] OnEventShootingStart
|
||||||
@@ -595,25 +617,29 @@ do -- Event Handling
|
|||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any unit stops firing its weapon. Event will always correspond with a shooting start event.
|
--- Occurs when any unit stops firing its weapon. Event will always correspond with a shooting start event.
|
||||||
-- initiator : The unit that was doing the shooting.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that was doing the shooting.
|
||||||
-- @function [parent=#BASE] OnEventShootingEnd
|
-- @function [parent=#BASE] OnEventShootingEnd
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a new mark was added.
|
--- Occurs when a new mark was added.
|
||||||
-- MarkID: ID of the mark.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- MarkID: ID of the mark.
|
||||||
-- @function [parent=#BASE] OnEventMarkAdded
|
-- @function [parent=#BASE] OnEventMarkAdded
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mark was removed.
|
--- Occurs when a mark was removed.
|
||||||
-- MarkID: ID of the mark.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- MarkID: ID of the mark.
|
||||||
-- @function [parent=#BASE] OnEventMarkRemoved
|
-- @function [parent=#BASE] OnEventMarkRemoved
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mark text was changed.
|
--- Occurs when a mark text was changed.
|
||||||
-- MarkID: ID of the mark.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
-- MarkID: ID of the mark.
|
||||||
-- @function [parent=#BASE] OnEventMarkChange
|
-- @function [parent=#BASE] OnEventMarkChange
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
@@ -628,13 +654,15 @@ do -- Event Handling
|
|||||||
|
|
||||||
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
||||||
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventScore
|
-- @function [parent=#BASE] OnEventScore
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
|
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
|
||||||
--
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- * initiator: The unit that killed the target.
|
--
|
||||||
|
-- * initiator: The unit that killed the target
|
||||||
-- * target: Target Object
|
-- * target: Target Object
|
||||||
-- * weapon: Weapon Object
|
-- * weapon: Weapon Object
|
||||||
--
|
--
|
||||||
@@ -644,12 +672,14 @@ do -- Event Handling
|
|||||||
|
|
||||||
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
||||||
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventScore
|
-- @function [parent=#BASE] OnEventScore
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when the game thinks an object is destroyed.
|
--- Occurs when the game thinks an object is destroyed.
|
||||||
--
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
--
|
||||||
-- * initiator: The unit that is was destroyed.
|
-- * initiator: The unit that is was destroyed.
|
||||||
--
|
--
|
||||||
-- @function [parent=#BASE] OnEventUnitLost
|
-- @function [parent=#BASE] OnEventUnitLost
|
||||||
@@ -657,7 +687,8 @@ do -- Event Handling
|
|||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs shortly after the landing animation of an ejected pilot touching the ground and standing up. Event does not occur if the pilot lands in the water and sub combs to Davey Jones Locker.
|
--- Occurs shortly after the landing animation of an ejected pilot touching the ground and standing up. Event does not occur if the pilot lands in the water and sub combs to Davey Jones Locker.
|
||||||
--
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
|
--
|
||||||
-- * initiator: Static object representing the ejected pilot. Place : Aircraft that the pilot ejected from.
|
-- * initiator: Static object representing the ejected pilot. Place : Aircraft that the pilot ejected from.
|
||||||
-- * place: may not return as a valid object if the aircraft has crashed into the ground and no longer exists.
|
-- * place: may not return as a valid object if the aircraft has crashed into the ground and no longer exists.
|
||||||
-- * subplace: is always 0 for unknown reasons.
|
-- * subplace: is always 0 for unknown reasons.
|
||||||
@@ -667,38 +698,45 @@ do -- Event Handling
|
|||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Paratrooper landing.
|
--- Paratrooper landing.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventParatrooperLanding
|
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Discard chair after ejection.
|
--- Discard chair after ejection.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventDiscardChairAfterEjection
|
-- @function [parent=#BASE] OnEventDiscardChairAfterEjection
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Weapon add. Fires when entering a mission per pylon with the name of the weapon (double pylons not counted, infinite wep reload not counted.
|
--- Weapon add. Fires when entering a mission per pylon with the name of the weapon (double pylons not counted, infinite wep reload not counted.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventParatrooperLanding
|
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Trigger zone.
|
--- Trigger zone.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventTriggerZone
|
-- @function [parent=#BASE] OnEventTriggerZone
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Landing quality mark.
|
--- Landing quality mark.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventLandingQualityMark
|
-- @function [parent=#BASE] OnEventLandingQualityMark
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- BDA.
|
--- BDA.
|
||||||
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventBDA
|
-- @function [parent=#BASE] OnEventBDA
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a player enters a slot and takes control of an aircraft.
|
--- Occurs when a player enters a slot and takes control of an aircraft.
|
||||||
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
|
-- Have a look at the class @{Core.Event#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that is being taken control of.
|
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
|
||||||
|
-- initiator : The unit that is being taken control of.
|
||||||
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
|
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
@@ -731,30 +769,48 @@ end
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param DCS#Time EventTime The time stamp of the event.
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
-- @param DCS#Object Initiator The initiating object of the event.
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
function BASE:CreateEventCrash( EventTime, Initiator )
|
function BASE:CreateEventCrash( EventTime, Initiator, IniObjectCategory )
|
||||||
self:F( { EventTime, Initiator } )
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = world.event.S_EVENT_CRASH,
|
id = world.event.S_EVENT_CRASH,
|
||||||
time = EventTime,
|
time = EventTime,
|
||||||
initiator = Initiator,
|
initiator = Initiator,
|
||||||
|
IniObjectCategory = IniObjectCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Creation of a Crash Event.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
|
function BASE:CreateEventUnitLost(EventTime, Initiator)
|
||||||
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = world.event.S_EVENT_UNIT_LOST,
|
||||||
|
time = EventTime,
|
||||||
|
initiator = Initiator,
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent( Event )
|
||||||
|
end
|
||||||
|
|
||||||
--- Creation of a Dead Event.
|
--- Creation of a Dead Event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param DCS#Time EventTime The time stamp of the event.
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
-- @param DCS#Object Initiator The initiating object of the event.
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
function BASE:CreateEventDead( EventTime, Initiator )
|
function BASE:CreateEventDead( EventTime, Initiator, IniObjectCategory )
|
||||||
self:F( { EventTime, Initiator } )
|
self:F( { EventTime, Initiator, IniObjectCategory } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = world.event.S_EVENT_DEAD,
|
id = world.event.S_EVENT_DEAD,
|
||||||
time = EventTime,
|
time = EventTime,
|
||||||
initiator = Initiator,
|
initiator = Initiator,
|
||||||
}
|
IniObjectCategory = IniObjectCategory,
|
||||||
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -791,22 +847,21 @@ function BASE:CreateEventTakeoff( EventTime, Initiator )
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
|
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
||||||
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
|
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
|
||||||
self:F( { PlayerUnit } )
|
self:F( { PlayerUnit } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.PlayerEnterAircraft,
|
id = EVENTS.PlayerEnterAircraft,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
initiator = PlayerUnit:GetDCSObject(),
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent(Event)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: Complete DCS#Event structure.
|
|
||||||
--- The main event handling function... This function captures all events generated for the class.
|
--- The main event handling function... This function captures all events generated for the class.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param DCS#Event event
|
-- @param DCS#Event event
|
||||||
@@ -845,32 +900,38 @@ do -- Scheduling
|
|||||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||||
-- @return #number The ScheduleID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||||
self:F2( { Start } )
|
|
||||||
self:T3( { ... } )
|
-- Object name.
|
||||||
|
|
||||||
local ObjectName = "-"
|
local ObjectName = "-"
|
||||||
ObjectName = self.ClassName .. self.ClassID
|
ObjectName = self.ClassName .. self.ClassID
|
||||||
|
|
||||||
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
-- Debug info.
|
||||||
|
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
||||||
|
|
||||||
if not self.Scheduler then
|
if not self.Scheduler then
|
||||||
self.Scheduler = SCHEDULER:New( self )
|
self.Scheduler = SCHEDULER:New( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
-- FF this was wrong!
|
||||||
self,
|
--[[
|
||||||
SchedulerFunction,
|
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||||
{ ... },
|
self,
|
||||||
Start,
|
SchedulerFunction,
|
||||||
nil,
|
{ ... },
|
||||||
nil,
|
Start,
|
||||||
nil
|
nil,
|
||||||
)
|
nil,
|
||||||
|
nil
|
||||||
self._.Schedules[#self._.Schedules + 1] = ScheduleID
|
)
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- NOTE: MasterObject (first parameter) needs to be nil or it will be the first argument passed to the SchedulerFunction!
|
||||||
|
local ScheduleID = self.Scheduler:Schedule(nil, SchedulerFunction, {...}, Start)
|
||||||
|
|
||||||
|
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||||
|
|
||||||
return self._.Schedules[#self._.Schedules]
|
return self._.Schedules[#self._.Schedules]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -882,7 +943,7 @@ do -- Scheduling
|
|||||||
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
|
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||||
-- @return #number The ScheduleID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function BASE:ScheduleRepeat( Start, Repeat, RandomizeFactor, Stop, SchedulerFunction, ... )
|
function BASE:ScheduleRepeat( Start, Repeat, RandomizeFactor, Stop, SchedulerFunction, ... )
|
||||||
self:F2( { Start } )
|
self:F2( { Start } )
|
||||||
self:T3( { ... } )
|
self:T3( { ... } )
|
||||||
@@ -895,32 +956,33 @@ do -- Scheduling
|
|||||||
if not self.Scheduler then
|
if not self.Scheduler then
|
||||||
self.Scheduler = SCHEDULER:New( self )
|
self.Scheduler = SCHEDULER:New( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- NOTE: MasterObject (first parameter) should(!) be nil as it will be the first argument passed to the SchedulerFunction!
|
||||||
local ScheduleID = self.Scheduler:Schedule(
|
local ScheduleID = self.Scheduler:Schedule(
|
||||||
self,
|
nil,
|
||||||
SchedulerFunction,
|
SchedulerFunction,
|
||||||
{ ... },
|
{ ... },
|
||||||
Start,
|
Start,
|
||||||
Repeat,
|
Repeat,
|
||||||
RandomizeFactor,
|
RandomizeFactor,
|
||||||
Stop,
|
Stop,
|
||||||
4
|
4
|
||||||
)
|
)
|
||||||
|
|
||||||
self._.Schedules[#self._.Schedules + 1] = ScheduleID
|
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||||
|
|
||||||
return self._.Schedules[#self._.Schedules]
|
return self._.Schedules[#self._.Schedules]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stops the Schedule.
|
--- Stops the Schedule.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #string SchedulerID (Optional) Scheduler ID to be stopped. If nil, all pending schedules are stopped.
|
||||||
function BASE:ScheduleStop( SchedulerFunction )
|
function BASE:ScheduleStop( SchedulerID )
|
||||||
|
|
||||||
self:F3( { "ScheduleStop:" } )
|
self:F3( { "ScheduleStop:" } )
|
||||||
|
|
||||||
if self.Scheduler then
|
if self.Scheduler then
|
||||||
_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
|
--_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
|
||||||
|
_SCHEDULEDISPATCHER:Stop(self.Scheduler, SchedulerID)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1061,7 +1123,7 @@ end
|
|||||||
|
|
||||||
--- Set tracing for a class
|
--- Set tracing for a class
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #string Class
|
-- @param #string Class Class name.
|
||||||
function BASE:TraceClass( Class )
|
function BASE:TraceClass( Class )
|
||||||
_TraceClass[Class] = true
|
_TraceClass[Class] = true
|
||||||
_TraceClassMethod[Class] = {}
|
_TraceClassMethod[Class] = {}
|
||||||
@@ -1070,8 +1132,8 @@ end
|
|||||||
|
|
||||||
--- Set tracing for a specific method of class
|
--- Set tracing for a specific method of class
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #string Class
|
-- @param #string Class Class name.
|
||||||
-- @param #string Method
|
-- @param #string Method Method.
|
||||||
function BASE:TraceClassMethod( Class, Method )
|
function BASE:TraceClassMethod( Class, Method )
|
||||||
if not _TraceClassMethod[Class] then
|
if not _TraceClassMethod[Class] then
|
||||||
_TraceClassMethod[Class] = {}
|
_TraceClassMethod[Class] = {}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
--- **Core** - TACAN and other beacons.
|
--- **Core** - TACAN and other beacons.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Provide beacon functionality to assist pilots.
|
-- * Provide beacon functionality to assist pilots.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -14,34 +14,34 @@
|
|||||||
-- @image Core_Radio.JPG
|
-- @image Core_Radio.JPG
|
||||||
|
|
||||||
--- *In order for the light to shine so brightly, the darkness must be present.* -- Francis Bacon
|
--- *In order for the light to shine so brightly, the darkness must be present.* -- Francis Bacon
|
||||||
--
|
--
|
||||||
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
||||||
-- There are two types of BEACONs available : the AA TACAN Beacon and the general purpose Radio Beacon.
|
-- There are two types of BEACONs available : the (aircraft) TACAN Beacon and the general purpose Radio Beacon.
|
||||||
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is
|
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very useful to simulate the battery time if your BEACON is
|
||||||
-- attach to a cargo crate, for exemple.
|
-- attach to a cargo crate, for example.
|
||||||
--
|
--
|
||||||
-- ## AA TACAN Beacon usage
|
-- ## Aircraft TACAN Beacon usage
|
||||||
--
|
--
|
||||||
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON:AATACAN}() to set the beacon parameters and start the beacon.
|
-- This beacon only works with airborne @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}. Use @{#BEACON.ActivateTACAN}() to set the beacon parameters and start the beacon.
|
||||||
-- Use @#BEACON:StopAATACAN}() to stop it.
|
-- Use @{#BEACON.StopRadioBeacon}() to stop it.
|
||||||
--
|
--
|
||||||
-- ## General Purpose Radio Beacon usage
|
-- ## General Purpose Radio Beacon usage
|
||||||
--
|
--
|
||||||
-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with
|
-- This beacon will work with any @{Wrapper.Positionable#POSITIONABLE}, but **it won't follow the @{Wrapper.Positionable#POSITIONABLE}** ! This means that you should only use it with
|
||||||
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON:RadioBeacon}() to set the beacon parameters and start the beacon.
|
-- @{Wrapper.Positionable#POSITIONABLE} that don't move, or move very slowly. Use @{#BEACON.RadioBeacon}() to set the beacon parameters and start the beacon.
|
||||||
-- Use @{#BEACON:StopRadioBeacon}() to stop it.
|
-- Use @{#BEACON.StopRadioBeacon}() to stop it.
|
||||||
--
|
--
|
||||||
-- @type BEACON
|
-- @type BEACON
|
||||||
-- @field #string ClassName Name of the class "BEACON".
|
-- @field #string ClassName Name of the class "BEACON".
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will receive radio capabilities.
|
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{Wrapper.Controllable#CONTROLLABLE} that will receive radio capabilities.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
BEACON = {
|
BEACON = {
|
||||||
ClassName = "BEACON",
|
ClassName = "BEACON",
|
||||||
Positionable = nil,
|
Positionable = nil,
|
||||||
name = nil,
|
name = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Beacon types supported by DCS.
|
--- Beacon types supported by DCS.
|
||||||
-- @type BEACON.Type
|
-- @type BEACON.Type
|
||||||
-- @field #number NULL
|
-- @field #number NULL
|
||||||
-- @field #number VOR
|
-- @field #number VOR
|
||||||
@@ -65,12 +65,12 @@ BEACON = {
|
|||||||
-- @field #number ICLS_GLIDESLOPE
|
-- @field #number ICLS_GLIDESLOPE
|
||||||
-- @field #number NAUTICAL_HOMER
|
-- @field #number NAUTICAL_HOMER
|
||||||
BEACON.Type={
|
BEACON.Type={
|
||||||
NULL = 0,
|
NULL = 0,
|
||||||
VOR = 1,
|
VOR = 1,
|
||||||
DME = 2,
|
DME = 2,
|
||||||
VOR_DME = 3,
|
VOR_DME = 3,
|
||||||
TACAN = 4,
|
TACAN = 4,
|
||||||
VORTAC = 5,
|
VORTAC = 5,
|
||||||
RSBN = 128,
|
RSBN = 128,
|
||||||
BROADCAST_STATION = 1024,
|
BROADCAST_STATION = 1024,
|
||||||
HOMER = 8,
|
HOMER = 8,
|
||||||
@@ -95,13 +95,13 @@ BEACON.Type={
|
|||||||
-- @field #number TACAN TACtical Air Navigation system on ground.
|
-- @field #number TACAN TACtical Air Navigation system on ground.
|
||||||
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
-- @field #number TACAN_TANKER_X TACtical Air Navigation system for tankers on X band.
|
||||||
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
-- @field #number TACAN_TANKER_Y TACtical Air Navigation system for tankers on Y band.
|
||||||
-- @field #number VOR Very High Frequency Omnidirectional Range
|
-- @field #number VOR Very High Frequency Omni-Directional Range
|
||||||
-- @field #number ILS_LOCALIZER ILS localizer
|
-- @field #number ILS_LOCALIZER ILS localizer
|
||||||
-- @field #number ILS_GLIDESLOPE ILS glide slope.
|
-- @field #number ILS_GLIDESLOPE ILS glide slope.
|
||||||
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
-- @field #number PRGM_LOCALIZER PRGM localizer.
|
||||||
-- @field #number PRGM_GLIDESLOPE PRGM glide slope.
|
-- @field #number PRGM_GLIDESLOPE PRGM glide slope.
|
||||||
-- @field #number BROADCAST_STATION Broadcast station.
|
-- @field #number BROADCAST_STATION Broadcast station.
|
||||||
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omnidirectional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
-- @field #number VORTAC Radio-based navigational aid for aircraft pilots consisting of a co-located VHF omni-directional range (VOR) beacon and a tactical air navigation system (TACAN) beacon.
|
||||||
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
-- @field #number TACAN_AA_MODE_X TACtical Air Navigation for aircraft on X band.
|
||||||
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
|
-- @field #number TACAN_AA_MODE_Y TACtical Air Navigation for aircraft on Y band.
|
||||||
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
|
-- @field #number VORDME Radio beacon that combines a VHF omnidirectional range (VOR) with a distance measuring equipment (DME).
|
||||||
@@ -130,25 +130,25 @@ BEACON.System={
|
|||||||
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.ActivateTACAN} etc.
|
--- Create a new BEACON Object. This doesn't activate the beacon, though, use @{#BEACON.ActivateTACAN} etc.
|
||||||
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
-- If you want to create a BEACON, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetBeacon}() instead.
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Wrapper.Positionable} that will receive radio capabilities.
|
||||||
-- @return #BEACON Beacon object or #nil if the POSITIONABLE is invalid.
|
-- @return #BEACON Beacon object or #nil if the positionable is invalid.
|
||||||
function BEACON:New( Positionable )
|
function BEACON:New(Positionable)
|
||||||
|
|
||||||
-- Inherit BASE.
|
-- Inherit BASE.
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #BEACON
|
local self=BASE:Inherit(self, BASE:New()) --#BEACON
|
||||||
|
|
||||||
-- Debug.
|
-- Debug.
|
||||||
self:F( Positionable )
|
self:F(Positionable)
|
||||||
|
|
||||||
-- Set positionable.
|
-- Set positionable.
|
||||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure POSITIONABLE is valid
|
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
||||||
self.Positionable = Positionable
|
self.Positionable = Positionable
|
||||||
self.name = Positionable:GetName()
|
self.name=Positionable:GetName()
|
||||||
self:I( string.format( "New BEACON %s", tostring( self.name ) ) )
|
self:I(string.format("New BEACON %s", tostring(self.name)))
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E( { "The passed POSITIONABLE is invalid, no BEACON created", Positionable } )
|
self:E({"The passed positionable is invalid, no BEACON created", Positionable})
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -161,53 +161,58 @@ end
|
|||||||
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
|
||||||
-- -- Let's create a TACAN Beacon for a tanker
|
-- -- Let's create a TACAN Beacon for a tanker
|
||||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||||
--
|
--
|
||||||
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
|
-- myBeacon:ActivateTACAN(20, "Y", "TEXACO", true) -- Activate the beacon
|
||||||
--
|
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||||
function BEACON:ActivateTACAN( Channel, Mode, Message, Bearing, Duration )
|
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
|
||||||
self:T( { channel = Channel, mode = Mode, callsign = Message, bearing = Bearing, duration = Duration } )
|
|
||||||
|
Mode=Mode or "Y"
|
||||||
|
|
||||||
-- Get frequency.
|
-- Get frequency.
|
||||||
local Frequency = UTILS.TACANToFrequency( Channel, Mode )
|
local Frequency=UTILS.TACANToFrequency(Channel, Mode)
|
||||||
|
|
||||||
-- Check.
|
-- Check.
|
||||||
if not Frequency then
|
if not Frequency then
|
||||||
self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
|
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Beacon type.
|
-- Beacon type.
|
||||||
local Type = BEACON.Type.TACAN
|
local Type=BEACON.Type.TACAN
|
||||||
|
|
||||||
-- Beacon system.
|
-- Beacon system.
|
||||||
local System = BEACON.System.TACAN
|
local System=BEACON.System.TACAN
|
||||||
|
|
||||||
-- Check if unit is an aircraft and set system accordingly.
|
-- Check if unit is an aircraft and set system accordingly.
|
||||||
local AA = self.Positionable:IsAir()
|
local AA=self.Positionable:IsAir()
|
||||||
|
|
||||||
|
|
||||||
if AA then
|
if AA then
|
||||||
System = 5 -- NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||||
-- Check if "Y" mode is selected for aircraft.
|
-- Check if "Y" mode is selected for aircraft.
|
||||||
if Mode ~= "Y" then
|
if Mode=="X" then
|
||||||
self:E( { "WARNING: The POSITIONABLE you want to attach the AA TACAN Beacon is an aircraft: Mode should Y! The BEACON is not emitting.", self.Positionable } )
|
--self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y!", self.Positionable})
|
||||||
|
System=BEACON.System.TACAN_TANKER_X
|
||||||
|
else
|
||||||
|
System=BEACON.System.TACAN_TANKER_Y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Attached unit.
|
-- Attached unit.
|
||||||
local UnitID = self.Positionable:GetID()
|
local UnitID=self.Positionable:GetID()
|
||||||
|
|
||||||
-- Debug.
|
-- Debug.
|
||||||
self:I( { string.format( "BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring( self.name ), Channel, Mode, Message, tostring( Bearing ), tostring( Duration ) ) } )
|
self:I({string.format("BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring(self.name), Channel, Mode, Message, tostring(Bearing), tostring(Duration))})
|
||||||
|
|
||||||
-- Start beacon.
|
-- Start beacon.
|
||||||
self.Positionable:CommandActivateBeacon( Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing )
|
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing)
|
||||||
|
|
||||||
-- Stop scheduler.
|
-- Stop scheduler.
|
||||||
if Duration then
|
if Duration then
|
||||||
self.Positionable:DeactivateBeacon( Duration )
|
self.Positionable:DeactivateBeacon(Duration)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -219,27 +224,54 @@ end
|
|||||||
-- @param #string Callsign The Message that is going to be coded in Morse and broadcasted by the beacon.
|
-- @param #string Callsign The Message that is going to be coded in Morse and broadcasted by the beacon.
|
||||||
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
function BEACON:ActivateICLS( Channel, Callsign, Duration )
|
function BEACON:ActivateICLS(Channel, Callsign, Duration)
|
||||||
self:F( { Channel = Channel, Callsign = Callsign, Duration = Duration } )
|
self:F({Channel=Channel, Callsign=Callsign, Duration=Duration})
|
||||||
|
|
||||||
-- Attached unit.
|
-- Attached unit.
|
||||||
local UnitID = self.Positionable:GetID()
|
local UnitID=self.Positionable:GetID()
|
||||||
|
|
||||||
-- Debug
|
-- Debug
|
||||||
self:T2( { "ICLS BEACON started!" } )
|
self:T2({"ICLS BEACON started!"})
|
||||||
|
|
||||||
-- Start beacon.
|
-- Start beacon.
|
||||||
self.Positionable:CommandActivateICLS( Channel, UnitID, Callsign )
|
self.Positionable:CommandActivateICLS(Channel, UnitID, Callsign)
|
||||||
|
|
||||||
-- Stop scheduler
|
-- Stop scheduler
|
||||||
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
self.Positionable:DeactivateBeacon( Duration )
|
self.Positionable:DeactivateBeacon(Duration)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Activates a TACAN BEACON on an Aircraft.
|
--- Activates a LINK4 BEACON. The unit the BEACON is attached to should be an aircraft carrier supporting this system.
|
||||||
|
-- @param #BEACON self
|
||||||
|
-- @param #number Frequency LINK4 FRequency in MHz, eg 336.
|
||||||
|
-- @param #string Morse The ID that is going to be coded in Morse and broadcasted by the beacon.
|
||||||
|
-- @param #number Duration How long will the beacon last in seconds. Omit for forever.
|
||||||
|
-- @return #BEACON self
|
||||||
|
function BEACON:ActivateLink4(Frequency, Morse, Duration)
|
||||||
|
self:F({Frequency=Frequency, Morse=Morse, Duration=Duration})
|
||||||
|
|
||||||
|
-- Attached unit.
|
||||||
|
local UnitID=self.Positionable:GetID()
|
||||||
|
|
||||||
|
-- Debug
|
||||||
|
self:T2({"LINK4 BEACON started!"})
|
||||||
|
|
||||||
|
-- Start beacon.
|
||||||
|
self.Positionable:CommandActivateLink4(Frequency,UnitID,Morse)
|
||||||
|
|
||||||
|
-- Stop sheduler
|
||||||
|
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
|
self.Positionable:CommandDeactivateLink4(Duration)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- DEPRECATED: Please use @{#BEACON.ActivateTACAN}() instead.
|
||||||
|
-- Activates a TACAN BEACON on an Aircraft.
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param #number TACANChannel (the "10" part in "10Y"). Note that AA TACAN are only available on Y Channels
|
-- @param #number TACANChannel (the "10" part in "10Y"). Note that AA TACAN are only available on Y Channels
|
||||||
-- @param #string Message The Message that is going to be coded in Morse and broadcasted by the beacon
|
-- @param #string Message The Message that is going to be coded in Morse and broadcasted by the beacon
|
||||||
@@ -247,54 +279,55 @@ end
|
|||||||
-- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever.
|
-- @param #number BeaconDuration How long will the beacon last in seconds. Omit for forever.
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
|
||||||
-- -- Let's create a TACAN Beacon for a tanker
|
-- -- Let's create a TACAN Beacon for a tanker
|
||||||
-- local myUnit = UNIT:FindByName("MyUnit")
|
-- local myUnit = UNIT:FindByName("MyUnit")
|
||||||
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
-- local myBeacon = myUnit:GetBeacon() -- Creates the beacon
|
||||||
--
|
--
|
||||||
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
-- myBeacon:AATACAN(20, "TEXACO", true) -- Activate the beacon
|
||||||
--
|
function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||||
function BEACON:AATACAN( TACANChannel, Message, Bearing, BeaconDuration )
|
self:F({TACANChannel, Message, Bearing, BeaconDuration})
|
||||||
self:F( { TACANChannel, Message, Bearing, BeaconDuration } )
|
|
||||||
|
|
||||||
local IsValid = true
|
local IsValid = true
|
||||||
|
|
||||||
if not self.Positionable:IsAir() then
|
if not self.Positionable:IsAir() then
|
||||||
self:E( { "The POSITIONABLE you want to attach the AA TACAN Beacon is not an aircraft! The BEACON is not emitting", self.Positionable } )
|
self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting", self.Positionable})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
local Frequency = self:_TACANToFrequency( TACANChannel, "Y" )
|
local Frequency = self:_TACANToFrequency(TACANChannel, "Y")
|
||||||
if not Frequency then
|
if not Frequency then
|
||||||
self:E( { "The passed TACAN channel is invalid, the BEACON is not emitting" } )
|
self:E({"The passed TACAN channel is invalid, the BEACON is not emitting"})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing
|
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing or 14 (TACAN_AA_MODE_Y) if it does not
|
||||||
-- or 14 (TACAN_AA_MODE_Y) if it does not
|
|
||||||
local System
|
local System
|
||||||
if Bearing then
|
if Bearing then
|
||||||
System = 5
|
System = BEACON.System.TACAN_TANKER_Y
|
||||||
else
|
else
|
||||||
System = 14
|
System = BEACON.System.TACAN_AA_MODE_Y
|
||||||
end
|
end
|
||||||
|
|
||||||
if IsValid then -- Starts the BEACON
|
if IsValid then -- Starts the BEACON
|
||||||
self:T2( { "AA TACAN BEACON started !" } )
|
self:T2({"AA TACAN BEACON started !"})
|
||||||
self.Positionable:SetCommand( {
|
self.Positionable:SetCommand({
|
||||||
id = "ActivateBeacon",
|
id = "ActivateBeacon",
|
||||||
params = {
|
params = {
|
||||||
type = 4,
|
type = BEACON.Type.TACAN,
|
||||||
system = System,
|
system = System,
|
||||||
callsign = Message,
|
callsign = Message,
|
||||||
|
AA = true,
|
||||||
frequency = Frequency,
|
frequency = Frequency,
|
||||||
},
|
bearing = Bearing,
|
||||||
} )
|
modeChannel = "Y",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
SCHEDULER:New( nil, function()
|
SCHEDULER:New(nil,
|
||||||
|
function()
|
||||||
self:StopAATACAN()
|
self:StopAATACAN()
|
||||||
end, {}, BeaconDuration )
|
end, {}, BeaconDuration)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -307,19 +340,20 @@ end
|
|||||||
function BEACON:StopAATACAN()
|
function BEACON:StopAATACAN()
|
||||||
self:F()
|
self:F()
|
||||||
if not self.Positionable then
|
if not self.Positionable then
|
||||||
self:E( { "Start the beacon first before stopping it!" } )
|
self:E({"Start the beacon first before stoping it !"})
|
||||||
else
|
else
|
||||||
self.Positionable:SetCommand( {
|
self.Positionable:SetCommand({
|
||||||
id = 'DeactivateBeacon',
|
id = 'DeactivateBeacon',
|
||||||
params = {},
|
params = {
|
||||||
} )
|
}
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Activates a general purpose Radio Beacon
|
--- Activates a general purpose Radio Beacon
|
||||||
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
|
-- This uses the very generic singleton function "trigger.action.radioTransmission()" provided by DCS to broadcast a sound file on a specific frequency.
|
||||||
-- Although any frequency could be used, only 2 DCS Modules can home on radio beacons at the time of writing : the Huey and the Mi-8.
|
-- Although any frequency could be used, only a few DCS Modules can home on radio beacons at the time of writing, i.e. the Mi-8, Huey, Gazelle etc.
|
||||||
-- They can home in on these specific frequencies :
|
-- The following e.g. can home in on these specific frequencies :
|
||||||
-- * **Mi8**
|
-- * **Mi8**
|
||||||
-- * R-828 -> 20-60MHz
|
-- * R-828 -> 20-60MHz
|
||||||
-- * ARKUD -> 100-150MHz (canal 1 : 114166, canal 2 : 114333, canal 3 : 114583, canal 4 : 121500, canal 5 : 123100, canal 6 : 124100) AM
|
-- * ARKUD -> 100-150MHz (canal 1 : 114166, canal 2 : 114333, canal 3 : 114583, canal 4 : 121500, canal 5 : 123100, canal 6 : 124100) AM
|
||||||
@@ -342,63 +376,64 @@ end
|
|||||||
--
|
--
|
||||||
-- -- Set the beacon and start it
|
-- -- Set the beacon and start it
|
||||||
-- UnitBeacon:RadioBeacon("MySoundFileSOS.ogg", 40, radio.modulation.FM, 20, 5*60)
|
-- UnitBeacon:RadioBeacon("MySoundFileSOS.ogg", 40, radio.modulation.FM, 20, 5*60)
|
||||||
function BEACON:RadioBeacon( FileName, Frequency, Modulation, Power, BeaconDuration )
|
function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDuration)
|
||||||
self:F( { FileName, Frequency, Modulation, Power, BeaconDuration } )
|
self:F({FileName, Frequency, Modulation, Power, BeaconDuration})
|
||||||
local IsValid = false
|
local IsValid = false
|
||||||
|
|
||||||
-- Check the filename
|
-- Check the filename
|
||||||
if type( FileName ) == "string" then
|
if type(FileName) == "string" then
|
||||||
if FileName:find( ".ogg" ) or FileName:find( ".wav" ) then
|
if FileName:find(".ogg") or FileName:find(".wav") then
|
||||||
if not FileName:find( "l10n/DEFAULT/" ) then
|
if not FileName:find("l10n/DEFAULT/") then
|
||||||
FileName = "l10n/DEFAULT/" .. FileName
|
FileName = "l10n/DEFAULT/" .. FileName
|
||||||
end
|
end
|
||||||
IsValid = true
|
IsValid = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not IsValid then
|
if not IsValid then
|
||||||
self:E( { "File name invalid. Maybe something wrong with the extension? ", FileName } )
|
self:E({"File name invalid. Maybe something wrong with the extension ? ", FileName})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check the Frequency
|
-- Check the Frequency
|
||||||
if type( Frequency ) ~= "number" and IsValid then
|
if type(Frequency) ~= "number" and IsValid then
|
||||||
self:E( { "Frequency invalid. ", Frequency } )
|
self:E({"Frequency invalid. ", Frequency})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
Frequency = Frequency * 1000000 -- Conversion to Hz
|
Frequency = Frequency * 1000000 -- Conversion to Hz
|
||||||
|
|
||||||
-- Check the modulation
|
-- Check the modulation
|
||||||
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then -- TODO: Maybe make this future proof if ED decides to add an other modulation ?
|
if Modulation ~= radio.modulation.AM and Modulation ~= radio.modulation.FM and IsValid then --TODO Maybe make this future proof if ED decides to add an other modulation ?
|
||||||
self:E( { "Modulation is invalid. Use DCS's enum radio.modulation.", Modulation } )
|
self:E({"Modulation is invalid. Use DCS's enum radio.modulation.", Modulation})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check the Power
|
-- Check the Power
|
||||||
if type( Power ) ~= "number" and IsValid then
|
if type(Power) ~= "number" and IsValid then
|
||||||
self:E( { "Power is invalid. ", Power } )
|
self:E({"Power is invalid. ", Power})
|
||||||
IsValid = false
|
IsValid = false
|
||||||
end
|
end
|
||||||
Power = math.floor( math.abs( Power ) ) -- TODO: Find what is the maximum power allowed by DCS and limit power to that
|
Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
|
||||||
|
|
||||||
if IsValid then
|
if IsValid then
|
||||||
self:T2( { "Activating Beacon on ", Frequency, Modulation } )
|
self:T2({"Activating Beacon on ", Frequency, Modulation})
|
||||||
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
|
-- Note that this is looped. I have to give this transmission a unique name, I use the class ID
|
||||||
trigger.action.radioTransmission( FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring( self.ID ) )
|
trigger.action.radioTransmission(FileName, self.Positionable:GetPositionVec3(), Modulation, true, Frequency, Power, tostring(self.ID))
|
||||||
|
|
||||||
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
if BeaconDuration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
SCHEDULER:New( nil, function()
|
SCHEDULER:New( nil,
|
||||||
self:StopRadioBeacon()
|
function()
|
||||||
end, {}, BeaconDuration )
|
self:StopRadioBeacon()
|
||||||
end
|
end, {}, BeaconDuration)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stops the AA TACAN BEACON
|
--- Stops the Radio Beacon
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
function BEACON:StopRadioBeacon()
|
function BEACON:StopRadioBeacon()
|
||||||
self:F()
|
self:F()
|
||||||
-- The unique name of the transmission is the class ID
|
-- The unique name of the transmission is the class ID
|
||||||
trigger.action.stopRadioTransmission( tostring( self.ID ) )
|
trigger.action.stopRadioTransmission(tostring(self.ID))
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -406,21 +441,21 @@ end
|
|||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @param #number TACANChannel
|
-- @param #number TACANChannel
|
||||||
-- @param #string TACANMode
|
-- @param #string TACANMode
|
||||||
-- @return #number Frequency
|
-- @return #number Frequecy
|
||||||
-- @return #nil if parameters are invalid
|
-- @return #nil if parameters are invalid
|
||||||
function BEACON:_TACANToFrequency( TACANChannel, TACANMode )
|
function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
|
||||||
self:F3( { TACANChannel, TACANMode } )
|
self:F3({TACANChannel, TACANMode})
|
||||||
|
|
||||||
if type( TACANChannel ) ~= "number" then
|
if type(TACANChannel) ~= "number" then
|
||||||
if TACANMode ~= "X" and TACANMode ~= "Y" then
|
if TACANMode ~= "X" and TACANMode ~= "Y" then
|
||||||
return nil -- error in arguments
|
return nil -- error in arguments
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
-- This code is largely based on ED's code, in DCS World\Scripts\World\Radio\BeaconTypes.lua, line 137.
|
||||||
-- I have no idea what it does but it seems to work
|
-- I have no idea what it does but it seems to work
|
||||||
local A = 1151 -- 'X', channel >= 64
|
local A = 1151 -- 'X', channel >= 64
|
||||||
local B = 64 -- channel >= 64
|
local B = 64 -- channel >= 64
|
||||||
|
|
||||||
if TACANChannel < 64 then
|
if TACANChannel < 64 then
|
||||||
B = 1
|
B = 1
|
||||||
|
|||||||
295
Moose Development/Moose/Core/Condition.lua
Normal file
295
Moose Development/Moose/Core/Condition.lua
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
--- **Core** - Define any or all conditions to be evaluated.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Add arbitrary numbers of conditon functions
|
||||||
|
-- * Evaluate *any* or *all* conditions
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Operation).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Core.Condition
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- CONDITON class.
|
||||||
|
-- @type CONDITION
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #boolean isAny General functions are evaluated as any condition.
|
||||||
|
-- @field #boolean negateResult Negeate result of evaluation.
|
||||||
|
-- @field #table functionsGen General condition functions.
|
||||||
|
-- @field #table functionsAny Any condition functions.
|
||||||
|
-- @field #table functionsAll All condition functions.
|
||||||
|
--
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *Better three hours too soon than a minute too late.* - William Shakespeare
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The CONDITION Concept
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #CONDITION
|
||||||
|
CONDITION = {
|
||||||
|
ClassName = "CONDITION",
|
||||||
|
lid = nil,
|
||||||
|
functionsGen = {},
|
||||||
|
functionsAny = {},
|
||||||
|
functionsAll = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Condition function.
|
||||||
|
-- @type CONDITION.Function
|
||||||
|
-- @field #function func Callback function to check for a condition. Should return a `#boolean`.
|
||||||
|
-- @field #table arg (Optional) Arguments passed to the condition callback function if any.
|
||||||
|
|
||||||
|
--- CONDITION class version.
|
||||||
|
-- @field #string version
|
||||||
|
CONDITION.version="0.1.0"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: Make FSM.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new CONDITION object.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #string Name (Optional) Name used in the logs.
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:New(Name)
|
||||||
|
|
||||||
|
-- Inherit BASE.
|
||||||
|
local self=BASE:Inherit(self, BASE:New()) --#CONDITION
|
||||||
|
|
||||||
|
self.name=Name or "Condition X"
|
||||||
|
|
||||||
|
self.lid=string.format("%s | ", self.name)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set that general condition functions return `true` if `any` function returns `true`. Default is that *all* functions must return `true`.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #boolean Any If `true`, *any* condition can be true. Else *all* conditions must result `true`.
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:SetAny(Any)
|
||||||
|
self.isAny=Any
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Negate result.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #boolean Negate If `true`, result is negated else not.
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:SetNegateResult(Negate)
|
||||||
|
self.negateResult=Negate
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
--
|
||||||
|
-- @usage
|
||||||
|
-- local function isAequalB(a, b)
|
||||||
|
-- return a==b
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- myCondition:AddFunction(isAequalB, a, b)
|
||||||
|
--
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:AddFunction(Function, ...)
|
||||||
|
|
||||||
|
-- Condition function.
|
||||||
|
local condition=self:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
-- Add to table.
|
||||||
|
table.insert(self.functionsGen, condition)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:AddFunctionAny(Function, ...)
|
||||||
|
|
||||||
|
-- Condition function.
|
||||||
|
local condition=self:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
-- Add to table.
|
||||||
|
table.insert(self.functionsAny, condition)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:AddFunctionAll(Function, ...)
|
||||||
|
|
||||||
|
-- Condition function.
|
||||||
|
local condition=self:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
-- Add to table.
|
||||||
|
table.insert(self.functionsAll, condition)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Evaluate conditon functions.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #boolean AnyTrue If `true`, evaluation return `true` if *any* condition function returns `true`. By default, *all* condition functions must return true.
|
||||||
|
-- @return #boolean Result of condition functions.
|
||||||
|
function CONDITION:Evaluate(AnyTrue)
|
||||||
|
|
||||||
|
-- Check if at least one function was given.
|
||||||
|
if #self.functionsAll + #self.functionsAny + #self.functionsAll == 0 then
|
||||||
|
if self.negateResult then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Any condition for gen.
|
||||||
|
local evalAny=self.isAny
|
||||||
|
if AnyTrue~=nil then
|
||||||
|
evalAny=AnyTrue
|
||||||
|
end
|
||||||
|
|
||||||
|
local isGen=nil
|
||||||
|
if evalAny then
|
||||||
|
isGen=self:_EvalConditionsAny(self.functionsGen)
|
||||||
|
else
|
||||||
|
isGen=self:_EvalConditionsAll(self.functionsGen)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Is any?
|
||||||
|
local isAny=self:_EvalConditionsAny(self.functionsAny)
|
||||||
|
|
||||||
|
-- Is all?
|
||||||
|
local isAll=self:_EvalConditionsAll(self.functionsAll)
|
||||||
|
|
||||||
|
-- Result.
|
||||||
|
local result=isGen and isAny and isAll
|
||||||
|
|
||||||
|
-- Negate result.
|
||||||
|
if self.negateResult then
|
||||||
|
result=not result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
self:T(self.lid..string.format("Evaluate: isGen=%s, isAny=%s, isAll=%s (negate=%s) ==> result=%s", tostring(isGen), tostring(isAny), tostring(isAll), tostring(self.negateResult), tostring(result)))
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if all given condition are true.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #table functions Functions to evaluate.
|
||||||
|
-- @return #boolean If true, all conditions were true (or functions was empty/nil). Returns false if at least one condition returned false.
|
||||||
|
function CONDITION:_EvalConditionsAll(functions)
|
||||||
|
|
||||||
|
-- At least one condition?
|
||||||
|
local gotone=false
|
||||||
|
|
||||||
|
|
||||||
|
-- Any stop condition must be true.
|
||||||
|
for _,_condition in pairs(functions or {}) do
|
||||||
|
local condition=_condition --#CONDITION.Function
|
||||||
|
|
||||||
|
-- At least one condition was defined.
|
||||||
|
gotone=true
|
||||||
|
|
||||||
|
-- Call function.
|
||||||
|
local istrue=condition.func(unpack(condition.arg))
|
||||||
|
|
||||||
|
-- Any false will return false.
|
||||||
|
if not istrue then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- All conditions were true.
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if any of the given conditions is true.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #table functions Functions to evaluate.
|
||||||
|
-- @return #boolean If true, at least one condition is true (or functions was emtpy/nil).
|
||||||
|
function CONDITION:_EvalConditionsAny(functions)
|
||||||
|
|
||||||
|
-- At least one condition?
|
||||||
|
local gotone=false
|
||||||
|
|
||||||
|
-- Any stop condition must be true.
|
||||||
|
for _,_condition in pairs(functions or {}) do
|
||||||
|
local condition=_condition --#CONDITION.Function
|
||||||
|
|
||||||
|
-- At least one condition was defined.
|
||||||
|
gotone=true
|
||||||
|
|
||||||
|
-- Call function.
|
||||||
|
local istrue=condition.func(unpack(condition.arg))
|
||||||
|
|
||||||
|
-- Any true will return true.
|
||||||
|
if istrue then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- No condition was true.
|
||||||
|
if gotone then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
-- No functions passed.
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create conditon function object.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
-- @return #CONDITION.Function Condition function.
|
||||||
|
function CONDITION:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
local condition={} --#CONDITION.Function
|
||||||
|
|
||||||
|
condition.func=Function
|
||||||
|
condition.arg={}
|
||||||
|
if arg then
|
||||||
|
condition.arg=arg
|
||||||
|
end
|
||||||
|
|
||||||
|
return condition
|
||||||
|
end
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@
|
|||||||
-- There are 5 types/levels of objects that the _EVENTDISPATCHER services:
|
-- There are 5 types/levels of objects that the _EVENTDISPATCHER services:
|
||||||
--
|
--
|
||||||
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
|
-- * _DATABASE object: The core of the MOOSE objects. Any object that is created, deleted or updated, is done in this database.
|
||||||
-- * SET_ derived classes: These are subsets of the _DATABASE object. These subsets are updated by the _EVENTDISPATCHER as the second priority.
|
-- * SET_ derived classes: These are subsets of the global _DATABASE object (an instance of @{Core.Database#DATABASE}). These subsets are updated by the _EVENTDISPATCHER as the second priority.
|
||||||
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed UNIT object.
|
-- * UNIT objects: UNIT objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed UNIT object.
|
||||||
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
|
-- * GROUP objects: GROUP objects can subscribe to DCS events. Each DCS event will be directly published to the subscribed GROUP object.
|
||||||
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
|
-- * Any other object: Various other objects can subscribe to DCS events. Each DCS event triggered will be published to each subscribed object.
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{BASE} class, @{UNIT} class and @{GROUP} class.
|
-- The actual event subscribing and handling is not facilitated through the _EVENTDISPATCHER, but it is done through the @{Core.Base#BASE} class, @{Wrapper.Unit#UNIT} class and @{Wrapper.Group#GROUP} class.
|
||||||
-- The _EVENTDISPATCHER is a component that is quietly working in the background of MOOSE.
|
-- The _EVENTDISPATCHER is a component that is quietly working in the background of MOOSE.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -131,8 +131,6 @@
|
|||||||
-- * Weapon data: Certain events populate weapon information.
|
-- * Weapon data: Certain events populate weapon information.
|
||||||
-- * Place data: Certain events populate place information.
|
-- * Place data: Certain events populate place information.
|
||||||
--
|
--
|
||||||
-- Example code snippet:
|
|
||||||
--
|
|
||||||
-- --- This function is an Event Handling function that will be called when Tank1 is Dead.
|
-- --- This function is an Event Handling function that will be called when Tank1 is Dead.
|
||||||
-- -- EventData is an EVENTDATA structure.
|
-- -- EventData is an EVENTDATA structure.
|
||||||
-- -- We use the EventData.IniUnit to smoke the tank Green.
|
-- -- We use the EventData.IniUnit to smoke the tank Green.
|
||||||
@@ -143,6 +141,7 @@
|
|||||||
-- EventData.IniUnit:SmokeGreen()
|
-- EventData.IniUnit:SmokeGreen()
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
|
--
|
||||||
-- Find below an overview which events populate which information categories:
|
-- Find below an overview which events populate which information categories:
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
@@ -152,7 +151,6 @@
|
|||||||
-- In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated.
|
-- In case a STATIC object is involved, the documentation indicates which fields will and won't not be populated.
|
||||||
-- The fields **IniObjectCategory** and **TgtObjectCategory** contain the indicator which **kind of object is involved** in the event.
|
-- The fields **IniObjectCategory** and **TgtObjectCategory** contain the indicator which **kind of object is involved** in the event.
|
||||||
-- You can use the enumerator **Object.Category.UNIT** and **Object.Category.STATIC** to check on IniObjectCategory and TgtObjectCategory.
|
-- You can use the enumerator **Object.Category.UNIT** and **Object.Category.STATIC** to check on IniObjectCategory and TgtObjectCategory.
|
||||||
--
|
|
||||||
-- Example code snippet:
|
-- Example code snippet:
|
||||||
--
|
--
|
||||||
-- if Event.IniObjectCategory == Object.Category.UNIT then
|
-- if Event.IniObjectCategory == Object.Category.UNIT then
|
||||||
@@ -174,6 +172,7 @@
|
|||||||
-- @module Core.Event
|
-- @module Core.Event
|
||||||
-- @image Core_Event.JPG
|
-- @image Core_Event.JPG
|
||||||
|
|
||||||
|
|
||||||
--- @type EVENT
|
--- @type EVENT
|
||||||
-- @field #EVENT.Events Events
|
-- @field #EVENT.Events Events
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
@@ -195,6 +194,7 @@ world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
|||||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
||||||
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
|
world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT = world.event.S_EVENT_MAX + 1007
|
||||||
|
|
||||||
|
|
||||||
--- The different types of events supported by MOOSE.
|
--- The different types of events supported by MOOSE.
|
||||||
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
|
-- Use this structure to subscribe to events using the @{Core.Base#BASE.HandleEvent}() method.
|
||||||
-- @type EVENTS
|
-- @type EVENTS
|
||||||
@@ -227,13 +227,13 @@ EVENTS = {
|
|||||||
MarkChange = world.event.S_EVENT_MARK_CHANGE,
|
MarkChange = world.event.S_EVENT_MARK_CHANGE,
|
||||||
MarkRemoved = world.event.S_EVENT_MARK_REMOVED,
|
MarkRemoved = world.event.S_EVENT_MARK_REMOVED,
|
||||||
-- Moose Events
|
-- Moose Events
|
||||||
NewCargo = world.event.S_EVENT_NEW_CARGO,
|
NewCargo = world.event.S_EVENT_NEW_CARGO,
|
||||||
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
||||||
NewZone = world.event.S_EVENT_NEW_ZONE,
|
NewZone = world.event.S_EVENT_NEW_ZONE,
|
||||||
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
|
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
|
||||||
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
||||||
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
||||||
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
||||||
PlayerEnterAircraft = world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT,
|
PlayerEnterAircraft = world.event.S_EVENT_PLAYER_ENTER_AIRCRAFT,
|
||||||
-- Added with DCS 2.5.6
|
-- Added with DCS 2.5.6
|
||||||
DetailedFailure = world.event.S_EVENT_DETAILED_FAILURE or -1, --We set this to -1 for backward compatibility to DCS 2.5.5 and earlier
|
DetailedFailure = world.event.S_EVENT_DETAILED_FAILURE or -1, --We set this to -1 for backward compatibility to DCS 2.5.5 and earlier
|
||||||
@@ -248,6 +248,18 @@ EVENTS = {
|
|||||||
TriggerZone = world.event.S_EVENT_TRIGGER_ZONE or -1,
|
TriggerZone = world.event.S_EVENT_TRIGGER_ZONE or -1,
|
||||||
LandingQualityMark = world.event.S_EVENT_LANDING_QUALITY_MARK or -1,
|
LandingQualityMark = world.event.S_EVENT_LANDING_QUALITY_MARK or -1,
|
||||||
BDA = world.event.S_EVENT_BDA or -1,
|
BDA = world.event.S_EVENT_BDA or -1,
|
||||||
|
-- Added with DCS 2.8.0
|
||||||
|
AIAbortMission = world.event.S_EVENT_AI_ABORT_MISSION or -1,
|
||||||
|
DayNight = world.event.S_EVENT_DAYNIGHT or -1,
|
||||||
|
FlightTime = world.event.S_EVENT_FLIGHT_TIME or -1,
|
||||||
|
SelfKillPilot = world.event.S_EVENT_PLAYER_SELF_KILL_PILOT or -1,
|
||||||
|
PlayerCaptureAirfield = world.event.S_EVENT_PLAYER_CAPTURE_AIRFIELD or -1,
|
||||||
|
EmergencyLanding = world.event.S_EVENT_EMERGENCY_LANDING or -1,
|
||||||
|
UnitCreateTask = world.event.S_EVENT_UNIT_CREATE_TASK or -1,
|
||||||
|
UnitDeleteTask = world.event.S_EVENT_UNIT_DELETE_TASK or -1,
|
||||||
|
SimulationStart = world.event.S_EVENT_SIMULATION_START or -1,
|
||||||
|
WeaponRearm = world.event.S_EVENT_WEAPON_REARM or -1,
|
||||||
|
WeaponDrop = world.event.S_EVENT_WEAPON_DROP or -1,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The Event structure
|
--- The Event structure
|
||||||
@@ -304,6 +316,8 @@ EVENTS = {
|
|||||||
-- @field Core.ZONE#ZONE Zone The zone object.
|
-- @field Core.ZONE#ZONE Zone The zone object.
|
||||||
-- @field #string ZoneName The name of the zone.
|
-- @field #string ZoneName The name of the zone.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local _EVENTMETA = {
|
local _EVENTMETA = {
|
||||||
[world.event.S_EVENT_SHOT] = {
|
[world.event.S_EVENT_SHOT] = {
|
||||||
Order = 1,
|
Order = 1,
|
||||||
@@ -558,6 +572,67 @@ local _EVENTMETA = {
|
|||||||
Event = "OnEventBDA",
|
Event = "OnEventBDA",
|
||||||
Text = "S_EVENT_BDA"
|
Text = "S_EVENT_BDA"
|
||||||
},
|
},
|
||||||
|
-- Added with DCS 2.8
|
||||||
|
[EVENTS.AIAbortMission] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventAIAbortMission",
|
||||||
|
Text = "S_EVENT_AI_ABORT_MISSION"
|
||||||
|
},
|
||||||
|
[EVENTS.DayNight] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventDayNight",
|
||||||
|
Text = "S_EVENT_DAYNIGHT"
|
||||||
|
},
|
||||||
|
[EVENTS.FlightTime] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventFlightTime",
|
||||||
|
Text = "S_EVENT_FLIGHT_TIME"
|
||||||
|
},
|
||||||
|
[EVENTS.SelfKillPilot] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventSelfKillPilot",
|
||||||
|
Text = "S_EVENT_PLAYER_SELF_KILL_PILOT"
|
||||||
|
},
|
||||||
|
[EVENTS.PlayerCaptureAirfield] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventPlayerCaptureAirfield",
|
||||||
|
Text = "S_EVENT_PLAYER_CAPTURE_AIRFIELD"
|
||||||
|
},
|
||||||
|
[EVENTS.EmergencyLanding] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventEmergencyLanding",
|
||||||
|
Text = "S_EVENT_EMERGENCY_LANDING"
|
||||||
|
},
|
||||||
|
[EVENTS.UnitCreateTask] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventUnitCreateTask",
|
||||||
|
Text = "S_EVENT_UNIT_CREATE_TASK"
|
||||||
|
},
|
||||||
|
[EVENTS.UnitDeleteTask] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventUnitDeleteTask",
|
||||||
|
Text = "S_EVENT_UNIT_DELETE_TASK"
|
||||||
|
},
|
||||||
|
[EVENTS.SimulationStart] = {
|
||||||
|
Order = 1,
|
||||||
|
Event = "OnEventSimulationStart",
|
||||||
|
Text = "S_EVENT_SIMULATION_START"
|
||||||
|
},
|
||||||
|
[EVENTS.WeaponRearm] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventWeaponRearm",
|
||||||
|
Text = "S_EVENT_WEAPON_REARM"
|
||||||
|
},
|
||||||
|
[EVENTS.WeaponDrop] = {
|
||||||
|
Order = 1,
|
||||||
|
Side = "I",
|
||||||
|
Event = "OnEventWeaponDrop",
|
||||||
|
Text = "S_EVENT_WEAPON_DROP"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The Events structure
|
--- The Events structure
|
||||||
@@ -573,11 +648,12 @@ function EVENT:New()
|
|||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
|
|
||||||
-- Add world event handler.
|
-- Add world event handler.
|
||||||
self.EventHandler = world.addEventHandler( self )
|
self.EventHandler = world.addEventHandler(self)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Initializes the Events structure for the event.
|
--- Initializes the Events structure for the event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param DCS#world.event EventID Event ID.
|
-- @param DCS#world.event EventID Event ID.
|
||||||
@@ -591,7 +667,7 @@ function EVENT:Init( EventID, EventClass )
|
|||||||
self.Events[EventID] = {}
|
self.Events[EventID] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Each event has a sub-table of EventClasses, ordered by EventPriority.
|
-- Each event has a subtable of EventClasses, ordered by EventPriority.
|
||||||
local EventPriority = EventClass:GetEventPriority()
|
local EventPriority = EventClass:GetEventPriority()
|
||||||
|
|
||||||
if not self.Events[EventID][EventPriority] then
|
if not self.Events[EventID][EventPriority] then
|
||||||
@@ -599,7 +675,7 @@ function EVENT:Init( EventID, EventClass )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not self.Events[EventID][EventPriority][EventClass] then
|
if not self.Events[EventID][EventPriority][EventClass] then
|
||||||
self.Events[EventID][EventPriority][EventClass] = {}
|
self.Events[EventID][EventPriority][EventClass] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
return self.Events[EventID][EventPriority][EventClass]
|
return self.Events[EventID][EventPriority][EventClass]
|
||||||
@@ -610,7 +686,7 @@ end
|
|||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param DCS#world.event EventID Event ID.
|
-- @param DCS#world.event EventID Event ID.
|
||||||
-- @return #EVENT self
|
-- @return #EVENT self
|
||||||
function EVENT:RemoveEvent( EventClass, EventID )
|
function EVENT:RemoveEvent( EventClass, EventID )
|
||||||
|
|
||||||
-- Debug info.
|
-- Debug info.
|
||||||
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
|
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
|
||||||
@@ -634,7 +710,7 @@ end
|
|||||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||||
-- @param DCS#world.event EventID Event ID.
|
-- @param DCS#world.event EventID Event ID.
|
||||||
-- @return #EVENT.Events
|
-- @return #EVENT.Events
|
||||||
function EVENT:Reset( EventObject ) -- R2.1
|
function EVENT:Reset( EventObject ) --R2.1
|
||||||
|
|
||||||
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
|
self:F( { "Resetting subscriptions for class: ", EventObject:GetClassNameAndID() } )
|
||||||
|
|
||||||
@@ -653,11 +729,12 @@ function EVENT:Reset( EventObject ) -- R2.1
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
--- Clears all event subscriptions for a @{Core.Base#BASE} derived object.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.Base#BASE EventClass The self class object for which the events are removed.
|
-- @param Core.Base#BASE EventClass The self class object for which the events are removed.
|
||||||
-- @return #EVENT self
|
-- @return #EVENT self
|
||||||
function EVENT:RemoveAll( EventClass )
|
function EVENT:RemoveAll(EventClass)
|
||||||
|
|
||||||
local EventClassName = EventClass:GetClassNameAndID()
|
local EventClassName = EventClass:GetClassNameAndID()
|
||||||
|
|
||||||
@@ -671,6 +748,8 @@ function EVENT:RemoveAll( EventClass )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Create an OnDead event handler for a group
|
--- Create an OnDead event handler for a group
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #table EventTemplate
|
-- @param #table EventTemplate
|
||||||
@@ -702,6 +781,7 @@ function EVENT:OnEventGeneric( EventFunction, EventClass, EventID )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set a new listener for an `S_EVENT_X` event for a UNIT.
|
--- Set a new listener for an `S_EVENT_X` event for a UNIT.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param #string UnitName The name of the UNIT.
|
-- @param #string UnitName The name of the UNIT.
|
||||||
@@ -789,6 +869,7 @@ do -- OnDead
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
do -- OnLand
|
do -- OnLand
|
||||||
|
|
||||||
--- Create an OnLand event handler for a group
|
--- Create an OnLand event handler for a group
|
||||||
@@ -855,7 +936,7 @@ do -- Event Creation
|
|||||||
id = EVENTS.NewCargo,
|
id = EVENTS.NewCargo,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
cargo = Cargo,
|
cargo = Cargo,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -870,7 +951,7 @@ do -- Event Creation
|
|||||||
id = EVENTS.DeleteCargo,
|
id = EVENTS.DeleteCargo,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
cargo = Cargo,
|
cargo = Cargo,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -885,7 +966,7 @@ do -- Event Creation
|
|||||||
id = EVENTS.NewZone,
|
id = EVENTS.NewZone,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
zone = Zone,
|
zone = Zone,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -900,7 +981,7 @@ do -- Event Creation
|
|||||||
id = EVENTS.DeleteZone,
|
id = EVENTS.DeleteZone,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
zone = Zone,
|
zone = Zone,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -915,14 +996,15 @@ do -- Event Creation
|
|||||||
id = EVENTS.NewZoneGoal,
|
id = EVENTS.NewZoneGoal,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
ZoneGoal = ZoneGoal,
|
ZoneGoal = ZoneGoal,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creation of a ZoneGoal Deletion Event.
|
--- Creation of a ZoneGoal Deletion Event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
-- @param Functional.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||||
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
|
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
|
||||||
self:F( { ZoneGoal } )
|
self:F( { ZoneGoal } )
|
||||||
|
|
||||||
@@ -930,11 +1012,12 @@ do -- Event Creation
|
|||||||
id = EVENTS.DeleteZoneGoal,
|
id = EVENTS.DeleteZoneGoal,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
ZoneGoal = ZoneGoal,
|
ZoneGoal = ZoneGoal,
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
||||||
-- @param #EVENT self
|
-- @param #EVENT self
|
||||||
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
||||||
@@ -944,8 +1027,8 @@ do -- Event Creation
|
|||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.PlayerEnterUnit,
|
id = EVENTS.PlayerEnterUnit,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
initiator = PlayerUnit:GetDCSObject(),
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -959,8 +1042,8 @@ do -- Event Creation
|
|||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.PlayerEnterAircraft,
|
id = EVENTS.PlayerEnterAircraft,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
initiator = PlayerUnit:GetDCSObject(),
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -972,24 +1055,25 @@ end
|
|||||||
-- @param #EVENTDATA Event Event data table.
|
-- @param #EVENTDATA Event Event data table.
|
||||||
function EVENT:onEvent( Event )
|
function EVENT:onEvent( Event )
|
||||||
|
|
||||||
|
--- Function to handle errors.
|
||||||
local ErrorHandler = function( errmsg )
|
local ErrorHandler = function( errmsg )
|
||||||
|
|
||||||
env.info( "Error in SCHEDULER function:" .. errmsg )
|
env.info( "Error in SCHEDULER function:" .. errmsg )
|
||||||
if BASE.Debug ~= nil then
|
if BASE.Debug ~= nil then
|
||||||
env.info( debug.traceback() )
|
env.info( debug.traceback() )
|
||||||
end
|
end
|
||||||
|
|
||||||
return errmsg
|
return errmsg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Get event meta data.
|
-- Get event meta data.
|
||||||
local EventMeta = _EVENTMETA[Event.id]
|
local EventMeta = _EVENTMETA[Event.id]
|
||||||
|
|
||||||
-- Check if this is a known event?
|
-- Check if this is a known event?
|
||||||
if EventMeta then
|
if EventMeta then
|
||||||
|
|
||||||
if self and self.Events and self.Events[Event.id] and self.MissionEnd == false and (Event.initiator ~= nil or (Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit)) then
|
if self and self.Events and self.Events[Event.id] and self.MissionEnd==false and (Event.initiator~=nil or (Event.initiator==nil and Event.id~=EVENTS.PlayerLeaveUnit)) then
|
||||||
|
|
||||||
|
-- Check if mission has ended.
|
||||||
if Event.id and Event.id == EVENTS.MissionEnd then
|
if Event.id and Event.id == EVENTS.MissionEnd then
|
||||||
self.MissionEnd = true
|
self.MissionEnd = true
|
||||||
end
|
end
|
||||||
@@ -997,50 +1081,27 @@ function EVENT:onEvent( Event )
|
|||||||
if Event.initiator then
|
if Event.initiator then
|
||||||
|
|
||||||
Event.IniObjectCategory = Event.initiator:getCategory()
|
Event.IniObjectCategory = Event.initiator:getCategory()
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.UNIT then
|
if Event.IniObjectCategory == Object.Category.STATIC then
|
||||||
Event.IniDCSUnit = Event.initiator
|
---
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
-- Static
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
---
|
||||||
Event.IniDCSGroup = Event.IniDCSUnit:getGroup()
|
if Event.id==31 then
|
||||||
Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName )
|
|
||||||
if not Event.IniUnit then
|
|
||||||
-- Unit can be a CLIENT. Most likely this will be the case ...
|
|
||||||
Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true )
|
|
||||||
end
|
|
||||||
Event.IniDCSGroupName = ""
|
|
||||||
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
|
||||||
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
|
||||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
|
||||||
-- if Event.IniGroup then
|
|
||||||
Event.IniGroupName = Event.IniDCSGroupName
|
|
||||||
-- end
|
|
||||||
end
|
|
||||||
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
|
|
||||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
|
||||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
|
||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
|
||||||
end
|
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.STATIC then
|
|
||||||
|
|
||||||
if Event.id == 31 then
|
|
||||||
|
|
||||||
-- Event.initiator is a Static object representing the pilot. But getName() errors due to DCS bug.
|
-- Event.initiator is a Static object representing the pilot. But getName() errors due to DCS bug.
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
local ID = Event.initiator.id_
|
local ID=Event.initiator.id_
|
||||||
Event.IniDCSUnitName = string.format( "Ejected Pilot ID %s", tostring( ID ) )
|
Event.IniDCSUnitName = string.format("Ejected Pilot ID %s", tostring(ID))
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
Event.IniCoalition = 0
|
Event.IniCoalition = 0
|
||||||
Event.IniCategory = 0
|
Event.IniCategory = 0
|
||||||
Event.IniTypeName = "Ejected Pilot"
|
Event.IniTypeName = "Ejected Pilot"
|
||||||
elseif Event.id == 33 then -- ejection seat discarded
|
elseif Event.id == 33 then -- ejection seat discarded
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
local ID = Event.initiator.id_
|
local ID=Event.initiator.id_
|
||||||
Event.IniDCSUnitName = string.format( "Ejection Seat ID %s", tostring( ID ) )
|
Event.IniDCSUnitName = string.format("Ejection Seat ID %s", tostring(ID))
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
Event.IniCoalition = 0
|
Event.IniCoalition = 0
|
||||||
Event.IniCategory = 0
|
Event.IniCategory = 0
|
||||||
Event.IniTypeName = "Ejection Seat"
|
Event.IniTypeName = "Ejection Seat"
|
||||||
else
|
else
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
@@ -1051,9 +1112,47 @@ function EVENT:onEvent( Event )
|
|||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Dead events of units can be delayed and the initiator changed to a static.
|
||||||
|
-- Take care of that.
|
||||||
|
local Unit=UNIT:FindByName(Event.IniDCSUnitName)
|
||||||
|
if Unit then
|
||||||
|
Event.IniObjectCategory = Object.Category.UNIT
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if Event.IniObjectCategory == Object.Category.UNIT then
|
||||||
|
---
|
||||||
|
-- Unit
|
||||||
|
---
|
||||||
|
Event.IniDCSUnit = Event.initiator
|
||||||
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
|
Event.IniDCSGroup = Event.IniDCSUnit:getGroup()
|
||||||
|
Event.IniUnit = UNIT:FindByName( Event.IniDCSUnitName )
|
||||||
|
|
||||||
|
if not Event.IniUnit then
|
||||||
|
-- Unit can be a CLIENT. Most likely this will be the case ...
|
||||||
|
Event.IniUnit = CLIENT:FindByName( Event.IniDCSUnitName, '', true )
|
||||||
|
end
|
||||||
|
|
||||||
|
Event.IniDCSGroupName = Event.IniUnit and Event.IniUnit.GroupName or ""
|
||||||
|
if Event.IniDCSGroup and Event.IniDCSGroup:isExist() then
|
||||||
|
Event.IniDCSGroupName = Event.IniDCSGroup:getName()
|
||||||
|
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||||
|
Event.IniGroupName = Event.IniDCSGroupName
|
||||||
|
end
|
||||||
|
|
||||||
|
Event.IniPlayerName = Event.IniDCSUnit:getPlayerName()
|
||||||
|
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||||
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.CARGO then
|
if Event.IniObjectCategory == Object.Category.CARGO then
|
||||||
|
---
|
||||||
|
-- Cargo
|
||||||
|
---
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
@@ -1064,19 +1163,26 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.SCENERY then
|
if Event.IniObjectCategory == Object.Category.SCENERY then
|
||||||
|
---
|
||||||
|
-- Scenery
|
||||||
|
---
|
||||||
|
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
Event.IniUnit = SCENERY:Register( Event.IniDCSUnitName, Event.initiator )
|
||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY" -- TODO: Bug fix for 2.1!
|
Event.IniTypeName = Event.initiator:isExist() and Event.IniDCSUnit:getTypeName() or "SCENERY"
|
||||||
end
|
end
|
||||||
|
|
||||||
if Event.IniObjectCategory == Object.Category.BASE then
|
if Event.IniObjectCategory == Object.Category.BASE then
|
||||||
|
---
|
||||||
|
-- Base Object
|
||||||
|
---
|
||||||
Event.IniDCSUnit = Event.initiator
|
Event.IniDCSUnit = Event.initiator
|
||||||
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
Event.IniDCSUnitName = Event.IniDCSUnit:getName()
|
||||||
Event.IniUnitName = Event.IniDCSUnitName
|
Event.IniUnitName = Event.IniDCSUnitName
|
||||||
Event.IniUnit = AIRBASE:FindByName( Event.IniDCSUnitName )
|
Event.IniUnit = AIRBASE:FindByName(Event.IniDCSUnitName)
|
||||||
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
Event.IniCoalition = Event.IniDCSUnit:getCoalition()
|
||||||
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
Event.IniCategory = Event.IniDCSUnit:getDesc().category
|
||||||
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
Event.IniTypeName = Event.IniDCSUnit:getTypeName()
|
||||||
@@ -1084,7 +1190,12 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Event.target then
|
if Event.target then
|
||||||
|
|
||||||
|
---
|
||||||
|
-- TARGET
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Target category.
|
||||||
Event.TgtObjectCategory = Event.target:getCategory()
|
Event.TgtObjectCategory = Event.target:getCategory()
|
||||||
|
|
||||||
if Event.TgtObjectCategory == Object.Category.UNIT then
|
if Event.TgtObjectCategory == Object.Category.UNIT then
|
||||||
@@ -1097,9 +1208,7 @@ function EVENT:onEvent( Event )
|
|||||||
if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then
|
if Event.TgtDCSGroup and Event.TgtDCSGroup:isExist() then
|
||||||
Event.TgtDCSGroupName = Event.TgtDCSGroup:getName()
|
Event.TgtDCSGroupName = Event.TgtDCSGroup:getName()
|
||||||
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
||||||
-- if Event.TgtGroup then
|
|
||||||
Event.TgtGroupName = Event.TgtDCSGroupName
|
Event.TgtGroupName = Event.TgtDCSGroupName
|
||||||
-- end
|
|
||||||
end
|
end
|
||||||
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
|
Event.TgtPlayerName = Event.TgtDCSUnit:getPlayerName()
|
||||||
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
Event.TgtCoalition = Event.TgtDCSUnit:getCoalition()
|
||||||
@@ -1118,18 +1227,18 @@ function EVENT:onEvent( Event )
|
|||||||
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
Event.TgtCategory = Event.TgtDCSUnit:getDesc().category
|
||||||
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
Event.TgtTypeName = Event.TgtDCSUnit:getTypeName()
|
||||||
else
|
else
|
||||||
Event.TgtDCSUnitName = string.format( "No target object for Event ID %s", tostring( Event.id ) )
|
Event.TgtDCSUnitName = string.format("No target object for Event ID %s", tostring(Event.id))
|
||||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
Event.TgtUnit = nil
|
Event.TgtUnit = nil
|
||||||
Event.TgtCoalition = 0
|
Event.TgtCoalition = 0
|
||||||
Event.TgtCategory = 0
|
Event.TgtCategory = 0
|
||||||
if Event.id == 6 then
|
if Event.id == 6 then
|
||||||
Event.TgtTypeName = "Ejected Pilot"
|
Event.TgtTypeName = "Ejected Pilot"
|
||||||
Event.TgtDCSUnitName = string.format( "Ejected Pilot ID %s", tostring( Event.IniDCSUnitName ) )
|
Event.TgtDCSUnitName = string.format("Ejected Pilot ID %s", tostring(Event.IniDCSUnitName))
|
||||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
elseif Event.id == 33 then
|
elseif Event.id == 33 then
|
||||||
Event.TgtTypeName = "Ejection Seat"
|
Event.TgtTypeName = "Ejection Seat"
|
||||||
Event.TgtDCSUnitName = string.format( "Ejection Seat ID %s", tostring( Event.IniDCSUnitName ) )
|
Event.TgtDCSUnitName = string.format("Ejection Seat ID %s", tostring(Event.IniDCSUnitName))
|
||||||
Event.TgtUnitName = Event.TgtDCSUnitName
|
Event.TgtUnitName = Event.TgtDCSUnitName
|
||||||
else
|
else
|
||||||
Event.TgtTypeName = "Static"
|
Event.TgtTypeName = "Static"
|
||||||
@@ -1147,6 +1256,7 @@ function EVENT:onEvent( Event )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Weapon.
|
||||||
if Event.weapon then
|
if Event.weapon then
|
||||||
Event.Weapon = Event.weapon
|
Event.Weapon = Event.weapon
|
||||||
Event.WeaponName = Event.Weapon:getTypeName()
|
Event.WeaponName = Event.Weapon:getTypeName()
|
||||||
@@ -1155,49 +1265,48 @@ function EVENT:onEvent( Event )
|
|||||||
Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition()
|
Event.WeaponCoalition = Event.WeaponUNIT and Event.Weapon:getCoalition()
|
||||||
Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category
|
Event.WeaponCategory = Event.WeaponUNIT and Event.Weapon:getDesc().category
|
||||||
Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName()
|
Event.WeaponTypeName = Event.WeaponUNIT and Event.Weapon:getTypeName()
|
||||||
-- Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
--Event.WeaponTgtDCSUnit = Event.Weapon:getTarget()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase.
|
-- Place should be given for takeoff and landing events as well as base captured. It should be a DCS airbase.
|
||||||
if Event.place then
|
if Event.place then
|
||||||
if Event.id == EVENTS.LandingAfterEjection then
|
if Event.id==EVENTS.LandingAfterEjection then
|
||||||
-- Place is here the UNIT of which the pilot ejected.
|
-- Place is here the UNIT of which the pilot ejected.
|
||||||
-- local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :(
|
--local name=Event.place:getName() -- This returns a DCS error "Airbase doesn't exit" :(
|
||||||
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
|
-- However, this is not a big thing, as the aircraft the pilot ejected from is usually long crashed before the ejected pilot touches the ground.
|
||||||
-- Event.Place=UNIT:Find(Event.place)
|
--Event.Place=UNIT:Find(Event.place)
|
||||||
else
|
else
|
||||||
Event.Place = AIRBASE:Find( Event.place )
|
Event.Place=AIRBASE:Find(Event.place)
|
||||||
Event.PlaceName = Event.Place:GetName()
|
Event.PlaceName=Event.Place:GetName()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Mark points.
|
-- Mark points.
|
||||||
if Event.idx then
|
if Event.idx then
|
||||||
Event.MarkID = Event.idx
|
Event.MarkID=Event.idx
|
||||||
Event.MarkVec3 = Event.pos
|
Event.MarkVec3=Event.pos
|
||||||
Event.MarkCoordinate = COORDINATE:NewFromVec3( Event.pos )
|
Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
|
||||||
Event.MarkText = Event.text
|
Event.MarkText=Event.text
|
||||||
Event.MarkCoalition = Event.coalition
|
Event.MarkCoalition=Event.coalition
|
||||||
Event.MarkGroupID = Event.groupID
|
Event.MarkGroupID = Event.groupID
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cargo object.
|
||||||
if Event.cargo then
|
if Event.cargo then
|
||||||
Event.Cargo = Event.cargo
|
Event.Cargo = Event.cargo
|
||||||
Event.CargoName = Event.cargo.Name
|
Event.CargoName = Event.cargo.Name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Zone object.
|
||||||
if Event.zone then
|
if Event.zone then
|
||||||
Event.Zone = Event.zone
|
Event.Zone = Event.zone
|
||||||
Event.ZoneName = Event.zone.ZoneName
|
Event.ZoneName = Event.zone.ZoneName
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Priority order.
|
||||||
local PriorityOrder = EventMeta.Order
|
local PriorityOrder = EventMeta.Order
|
||||||
local PriorityBegin = PriorityOrder == -1 and 5 or 1
|
local PriorityBegin = PriorityOrder == -1 and 5 or 1
|
||||||
local PriorityEnd = PriorityOrder == -1 and 1 or 5
|
local PriorityEnd = PriorityOrder == -1 and 1 or 5
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= Object.Category.STATIC then
|
|
||||||
self:F( { EventMeta.Text, Event, Event.IniDCSUnitName, Event.TgtDCSUnitName, PriorityOrder } )
|
|
||||||
end
|
|
||||||
|
|
||||||
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
|
for EventPriority = PriorityBegin, PriorityEnd, PriorityOrder do
|
||||||
|
|
||||||
@@ -1206,12 +1315,12 @@ function EVENT:onEvent( Event )
|
|||||||
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
|
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
|
||||||
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
|
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
|
||||||
|
|
||||||
-- if Event.IniObjectCategory ~= Object.Category.STATIC then
|
--if Event.IniObjectCategory ~= Object.Category.STATIC then
|
||||||
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
||||||
-- end
|
--end
|
||||||
|
|
||||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
Event.IniGroup = Event.IniGroup or GROUP:FindByName( Event.IniDCSGroupName )
|
||||||
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
Event.TgtGroup = Event.TgtGroup or GROUP:FindByName( Event.TgtDCSGroupName )
|
||||||
|
|
||||||
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
|
-- If the EventData is for a UNIT, the call directly the EventClass EventFunction for that UNIT.
|
||||||
if EventData.EventUnit then
|
if EventData.EventUnit then
|
||||||
@@ -1221,39 +1330,35 @@ function EVENT:onEvent( Event )
|
|||||||
Event.id == EVENTS.PlayerEnterUnit or
|
Event.id == EVENTS.PlayerEnterUnit or
|
||||||
Event.id == EVENTS.Crash or
|
Event.id == EVENTS.Crash or
|
||||||
Event.id == EVENTS.Dead or
|
Event.id == EVENTS.Dead or
|
||||||
Event.id == EVENTS.RemoveUnit then
|
Event.id == EVENTS.RemoveUnit or
|
||||||
|
Event.id == EVENTS.UnitLost then
|
||||||
|
|
||||||
local UnitName = EventClass:GetName()
|
local UnitName = EventClass:GetName()
|
||||||
|
|
||||||
if (EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName) or
|
if ( EventMeta.Side == "I" and UnitName == Event.IniDCSUnitName ) or
|
||||||
(EventMeta.Side == "T" and UnitName == Event.TgtDCSUnitName) then
|
( EventMeta.Side == "T" and UnitName == Event.TgtDCSUnitName ) then
|
||||||
|
|
||||||
-- First test if a EventFunction is Set, otherwise search for the default function
|
-- First test if a EventFunction is Set, otherwise search for the default function
|
||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling EventFunction for UNIT ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
function()
|
||||||
end
|
return EventData.EventFunction( EventClass, Event )
|
||||||
|
end, ErrorHandler )
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventData.EventFunction( EventClass, Event )
|
|
||||||
end, ErrorHandler )
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
||||||
local EventFunction = EventClass[EventMeta.Event]
|
local EventFunction = EventClass[ EventMeta.Event ]
|
||||||
if EventFunction and type( EventFunction ) == "function" then
|
if EventFunction and type( EventFunction ) == "function" then
|
||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
return EventFunction( EventClass, Event )
|
||||||
|
end, ErrorHandler )
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventFunction( EventClass, Event )
|
|
||||||
end, ErrorHandler )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1271,48 +1376,43 @@ function EVENT:onEvent( Event )
|
|||||||
Event.id == EVENTS.PlayerEnterUnit or
|
Event.id == EVENTS.PlayerEnterUnit or
|
||||||
Event.id == EVENTS.Crash or
|
Event.id == EVENTS.Crash or
|
||||||
Event.id == EVENTS.Dead or
|
Event.id == EVENTS.Dead or
|
||||||
Event.id == EVENTS.RemoveUnit then
|
Event.id == EVENTS.RemoveUnit or
|
||||||
|
Event.id == EVENTS.UnitLost then
|
||||||
|
|
||||||
-- We can get the name of the EventClass, which is now always a GROUP object.
|
-- We can get the name of the EventClass, which is now always a GROUP object.
|
||||||
local GroupName = EventClass:GetName()
|
local GroupName = EventClass:GetName()
|
||||||
|
|
||||||
if (EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName) or
|
if ( EventMeta.Side == "I" and GroupName == Event.IniDCSGroupName ) or
|
||||||
(EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName) then
|
( EventMeta.Side == "T" and GroupName == Event.TgtDCSGroupName ) then
|
||||||
|
|
||||||
-- First test if a EventFunction is Set, otherwise search for the default function
|
-- First test if a EventFunction is Set, otherwise search for the default function
|
||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling EventFunction for GROUP ", EventClass:GetClassNameAndID(), ", Unit ", Event.IniUnitName, EventPriority } )
|
function()
|
||||||
end
|
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||||
|
end, ErrorHandler )
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
|
||||||
end, ErrorHandler )
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
||||||
local EventFunction = EventClass[EventMeta.Event]
|
local EventFunction = EventClass[ EventMeta.Event ]
|
||||||
if EventFunction and type( EventFunction ) == "function" then
|
if EventFunction and type( EventFunction ) == "function" then
|
||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F( { "Calling " .. EventMeta.Event .. " for GROUP ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||||
|
end, ErrorHandler )
|
||||||
local Result, Value = xpcall( function()
|
|
||||||
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
|
||||||
end, ErrorHandler )
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
|
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
|
||||||
-- self:RemoveEvent( EventClass, Event.id )
|
--self:RemoveEvent( EventClass, Event.id )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
||||||
-- If the EventData is not bound to a specific unit, then call the EventClass EventFunction.
|
-- If the EventData is not bound to a specific unit, then call the EventClass EventFunction.
|
||||||
-- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon.
|
-- Note that here the EventFunction will need to implement and determine the logic for the relevant source- or target unit, or weapon.
|
||||||
if not EventData.EventUnit then
|
if not EventData.EventUnit then
|
||||||
@@ -1321,28 +1421,25 @@ function EVENT:onEvent( Event )
|
|||||||
if EventData.EventFunction then
|
if EventData.EventFunction then
|
||||||
|
|
||||||
-- There is an EventFunction defined, so call the EventFunction.
|
-- There is an EventFunction defined, so call the EventFunction.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F2( { "Calling EventFunction for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
return EventData.EventFunction( EventClass, Event )
|
||||||
local Result, Value = xpcall( function()
|
end, ErrorHandler )
|
||||||
return EventData.EventFunction( EventClass, Event )
|
|
||||||
end, ErrorHandler )
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
-- There is no EventFunction defined, so try to find if a default OnEvent function is defined on the object.
|
||||||
local EventFunction = EventClass[EventMeta.Event]
|
local EventFunction = EventClass[ EventMeta.Event ]
|
||||||
if EventFunction and type( EventFunction ) == "function" then
|
if EventFunction and type( EventFunction ) == "function" then
|
||||||
|
|
||||||
-- Now call the default event function.
|
-- Now call the default event function.
|
||||||
if Event.IniObjectCategory ~= 3 then
|
local Result, Value = xpcall(
|
||||||
self:F2( { "Calling " .. EventMeta.Event .. " for Class ", EventClass:GetClassNameAndID(), EventPriority } )
|
function()
|
||||||
end
|
local Result, Value = EventFunction( EventClass, Event )
|
||||||
|
return Result, Value
|
||||||
local Result, Value = xpcall( function()
|
end, ErrorHandler )
|
||||||
local Result, Value = EventFunction( EventClass, Event )
|
|
||||||
return Result, Value
|
|
||||||
end, ErrorHandler )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1365,7 +1462,7 @@ function EVENT:onEvent( Event )
|
|||||||
self:T( { EventMeta.Text, Event } )
|
self:T( { EventMeta.Text, Event } )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E( string.format( "WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring( Event.id ) ) )
|
self:E(string.format("WARNING: Could not get EVENTMETA data for event ID=%d! Is this an unknown/new DCS event?", tostring(Event.id)))
|
||||||
end
|
end
|
||||||
|
|
||||||
Event = nil
|
Event = nil
|
||||||
|
|||||||
@@ -47,9 +47,9 @@
|
|||||||
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
||||||
-- Each of these FSM implementation classes start either with:
|
-- Each of these FSM implementation classes start either with:
|
||||||
--
|
--
|
||||||
-- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
-- * an acronym **AI\_**, which indicates a FSM implementation directing **AI controlled** @{Wrapper.Group#GROUP} and/or @{Wrapper.Unit#UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
||||||
-- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
-- * an acronym **TASK\_**, which indicates a FSM implementation executing a @{Tasking.Task#TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
||||||
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{Tasking.Task#TASK}, seated in a @{Wrapper.Client#CLIENT} (slot) or a @{Wrapper.Unit#UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
||||||
--
|
--
|
||||||
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
|
-- Detailed explanations and API specifics are further below clarified and FSM derived class specifics are described in those class documentation sections.
|
||||||
--
|
--
|
||||||
@@ -61,10 +61,10 @@
|
|||||||
--
|
--
|
||||||
-- The following derived classes are available in the MOOSE framework, that implement a specialized form of a FSM:
|
-- The following derived classes are available in the MOOSE framework, that implement a specialized form of a FSM:
|
||||||
--
|
--
|
||||||
-- * @{#FSM_TASK}: Models Finite State Machines for @{Task}s.
|
-- * @{#FSM_TASK}: Models Finite State Machines for @{Tasking.Task}s.
|
||||||
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Task} actions, which control @{Client}s.
|
-- * @{#FSM_PROCESS}: Models Finite State Machines for @{Tasking.Task} actions, which control @{Wrapper.Client}s.
|
||||||
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
|
-- * @{#FSM_CONTROLLABLE}: Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Wrapper.Client}s.
|
||||||
-- * @{#FSM_SET}: Models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
-- * @{#FSM_SET}: Models Finite State Machines for @{Core.Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
||||||
-- for multiple objects or the position of the state machine in the process.
|
-- for multiple objects or the position of the state machine in the process.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -119,9 +119,9 @@ do -- FSM
|
|||||||
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
-- and tailored** by mission designers through **the implementation of Transition Handlers**.
|
||||||
-- Each of these FSM implementation classes start either with:
|
-- Each of these FSM implementation classes start either with:
|
||||||
--
|
--
|
||||||
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{GROUP} and/or @{UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
-- * an acronym **AI\_**, which indicates an FSM implementation directing **AI controlled** @{Wrapper.Group#GROUP} and/or @{Wrapper.Unit#UNIT}. These AI\_ classes derive the @{#FSM_CONTROLLABLE} class.
|
||||||
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
-- * an acronym **TASK\_**, which indicates an FSM implementation executing a @{Tasking.Task#TASK} executed by Groups of players. These TASK\_ classes derive the @{#FSM_TASK} class.
|
||||||
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{TASK}, seated in a @{CLIENT} (slot) or a @{UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
-- * an acronym **ACT\_**, which indicates an Sub-FSM implementation, directing **Humans actions** that need to be done in a @{Tasking.Task#TASK}, seated in a @{Wrapper.Client#CLIENT} (slot) or a @{Wrapper.Unit#UNIT} (CA join). These ACT\_ classes derive the @{#FSM_PROCESS} class.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -405,8 +405,8 @@ do -- FSM
|
|||||||
Transition.To = To
|
Transition.To = To
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2( Transition )
|
--self:T3( Transition )
|
||||||
|
|
||||||
self._Transitions[Transition] = Transition
|
self._Transitions[Transition] = Transition
|
||||||
self:_eventmap( self.Events, Transition )
|
self:_eventmap( self.Events, Transition )
|
||||||
end
|
end
|
||||||
@@ -418,7 +418,7 @@ do -- FSM
|
|||||||
return self._Transitions or {}
|
return self._Transitions or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set the default @{Process} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Wrapper.Controllable} by the task.
|
--- Set the default @{#FSM_PROCESS} template with key ProcessName providing the ProcessClass and the process object when it is assigned to a @{Wrapper.Controllable} by the task.
|
||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states.
|
-- @param #table From Can contain a string indicating the From state or a table of strings containing multiple From states.
|
||||||
-- @param #string Event The Event name.
|
-- @param #string Event The Event name.
|
||||||
@@ -426,8 +426,8 @@ do -- FSM
|
|||||||
-- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM.
|
-- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM.
|
||||||
-- @return Core.Fsm#FSM_PROCESS The SubFSM.
|
-- @return Core.Fsm#FSM_PROCESS The SubFSM.
|
||||||
function FSM:AddProcess( From, Event, Process, ReturnEvents )
|
function FSM:AddProcess( From, Event, Process, ReturnEvents )
|
||||||
self:T( { From, Event } )
|
--self:T3( { From, Event } )
|
||||||
|
|
||||||
local Sub = {}
|
local Sub = {}
|
||||||
Sub.From = From
|
Sub.From = From
|
||||||
Sub.Event = Event
|
Sub.Event = Event
|
||||||
@@ -524,9 +524,9 @@ do -- FSM
|
|||||||
Process._Scores[State] = Process._Scores[State] or {}
|
Process._Scores[State] = Process._Scores[State] or {}
|
||||||
Process._Scores[State].ScoreText = ScoreText
|
Process._Scores[State].ScoreText = ScoreText
|
||||||
Process._Scores[State].Score = Score
|
Process._Scores[State].Score = Score
|
||||||
|
|
||||||
self:T( Process._Scores )
|
--self:T3( Process._Scores )
|
||||||
|
|
||||||
return Process
|
return Process
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -560,19 +560,19 @@ do -- FSM
|
|||||||
-- @param #table Events Events.
|
-- @param #table Events Events.
|
||||||
-- @param #table EventStructure Event structure.
|
-- @param #table EventStructure Event structure.
|
||||||
function FSM:_eventmap( Events, EventStructure )
|
function FSM:_eventmap( Events, EventStructure )
|
||||||
|
|
||||||
local Event = EventStructure.Event
|
local Event = EventStructure.Event
|
||||||
local __Event = "__" .. EventStructure.Event
|
local __Event = "__" .. EventStructure.Event
|
||||||
|
|
||||||
self[Event] = self[Event] or self:_create_transition( Event )
|
self[Event] = self[Event] or self:_create_transition(Event)
|
||||||
self[__Event] = self[__Event] or self:_delayed_transition( Event )
|
self[__Event] = self[__Event] or self:_delayed_transition(Event)
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2( "Added methods: " .. Event .. ", " .. __Event )
|
--self:T3( "Added methods: " .. Event .. ", " .. __Event )
|
||||||
|
|
||||||
Events[Event] = self.Events[Event] or { map = {} }
|
Events[Event] = self.Events[Event] or { map = {} }
|
||||||
self:_add_to_map( Events[Event].map, EventStructure )
|
self:_add_to_map( Events[Event].map, EventStructure )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sub maps.
|
--- Sub maps.
|
||||||
@@ -784,8 +784,8 @@ do -- FSM
|
|||||||
return function( self, DelaySeconds, ... )
|
return function( self, DelaySeconds, ... )
|
||||||
|
|
||||||
-- Debug.
|
-- Debug.
|
||||||
self:T2( "Delayed Event: " .. EventName )
|
self:T3( "Delayed Event: " .. EventName )
|
||||||
|
|
||||||
local CallID = 0
|
local CallID = 0
|
||||||
if DelaySeconds ~= nil then
|
if DelaySeconds ~= nil then
|
||||||
|
|
||||||
@@ -802,23 +802,23 @@ do -- FSM
|
|||||||
self._EventSchedules[EventName] = CallID
|
self._EventSchedules[EventName] = CallID
|
||||||
|
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
|
self:T2(string.format("NEGATIVE Event %s delayed by %.3f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||||
else
|
else
|
||||||
self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds ) )
|
self:T2(string.format("NEGATIVE Event %s delayed by %.3f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds))
|
||||||
-- reschedule
|
-- reschedule
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
||||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||||
|
|
||||||
self:T2( string.format( "Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
|
self:T2(string.format("Event %s delayed by %.3f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug.
|
-- Debug.
|
||||||
self:T2( { CallID = CallID } )
|
--self:T3( { CallID = CallID } )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -841,7 +841,7 @@ do -- FSM
|
|||||||
function FSM:_gosub( ParentFrom, ParentEvent )
|
function FSM:_gosub( ParentFrom, ParentEvent )
|
||||||
local fsmtable = {}
|
local fsmtable = {}
|
||||||
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
|
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
|
||||||
self:T( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } )
|
--self:T3( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } )
|
||||||
return self.subs[ParentFrom][ParentEvent]
|
return self.subs[ParentFrom][ParentEvent]
|
||||||
else
|
else
|
||||||
return {}
|
return {}
|
||||||
@@ -887,8 +887,8 @@ do -- FSM
|
|||||||
Map[From] = Event.To
|
Map[From] = Event.To
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T3( { Map, Event } )
|
--self:T3( { Map, Event } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get current state.
|
--- Get current state.
|
||||||
@@ -908,7 +908,7 @@ do -- FSM
|
|||||||
--- Check if FSM is in state.
|
--- Check if FSM is in state.
|
||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @param #string State State name.
|
-- @param #string State State name.
|
||||||
-- @param #boolean If true, FSM is in this state.
|
-- @return #boolean If true, FSM is in this state.
|
||||||
function FSM:Is( State )
|
function FSM:Is( State )
|
||||||
return self.current == State
|
return self.current == State
|
||||||
end
|
end
|
||||||
@@ -916,8 +916,8 @@ do -- FSM
|
|||||||
--- Check if FSM is in state.
|
--- Check if FSM is in state.
|
||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @param #string State State name.
|
-- @param #string State State name.
|
||||||
-- @param #boolean If true, FSM is in this state.
|
-- @return #boolean If true, FSM is in this state.
|
||||||
function FSM:is( state )
|
function FSM:is(state)
|
||||||
return self.current == state
|
return self.current == state
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -953,7 +953,7 @@ do -- FSM_CONTROLLABLE
|
|||||||
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @field Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Client}s.
|
--- Models Finite State Machines for @{Wrapper.Controllable}s, which are @{Wrapper.Group}s, @{Wrapper.Unit}s, @{Wrapper.Client}s.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -1086,7 +1086,7 @@ do -- FSM_PROCESS
|
|||||||
-- @field Tasking.Task#TASK Task
|
-- @field Tasking.Task#TASK Task
|
||||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||||
|
|
||||||
--- FSM_PROCESS class models Finite State Machines for @{Task} actions, which control @{Client}s.
|
--- FSM_PROCESS class models Finite State Machines for @{Tasking.Task} actions, which control @{Wrapper.Client}s.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -1146,7 +1146,7 @@ do -- FSM_PROCESS
|
|||||||
-- @param #FSM_PROCESS self
|
-- @param #FSM_PROCESS self
|
||||||
-- @return #FSM_PROCESS
|
-- @return #FSM_PROCESS
|
||||||
function FSM_PROCESS:Copy( Controllable, Task )
|
function FSM_PROCESS:Copy( Controllable, Task )
|
||||||
self:T( { self:GetClassNameAndID() } )
|
--self:T3( { self:GetClassNameAndID() } )
|
||||||
|
|
||||||
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
|
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
|
||||||
|
|
||||||
@@ -1171,13 +1171,13 @@ do -- FSM_PROCESS
|
|||||||
|
|
||||||
-- Copy End States
|
-- Copy End States
|
||||||
for EndStateID, EndState in pairs( self:GetEndStates() ) do
|
for EndStateID, EndState in pairs( self:GetEndStates() ) do
|
||||||
self:T( EndState )
|
--self:T3( EndState )
|
||||||
NewFsm:AddEndState( EndState )
|
NewFsm:AddEndState( EndState )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Copy the score tables
|
-- Copy the score tables
|
||||||
for ScoreID, Score in pairs( self:GetScores() ) do
|
for ScoreID, Score in pairs( self:GetScores() ) do
|
||||||
self:T( Score )
|
--self:T3( Score )
|
||||||
NewFsm:AddScore( ScoreID, Score.ScoreText, Score.Score )
|
NewFsm:AddScore( ScoreID, Score.ScoreText, Score.Score )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1241,7 +1241,7 @@ do -- FSM_PROCESS
|
|||||||
|
|
||||||
-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP.
|
-- TODO: Need to check and fix that an FSM_PROCESS is only for a UNIT. Not for a GROUP.
|
||||||
|
|
||||||
--- Send a message of the @{Task} to the Group of the Unit.
|
--- Send a message of the @{Tasking.Task} to the Group of the Unit.
|
||||||
-- @param #FSM_PROCESS self
|
-- @param #FSM_PROCESS self
|
||||||
function FSM_PROCESS:Message( Message )
|
function FSM_PROCESS:Message( Message )
|
||||||
self:F( { Message = Message } )
|
self:F( { Message = Message } )
|
||||||
@@ -1382,7 +1382,7 @@ do -- FSM_SET
|
|||||||
-- @field Core.Set#SET_BASE Set
|
-- @field Core.Set#SET_BASE Set
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- FSM_SET class models Finite State Machines for @{Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
--- FSM_SET class models Finite State Machines for @{Core.Set}s. Note that these FSMs control multiple objects!!! So State concerns here
|
||||||
-- for multiple objects or the position of the state machine in the process.
|
-- for multiple objects or the position of the state machine in the process.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -1422,7 +1422,7 @@ do -- FSM_SET
|
|||||||
-- @param #FSM_SET self
|
-- @param #FSM_SET self
|
||||||
-- @return Core.Set#SET_BASE
|
-- @return Core.Set#SET_BASE
|
||||||
function FSM_SET:Get()
|
function FSM_SET:Get()
|
||||||
return self.Controllable
|
return self.Set
|
||||||
end
|
end
|
||||||
|
|
||||||
function FSM_SET:_call_handler( step, trigger, params, EventName )
|
function FSM_SET:_call_handler( step, trigger, params, EventName )
|
||||||
|
|||||||
267
Moose Development/Moose/Core/MarkerOps_Base.lua
Normal file
267
Moose Development/Moose/Core/MarkerOps_Base.lua
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
--- **Core** - Tap into markers added to the F10 map by users.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Create an easy way to tap into markers added to the F10 map by users.
|
||||||
|
-- * Recognize own tag and list of keywords.
|
||||||
|
-- * Matched keywords are handed down to functions.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **Applevangelist**
|
||||||
|
--
|
||||||
|
-- Date: 5 May 2021
|
||||||
|
-- Last Update: Sep 2022
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
---
|
||||||
|
-- @module Core.MarkerOps_Base
|
||||||
|
-- @image MOOSE_Core.JPG
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
-- MARKEROPS_BASE Class Definition.
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- MARKEROPS_BASE class.
|
||||||
|
-- @type MARKEROPS_BASE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string Tag Tag to identify commands.
|
||||||
|
-- @field #table Keywords Table of keywords to recognize.
|
||||||
|
-- @field #string version Version of #MARKEROPS_BASE.
|
||||||
|
-- @field #boolean Casesensitive Enforce case when identifying the Tag, i.e. tag ~= Tag
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
--- *Fiat lux.* -- Latin proverb.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The MARKEROPS_BASE Concept
|
||||||
|
--
|
||||||
|
-- This class enable scripting text-based actions from markers.
|
||||||
|
--
|
||||||
|
-- @field #MARKEROPS_BASE
|
||||||
|
MARKEROPS_BASE = {
|
||||||
|
ClassName = "MARKEROPS",
|
||||||
|
Tag = "mytag",
|
||||||
|
Keywords = {},
|
||||||
|
version = "0.1.0",
|
||||||
|
debug = false,
|
||||||
|
Casesensitive = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Function to instantiate a new #MARKEROPS_BASE object.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string Tagname Name to identify us from the event text.
|
||||||
|
-- @param #table Keywords Table of keywords recognized from the event text.
|
||||||
|
-- @param #boolean Casesensitive (Optional) Switch case sensitive identification of Tagname. Defaults to true.
|
||||||
|
-- @return #MARKEROPS_BASE self
|
||||||
|
function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
||||||
|
-- Inherit FSM
|
||||||
|
local self=BASE:Inherit(self, FSM:New()) -- #MARKEROPS_BASE
|
||||||
|
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("MARKEROPS_BASE %s | ", tostring(self.version))
|
||||||
|
|
||||||
|
self.Tag = Tagname or "mytag"-- #string
|
||||||
|
self.Keywords = Keywords or {} -- #table - might want to use lua regex here, too
|
||||||
|
self.debug = false
|
||||||
|
self.Casesensitive = true
|
||||||
|
|
||||||
|
if Casesensitive and Casesensitive == false then
|
||||||
|
self.Casesensitive = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
--- FSM Transitions ---
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
-- Start State.
|
||||||
|
self:SetStartState("Stopped")
|
||||||
|
|
||||||
|
-- Add FSM transitions.
|
||||||
|
-- From State --> Event --> To State
|
||||||
|
self:AddTransition("Stopped", "Start", "Running") -- Start the FSM.
|
||||||
|
self:AddTransition("*", "MarkAdded", "*") -- Start the FSM.
|
||||||
|
self:AddTransition("*", "MarkChanged", "*") -- Start the FSM.
|
||||||
|
self:AddTransition("*", "MarkDeleted", "*") -- Start the FSM.
|
||||||
|
self:AddTransition("Running", "Stop", "Stopped") -- Stop the FSM.
|
||||||
|
|
||||||
|
self:HandleEvent(EVENTS.MarkAdded, self.OnEventMark)
|
||||||
|
self:HandleEvent(EVENTS.MarkChange, self.OnEventMark)
|
||||||
|
self:HandleEvent(EVENTS.MarkRemoved, self.OnEventMark)
|
||||||
|
|
||||||
|
-- start
|
||||||
|
self:I(self.lid..string.format("started for %s",self.Tag))
|
||||||
|
self:__Start(1)
|
||||||
|
return self
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
-- PSEUDO Functions
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
|
||||||
|
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
|
||||||
|
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
|
||||||
|
--- "Stop" trigger. Used to stop the function an unhandle events
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] Stop
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (internal) Handle events.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA Event
|
||||||
|
function MARKEROPS_BASE:OnEventMark(Event)
|
||||||
|
self:T({Event})
|
||||||
|
if Event == nil or Event.idx == nil then
|
||||||
|
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
--position
|
||||||
|
local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}
|
||||||
|
local coord=COORDINATE:NewFromVec3(vec3)
|
||||||
|
if self.debug then
|
||||||
|
local coordtext = coord:ToStringLLDDM()
|
||||||
|
local text = tostring(Event.text)
|
||||||
|
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||||
|
end
|
||||||
|
-- decision
|
||||||
|
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||||
|
self:T({event="S_EVENT_MARK_ADDED", carrier=self.groupname, vec3=Event.pos})
|
||||||
|
-- Handle event
|
||||||
|
local Eventtext = tostring(Event.text)
|
||||||
|
if Eventtext~=nil then
|
||||||
|
if self:_MatchTag(Eventtext) then
|
||||||
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
|
self:MarkAdded(Eventtext,matchtable,coord)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||||
|
self:T({event="S_EVENT_MARK_CHANGE", carrier=self.groupname, vec3=Event.pos})
|
||||||
|
-- Handle event.
|
||||||
|
local Eventtext = tostring(Event.text)
|
||||||
|
if Eventtext~=nil then
|
||||||
|
if self:_MatchTag(Eventtext) then
|
||||||
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
|
self:MarkChanged(Eventtext,matchtable,coord)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||||
|
self:T({event="S_EVENT_MARK_REMOVED", carrier=self.groupname, vec3=Event.pos})
|
||||||
|
-- Hande event.
|
||||||
|
local Eventtext = tostring(Event.text)
|
||||||
|
if Eventtext~=nil then
|
||||||
|
if self:_MatchTag(Eventtext) then
|
||||||
|
self:MarkDeleted()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (internal) Match tag.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string Eventtext Text added to the marker.
|
||||||
|
-- @return #boolean
|
||||||
|
function MARKEROPS_BASE:_MatchTag(Eventtext)
|
||||||
|
local matches = false
|
||||||
|
if not self.Casesensitive then
|
||||||
|
local type = string.lower(self.Tag) -- #string
|
||||||
|
if string.find(string.lower(Eventtext),type) then
|
||||||
|
matches = true --event text contains tag
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local type = self.Tag -- #string
|
||||||
|
if string.find(Eventtext,type) then
|
||||||
|
matches = true --event text contains tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return matches
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (internal) Match keywords table.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string Eventtext Text added to the marker.
|
||||||
|
-- @return #table
|
||||||
|
function MARKEROPS_BASE:_MatchKeywords(Eventtext)
|
||||||
|
local matchtable = {}
|
||||||
|
local keytable = self.Keywords
|
||||||
|
for _index,_word in pairs (keytable) do
|
||||||
|
if string.find(string.lower(Eventtext),string.lower(_word))then
|
||||||
|
table.insert(matchtable,_word)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return matchtable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On before "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
|
||||||
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On before "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
|
||||||
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On before "MarkDeleted" event. Triggered when a Marker is removed from the F10 map.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
function MARKEROPS_BASE:onbeforeMarkDeleted(From,Event,To)
|
||||||
|
self:T({self.lid,From,Event,To})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On enter "Stopped" event. Unsubscribe events.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
function MARKEROPS_BASE:onenterStopped(From,Event,To)
|
||||||
|
self:T({self.lid,From,Event,To})
|
||||||
|
-- unsubscribe from events
|
||||||
|
self:UnHandleEvent(EVENTS.MarkAdded)
|
||||||
|
self:UnHandleEvent(EVENTS.MarkChange)
|
||||||
|
self:UnHandleEvent(EVENTS.MarkRemoved)
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
-- MARKEROPS_BASE Class Definition End.
|
||||||
|
--------------------------------------------------------------------------
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,8 @@
|
|||||||
-- * Send message to all players.
|
-- * Send message to all players.
|
||||||
-- * Send messages to a coalition.
|
-- * Send messages to a coalition.
|
||||||
-- * Send messages to a specific group.
|
-- * Send messages to a specific group.
|
||||||
--
|
-- * Send messages to a specific unit or client.
|
||||||
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Core.Message
|
-- @module Core.Message
|
||||||
@@ -33,8 +34,9 @@
|
|||||||
--
|
--
|
||||||
-- Messages are sent:
|
-- Messages are sent:
|
||||||
--
|
--
|
||||||
-- * To a @{Client} using @{#MESSAGE.ToClient}().
|
-- * To a @{Wrapper.Client} using @{#MESSAGE.ToClient}().
|
||||||
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
-- * To a @{Wrapper.Group} using @{#MESSAGE.ToGroup}()
|
||||||
|
-- * To a @{Wrapper.Unit} using @{#MESSAGE.ToUnit}()
|
||||||
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
-- * To a coalition using @{#MESSAGE.ToCoalition}().
|
||||||
-- * To the red coalition using @{#MESSAGE.ToRed}().
|
-- * To the red coalition using @{#MESSAGE.ToRed}().
|
||||||
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
|
-- * To the blue coalition using @{#MESSAGE.ToBlue}().
|
||||||
@@ -126,7 +128,7 @@ end
|
|||||||
--- Creates a new MESSAGE object of a certain type.
|
--- Creates a new MESSAGE object of a certain type.
|
||||||
-- Note that these MESSAGE objects are not yet displayed on the display panel.
|
-- Note that these MESSAGE objects are not yet displayed on the display panel.
|
||||||
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||||
-- The message display times are automatically defined based on the timing settings in the @{Settings} menu.
|
-- The message display times are automatically defined based on the timing settings in the @{Core.Settings} menu.
|
||||||
-- @param self
|
-- @param self
|
||||||
-- @param #string MessageText is the text of the Message.
|
-- @param #string MessageText is the text of the Message.
|
||||||
-- @param #MESSAGE.Type MessageType The type of the message.
|
-- @param #MESSAGE.Type MessageType The type of the message.
|
||||||
@@ -169,7 +171,7 @@ end
|
|||||||
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
|
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
|
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
|
||||||
-- @param Core.Settings#SETTINGS Settings Settings used to display the message.
|
-- @param Core.Settings#SETTINGS Settings used to display the message.
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -180,11 +182,11 @@ end
|
|||||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
||||||
-- or
|
-- or
|
||||||
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
-- MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25 ):ToClient( ClientGroup )
|
||||||
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" ):ToClient( ClientGroup )
|
-- MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25 ):ToClient( ClientGroup )
|
||||||
-- or
|
-- or
|
||||||
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25, "Score" )
|
-- MessageClient1 = MESSAGE:New( "Congratulations, you've just hit a target", "Score", 25 )
|
||||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
|
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25 )
|
||||||
-- MessageClient1:ToClient( ClientGroup )
|
-- MessageClient1:ToClient( ClientGroup )
|
||||||
-- MessageClient2:ToClient( ClientGroup )
|
-- MessageClient2:ToClient( ClientGroup )
|
||||||
--
|
--
|
||||||
@@ -194,19 +196,22 @@ function MESSAGE:ToClient( Client, Settings )
|
|||||||
if Client and Client:GetClientGroupID() then
|
if Client and Client:GetClientGroupID() then
|
||||||
|
|
||||||
if self.MessageType then
|
if self.MessageType then
|
||||||
local Settings = Settings or (Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() )) or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local Unit = Client:GetClient()
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
local ClientGroupID = Client:GetClientGroupID()
|
local ClientGroupID = Client:GetClientGroupID()
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ) .. " / " .. self.MessageDuration )
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub( "\n$", "" ):gsub( "\n$", "" ), self.MessageDuration, self.ClearScreen )
|
--trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
end
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
return self
|
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sends a MESSAGE to a Group.
|
--- Sends a MESSAGE to a Group.
|
||||||
@@ -232,17 +237,42 @@ function MESSAGE:ToGroup( Group, Settings )
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sends a MESSAGE to a Unit.
|
||||||
|
-- @param #MESSAGE self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
|
||||||
|
-- @return #MESSAGE Message object.
|
||||||
|
function MESSAGE:ToUnit( Unit, Settings )
|
||||||
|
self:F( Unit.IdentifiableName )
|
||||||
|
|
||||||
|
if Unit then
|
||||||
|
|
||||||
|
if self.MessageType then
|
||||||
|
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.MessageDuration ~= 0 then
|
||||||
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Sends a MESSAGE to the Blue coalition.
|
--- Sends a MESSAGE to the Blue coalition.
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Send a message created with the @{New} method to the BLUE coalition.
|
-- -- Send a message created with the @{New} method to the BLUE coalition.
|
||||||
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
|
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25):ToBlue()
|
||||||
-- or
|
-- or
|
||||||
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToBlue()
|
-- MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToBlue()
|
||||||
-- or
|
-- or
|
||||||
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
|
-- MessageBLUE = MESSAGE:New( "To the BLUE Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 )
|
||||||
-- MessageBLUE:ToBlue()
|
-- MessageBLUE:ToBlue()
|
||||||
--
|
--
|
||||||
function MESSAGE:ToBlue()
|
function MESSAGE:ToBlue()
|
||||||
@@ -259,11 +289,11 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Send a message created with the @{New} method to the RED coalition.
|
-- -- Send a message created with the @{New} method to the RED coalition.
|
||||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
|
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToRed()
|
||||||
-- or
|
-- or
|
||||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToRed()
|
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToRed()
|
||||||
-- or
|
-- or
|
||||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
|
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 )
|
||||||
-- MessageRED:ToRed()
|
-- MessageRED:ToRed()
|
||||||
--
|
--
|
||||||
function MESSAGE:ToRed()
|
function MESSAGE:ToRed()
|
||||||
@@ -282,11 +312,11 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Send a message created with the @{New} method to the RED coalition.
|
-- -- Send a message created with the @{New} method to the RED coalition.
|
||||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
|
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToCoalition( coalition.side.RED )
|
||||||
-- or
|
-- or
|
||||||
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" ):ToCoalition( coalition.side.RED )
|
-- MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 ):ToCoalition( coalition.side.RED )
|
||||||
-- or
|
-- or
|
||||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
|
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25 )
|
||||||
-- MessageRED:ToCoalition( coalition.side.RED )
|
-- MessageRED:ToCoalition( coalition.side.RED )
|
||||||
--
|
--
|
||||||
function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
||||||
@@ -330,11 +360,11 @@ end
|
|||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- -- Send a message created to all players.
|
-- -- Send a message created to all players.
|
||||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
|
||||||
-- or
|
-- or
|
||||||
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" ):ToAll()
|
-- MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 ):ToAll()
|
||||||
-- or
|
-- or
|
||||||
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25, "Win" )
|
-- MessageAll = MESSAGE:New( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", "End of Mission", 25 )
|
||||||
-- MessageAll:ToAll()
|
-- MessageAll:ToAll()
|
||||||
--
|
--
|
||||||
function MESSAGE:ToAll( Settings )
|
function MESSAGE:ToAll( Settings )
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ do -- COORDINATE
|
|||||||
--
|
--
|
||||||
-- Calculate if the coordinate has Line of Sight (LOS) with the other given coordinate.
|
-- Calculate if the coordinate has Line of Sight (LOS) with the other given coordinate.
|
||||||
-- Mountains, trees and other objects can be positioned between the two 3D points, preventing visibilty in a straight continuous line.
|
-- Mountains, trees and other objects can be positioned between the two 3D points, preventing visibilty in a straight continuous line.
|
||||||
-- The method @{#COORDINATE.IsLOS}() returns if the two coodinates have LOS.
|
-- The method @{#COORDINATE.IsLOS}() returns if the two coordinates have LOS.
|
||||||
--
|
--
|
||||||
-- ## 4.7) Check the coordinate position.
|
-- ## 4.7) Check the coordinate position.
|
||||||
--
|
--
|
||||||
@@ -194,7 +194,12 @@ do -- COORDINATE
|
|||||||
-- ## 9) Coordinate text generation
|
-- ## 9) Coordinate text generation
|
||||||
--
|
--
|
||||||
-- * @{#COORDINATE.ToStringBR}(): Generates a Bearing & Range text in the format of DDD for DI where DDD is degrees and DI is distance.
|
-- * @{#COORDINATE.ToStringBR}(): Generates a Bearing & Range text in the format of DDD for DI where DDD is degrees and DI is distance.
|
||||||
-- * @{#COORDINATE.ToStringLL}(): Generates a Latutude & Longutude text.
|
-- * @{#COORDINATE.ToStringBRA}(): Generates a Bearing, Range & Altitude text.
|
||||||
|
-- * @{#COORDINATE.ToStringBRAANATO}(): Generates a Generates a Bearing, Range, Aspect & Altitude text in NATOPS.
|
||||||
|
-- * @{#COORDINATE.ToStringLL}(): Generates a Latutide & Longitude text.
|
||||||
|
-- * @{#COORDINATE.ToStringLLDMS}(): Generates a Lat, Lon, Degree, Minute, Second text.
|
||||||
|
-- * @{#COORDINATE.ToStringLLDDM}(): Generates a Lat, Lon, Degree, decimal Minute text.
|
||||||
|
-- * @{#COORDINATE.ToStringMGRS}(): Generates a MGRS grid coordinate text.
|
||||||
--
|
--
|
||||||
-- ## 10) Drawings on F10 map
|
-- ## 10) Drawings on F10 map
|
||||||
--
|
--
|
||||||
@@ -589,7 +594,7 @@ do -- COORDINATE
|
|||||||
--- Scan/find SCENERY objects within a certain radius around the coordinate using the world.searchObjects() DCS API function.
|
--- Scan/find SCENERY objects within a certain radius around the coordinate using the world.searchObjects() DCS API function.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number radius (Optional) Scan radius in meters. Default 100 m.
|
-- @param #number radius (Optional) Scan radius in meters. Default 100 m.
|
||||||
-- @return table Set of scenery objects.
|
-- @return table Table of SCENERY objects.
|
||||||
function COORDINATE:ScanScenery(radius)
|
function COORDINATE:ScanScenery(radius)
|
||||||
|
|
||||||
local _,_,_,_,_,scenerys=self:ScanObjects(radius, false, false, true)
|
local _,_,_,_,_,scenerys=self:ScanObjects(radius, false, false, true)
|
||||||
@@ -649,7 +654,7 @@ do -- COORDINATE
|
|||||||
-- @param DCS#Distance Distance The Distance to be added in meters.
|
-- @param DCS#Distance Distance The Distance to be added in meters.
|
||||||
-- @param DCS#Angle Angle The Angle in degrees. Defaults to 0 if not specified (nil).
|
-- @param DCS#Angle Angle The Angle in degrees. Defaults to 0 if not specified (nil).
|
||||||
-- @param #boolean Keepalt If true, keep altitude of original coordinate. Default is that the new coordinate is created at the translated land height.
|
-- @param #boolean Keepalt If true, keep altitude of original coordinate. Default is that the new coordinate is created at the translated land height.
|
||||||
-- @param #boolean Overwrite If true, overwrite the original COORDINATE with the translated one. Otherwise, create a new COODINATE.
|
-- @param #boolean Overwrite If true, overwrite the original COORDINATE with the translated one. Otherwise, create a new COORDINATE.
|
||||||
-- @return #COORDINATE The new calculated COORDINATE.
|
-- @return #COORDINATE The new calculated COORDINATE.
|
||||||
function COORDINATE:Translate( Distance, Angle, Keepalt, Overwrite )
|
function COORDINATE:Translate( Distance, Angle, Keepalt, Overwrite )
|
||||||
|
|
||||||
@@ -820,7 +825,11 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
||||||
-- @return DCS#Vec3 DirectionVec3 The direction vector in Vec3 format.
|
-- @return DCS#Vec3 DirectionVec3 The direction vector in Vec3 format.
|
||||||
function COORDINATE:GetDirectionVec3( TargetCoordinate )
|
function COORDINATE:GetDirectionVec3( TargetCoordinate )
|
||||||
return { x = TargetCoordinate.x - self.x, y = TargetCoordinate.y - self.y, z = TargetCoordinate.z - self.z }
|
if TargetCoordinate then
|
||||||
|
return { x = TargetCoordinate.x - self.x, y = TargetCoordinate.y - self.y, z = TargetCoordinate.z - self.z }
|
||||||
|
else
|
||||||
|
return { x=0,y=0,z=0}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -869,6 +878,11 @@ do -- COORDINATE
|
|||||||
|
|
||||||
-- Get the vector from A to B
|
-- Get the vector from A to B
|
||||||
local vec=UTILS.VecSubstract(ToCoordinate, self)
|
local vec=UTILS.VecSubstract(ToCoordinate, self)
|
||||||
|
|
||||||
|
if f>1 then
|
||||||
|
local norm=UTILS.VecNorm(vec)
|
||||||
|
f=Fraction/norm
|
||||||
|
end
|
||||||
|
|
||||||
-- Scale the vector.
|
-- Scale the vector.
|
||||||
vec.x=f*vec.x
|
vec.x=f*vec.x
|
||||||
@@ -878,7 +892,9 @@ do -- COORDINATE
|
|||||||
-- Move the vector to start at the end of A.
|
-- Move the vector to start at the end of A.
|
||||||
vec=UTILS.VecAdd(self, vec)
|
vec=UTILS.VecAdd(self, vec)
|
||||||
|
|
||||||
|
-- Create a new coordiante object.
|
||||||
local coord=COORDINATE:New(vec.x,vec.y,vec.z)
|
local coord=COORDINATE:New(vec.x,vec.y,vec.z)
|
||||||
|
|
||||||
return coord
|
return coord
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -887,9 +903,8 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE. Can also be a DCS#Vec3.
|
-- @param #COORDINATE TargetCoordinate The target COORDINATE. Can also be a DCS#Vec3.
|
||||||
-- @return DCS#Distance Distance The distance in meters.
|
-- @return DCS#Distance Distance The distance in meters.
|
||||||
function COORDINATE:Get2DDistance(TargetCoordinate)
|
function COORDINATE:Get2DDistance(TargetCoordinate)
|
||||||
|
if not TargetCoordinate then return 1000000 end
|
||||||
local a={x=TargetCoordinate.x-self.x, y=0, z=TargetCoordinate.z-self.z}
|
local a={x=TargetCoordinate.x-self.x, y=0, z=TargetCoordinate.z-self.z}
|
||||||
|
|
||||||
local norm=UTILS.VecNorm(a)
|
local norm=UTILS.VecNorm(a)
|
||||||
return norm
|
return norm
|
||||||
end
|
end
|
||||||
@@ -908,7 +923,7 @@ do -- COORDINATE
|
|||||||
return T-273.15
|
return T-273.15
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a text of the temperature according the measurement system @{Settings}.
|
--- Returns a text of the temperature according the measurement system @{Core.Settings}.
|
||||||
-- The text will reflect the temperature like this:
|
-- The text will reflect the temperature like this:
|
||||||
--
|
--
|
||||||
-- - For Russian and European aircraft using the metric system - Degrees Celcius (°C)
|
-- - For Russian and European aircraft using the metric system - Degrees Celcius (°C)
|
||||||
@@ -921,7 +936,7 @@ do -- COORDINATE
|
|||||||
--
|
--
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param height (Optional) parameter specifying the height ASL.
|
-- @param height (Optional) parameter specifying the height ASL.
|
||||||
-- @return #string Temperature according the measurement system @{Settings}.
|
-- @return #string Temperature according the measurement system @{Core.Settings}.
|
||||||
function COORDINATE:GetTemperatureText( height, Settings )
|
function COORDINATE:GetTemperatureText( height, Settings )
|
||||||
|
|
||||||
local DegreesCelcius = self:GetTemperature( height )
|
local DegreesCelcius = self:GetTemperature( height )
|
||||||
@@ -954,7 +969,7 @@ do -- COORDINATE
|
|||||||
return P/100
|
return P/100
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a text of the pressure according the measurement system @{Settings}.
|
--- Returns a text of the pressure according the measurement system @{Core.Settings}.
|
||||||
-- The text will contain always the pressure in hPa and:
|
-- The text will contain always the pressure in hPa and:
|
||||||
--
|
--
|
||||||
-- - For Russian and European aircraft using the metric system - hPa and mmHg
|
-- - For Russian and European aircraft using the metric system - hPa and mmHg
|
||||||
@@ -967,7 +982,7 @@ do -- COORDINATE
|
|||||||
--
|
--
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param height (Optional) parameter specifying the height ASL. E.g. set height=0 for QNH.
|
-- @param height (Optional) parameter specifying the height ASL. E.g. set height=0 for QNH.
|
||||||
-- @return #string Pressure in hPa and mmHg or inHg depending on the measurement system @{Settings}.
|
-- @return #string Pressure in hPa and mmHg or inHg depending on the measurement system @{Core.Settings}.
|
||||||
function COORDINATE:GetPressureText( height, Settings )
|
function COORDINATE:GetPressureText( height, Settings )
|
||||||
|
|
||||||
local Pressure_hPa = self:GetPressure( height )
|
local Pressure_hPa = self:GetPressure( height )
|
||||||
@@ -1047,7 +1062,7 @@ do -- COORDINATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Settings}.
|
--- Returns a text documenting the wind direction (from) and strength according the measurement system @{Core.Settings}.
|
||||||
-- The text will reflect the wind like this:
|
-- The text will reflect the wind like this:
|
||||||
--
|
--
|
||||||
-- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps).
|
-- - For Russian and European aircraft using the metric system - Wind direction in degrees (°) and wind speed in meters per second (mps).
|
||||||
@@ -1060,7 +1075,7 @@ do -- COORDINATE
|
|||||||
--
|
--
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
|
-- @param height (Optional) parameter specifying the height ASL. The minimum height will be always be the land height since the wind is zero below the ground.
|
||||||
-- @return #string Wind direction and strength according the measurement system @{Settings}.
|
-- @return #string Wind direction and strength according the measurement system @{Core.Settings}.
|
||||||
function COORDINATE:GetWindText( height, Settings )
|
function COORDINATE:GetWindText( height, Settings )
|
||||||
|
|
||||||
local Direction, Strength = self:GetWind( height )
|
local Direction, Strength = self:GetWind( height )
|
||||||
@@ -1096,15 +1111,25 @@ do -- COORDINATE
|
|||||||
-- @param #number AngleRadians The angle in randians.
|
-- @param #number AngleRadians The angle in randians.
|
||||||
-- @param #number Precision The precision.
|
-- @param #number Precision The precision.
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings
|
||||||
|
-- @param #boolean MagVar If true, include magentic degrees
|
||||||
-- @return #string The bearing text in degrees.
|
-- @return #string The bearing text in degrees.
|
||||||
function COORDINATE:GetBearingText( AngleRadians, Precision, Settings, Language )
|
function COORDINATE:GetBearingText( AngleRadians, Precision, Settings, MagVar )
|
||||||
|
|
||||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
|
||||||
local AngleDegrees = UTILS.Round( UTILS.ToDegree( AngleRadians ), Precision )
|
local AngleDegrees = UTILS.Round( UTILS.ToDegree( AngleRadians ), Precision )
|
||||||
|
|
||||||
local s = string.format( '%03d°', AngleDegrees )
|
local s = string.format( '%03d°', AngleDegrees )
|
||||||
|
|
||||||
|
if MagVar then
|
||||||
|
local variation = UTILS.GetMagneticDeclination() or 0
|
||||||
|
local AngleMagnetic = AngleDegrees - variation
|
||||||
|
|
||||||
|
if AngleMagnetic < 0 then AngleMagnetic = 360-AngleMagnetic end
|
||||||
|
|
||||||
|
s = string.format( '%03d°M|%03d°', AngleMagnetic,AngleDegrees )
|
||||||
|
end
|
||||||
|
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1112,25 +1137,29 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Distance The distance in meters.
|
-- @param #number Distance The distance in meters.
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings
|
||||||
|
-- @param #string Language (optional) "EN" or "RU"
|
||||||
|
-- @param #number Precision (optional) round to this many decimal places
|
||||||
-- @return #string The distance text expressed in the units of measurement.
|
-- @return #string The distance text expressed in the units of measurement.
|
||||||
function COORDINATE:GetDistanceText( Distance, Settings, Language )
|
function COORDINATE:GetDistanceText( Distance, Settings, Language, Precision )
|
||||||
|
|
||||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
local Language = Language or "EN"
|
local Language = Language or Settings.Locale or _SETTINGS.Locale or "EN"
|
||||||
|
Language = string.lower(Language)
|
||||||
|
local Precision = Precision or 0
|
||||||
|
|
||||||
local DistanceText
|
local DistanceText
|
||||||
|
|
||||||
if Settings:IsMetric() then
|
if Settings:IsMetric() then
|
||||||
if Language == "EN" then
|
if Language == "en" then
|
||||||
DistanceText = " for " .. UTILS.Round( Distance / 1000, 2 ) .. " km"
|
DistanceText = " for " .. UTILS.Round( Distance / 1000, Precision ) .. " km"
|
||||||
elseif Language == "RU" then
|
elseif Language == "ru" then
|
||||||
DistanceText = " за " .. UTILS.Round( Distance / 1000, 2 ) .. " километров"
|
DistanceText = " за " .. UTILS.Round( Distance / 1000, Precision ) .. " километров"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if Language == "EN" then
|
if Language == "en" then
|
||||||
DistanceText = " for " .. UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) .. " miles"
|
DistanceText = " for " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " miles"
|
||||||
elseif Language == "RU" then
|
elseif Language == "ru" then
|
||||||
DistanceText = " за " .. UTILS.Round( UTILS.MetersToNM( Distance ), 2 ) .. " миль"
|
DistanceText = " за " .. UTILS.Round( UTILS.MetersToNM( Distance ), Precision ) .. " миль"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1143,19 +1172,21 @@ do -- COORDINATE
|
|||||||
function COORDINATE:GetAltitudeText( Settings, Language )
|
function COORDINATE:GetAltitudeText( Settings, Language )
|
||||||
local Altitude = self.y
|
local Altitude = self.y
|
||||||
local Settings = Settings or _SETTINGS
|
local Settings = Settings or _SETTINGS
|
||||||
local Language = Language or "EN"
|
local Language = Language or Settings.Locale or _SETTINGS.Locale or "EN"
|
||||||
|
|
||||||
|
Language = string.lower(Language)
|
||||||
|
|
||||||
if Altitude ~= 0 then
|
if Altitude ~= 0 then
|
||||||
if Settings:IsMetric() then
|
if Settings:IsMetric() then
|
||||||
if Language == "EN" then
|
if Language == "en" then
|
||||||
return " at " .. UTILS.Round( self.y, -3 ) .. " meters"
|
return " at " .. UTILS.Round( self.y, -3 ) .. " meters"
|
||||||
elseif Language == "RU" then
|
elseif Language == "ru" then
|
||||||
return " в " .. UTILS.Round( self.y, -3 ) .. " метры"
|
return " в " .. UTILS.Round( self.y, -3 ) .. " метры"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if Language == "EN" then
|
if Language == "en" then
|
||||||
return " at " .. UTILS.Round( UTILS.MetersToFeet( self.y ), -3 ) .. " feet"
|
return " at " .. UTILS.Round( UTILS.MetersToFeet( self.y ), -3 ) .. " feet"
|
||||||
elseif Language == "RU" then
|
elseif Language == "ru" then
|
||||||
return " в " .. UTILS.Round( self.y, -3 ) .. " ноги"
|
return " в " .. UTILS.Round( self.y, -3 ) .. " ноги"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1202,13 +1233,15 @@ do -- COORDINATE
|
|||||||
-- @param #number AngleRadians The angle in randians
|
-- @param #number AngleRadians The angle in randians
|
||||||
-- @param #number Distance The distance
|
-- @param #number Distance The distance
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings
|
||||||
|
-- @param #string Language (Optional) Language "en" or "ru"
|
||||||
|
-- @param #boolean MagVar If true, also state angle in magnetic
|
||||||
-- @return #string The BR Text
|
-- @return #string The BR Text
|
||||||
function COORDINATE:GetBRText( AngleRadians, Distance, Settings, Language )
|
function COORDINATE:GetBRText( AngleRadians, Distance, Settings, Language, MagVar )
|
||||||
|
|
||||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
|
||||||
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, Language )
|
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, MagVar )
|
||||||
local DistanceText = self:GetDistanceText( Distance, Settings, Language )
|
local DistanceText = self:GetDistanceText( Distance, Settings, Language, 0 )
|
||||||
|
|
||||||
local BRText = BearingText .. DistanceText
|
local BRText = BearingText .. DistanceText
|
||||||
|
|
||||||
@@ -1220,13 +1253,15 @@ do -- COORDINATE
|
|||||||
-- @param #number AngleRadians The angle in randians
|
-- @param #number AngleRadians The angle in randians
|
||||||
-- @param #number Distance The distance
|
-- @param #number Distance The distance
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings
|
||||||
|
-- @param #string Language (Optional) Language "en" or "ru"
|
||||||
|
-- @param #boolean MagVar If true, also state angle in magnetic
|
||||||
-- @return #string The BRA Text
|
-- @return #string The BRA Text
|
||||||
function COORDINATE:GetBRAText( AngleRadians, Distance, Settings, Language )
|
function COORDINATE:GetBRAText( AngleRadians, Distance, Settings, Language, MagVar )
|
||||||
|
|
||||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
|
||||||
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, Language )
|
local BearingText = self:GetBearingText( AngleRadians, 0, Settings, MagVar )
|
||||||
local DistanceText = self:GetDistanceText( Distance, Settings, Language )
|
local DistanceText = self:GetDistanceText( Distance, Settings, Language, 0 )
|
||||||
local AltitudeText = self:GetAltitudeText( Settings, Language )
|
local AltitudeText = self:GetAltitudeText( Settings, Language )
|
||||||
|
|
||||||
local BRAText = BearingText .. DistanceText .. AltitudeText -- When the POINT is a VEC2, there will be no altitude shown.
|
local BRAText = BearingText .. DistanceText .. AltitudeText -- When the POINT is a VEC2, there will be no altitude shown.
|
||||||
@@ -1501,7 +1536,7 @@ do -- COORDINATE
|
|||||||
-- @param #number Coalition (Optional) Coalition of the airbase.
|
-- @param #number Coalition (Optional) Coalition of the airbase.
|
||||||
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
||||||
-- @return #number Distance to the closest airbase in meters.
|
-- @return #number Distance to the closest airbase in meters.
|
||||||
function COORDINATE:GetClosestAirbase2(Category, Coalition)
|
function COORDINATE:GetClosestAirbase(Category, Coalition)
|
||||||
|
|
||||||
-- Get all airbases of the map.
|
-- Get all airbases of the map.
|
||||||
local airbases=AIRBASE.GetAllAirbases(Coalition)
|
local airbases=AIRBASE.GetAllAirbases(Coalition)
|
||||||
@@ -1535,34 +1570,15 @@ do -- COORDINATE
|
|||||||
return closest,distmin
|
return closest,distmin
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the nearest airbase with respect to the current coordinates.
|
--- [kept for downwards compatibility only] Gets the nearest airbase with respect to the current coordinates.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #number Category (Optional) Category of the airbase. Enumerator of @{Wrapper.Airbase#AIRBASE.Category}.
|
-- @param #number Category (Optional) Category of the airbase. Enumerator of @{Wrapper.Airbase#AIRBASE.Category}.
|
||||||
-- @param #number Coalition (Optional) Coalition of the airbase.
|
-- @param #number Coalition (Optional) Coalition of the airbase.
|
||||||
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
|
||||||
-- @return #number Distance to the closest airbase in meters.
|
-- @return #number Distance to the closest airbase in meters.
|
||||||
function COORDINATE:GetClosestAirbase(Category, Coalition)
|
function COORDINATE:GetClosestAirbase2(Category, Coalition)
|
||||||
|
local closest, distmin = self:GetClosestAirbase(Category, Coalition)
|
||||||
local a=self:GetVec3()
|
return closest, distmin
|
||||||
|
|
||||||
local distmin=math.huge
|
|
||||||
local airbase=nil
|
|
||||||
for DCSairbaseID, DCSairbase in pairs(world.getAirbases(Coalition)) do
|
|
||||||
local b=DCSairbase:getPoint()
|
|
||||||
|
|
||||||
local c=UTILS.VecSubstract(a,b)
|
|
||||||
local dist=UTILS.VecNorm(c)
|
|
||||||
|
|
||||||
--env.info(string.format("Airbase %s dist=%d category=%d", DCSairbase:getName(), dist, DCSairbase:getCategory()))
|
|
||||||
|
|
||||||
if dist<distmin and (Category==nil or Category==DCSairbase:getDesc().category) then
|
|
||||||
distmin=dist
|
|
||||||
airbase=DCSairbase
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return AIRBASE:Find(airbase)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the nearest parking spot.
|
--- Gets the nearest parking spot.
|
||||||
@@ -2164,14 +2180,21 @@ do -- COORDINATE
|
|||||||
if ReadOnly==nil then
|
if ReadOnly==nil then
|
||||||
ReadOnly=false
|
ReadOnly=false
|
||||||
end
|
end
|
||||||
|
|
||||||
local vec3=self:GetVec3()
|
local vec3=self:GetVec3()
|
||||||
|
|
||||||
Radius=Radius or 1000
|
Radius=Radius or 1000
|
||||||
|
|
||||||
Coalition=Coalition or -1
|
Coalition=Coalition or -1
|
||||||
|
|
||||||
Color=Color or {1,0,0}
|
Color=Color or {1,0,0}
|
||||||
Color[4]=Alpha or 1.0
|
Color[4]=Alpha or 1.0
|
||||||
|
|
||||||
LineType=LineType or 1
|
LineType=LineType or 1
|
||||||
FillColor=FillColor or Color
|
|
||||||
|
FillColor=FillColor or UTILS.DeepCopy(Color)
|
||||||
FillColor[4]=FillAlpha or 0.15
|
FillColor[4]=FillAlpha or 0.15
|
||||||
|
|
||||||
trigger.action.circleToAll(Coalition, MarkID, vec3, Radius, Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.circleToAll(Coalition, MarkID, vec3, Radius, Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
return MarkID
|
return MarkID
|
||||||
end
|
end
|
||||||
@@ -2196,13 +2219,19 @@ do -- COORDINATE
|
|||||||
if ReadOnly==nil then
|
if ReadOnly==nil then
|
||||||
ReadOnly=false
|
ReadOnly=false
|
||||||
end
|
end
|
||||||
|
|
||||||
local vec3=Endpoint:GetVec3()
|
local vec3=Endpoint:GetVec3()
|
||||||
|
|
||||||
Coalition=Coalition or -1
|
Coalition=Coalition or -1
|
||||||
|
|
||||||
Color=Color or {1,0,0}
|
Color=Color or {1,0,0}
|
||||||
Color[4]=Alpha or 1.0
|
Color[4]=Alpha or 1.0
|
||||||
|
|
||||||
LineType=LineType or 1
|
LineType=LineType or 1
|
||||||
FillColor=FillColor or Color
|
|
||||||
|
FillColor=FillColor or UTILS.DeepCopy(Color)
|
||||||
FillColor[4]=FillAlpha or 0.15
|
FillColor[4]=FillAlpha or 0.15
|
||||||
|
|
||||||
trigger.action.rectToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.rectToAll(Coalition, MarkID, self:GetVec3(), vec3, Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
return MarkID
|
return MarkID
|
||||||
end
|
end
|
||||||
@@ -2226,22 +2255,28 @@ do -- COORDINATE
|
|||||||
if ReadOnly==nil then
|
if ReadOnly==nil then
|
||||||
ReadOnly=false
|
ReadOnly=false
|
||||||
end
|
end
|
||||||
|
|
||||||
local point1=self:GetVec3()
|
local point1=self:GetVec3()
|
||||||
local point2=Coord2:GetVec3()
|
local point2=Coord2:GetVec3()
|
||||||
local point3=Coord3:GetVec3()
|
local point3=Coord3:GetVec3()
|
||||||
local point4=Coord4:GetVec3()
|
local point4=Coord4:GetVec3()
|
||||||
|
|
||||||
Coalition=Coalition or -1
|
Coalition=Coalition or -1
|
||||||
|
|
||||||
Color=Color or {1,0,0}
|
Color=Color or {1,0,0}
|
||||||
Color[4]=Alpha or 1.0
|
Color[4]=Alpha or 1.0
|
||||||
|
|
||||||
LineType=LineType or 1
|
LineType=LineType or 1
|
||||||
FillColor=FillColor or Color
|
|
||||||
|
FillColor=FillColor or UTILS.DeepCopy(Color)
|
||||||
FillColor[4]=FillAlpha or 0.15
|
FillColor[4]=FillAlpha or 0.15
|
||||||
trigger.action.quadToAll(Coalition, MarkID, self:GetVec3(), point2, point3, point4, Color, FillColor, LineType, ReadOnly, Text or "")
|
|
||||||
|
trigger.action.quadToAll(Coalition, MarkID, point1, point2, point3, point4, Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
return MarkID
|
return MarkID
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified.
|
--- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified.
|
||||||
-- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 10 points** in total are supported.
|
-- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 15 points** in total are supported.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #table Coordinates Table of coordinates of the remaining points of the shape.
|
-- @param #table Coordinates Table of coordinates of the remaining points of the shape.
|
||||||
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
||||||
@@ -2294,8 +2329,28 @@ do -- COORDINATE
|
|||||||
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
elseif #vecs==10 then
|
elseif #vecs==10 then
|
||||||
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==11 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==12 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==13 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12], vecs[13],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==14 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12], vecs[13], vecs[14],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==15 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12], vecs[13], vecs[14], vecs[15],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
else
|
else
|
||||||
self:E("ERROR: Currently a free form polygon can only have 10 points in total!")
|
self:E("ERROR: Currently a free form polygon can only have 15 points in total!")
|
||||||
-- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :(
|
-- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :(
|
||||||
trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
end
|
end
|
||||||
@@ -2320,11 +2375,15 @@ do -- COORDINATE
|
|||||||
ReadOnly=false
|
ReadOnly=false
|
||||||
end
|
end
|
||||||
Coalition=Coalition or -1
|
Coalition=Coalition or -1
|
||||||
|
|
||||||
Color=Color or {1,0,0}
|
Color=Color or {1,0,0}
|
||||||
Color[4]=Alpha or 1.0
|
Color[4]=Alpha or 1.0
|
||||||
FillColor=FillColor or Color
|
|
||||||
|
FillColor=FillColor or UTILS.DeepCopy(Color)
|
||||||
FillColor[4]=FillAlpha or 0.3
|
FillColor[4]=FillAlpha or 0.3
|
||||||
|
|
||||||
FontSize=FontSize or 14
|
FontSize=FontSize or 14
|
||||||
|
|
||||||
trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World")
|
trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World")
|
||||||
return MarkID
|
return MarkID
|
||||||
end
|
end
|
||||||
@@ -2346,13 +2405,19 @@ do -- COORDINATE
|
|||||||
if ReadOnly==nil then
|
if ReadOnly==nil then
|
||||||
ReadOnly=false
|
ReadOnly=false
|
||||||
end
|
end
|
||||||
|
|
||||||
local vec3=Endpoint:GetVec3()
|
local vec3=Endpoint:GetVec3()
|
||||||
|
|
||||||
Coalition=Coalition or -1
|
Coalition=Coalition or -1
|
||||||
|
|
||||||
Color=Color or {1,0,0}
|
Color=Color or {1,0,0}
|
||||||
Color[4]=Alpha or 1.0
|
Color[4]=Alpha or 1.0
|
||||||
|
|
||||||
LineType=LineType or 1
|
LineType=LineType or 1
|
||||||
FillColor=FillColor or Color
|
|
||||||
|
FillColor=FillColor or UTILS.DeepCopy(Color)
|
||||||
FillColor[4]=FillAlpha or 0.15
|
FillColor[4]=FillAlpha or 0.15
|
||||||
|
|
||||||
--trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World")
|
--trigger.action.textToAll(Coalition, MarkID, self:GetVec3(), Color, FillColor, FontSize, ReadOnly, Text or "Hello World")
|
||||||
trigger.action.arrowToAll(Coalition, MarkID, vec3, self:GetVec3(), Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.arrowToAll(Coalition, MarkID, vec3, self:GetVec3(), Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
return MarkID
|
return MarkID
|
||||||
@@ -2707,39 +2772,130 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
|
||||||
-- @return #string The BR text.
|
-- @return #string The BR text.
|
||||||
function COORDINATE:ToStringBR( FromCoordinate, Settings )
|
function COORDINATE:ToStringBR( FromCoordinate, Settings, MagVar )
|
||||||
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
||||||
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
local Distance = self:Get2DDistance( FromCoordinate )
|
local Distance = self:Get2DDistance( FromCoordinate )
|
||||||
return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings )
|
return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a BRAA string from a COORDINATE to the COORDINATE.
|
--- Return a BRA string from a COORDINATE to the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
|
||||||
-- @return #string The BR text.
|
-- @return #string The BR text.
|
||||||
function COORDINATE:ToStringBRA( FromCoordinate, Settings, Language )
|
function COORDINATE:ToStringBRA( FromCoordinate, Settings, MagVar )
|
||||||
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
||||||
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
local Distance = FromCoordinate:Get2DDistance( self )
|
local Distance = FromCoordinate:Get2DDistance( self )
|
||||||
local Altitude = self:GetAltitudeText()
|
local Altitude = self:GetAltitudeText()
|
||||||
return "BRA, " .. self:GetBRAText( AngleRadians, Distance, Settings, Language )
|
return "BRA, " .. self:GetBRAText( AngleRadians, Distance, Settings, nil, MagVar )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Create a BRAA NATO call string to this COORDINATE from the FromCOORDINATE. Note - BRA delivered if no aspect can be obtained and "Merged" if range < 3nm
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||||
|
-- @param #boolean Bogey Add "Bogey" at the end if true (not yet declared hostile or friendly)
|
||||||
|
-- @param #boolean Spades Add "Spades" at the end if true (no IFF/VID ID yet known)
|
||||||
|
-- @param #boolean SSML Add SSML tags speaking aspect as 0 1 2 and "brah" instead of BRAA
|
||||||
|
-- @param #boolean Angels If true, altitude is e.g. "Angels 25" (i.e., a friendly plane), else "25 thousand"
|
||||||
|
-- @param #boolean Zeros If using SSML, be aware that Google TTS will say "oh" and not "zero" for "0"; if Zeros is set to true, "0" will be replaced with "zero"
|
||||||
|
-- @return #string The BRAA text.
|
||||||
|
function COORDINATE:ToStringBRAANATO(FromCoordinate,Bogey,Spades,SSML,Angels,Zeros)
|
||||||
|
|
||||||
|
-- Thanks to @Pikey
|
||||||
|
local BRAANATO = "Merged."
|
||||||
|
|
||||||
|
local currentCoord = FromCoordinate
|
||||||
|
local DirectionVec3 = FromCoordinate:GetDirectionVec3( self )
|
||||||
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
|
|
||||||
|
local bearing = UTILS.Round( UTILS.ToDegree( AngleRadians ),0 )
|
||||||
|
|
||||||
|
local rangeMetres = self:Get2DDistance(currentCoord)
|
||||||
|
local rangeNM = UTILS.Round( UTILS.MetersToNM(rangeMetres), 0)
|
||||||
|
|
||||||
|
local aspect = self:ToStringAspect(currentCoord)
|
||||||
|
|
||||||
|
local alt = UTILS.Round(UTILS.MetersToFeet(self.y)/1000,0)--*1000
|
||||||
|
|
||||||
|
local alttext = string.format("%d thousand",alt)
|
||||||
|
|
||||||
|
if Angels then
|
||||||
|
alttext = string.format("Angels %d",alt)
|
||||||
|
end
|
||||||
|
|
||||||
|
if alt < 1 then
|
||||||
|
alttext = "very low"
|
||||||
|
end
|
||||||
|
|
||||||
|
local track = UTILS.BearingToCardinal(bearing) or "North"
|
||||||
|
|
||||||
|
if rangeNM > 3 then
|
||||||
|
if SSML then -- google says "oh" instead of zero, be aware
|
||||||
|
if Zeros then
|
||||||
|
bearing = string.format("%03d",bearing)
|
||||||
|
local AngleDegText = string.gsub(bearing,"%d","%1 ") -- "0 5 1 "
|
||||||
|
AngleDegText = string.gsub(AngleDegText," $","") -- "0 5 1"
|
||||||
|
AngleDegText = string.gsub(AngleDegText,"0","zero")
|
||||||
|
if aspect == "" then
|
||||||
|
BRAANATO = string.format("brah %s, %d miles, %s, Track %s", AngleDegText, rangeNM, alttext, track)
|
||||||
|
else
|
||||||
|
BRAANATO = string.format("brah %s, %d miles, %s, %s, Track %s", AngleDegText, rangeNM, alttext, aspect, track)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if aspect == "" then
|
||||||
|
BRAANATO = string.format("brah <say-as interpret-as='characters'>%03d</say-as>, %d miles, %s, Track %s", bearing, rangeNM, alttext, track)
|
||||||
|
else
|
||||||
|
BRAANATO = string.format("brah <say-as interpret-as='characters'>%03d</say-as>, %d miles, %s, %s, Track %s", bearing, rangeNM, alttext, aspect, track)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Bogey and Spades then
|
||||||
|
BRAANATO = BRAANATO..", Bogey, Spades."
|
||||||
|
elseif Bogey then
|
||||||
|
BRAANATO = BRAANATO..", Bogey."
|
||||||
|
elseif Spades then
|
||||||
|
BRAANATO = BRAANATO..", Spades."
|
||||||
|
else
|
||||||
|
BRAANATO = BRAANATO.."."
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if aspect == "" then
|
||||||
|
BRAANATO = string.format("BRA %03d, %d miles, %s, Track %s",bearing, rangeNM, alttext, track)
|
||||||
|
else
|
||||||
|
BRAANATO = string.format("BRAA %03d, %d miles, %s, %s, Track %s",bearing, rangeNM, alttext, aspect, track)
|
||||||
|
end
|
||||||
|
if Bogey and Spades then
|
||||||
|
BRAANATO = BRAANATO..", Bogey, Spades."
|
||||||
|
elseif Bogey then
|
||||||
|
BRAANATO = BRAANATO..", Bogey."
|
||||||
|
elseif Spades then
|
||||||
|
BRAANATO = BRAANATO..", Spades."
|
||||||
|
else
|
||||||
|
BRAANATO = BRAANATO.."."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return BRAANATO
|
||||||
|
end
|
||||||
|
|
||||||
--- Return a BULLS string out of the BULLS of the coalition to the COORDINATE.
|
--- Return a BULLS string out of the BULLS of the coalition to the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param DCS#coalition.side Coalition The coalition.
|
-- @param DCS#coalition.side Coalition The coalition.
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
-- @param #boolean MagVar If true, als get angle in magnetic
|
||||||
-- @return #string The BR text.
|
-- @return #string The BR text.
|
||||||
function COORDINATE:ToStringBULLS( Coalition, Settings )
|
function COORDINATE:ToStringBULLS( Coalition, Settings, MagVar )
|
||||||
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
|
local BullsCoordinate = COORDINATE:NewFromVec3( coalition.getMainRefPoint( Coalition ) )
|
||||||
local DirectionVec3 = BullsCoordinate:GetDirectionVec3( self )
|
local DirectionVec3 = BullsCoordinate:GetDirectionVec3( self )
|
||||||
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
local Distance = self:Get2DDistance( BullsCoordinate )
|
local Distance = self:Get2DDistance( BullsCoordinate )
|
||||||
local Altitude = self:GetAltitudeText()
|
local Altitude = self:GetAltitudeText()
|
||||||
return "BULLS, " .. self:GetBRText( AngleRadians, Distance, Settings )
|
return "BULLS, " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return an aspect string from a COORDINATE to the Angle of the object.
|
--- Return an aspect string from a COORDINATE to the Angle of the object.
|
||||||
@@ -2803,7 +2959,7 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The MGRS Text
|
-- @return #string The MGRS Text
|
||||||
function COORDINATE:ToStringMGRS( Settings ) --R2.1 Fixes issue #424.
|
function COORDINATE:ToStringMGRS( Settings )
|
||||||
|
|
||||||
local MGRS_Accuracy = Settings and Settings.MGRS_Accuracy or _SETTINGS.MGRS_Accuracy
|
local MGRS_Accuracy = Settings and Settings.MGRS_Accuracy or _SETTINGS.MGRS_Accuracy
|
||||||
local lat, lon = coord.LOtoLL( self:GetVec3() )
|
local lat, lon = coord.LOtoLL( self:GetVec3() )
|
||||||
@@ -2815,12 +2971,13 @@ do -- COORDINATE
|
|||||||
-- * Uses default settings in COORDINATE.
|
-- * Uses default settings in COORDINATE.
|
||||||
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE ReferenceCoord The refrence coordinate.
|
-- @param #COORDINATE ReferenceCoord The reference coordinate.
|
||||||
-- @param #string ReferenceName The refrence name.
|
-- @param #string ReferenceName The reference name.
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
-- @param #boolean MagVar If true also show angle in magnetic
|
||||||
-- @return #string The coordinate Text in the configured coordinate system.
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings )
|
function COORDINATE:ToStringFromRP( ReferenceCoord, ReferenceName, Controllable, Settings, MagVar )
|
||||||
|
|
||||||
self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
|
self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
|
||||||
|
|
||||||
@@ -2832,24 +2989,59 @@ do -- COORDINATE
|
|||||||
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
|
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
|
||||||
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
local Distance = self:Get2DDistance( ReferenceCoord )
|
local Distance = self:Get2DDistance( ReferenceCoord )
|
||||||
return "Targets are the last seen " .. self:GetBRText( AngleRadians, Distance, Settings ) .. " from " .. ReferenceName
|
return "Targets are the last seen " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
|
||||||
else
|
else
|
||||||
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
|
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
|
||||||
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
local Distance = self:Get2DDistance( ReferenceCoord )
|
local Distance = self:Get2DDistance( ReferenceCoord )
|
||||||
return "Target are located " .. self:GetBRText( AngleRadians, Distance, Settings ) .. " from " .. ReferenceName
|
return "Target are located " .. self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Provides a coordinate string of the point, based on a coordinate format system:
|
||||||
|
-- * Uses default settings in COORDINATE.
|
||||||
|
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||||
|
-- @param #COORDINATE self
|
||||||
|
-- @param #COORDINATE ReferenceCoord The reference coordinate.
|
||||||
|
-- @param #string ReferenceName The reference name.
|
||||||
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
-- @param #boolean MagVar If true also get the angle as magnetic
|
||||||
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
|
function COORDINATE:ToStringFromRPShort( ReferenceCoord, ReferenceName, Controllable, Settings, MagVar )
|
||||||
|
|
||||||
|
self:F2( { ReferenceCoord = ReferenceCoord, ReferenceName = ReferenceName } )
|
||||||
|
|
||||||
|
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
|
||||||
|
|
||||||
|
local IsAir = Controllable and Controllable:IsAirPlane() or false
|
||||||
|
|
||||||
|
if IsAir then
|
||||||
|
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
|
||||||
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
|
local Distance = self:Get2DDistance( ReferenceCoord )
|
||||||
|
return self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
|
||||||
|
else
|
||||||
|
local DirectionVec3 = ReferenceCoord:GetDirectionVec3( self )
|
||||||
|
local AngleRadians = self:GetAngleRadians( DirectionVec3 )
|
||||||
|
local Distance = self:Get2DDistance( ReferenceCoord )
|
||||||
|
return self:GetBRText( AngleRadians, Distance, Settings, nil, MagVar ) .. " from " .. ReferenceName
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Provides a coordinate string of the point, based on the A2G coordinate format system.
|
--- Provides a coordinate string of the point, based on the A2G coordinate format system.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
|
||||||
-- @return #string The coordinate Text in the configured coordinate system.
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
function COORDINATE:ToStringA2G( Controllable, Settings )
|
function COORDINATE:ToStringA2G( Controllable, Settings, MagVar )
|
||||||
|
|
||||||
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
||||||
|
|
||||||
@@ -2859,7 +3051,7 @@ do -- COORDINATE
|
|||||||
-- If no Controllable is given to calculate the BR from, then MGRS will be used!!!
|
-- If no Controllable is given to calculate the BR from, then MGRS will be used!!!
|
||||||
if Controllable then
|
if Controllable then
|
||||||
local Coordinate = Controllable:GetCoordinate()
|
local Coordinate = Controllable:GetCoordinate()
|
||||||
return Controllable and self:ToStringBR( Coordinate, Settings ) or self:ToStringMGRS( Settings )
|
return Controllable and self:ToStringBR( Coordinate, Settings, MagVar ) or self:ToStringMGRS( Settings )
|
||||||
else
|
else
|
||||||
return self:ToStringMGRS( Settings )
|
return self:ToStringMGRS( Settings )
|
||||||
end
|
end
|
||||||
@@ -2883,33 +3075,34 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
-- @param #boolean MagVar If true, also get angle in MagVar for BR/BRA
|
||||||
-- @return #string The coordinate Text in the configured coordinate system.
|
-- @return #string The coordinate Text in the configured coordinate system.
|
||||||
function COORDINATE:ToStringA2A( Controllable, Settings, Language ) -- R2.2
|
function COORDINATE:ToStringA2A( Controllable, Settings, MagVar )
|
||||||
|
|
||||||
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
||||||
|
|
||||||
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
|
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
|
||||||
|
|
||||||
if Settings:IsA2A_BRAA() then
|
if Settings:IsA2A_BRAA() then
|
||||||
if Controllable then
|
if Controllable then
|
||||||
local Coordinate = Controllable:GetCoordinate()
|
local Coordinate = Controllable:GetCoordinate()
|
||||||
return self:ToStringBRA( Coordinate, Settings, Language )
|
return self:ToStringBRA( Coordinate, Settings, MagVar )
|
||||||
else
|
else
|
||||||
return self:ToStringMGRS( Settings, Language )
|
return self:ToStringMGRS( Settings )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if Settings:IsA2A_BULLS() then
|
if Settings:IsA2A_BULLS() then
|
||||||
local Coalition = Controllable:GetCoalition()
|
local Coalition = Controllable:GetCoalition()
|
||||||
return self:ToStringBULLS( Coalition, Settings, Language )
|
return self:ToStringBULLS( Coalition, Settings, MagVar )
|
||||||
end
|
end
|
||||||
if Settings:IsA2A_LL_DMS() then
|
if Settings:IsA2A_LL_DMS() then
|
||||||
return self:ToStringLLDMS( Settings, Language )
|
return self:ToStringLLDMS( Settings )
|
||||||
end
|
end
|
||||||
if Settings:IsA2A_LL_DDM() then
|
if Settings:IsA2A_LL_DDM() then
|
||||||
return self:ToStringLLDDM( Settings, Language )
|
return self:ToStringLLDDM( Settings )
|
||||||
end
|
end
|
||||||
if Settings:IsA2A_MGRS() then
|
if Settings:IsA2A_MGRS() then
|
||||||
return self:ToStringMGRS( Settings, Language )
|
return self:ToStringMGRS( Settings )
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -2977,7 +3170,7 @@ do -- COORDINATE
|
|||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
-- @return #string The pressure text in the configured measurement system.
|
-- @return #string The pressure text in the configured measurement system.
|
||||||
function COORDINATE:ToStringPressure( Controllable, Settings ) -- R2.3
|
function COORDINATE:ToStringPressure( Controllable, Settings )
|
||||||
|
|
||||||
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
self:F2( { Controllable = Controllable and Controllable:GetName() } )
|
||||||
|
|
||||||
@@ -3154,21 +3347,21 @@ do -- POINT_VEC3
|
|||||||
|
|
||||||
--- Return the x coordinate of the POINT_VEC3.
|
--- Return the x coordinate of the POINT_VEC3.
|
||||||
-- @param #POINT_VEC3 self
|
-- @param #POINT_VEC3 self
|
||||||
-- @return #number The x coodinate.
|
-- @return #number The x coordinate.
|
||||||
function POINT_VEC3:GetX()
|
function POINT_VEC3:GetX()
|
||||||
return self.x
|
return self.x
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return the y coordinate of the POINT_VEC3.
|
--- Return the y coordinate of the POINT_VEC3.
|
||||||
-- @param #POINT_VEC3 self
|
-- @param #POINT_VEC3 self
|
||||||
-- @return #number The y coodinate.
|
-- @return #number The y coordinate.
|
||||||
function POINT_VEC3:GetY()
|
function POINT_VEC3:GetY()
|
||||||
return self.y
|
return self.y
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return the z coordinate of the POINT_VEC3.
|
--- Return the z coordinate of the POINT_VEC3.
|
||||||
-- @param #POINT_VEC3 self
|
-- @param #POINT_VEC3 self
|
||||||
-- @return #number The z coodinate.
|
-- @return #number The z coordinate.
|
||||||
function POINT_VEC3:GetZ()
|
function POINT_VEC3:GetZ()
|
||||||
return self.z
|
return self.z
|
||||||
end
|
end
|
||||||
@@ -3202,7 +3395,7 @@ do -- POINT_VEC3
|
|||||||
|
|
||||||
--- Add to the x coordinate of the POINT_VEC3.
|
--- Add to the x coordinate of the POINT_VEC3.
|
||||||
-- @param #POINT_VEC3 self
|
-- @param #POINT_VEC3 self
|
||||||
-- @param #number x The x coordinate value to add to the current x coodinate.
|
-- @param #number x The x coordinate value to add to the current x coordinate.
|
||||||
-- @return #POINT_VEC3
|
-- @return #POINT_VEC3
|
||||||
function POINT_VEC3:AddX( x )
|
function POINT_VEC3:AddX( x )
|
||||||
self.x = self.x + x
|
self.x = self.x + x
|
||||||
@@ -3211,7 +3404,7 @@ do -- POINT_VEC3
|
|||||||
|
|
||||||
--- Add to the y coordinate of the POINT_VEC3.
|
--- Add to the y coordinate of the POINT_VEC3.
|
||||||
-- @param #POINT_VEC3 self
|
-- @param #POINT_VEC3 self
|
||||||
-- @param #number y The y coordinate value to add to the current y coodinate.
|
-- @param #number y The y coordinate value to add to the current y coordinate.
|
||||||
-- @return #POINT_VEC3
|
-- @return #POINT_VEC3
|
||||||
function POINT_VEC3:AddY( y )
|
function POINT_VEC3:AddY( y )
|
||||||
self.y = self.y + y
|
self.y = self.y + y
|
||||||
@@ -3220,7 +3413,7 @@ do -- POINT_VEC3
|
|||||||
|
|
||||||
--- Add to the z coordinate of the POINT_VEC3.
|
--- Add to the z coordinate of the POINT_VEC3.
|
||||||
-- @param #POINT_VEC3 self
|
-- @param #POINT_VEC3 self
|
||||||
-- @param #number z The z coordinate value to add to the current z coodinate.
|
-- @param #number z The z coordinate value to add to the current z coordinate.
|
||||||
-- @return #POINT_VEC3
|
-- @return #POINT_VEC3
|
||||||
function POINT_VEC3:AddZ( z )
|
function POINT_VEC3:AddZ( z )
|
||||||
self.z = self.z +z
|
self.z = self.z +z
|
||||||
@@ -3326,14 +3519,14 @@ do -- POINT_VEC2
|
|||||||
|
|
||||||
--- Return the x coordinate of the POINT_VEC2.
|
--- Return the x coordinate of the POINT_VEC2.
|
||||||
-- @param #POINT_VEC2 self
|
-- @param #POINT_VEC2 self
|
||||||
-- @return #number The x coodinate.
|
-- @return #number The x coordinate.
|
||||||
function POINT_VEC2:GetX()
|
function POINT_VEC2:GetX()
|
||||||
return self.x
|
return self.x
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return the y coordinate of the POINT_VEC2.
|
--- Return the y coordinate of the POINT_VEC2.
|
||||||
-- @param #POINT_VEC2 self
|
-- @param #POINT_VEC2 self
|
||||||
-- @return #number The y coodinate.
|
-- @return #number The y coordinate.
|
||||||
function POINT_VEC2:GetY()
|
function POINT_VEC2:GetY()
|
||||||
return self.z
|
return self.z
|
||||||
end
|
end
|
||||||
@@ -3358,7 +3551,7 @@ do -- POINT_VEC2
|
|||||||
|
|
||||||
--- Return Return the Lat(itude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.x).
|
--- Return Return the Lat(itude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.x).
|
||||||
-- @param #POINT_VEC2 self
|
-- @param #POINT_VEC2 self
|
||||||
-- @return #number The x coodinate.
|
-- @return #number The x coordinate.
|
||||||
function POINT_VEC2:GetLat()
|
function POINT_VEC2:GetLat()
|
||||||
return self.x
|
return self.x
|
||||||
end
|
end
|
||||||
@@ -3374,7 +3567,7 @@ do -- POINT_VEC2
|
|||||||
|
|
||||||
--- Return the Lon(gitude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.z).
|
--- Return the Lon(gitude) coordinate of the POINT_VEC2 (ie: (parent)POINT_VEC3.z).
|
||||||
-- @param #POINT_VEC2 self
|
-- @param #POINT_VEC2 self
|
||||||
-- @return #number The y coodinate.
|
-- @return #number The y coordinate.
|
||||||
function POINT_VEC2:GetLon()
|
function POINT_VEC2:GetLon()
|
||||||
return self.z
|
return self.z
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Core** -- SCHEDULEDISPATCHER dispatches the different schedules.
|
--- **Core** - SCHEDULEDISPATCHER dispatches the different schedules.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -109,9 +109,11 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
|
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
|
||||||
|
|
||||||
if Scheduler.MasterObject then
|
if Scheduler.MasterObject then
|
||||||
|
--env.info("FF Object Scheduler")
|
||||||
self.ObjectSchedulers[CallID] = Scheduler
|
self.ObjectSchedulers[CallID] = Scheduler
|
||||||
self:F3( { CallID = CallID, ObjectScheduler = tostring( self.ObjectSchedulers[CallID] ), MasterObject = tostring( Scheduler.MasterObject ) } )
|
self:F3( { CallID = CallID, ObjectScheduler = tostring( self.ObjectSchedulers[CallID] ), MasterObject = tostring( Scheduler.MasterObject ) } )
|
||||||
else
|
else
|
||||||
|
--env.info("FF Persistent Scheduler")
|
||||||
self.PersistentSchedulers[CallID] = Scheduler
|
self.PersistentSchedulers[CallID] = Scheduler
|
||||||
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
|
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
|
||||||
end
|
end
|
||||||
@@ -121,8 +123,8 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
self.Schedule[Scheduler][CallID] = {} -- #SCHEDULEDISPATCHER.ScheduleData
|
self.Schedule[Scheduler][CallID] = {} -- #SCHEDULEDISPATCHER.ScheduleData
|
||||||
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
|
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
|
||||||
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
|
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
|
||||||
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + (Start or 0)
|
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
|
||||||
self.Schedule[Scheduler][CallID].Start = Start + 0.1
|
self.Schedule[Scheduler][CallID].Start = Start + 0.001
|
||||||
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
||||||
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
||||||
self.Schedule[Scheduler][CallID].Stop = Stop
|
self.Schedule[Scheduler][CallID].Stop = Stop
|
||||||
@@ -217,7 +219,8 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
if ShowTrace then
|
if ShowTrace then
|
||||||
SchedulerObject:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
|
SchedulerObject:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
|
||||||
end
|
end
|
||||||
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
|
-- The master object is passed as first parameter. A few :Schedule() calls in MOOSE expect this currently. But in principle it should be removed.
|
||||||
|
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
|
||||||
end
|
end
|
||||||
Status, Result = xpcall( Timer, ErrorHandler )
|
Status, Result = xpcall( Timer, ErrorHandler )
|
||||||
else
|
else
|
||||||
@@ -314,7 +317,7 @@ end
|
|||||||
--- Stop dispatcher.
|
--- Stop dispatcher.
|
||||||
-- @param #SCHEDULEDISPATCHER self
|
-- @param #SCHEDULEDISPATCHER self
|
||||||
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
|
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
|
||||||
-- @param #table CallID Call ID.
|
-- @param #string CallID (Optional) Scheduler Call ID. If nil, all pending schedules are stopped recursively.
|
||||||
function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||||
self:F2( { Stop = CallID, Scheduler = Scheduler } )
|
self:F2( { Stop = CallID, Scheduler = Scheduler } )
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
--- **Core** - Prepares and handles the execution of functions over scheduled time (intervals).
|
--- **Core** - Prepares and handles the execution of functions over scheduled time (intervals).
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Schedule functions over time,
|
-- * Schedule functions over time,
|
||||||
@@ -13,9 +13,9 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- # Demo Missions
|
-- # Demo Missions
|
||||||
--
|
--
|
||||||
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SCH%20-%20Scheduler)
|
-- ### [SCHEDULER Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||||
--
|
--
|
||||||
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
-- ### [SCHEDULER Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SCH%20-%20Scheduler)
|
||||||
--
|
--
|
||||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||||
@@ -237,7 +237,7 @@ end
|
|||||||
-- @param #number Stop Time interval in seconds after which the scheduler will be stopped.
|
-- @param #number Stop Time interval in seconds after which the scheduler will be stopped.
|
||||||
-- @param #number TraceLevel Trace level [0,3]. Default 3.
|
-- @param #number TraceLevel Trace level [0,3]. Default 3.
|
||||||
-- @param Core.Fsm#FSM Fsm Finite state model.
|
-- @param Core.Fsm#FSM Fsm Finite state model.
|
||||||
-- @return #table The ScheduleID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, TraceLevel, Fsm )
|
function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, TraceLevel, Fsm )
|
||||||
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
|
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
|
||||||
self:T3( { SchedulerArguments } )
|
self:T3( { SchedulerArguments } )
|
||||||
@@ -271,7 +271,7 @@ end
|
|||||||
|
|
||||||
--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided.
|
--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided.
|
||||||
-- @param #SCHEDULER self
|
-- @param #SCHEDULER self
|
||||||
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
-- @param #string ScheduleID (Optional) The Schedule ID of the planned (repeating) schedule.
|
||||||
function SCHEDULER:Start( ScheduleID )
|
function SCHEDULER:Start( ScheduleID )
|
||||||
self:F3( { ScheduleID } )
|
self:F3( { ScheduleID } )
|
||||||
self:T( string.format( "Starting scheduler ID=%s", tostring( ScheduleID ) ) )
|
self:T( string.format( "Starting scheduler ID=%s", tostring( ScheduleID ) ) )
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
--- **Core** - Manages various settings for running missions, consumed by moose classes and provides a menu system for players to tweak settings in running missions.
|
--- **Core** - Manages various settings for missions, providing a menu for players to tweak settings in running missions.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -251,6 +251,7 @@ do -- SETTINGS
|
|||||||
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
|
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
|
||||||
self:SetMessageTime( MESSAGE.Type.Update, 15 )
|
self:SetMessageTime( MESSAGE.Type.Update, 15 )
|
||||||
self:SetEraModern()
|
self:SetEraModern()
|
||||||
|
self:SetLocale("en")
|
||||||
return self
|
return self
|
||||||
else
|
else
|
||||||
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
|
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
|
||||||
@@ -282,7 +283,21 @@ do -- SETTINGS
|
|||||||
function SETTINGS:SetMetric()
|
function SETTINGS:SetMetric()
|
||||||
self.Metric = true
|
self.Metric = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sets the SETTINGS default text locale.
|
||||||
|
-- @param #SETTINGS self
|
||||||
|
-- @param #string Locale
|
||||||
|
function SETTINGS:SetLocale(Locale)
|
||||||
|
self.Locale = Locale or "en"
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the SETTINGS text locale.
|
||||||
|
-- @param #SETTINGS self
|
||||||
|
-- @return #string
|
||||||
|
function SETTINGS:GetLocale()
|
||||||
|
return self.Locale or _SETTINGS:GetLocale()
|
||||||
|
end
|
||||||
|
|
||||||
--- Gets if the SETTINGS is metric.
|
--- Gets if the SETTINGS is metric.
|
||||||
-- @param #SETTINGS self
|
-- @param #SETTINGS self
|
||||||
-- @return #boolean true if metric.
|
-- @return #boolean true if metric.
|
||||||
@@ -300,7 +315,7 @@ do -- SETTINGS
|
|||||||
-- @param #SETTINGS self
|
-- @param #SETTINGS self
|
||||||
-- @return #boolean true if imperial.
|
-- @return #boolean true if imperial.
|
||||||
function SETTINGS:IsImperial()
|
function SETTINGS:IsImperial()
|
||||||
return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsMetric())
|
return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsImperial())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets the SETTINGS LL accuracy.
|
--- Sets the SETTINGS LL accuracy.
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
-- * Enquiry methods to check on spawn status.
|
-- * Enquiry methods to check on spawn status.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/SPA%20-%20Spawning)
|
-- ### [Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/SPA%20-%20Spawning)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL)
|
-- ### [YouTube Playlist](https://www.youtube.com/playlist?list=PL7ZUrU4zZUl1jirWIo4t4YxqN-HxjqRkL)
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
--
|
--
|
||||||
-- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Wrapper.Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens.
|
-- * @{#SPAWN.InitRandomizePosition}(): Randomizes the position of @{Wrapper.Group}s that are spawned within a **radius band**, given an Outer and Inner radius, from the point that the spawn happens.
|
||||||
-- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Wrapper.Unit}s in the @{Wrapper.Group} that is spawned within a **radius band**, given an Outer and Inner radius.
|
-- * @{#SPAWN.InitRandomizeUnits}(): Randomizes the @{Wrapper.Unit}s in the @{Wrapper.Group} that is spawned within a **radius band**, given an Outer and Inner radius.
|
||||||
-- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Zone}s that are declared using this function. Each zone can be given a probability factor.
|
-- * @{#SPAWN.InitRandomizeZones}(): Randomizes the spawning between a predefined list of @{Core.Zone}s that are declared using this function. Each zone can be given a probability factor.
|
||||||
--
|
--
|
||||||
-- ### Enable / Disable AI when spawning a new @{Wrapper.Group}
|
-- ### Enable / Disable AI when spawning a new @{Wrapper.Group}
|
||||||
--
|
--
|
||||||
@@ -200,13 +200,13 @@
|
|||||||
-- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index.
|
-- * @{#SPAWN.ReSpawn}(): Re-spawn a group based on a given index.
|
||||||
-- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air).
|
-- * @{#SPAWN.SpawnFromVec3}(): Spawn a new group from a Vec3 coordinate. (The group will can be spawned at a point in the air).
|
||||||
-- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ).
|
-- * @{#SPAWN.SpawnFromVec2}(): Spawn a new group from a Vec2 coordinate. (The group will be spawned at land height ).
|
||||||
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}.
|
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Wrapper.Static}.
|
||||||
-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Wrapper.Unit}.
|
-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Wrapper.Unit}.
|
||||||
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}.
|
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Core.Zone}.
|
||||||
-- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Wrapper.Airbase}, which can be an airdrome, ship or helipad.
|
-- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Wrapper.Airbase}, which can be an airdrome, ship or helipad.
|
||||||
--
|
--
|
||||||
-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{Wrapper.Group#GROUP.New} object, that contains a reference to the DCSGroup object.
|
-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{Wrapper.Group#GROUP.New} object, that contains a reference to the DCSGroup object.
|
||||||
-- You can use the @{GROUP} object to do further actions with the DCSGroup.
|
-- You can use the @{Wrapper.Group#GROUP} object to do further actions with the DCSGroup.
|
||||||
--
|
--
|
||||||
-- ### **Scheduled** spawning methods
|
-- ### **Scheduled** spawning methods
|
||||||
--
|
--
|
||||||
@@ -765,7 +765,7 @@ end
|
|||||||
|
|
||||||
--- Randomizes the UNITs that are spawned within a radius band given an Outer and Inner radius.
|
--- Randomizes the UNITs that are spawned within a radius band given an Outer and Inner radius.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{UNIT}s position within the group between a given outer and inner radius.
|
-- @param #boolean RandomizeUnits If true, SPAWN will perform the randomization of the @{Wrapper.Unit#UNIT}s position within the group between a given outer and inner radius.
|
||||||
-- @param DCS#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned.
|
-- @param DCS#Distance OuterRadius (optional) The outer radius in meters where the new group will be spawned.
|
||||||
-- @param DCS#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned.
|
-- @param DCS#Distance InnerRadius (optional) The inner radius in meters where the new group will NOT be spawned.
|
||||||
-- @return #SPAWN
|
-- @return #SPAWN
|
||||||
@@ -906,7 +906,7 @@ end
|
|||||||
|
|
||||||
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
|
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #table SpawnZoneTable A table with @{Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Zone}s objects.
|
-- @param #table SpawnZoneTable A table with @{Core.Zone} objects. If this table is given, then each spawn will be executed within the given list of @{Core.Zone}s objects.
|
||||||
-- @return #SPAWN
|
-- @return #SPAWN
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -1159,7 +1159,7 @@ do -- Delay methods
|
|||||||
end -- Delay methods
|
end -- Delay methods
|
||||||
|
|
||||||
--- Will spawn a group based on the internal index.
|
--- Will spawn a group based on the internal index.
|
||||||
-- Note: Uses @{DATABASE} module defined in MOOSE.
|
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
|
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
|
||||||
function SPAWN:Spawn()
|
function SPAWN:Spawn()
|
||||||
@@ -1174,7 +1174,7 @@ function SPAWN:Spawn()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Will re-spawn a group based on a given index.
|
--- Will re-spawn a group based on a given index.
|
||||||
-- Note: Uses @{DATABASE} module defined in MOOSE.
|
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #string SpawnIndex The index of the group to be spawned.
|
-- @param #string SpawnIndex The index of the group to be spawned.
|
||||||
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
|
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
|
||||||
@@ -1222,7 +1222,7 @@ function SPAWN:SetSpawnIndex( SpawnIndex )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Will spawn a group with a specified index number.
|
--- Will spawn a group with a specified index number.
|
||||||
-- Uses @{DATABASE} global object defined in MOOSE.
|
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #string SpawnIndex The index of the group to be spawned.
|
-- @param #string SpawnIndex The index of the group to be spawned.
|
||||||
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
|
-- @return Wrapper.Group#GROUP The group that was spawned. You can use this group for further actions.
|
||||||
@@ -1418,7 +1418,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
end
|
end
|
||||||
-- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats.
|
-- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats.
|
||||||
-- if self.Repeat then
|
-- if self.Repeat then
|
||||||
-- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" )
|
-- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" )
|
||||||
-- end
|
-- end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2403,8 +2403,7 @@ end
|
|||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param DCS#Vec3 Vec3 The Vec3 coordinates where to spawn the group.
|
-- @param DCS#Vec3 Vec3 The Vec3 coordinates where to spawn the group.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||||
self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
||||||
|
|
||||||
@@ -2472,8 +2471,7 @@ end
|
|||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group.
|
-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex )
|
function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex )
|
||||||
self:F( { self.SpawnTemplatePrefix, SpawnIndex } )
|
self:F( { self.SpawnTemplatePrefix, SpawnIndex } )
|
||||||
|
|
||||||
@@ -2487,8 +2485,7 @@ end
|
|||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group.
|
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground.
|
-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground.
|
||||||
@@ -2511,8 +2508,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnVec2 = ZONE:New( ZoneName ):GetVec2()
|
-- local SpawnVec2 = ZONE:New( ZoneName ):GetVec2()
|
||||||
@@ -2544,8 +2540,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2()
|
-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2()
|
||||||
@@ -2599,8 +2594,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnStatic = STATIC:FindByName( StaticName )
|
-- local SpawnStatic = STATIC:FindByName( StaticName )
|
||||||
@@ -2621,8 +2615,8 @@ function SPAWN:SpawnFromStatic( HostStatic, MinHeight, MaxHeight, SpawnIndex )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Will spawn a Group within a given @{Zone}.
|
--- Will spawn a Group within a given @{Core.Zone}.
|
||||||
-- The @{Zone} can be of any type derived from @{Core.Zone#ZONE_BASE}.
|
-- The @{Core.Zone} can be of any type derived from @{Core.Zone#ZONE_BASE}.
|
||||||
-- Once the @{Wrapper.Group} is spawned within the zone, the @{Wrapper.Group} will continue on its route.
|
-- Once the @{Wrapper.Group} is spawned within the zone, the @{Wrapper.Group} will continue on its route.
|
||||||
-- The **first waypoint** (where the group is spawned) is replaced with the zone location coordinates.
|
-- The **first waypoint** (where the group is spawned) is replaced with the zone location coordinates.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
@@ -2631,8 +2625,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil when nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnZone = ZONE:New( ZoneName )
|
-- local SpawnZone = ZONE:New( ZoneName )
|
||||||
@@ -2827,21 +2820,40 @@ end
|
|||||||
-- The method will search for a #-mark, and will return the text before the #-mark.
|
-- The method will search for a #-mark, and will return the text before the #-mark.
|
||||||
-- It will return nil of no prefix was found.
|
-- It will return nil of no prefix was found.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param DCS#UNIT DCSUnit The @{DCSUnit} to be searched.
|
-- @param Wrapper.Group#GROUP SpawnGroup The GROUP object.
|
||||||
-- @return #string The prefix
|
-- @return #string The prefix or #nil if nothing was found.
|
||||||
-- @return #nil Nothing found
|
|
||||||
function SPAWN:_GetPrefixFromGroup( SpawnGroup )
|
function SPAWN:_GetPrefixFromGroup( SpawnGroup )
|
||||||
self:F3( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix, SpawnGroup } )
|
|
||||||
|
|
||||||
local GroupName = SpawnGroup:GetName()
|
local GroupName = SpawnGroup:GetName()
|
||||||
|
|
||||||
if GroupName then
|
if GroupName then
|
||||||
local SpawnPrefix = string.match( GroupName, ".*#" )
|
|
||||||
if SpawnPrefix then
|
local SpawnPrefix=self:_GetPrefixFromGroupName(GroupName)
|
||||||
SpawnPrefix = SpawnPrefix:sub( 1, -2 )
|
|
||||||
end
|
|
||||||
return SpawnPrefix
|
return SpawnPrefix
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return the prefix of a spawned group.
|
||||||
|
-- The method will search for a `#`-mark, and will return the text before the `#`-mark. It will return nil of no prefix was found.
|
||||||
|
-- @param #SPAWN self
|
||||||
|
-- @param #string SpawnGroupName The name of the spawned group.
|
||||||
|
-- @return #string The prefix or #nil if nothing was found.
|
||||||
|
function SPAWN:_GetPrefixFromGroupName(SpawnGroupName)
|
||||||
|
|
||||||
|
if SpawnGroupName then
|
||||||
|
|
||||||
|
local SpawnPrefix=string.match(SpawnGroupName, ".*#")
|
||||||
|
|
||||||
|
if SpawnPrefix then
|
||||||
|
SpawnPrefix = SpawnPrefix:sub(1, -2)
|
||||||
|
end
|
||||||
|
|
||||||
|
return SpawnPrefix
|
||||||
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2925,7 +2937,7 @@ function SPAWN:_GetGroupCountryID( SpawnPrefix )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the Group Template from the ME environment definition.
|
--- Gets the Group Template from the ME environment definition.
|
||||||
-- This method used the @{DATABASE} object, which contains ALL initial and new spawned object in MOOSE.
|
-- Note: This method uses the global _DATABASE object (an instance of @{Core.Database#DATABASE}), which contains ALL initial and new spawned objects in MOOSE.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #string SpawnTemplatePrefix
|
-- @param #string SpawnTemplatePrefix
|
||||||
-- @return @SPAWN self
|
-- @return @SPAWN self
|
||||||
@@ -2959,9 +2971,9 @@ end
|
|||||||
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
||||||
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
|
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
|
||||||
|
|
||||||
-- if not self.SpawnTemplate then
|
-- if not self.SpawnTemplate then
|
||||||
-- self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
|
-- self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
local SpawnTemplate
|
local SpawnTemplate
|
||||||
if self.TweakedTemplate ~= nil and self.TweakedTemplate == true then
|
if self.TweakedTemplate ~= nil and self.TweakedTemplate == true then
|
||||||
@@ -3096,7 +3108,7 @@ function SPAWN:_RandomizeTemplate( SpawnIndex )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Private method that randomizes the @{Zone}s where the Group will be spawned.
|
--- Private method that randomizes the @{Core.Zone}s where the Group will be spawned.
|
||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param #number SpawnIndex
|
-- @param #number SpawnIndex
|
||||||
-- @return #SPAWN self
|
-- @return #SPAWN self
|
||||||
@@ -3235,24 +3247,27 @@ function SPAWN:_OnBirth( EventData )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Obscolete
|
|
||||||
-- @todo Need to delete this... _DATABASE does this now ...
|
|
||||||
|
|
||||||
--- @param #SPAWN self
|
--- @param #SPAWN self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
function SPAWN:_OnDeadOrCrash( EventData )
|
function SPAWN:_OnDeadOrCrash( EventData )
|
||||||
self:F( self.SpawnTemplatePrefix )
|
self:F( self.SpawnTemplatePrefix )
|
||||||
|
|
||||||
local SpawnGroup = EventData.IniGroup
|
local unit=UNIT:FindByName(EventData.IniUnitName)
|
||||||
|
|
||||||
if SpawnGroup then
|
if unit then
|
||||||
local EventPrefix = self:_GetPrefixFromGroup( SpawnGroup )
|
|
||||||
|
local EventPrefix = self:_GetPrefixFromGroupName(unit.GroupName)
|
||||||
|
|
||||||
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
if EventPrefix then -- EventPrefix can be nil if no # is found, which means, no spawnable group!
|
||||||
self:T( { "Dead event: " .. EventPrefix } )
|
self:T( { "Dead event: " .. EventPrefix } )
|
||||||
if EventPrefix == self.SpawnTemplatePrefix or (self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix) then
|
|
||||||
self.AliveUnits = self.AliveUnits - 1
|
if EventPrefix == self.SpawnTemplatePrefix or ( self.SpawnAliasPrefix and EventPrefix == self.SpawnAliasPrefix ) then
|
||||||
self:T( "Alive Units: " .. self.AliveUnits )
|
|
||||||
|
self.AliveUnits = self.AliveUnits - 1
|
||||||
|
|
||||||
|
self:T( "Alive Units: " .. self.AliveUnits )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3350,12 +3365,16 @@ end
|
|||||||
-- @return #boolean True = Continue Scheduler
|
-- @return #boolean True = Continue Scheduler
|
||||||
function SPAWN:_SpawnCleanUpScheduler()
|
function SPAWN:_SpawnCleanUpScheduler()
|
||||||
self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } )
|
self:F( { "CleanUp Scheduler:", self.SpawnTemplatePrefix } )
|
||||||
|
|
||||||
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
|
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
|
||||||
self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
||||||
|
|
||||||
|
local IsHelo = false
|
||||||
|
|
||||||
while SpawnGroup do
|
while SpawnGroup do
|
||||||
|
|
||||||
|
IsHelo = SpawnGroup:IsHelicopter()
|
||||||
|
|
||||||
local SpawnUnits = SpawnGroup:GetUnits()
|
local SpawnUnits = SpawnGroup:GetUnits()
|
||||||
|
|
||||||
for UnitID, UnitData in pairs( SpawnUnits ) do
|
for UnitID, UnitData in pairs( SpawnUnits ) do
|
||||||
@@ -3368,8 +3387,8 @@ function SPAWN:_SpawnCleanUpScheduler()
|
|||||||
self:T( { SpawnUnitName, Stamp } )
|
self:T( { SpawnUnitName, Stamp } )
|
||||||
|
|
||||||
if Stamp.Vec2 then
|
if Stamp.Vec2 then
|
||||||
if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then
|
if (SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1) or IsHelo then
|
||||||
local NewVec2 = SpawnUnit:GetVec2()
|
local NewVec2 = SpawnUnit:GetVec2() or {x=0, y=0}
|
||||||
if (Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y) or (SpawnUnit:GetLife() <= 1) then
|
if (Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y) or (SpawnUnit:GetLife() <= 1) then
|
||||||
-- If the plane is not moving or dead , and is on the ground, assign it with a timestamp...
|
-- If the plane is not moving or dead , and is on the ground, assign it with a timestamp...
|
||||||
if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then
|
if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then
|
||||||
@@ -3387,8 +3406,8 @@ function SPAWN:_SpawnCleanUpScheduler()
|
|||||||
Stamp.Time = nil
|
Stamp.Time = nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if SpawnUnit:InAir() == false then
|
if SpawnUnit:InAir() == false or (IsHelo and SpawnUnit:GetLife() <= 1) then
|
||||||
Stamp.Vec2 = SpawnUnit:GetVec2()
|
Stamp.Vec2 = SpawnUnit:GetVec2() or {x=0, y=0}
|
||||||
if (SpawnUnit:GetVelocityKMH() < 1) then
|
if (SpawnUnit:GetVelocityKMH() < 1) then
|
||||||
Stamp.Time = timer.getTime()
|
Stamp.Time = timer.getTime()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -46,26 +46,26 @@
|
|||||||
-- @field #number InitOffsetAngle Link offset angle in degrees.
|
-- @field #number InitOffsetAngle Link offset angle in degrees.
|
||||||
-- @field #number InitStaticHeading Heading of the static.
|
-- @field #number InitStaticHeading Heading of the static.
|
||||||
-- @field #string InitStaticLivery Livery for aircraft.
|
-- @field #string InitStaticLivery Livery for aircraft.
|
||||||
-- @field #string InitStaticShape Shape of teh static.
|
-- @field #string InitStaticShape Shape of the static.
|
||||||
-- @field #string InitStaticType Type of the static.
|
-- @field #string InitStaticType Type of the static.
|
||||||
-- @field #string InitStaticCategory Categrory of the static.
|
-- @field #string InitStaticCategory Categrory of the static.
|
||||||
-- @field #string InitStaticName Name of the static.
|
-- @field #string InitStaticName Name of the static.
|
||||||
-- @field Core.Point#COORDINATE InitStaticCoordinate Coordinate where to spawn the static.
|
-- @field Core.Point#COORDINATE InitStaticCoordinate Coordinate where to spawn the static.
|
||||||
-- @field #boolean InitDead Set static to be dead if true.
|
-- @field #boolean InitStaticDead Set static to be dead if true.
|
||||||
-- @field #boolean InitCargo If true, static can act as cargo.
|
-- @field #boolean InitStaticCargo If true, static can act as cargo.
|
||||||
-- @field #number InitCargoMass Mass of cargo in kg.
|
-- @field #number InitStaticCargoMass Mass of cargo in kg.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- Allows to spawn dynamically new @{Static}s into your mission.
|
--- Allows to spawn dynamically new @{Wrapper.Static}s into your mission.
|
||||||
--
|
--
|
||||||
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc),
|
-- Through creating a copy of an existing static object template as defined in the Mission Editor (ME), SPAWNSTATIC can retireve the properties of the defined static object template (like type, category etc),
|
||||||
-- and "copy" these properties to create a new static object and place it at the desired coordinate.
|
-- and "copy" these properties to create a new static object and place it at the desired coordinate.
|
||||||
--
|
--
|
||||||
-- New spawned @{Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
|
-- New spawned @{Wrapper.Static}s get **the same name** as the name of the template Static, or gets the given name when a new name is provided at the Spawn method.
|
||||||
-- By default, spawned @{Static}s will follow a naming convention at run-time:
|
-- By default, spawned @{Wrapper.Static}s will follow a naming convention at run-time:
|
||||||
--
|
--
|
||||||
-- * Spawned @{Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
|
-- * Spawned @{Wrapper.Static}s will have the name _StaticName_#_nnn_, where _StaticName_ is the name of the **Template Static**, and _nnn_ is a **counter from 0 to 99999**.
|
||||||
--
|
--
|
||||||
-- # SPAWNSTATIC Constructors
|
-- # SPAWNSTATIC Constructors
|
||||||
--
|
--
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.Spawn}(Heading, NewName) spawns the static with the set parameters. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromCoordinate}(Coordinate, Heading, NewName) spawn the static at the given coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromPointVec2}(PointVec2, Heading, NewName) spawns the static at a POINT_VEC2 coordinate. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
-- * @{#SPAWNSTATIC.SpawnFromZone}(Zone, Heading, NewName) spawns the static at the center of a @{Core.Zone}. Optionally, heading and name can be given. The name **must be unique**!
|
||||||
--
|
--
|
||||||
-- @field #SPAWNSTATIC SPAWNSTATIC
|
-- @field #SPAWNSTATIC SPAWNSTATIC
|
||||||
--
|
--
|
||||||
@@ -131,7 +131,7 @@ SPAWNSTATIC = {
|
|||||||
-- @field #number mass Cargo mass in kg.
|
-- @field #number mass Cargo mass in kg.
|
||||||
-- @field #boolean canCargo Static can be a cargo.
|
-- @field #boolean canCargo Static can be a cargo.
|
||||||
|
|
||||||
--- Creates the main object to spawn a @{Static} defined in the mission editor (ME).
|
--- Creates the main object to spawn a @{Wrapper.Static} defined in the mission editor (ME).
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #string SpawnTemplateName Name of the static object in the ME. Each new static will have the name starting with this prefix.
|
-- @param #string SpawnTemplateName Name of the static object in the ME. Each new static will have the name starting with this prefix.
|
||||||
-- @param DCS#country.id SpawnCountryID (Optional) The ID of the country.
|
-- @param DCS#country.id SpawnCountryID (Optional) The ID of the country.
|
||||||
@@ -158,7 +158,7 @@ function SPAWNSTATIC:NewFromStatic(SpawnTemplateName, SpawnCountryID)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates the main object to spawn a @{Static} given a template table.
|
--- Creates the main object to spawn a @{Wrapper.Static} given a template table.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #table SpawnTemplate Template used for spawning.
|
-- @param #table SpawnTemplate Template used for spawning.
|
||||||
-- @param DCS#country.id CountryID The ID of the country. Default `country.id.USA`.
|
-- @param DCS#country.id CountryID The ID of the country. Default `country.id.USA`.
|
||||||
@@ -174,7 +174,7 @@ function SPAWNSTATIC:NewFromTemplate(SpawnTemplate, CountryID)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates the main object to spawn a @{Static} from a given type.
|
--- Creates the main object to spawn a @{Wrapper.Static} from a given type.
|
||||||
-- NOTE that you have to init many other parameters as spawn coordinate etc.
|
-- NOTE that you have to init many other parameters as spawn coordinate etc.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param #string StaticType Type of the static.
|
-- @param #string StaticType Type of the static.
|
||||||
@@ -260,7 +260,7 @@ end
|
|||||||
-- @param #number Mass Mass of the cargo in kg.
|
-- @param #number Mass Mass of the cargo in kg.
|
||||||
-- @return #SPAWNSTATIC self
|
-- @return #SPAWNSTATIC self
|
||||||
function SPAWNSTATIC:InitCargoMass(Mass)
|
function SPAWNSTATIC:InitCargoMass(Mass)
|
||||||
self.InitCargoMass=Mass
|
self.InitStaticCargoMass=Mass
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -269,7 +269,16 @@ end
|
|||||||
-- @param #boolean IsCargo If true, this static can act as cargo.
|
-- @param #boolean IsCargo If true, this static can act as cargo.
|
||||||
-- @return #SPAWNSTATIC self
|
-- @return #SPAWNSTATIC self
|
||||||
function SPAWNSTATIC:InitCargo(IsCargo)
|
function SPAWNSTATIC:InitCargo(IsCargo)
|
||||||
self.InitCargo=IsCargo
|
self.InitStaticCargo=IsCargo
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize as dead.
|
||||||
|
-- @param #SPAWNSTATIC self
|
||||||
|
-- @param #boolean IsCargo If true, this static is dead.
|
||||||
|
-- @return #SPAWNSTATIC self
|
||||||
|
function SPAWNSTATIC:InitDead(IsDead)
|
||||||
|
self.InitStaticDead=IsDead
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -327,7 +336,7 @@ function SPAWNSTATIC:Spawn(Heading, NewName)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a new @{Static} from a POINT_VEC2.
|
--- Creates a new @{Wrapper.Static} from a POINT_VEC2.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
-- @param Core.Point#POINT_VEC2 PointVec2 The 2D coordinate where to spawn the static.
|
||||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
||||||
@@ -343,7 +352,7 @@ function SPAWNSTATIC:SpawnFromPointVec2(PointVec2, Heading, NewName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new @{Static} from a COORDINATE.
|
--- Creates a new @{Wrapper.Static} from a COORDINATE.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Point#COORDINATE Coordinate The 3D coordinate where to spawn the static.
|
-- @param Core.Point#COORDINATE Coordinate The 3D coordinate where to spawn the static.
|
||||||
-- @param #number Heading (Optional) Heading The heading of the static in degrees. Default is 0 degrees.
|
-- @param #number Heading (Optional) Heading The heading of the static in degrees. Default is 0 degrees.
|
||||||
@@ -366,7 +375,7 @@ function SPAWNSTATIC:SpawnFromCoordinate(Coordinate, Heading, NewName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new @{Static} from a @{Zone}.
|
--- Creates a new @{Wrapper.Static} from a @{Core.Zone}.
|
||||||
-- @param #SPAWNSTATIC self
|
-- @param #SPAWNSTATIC self
|
||||||
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
|
-- @param Core.Zone#ZONE_BASE Zone The Zone where to spawn the static.
|
||||||
-- @param #number Heading (Optional)The heading of the static in degrees. Default is the heading of the template.
|
-- @param #number Heading (Optional)The heading of the static in degrees. Default is the heading of the template.
|
||||||
@@ -417,16 +426,16 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
Template.livery_id=self.InitStaticLivery
|
Template.livery_id=self.InitStaticLivery
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitDead~=nil then
|
if self.InitStaticDead~=nil then
|
||||||
Template.dead=self.InitDead
|
Template.dead=self.InitStaticDead
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitCargo~=nil then
|
if self.InitStaticCargo~=nil then
|
||||||
Template.canCargo=self.InitCargo
|
Template.canCargo=self.InitStaticCargo
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitCargoMass~=nil then
|
if self.InitStaticCargoMass~=nil then
|
||||||
Template.mass=self.InitCargoMass
|
Template.mass=self.InitStaticCargoMass
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.InitLinkUnit then
|
if self.InitLinkUnit then
|
||||||
@@ -479,6 +488,8 @@ function SPAWNSTATIC:_SpawnStatic(Template, CountryID)
|
|||||||
-- ED's dirty way to spawn FARPS.
|
-- ED's dirty way to spawn FARPS.
|
||||||
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
Static=coalition.addGroup(CountryID, -1, TemplateGroup)
|
||||||
else
|
else
|
||||||
|
self:T("Spawning Static")
|
||||||
|
self:T2({Template=Template})
|
||||||
Static=coalition.addStaticObject(CountryID, Template)
|
Static=coalition.addStaticObject(CountryID, Template)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -249,8 +249,10 @@ do
|
|||||||
|
|
||||||
local RecceDcsUnit = self.Recce:GetDCSObject()
|
local RecceDcsUnit = self.Recce:GetDCSObject()
|
||||||
|
|
||||||
self.SpotIR = Spot.createInfraRed( RecceDcsUnit, { x = 0, y = 2, z = 0 }, Target:GetPointVec3():AddY(1):GetVec3() )
|
local relativespot = self.relstartpos or { x = 0, y = 2, z = 0 }
|
||||||
self.SpotLaser = Spot.createLaser( RecceDcsUnit, { x = 0, y = 2, z = 0 }, Target:GetPointVec3():AddY(1):GetVec3(), LaserCode )
|
|
||||||
|
self.SpotIR = Spot.createInfraRed( RecceDcsUnit, relativespot, Target:GetPointVec3():AddY(1):GetVec3() )
|
||||||
|
self.SpotLaser = Spot.createLaser( RecceDcsUnit, relativespot, Target:GetPointVec3():AddY(1):GetVec3(), LaserCode )
|
||||||
|
|
||||||
if Duration then
|
if Duration then
|
||||||
self.ScheduleID = self.LaseScheduler:Schedule( self, StopLase, {self}, Duration )
|
self.ScheduleID = self.LaseScheduler:Schedule( self, StopLase, {self}, Duration )
|
||||||
@@ -368,4 +370,16 @@ do
|
|||||||
return self.Lasing
|
return self.Lasing
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
--- Set laser start position relative to the lasing unit.
|
||||||
|
-- @param #SPOT self
|
||||||
|
-- @param #table position Start position of the laser relative to the lasing unit. Default is { x = 0, y = 2, z = 0 }
|
||||||
|
-- @return #SPOT self
|
||||||
|
-- @usage
|
||||||
|
-- -- Set lasing position to be the position of the optics of the Gazelle M:
|
||||||
|
-- myspot:SetRelativeStartPosition({ x = 1.7, y = 1.2, z = 0 })
|
||||||
|
function SPOT:SetRelativeStartPosition(position)
|
||||||
|
self.relstartpos = position or { x = 0, y = 2, z = 0 }
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
202
Moose Development/Moose/Core/TextAndSound.lua
Normal file
202
Moose Development/Moose/Core/TextAndSound.lua
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
--- **Core** - A Moose GetText system.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Main Features:
|
||||||
|
--
|
||||||
|
-- * A GetText for Moose
|
||||||
|
-- * Build a set of localized text entries, alongside their sounds and subtitles
|
||||||
|
-- * Aimed at class developers to offer localizable language support
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **applevangelist**
|
||||||
|
-- ## Date: April 2022
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Core.TextAndSound
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- Text and Sound class.
|
||||||
|
-- @type TEXTANDSOUND
|
||||||
|
-- @field #string ClassName Name of this class.
|
||||||
|
-- @field #string version Versioning.
|
||||||
|
-- @field #string lid LID for log entries.
|
||||||
|
-- @field #string locale Default locale of this object.
|
||||||
|
-- @field #table entries Table of entries.
|
||||||
|
-- @field #string textclass Name of the class the texts belong to.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
---
|
||||||
|
--
|
||||||
|
-- @field #TEXTANDSOUND
|
||||||
|
TEXTANDSOUND = {
|
||||||
|
ClassName = "TEXTANDSOUND",
|
||||||
|
version = "0.0.1",
|
||||||
|
lid = "",
|
||||||
|
locale = "en",
|
||||||
|
entries = {},
|
||||||
|
textclass = "",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Text and Sound entry.
|
||||||
|
-- @type TEXTANDSOUND.Entry
|
||||||
|
-- @field #string Classname Name of the class this entry is for.
|
||||||
|
-- @field #string Locale Locale of this entry, defaults to "en".
|
||||||
|
-- @field #table Data The list of entries.
|
||||||
|
|
||||||
|
--- Text and Sound data
|
||||||
|
-- @type TEXTANDSOUND.Data
|
||||||
|
-- @field #string ID ID of this entry for retrieval.
|
||||||
|
-- @field #string Text Text of this entry.
|
||||||
|
-- @field #string Soundfile (optional) Soundfile File name of the corresponding sound file.
|
||||||
|
-- @field #number Soundlength (optional) Length of the sound file in seconds.
|
||||||
|
-- @field #string Subtitle (optional) Subtitle for the sound file.
|
||||||
|
|
||||||
|
--- Instantiate a new object
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string ClassName Name of the class this instance is providing texts for.
|
||||||
|
-- @param #string Defaultlocale (Optional) Default locale of this instance, defaults to "en".
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:New(ClassName,Defaultlocale)
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
local self=BASE:Inherit(self, BASE:New())
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("%s (%s) | ", self.ClassName, self.version)
|
||||||
|
self.locale = Defaultlocale or (_SETTINGS:GetLocale() or "en")
|
||||||
|
self.textclass = ClassName or "none"
|
||||||
|
self.entries = {}
|
||||||
|
local initentry = {} -- #TEXTANDSOUND.Entry
|
||||||
|
initentry.Classname = ClassName
|
||||||
|
initentry.Data = {}
|
||||||
|
initentry.Locale = self.locale
|
||||||
|
self.entries[self.locale] = initentry
|
||||||
|
self:I(self.lid .. "Instantiated.")
|
||||||
|
self:T({self.entries[self.locale]})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add an entry
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string Locale Locale to set for this entry, e.g. "de".
|
||||||
|
-- @param #string ID Unique(!) ID of this entry under this locale (i.e. use the same ID to get localized text for the entry in another language).
|
||||||
|
-- @param #string Text Text for this entry.
|
||||||
|
-- @param #string Soundfile (Optional) Sound file name for this entry.
|
||||||
|
-- @param #number Soundlength (Optional) Length of the sound file in seconds.
|
||||||
|
-- @param #string Subtitle (Optional) Subtitle to be used alongside the sound file.
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:AddEntry(Locale,ID,Text,Soundfile,Soundlength,Subtitle)
|
||||||
|
self:T(self.lid .. "AddEntry")
|
||||||
|
local locale = Locale or self.locale
|
||||||
|
local dataentry = {} -- #TEXTANDSOUND.Data
|
||||||
|
dataentry.ID = ID or "1"
|
||||||
|
dataentry.Text = Text or "none"
|
||||||
|
dataentry.Soundfile = Soundfile
|
||||||
|
dataentry.Soundlength = Soundlength or 0
|
||||||
|
dataentry.Subtitle = Subtitle
|
||||||
|
if not self.entries[locale] then
|
||||||
|
local initentry = {} -- #TEXTANDSOUND.Entry
|
||||||
|
initentry.Classname = self.textclass -- class name entry
|
||||||
|
initentry.Data = {} -- data array
|
||||||
|
initentry.Locale = locale -- default locale
|
||||||
|
self.entries[locale] = initentry
|
||||||
|
end
|
||||||
|
self.entries[locale].Data[ID] = dataentry
|
||||||
|
self:T({self.entries[locale].Data})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get an entry
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string ID The unique ID of the data to be retrieved.
|
||||||
|
-- @param #string Locale (Optional) The locale of the text to be retrieved - defauls to default locale set with `New()`.
|
||||||
|
-- @return #string Text Text or nil if not found and no fallback.
|
||||||
|
-- @return #string Soundfile Filename or nil if not found and no fallback.
|
||||||
|
-- @return #string Soundlength Length of the sound or 0 if not found and no fallback.
|
||||||
|
-- @return #string Subtitle Text for subtitle or nil if not found and no fallback.
|
||||||
|
function TEXTANDSOUND:GetEntry(ID,Locale)
|
||||||
|
self:T(self.lid .. "GetEntry")
|
||||||
|
local locale = Locale or self.locale
|
||||||
|
if not self.entries[locale] then
|
||||||
|
-- fall back to default "en"
|
||||||
|
locale = self.locale
|
||||||
|
end
|
||||||
|
local Text,Soundfile,Soundlength,Subtitle = nil, nil, 0, nil
|
||||||
|
if self.entries[locale] then
|
||||||
|
if self.entries[locale].Data then
|
||||||
|
local data = self.entries[locale].Data[ID] -- #TEXTANDSOUND.Data
|
||||||
|
if data then
|
||||||
|
Text = data.Text
|
||||||
|
Soundfile = data.Soundfile
|
||||||
|
Soundlength = data.Soundlength
|
||||||
|
Subtitle = data.Subtitle
|
||||||
|
elseif self.entries[self.locale].Data[ID] then
|
||||||
|
-- no matching entry, try default
|
||||||
|
local data = self.entries[self.locale].Data[ID]
|
||||||
|
Text = data.Text
|
||||||
|
Soundfile = data.Soundfile
|
||||||
|
Soundlength = data.Soundlength
|
||||||
|
Subtitle = data.Subtitle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil, nil, 0, nil
|
||||||
|
end
|
||||||
|
return Text,Soundfile,Soundlength,Subtitle
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the default locale of this object
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @return #string locale
|
||||||
|
function TEXTANDSOUND:GetDefaultLocale()
|
||||||
|
self:T(self.lid .. "GetDefaultLocale")
|
||||||
|
return self.locale
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set default locale of this object
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string locale
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:SetDefaultLocale(locale)
|
||||||
|
self:T(self.lid .. "SetDefaultLocale")
|
||||||
|
self.locale = locale or "en"
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a locale exists
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @return #boolean outcome
|
||||||
|
function TEXTANDSOUND:HasLocale(Locale)
|
||||||
|
self:T(self.lid .. "HasLocale")
|
||||||
|
return self.entries[Locale] and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Flush all entries to the log
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:FlushToLog()
|
||||||
|
self:I(self.lid .. "Flushing entries:")
|
||||||
|
local text = string.format("Textclass: %s | Default Locale: %s",self.textclass, self.locale)
|
||||||
|
for _,_entry in pairs(self.entries) do
|
||||||
|
local entry = _entry -- #TEXTANDSOUND.Entry
|
||||||
|
local text = string.format("Textclassname: %s | Locale: %s",entry.Classname, entry.Locale)
|
||||||
|
self:I(text)
|
||||||
|
for _ID,_data in pairs(entry.Data) do
|
||||||
|
local data = _data -- #TEXTANDSOUND.Data
|
||||||
|
local text = string.format("ID: %s\nText: %s\nSoundfile: %s With length: %d\nSubtitle: %s",tostring(_ID), data.Text or "none",data.Soundfile or "none",data.Soundlength or 0,data.Subtitle or "none")
|
||||||
|
self:I(text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- End TextAndSound
|
||||||
|
----------------------------------------------------------------
|
||||||
@@ -34,8 +34,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # The TIMER Concept
|
-- # The TIMER Concept
|
||||||
--
|
--
|
||||||
-- The TIMER class is the little sister of the @{Core.Scheduler#SCHEDULER} class. It does the same thing but is a bit easier to use and has less overhead. It should be sufficient in many cases.
|
-- The TIMER class is the little sister of the @{Core.Scheduler#SCHEDULER} class. It does the same thing but is a bit easier to use and has less overhead. It should be sufficient in many cases.
|
||||||
@@ -107,19 +105,17 @@ TIMER = {
|
|||||||
--- Timer ID.
|
--- Timer ID.
|
||||||
_TIMERID=0
|
_TIMERID=0
|
||||||
|
|
||||||
--- Timer data base.
|
|
||||||
--_TIMERDB={}
|
|
||||||
|
|
||||||
--- TIMER class version.
|
--- TIMER class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
TIMER.version="0.1.1"
|
TIMER.version="0.1.2"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: A lot.
|
-- TODO: Randomization.
|
||||||
-- TODO: Write docs.
|
-- TODO: Pause/unpause.
|
||||||
|
-- DONE: Write docs.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
@@ -156,9 +152,6 @@ function TIMER:New(Function, ...)
|
|||||||
-- Log id.
|
-- Log id.
|
||||||
self.lid=string.format("TIMER UID=%d | ", self.uid)
|
self.lid=string.format("TIMER UID=%d | ", self.uid)
|
||||||
|
|
||||||
-- Add to DB.
|
|
||||||
--_TIMERDB[self.uid]=self
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -174,7 +167,7 @@ function TIMER:Start(Tstart, dT, Duration)
|
|||||||
local Tnow=timer.getTime()
|
local Tnow=timer.getTime()
|
||||||
|
|
||||||
-- Start time in sec.
|
-- Start time in sec.
|
||||||
self.Tstart=Tstart and Tnow+Tstart or Tnow+0.001 -- one millisecond delay if Tstart=nil
|
self.Tstart=Tstart and Tnow+math.max(Tstart, 0.001) or Tnow+0.001 -- one millisecond delay if Tstart=nil
|
||||||
|
|
||||||
-- Set time interval.
|
-- Set time interval.
|
||||||
self.dT=dT
|
self.dT=dT
|
||||||
@@ -219,10 +212,7 @@ function TIMER:Stop(Delay)
|
|||||||
|
|
||||||
-- Not running any more.
|
-- Not running any more.
|
||||||
self.isrunning=false
|
self.isrunning=false
|
||||||
|
|
||||||
-- Remove DB entry.
|
|
||||||
--_TIMERDB[self.uid]=nil
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -239,6 +229,15 @@ function TIMER:SetMaxFunctionCalls(Nmax)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set time interval. Can also be set when the timer is already running and is applied after the next function call.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @param #number dT Time interval in seconds.
|
||||||
|
-- @return #TIMER self
|
||||||
|
function TIMER:SetTimeInterval(dT)
|
||||||
|
self.dT=dT
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if the timer has been started and was not stopped.
|
--- Check if the timer has been started and was not stopped.
|
||||||
-- @param #TIMER self
|
-- @param #TIMER self
|
||||||
-- @return #boolean If `true`, the timer is running.
|
-- @return #boolean If `true`, the timer is running.
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ do -- UserFlag
|
|||||||
ClassName = "USERFLAG",
|
ClassName = "USERFLAG",
|
||||||
UserFlagName = nil,
|
UserFlagName = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- USERFLAG Constructor.
|
--- USERFLAG Constructor.
|
||||||
-- @param #USERFLAG self
|
-- @param #USERFLAG self
|
||||||
-- @param #string UserFlagName The name of the userflag, which is a free text string.
|
-- @param #string UserFlagName The name of the userflag, which is a free text string.
|
||||||
-- @return #USERFLAG
|
-- @return #USERFLAG
|
||||||
function USERFLAG:New( UserFlagName ) --R2.3
|
function USERFLAG:New( UserFlagName ) --R2.3
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #USERFLAG
|
local self = BASE:Inherit( self, BASE:New() ) -- #USERFLAG
|
||||||
|
|
||||||
self.UserFlagName = UserFlagName
|
self.UserFlagName = UserFlagName
|
||||||
@@ -52,7 +52,7 @@ do -- UserFlag
|
|||||||
--- Get the userflag name.
|
--- Get the userflag name.
|
||||||
-- @param #USERFLAG self
|
-- @param #USERFLAG self
|
||||||
-- @return #string Name of the user flag.
|
-- @return #string Name of the user flag.
|
||||||
function USERFLAG:GetName()
|
function USERFLAG:GetName()
|
||||||
return self.UserFlagName
|
return self.UserFlagName
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -66,18 +66,17 @@ do -- UserFlag
|
|||||||
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
|
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
|
||||||
--
|
--
|
||||||
function USERFLAG:Set( Number, Delay ) --R2.3
|
function USERFLAG:Set( Number, Delay ) --R2.3
|
||||||
|
|
||||||
if Delay and Delay>0 then
|
if Delay and Delay>0 then
|
||||||
self:ScheduleOnce(Delay, USERFLAG.Set, self, Number)
|
self:ScheduleOnce(Delay, USERFLAG.Set, self, Number)
|
||||||
else
|
else
|
||||||
--env.info(string.format("Setting flag \"%s\" to %d at T=%.1f", self.UserFlagName, Number, timer.getTime()))
|
--env.info(string.format("Setting flag \"%s\" to %d at T=%.1f", self.UserFlagName, Number, timer.getTime()))
|
||||||
trigger.action.setUserFlag( self.UserFlagName, Number )
|
trigger.action.setUserFlag( self.UserFlagName, Number )
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Get the userflag Number.
|
--- Get the userflag Number.
|
||||||
-- @param #USERFLAG self
|
-- @param #USERFLAG self
|
||||||
-- @return #number Number The number value to be checked if it is the same as the userflag.
|
-- @return #number Number The number value to be checked if it is the same as the userflag.
|
||||||
@@ -86,12 +85,10 @@ do -- UserFlag
|
|||||||
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
|
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
|
||||||
--
|
--
|
||||||
function USERFLAG:Get() --R2.3
|
function USERFLAG:Get() --R2.3
|
||||||
|
|
||||||
return trigger.misc.getUserFlag( self.UserFlagName )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
return trigger.misc.getUserFlag( self.UserFlagName )
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if the userflag has a value of Number.
|
--- Check if the userflag has a value of Number.
|
||||||
-- @param #USERFLAG self
|
-- @param #USERFLAG self
|
||||||
-- @param #number Number The number value to be checked if it is the same as the userflag.
|
-- @param #number Number The number value to be checked if it is the same as the userflag.
|
||||||
@@ -102,9 +99,9 @@ do -- UserFlag
|
|||||||
-- return "Blue has won"
|
-- return "Blue has won"
|
||||||
-- end
|
-- end
|
||||||
function USERFLAG:Is( Number ) --R2.3
|
function USERFLAG:Is( Number ) --R2.3
|
||||||
|
|
||||||
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
|
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -54,7 +54,7 @@ do -- Velocity
|
|||||||
self.Velocity = VelocityMps
|
self.Velocity = VelocityMps
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the velocity in Mps (meters per second).
|
--- Get the velocity in Mps (meters per second).
|
||||||
-- @param #VELOCITY self
|
-- @param #VELOCITY self
|
||||||
-- @return #number The velocity in meters per second.
|
-- @return #number The velocity in meters per second.
|
||||||
@@ -70,12 +70,12 @@ do -- Velocity
|
|||||||
self.Velocity = UTILS.KmphToMps( VelocityKmph )
|
self.Velocity = UTILS.KmphToMps( VelocityKmph )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the velocity in Kmph (kilometers per hour).
|
--- Get the velocity in Kmph (kilometers per hour).
|
||||||
-- @param #VELOCITY self
|
-- @param #VELOCITY self
|
||||||
-- @return #number The velocity in kilometers per hour.
|
-- @return #number The velocity in kilometers per hour.
|
||||||
function VELOCITY:GetKmph()
|
function VELOCITY:GetKmph()
|
||||||
|
|
||||||
return UTILS.MpsToKmph( self.Velocity )
|
return UTILS.MpsToKmph( self.Velocity )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ do -- Velocity
|
|||||||
self.Velocity = UTILS.MiphToMps( VelocityMiph )
|
self.Velocity = UTILS.MiphToMps( VelocityMiph )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the velocity in Miph (miles per hour).
|
--- Get the velocity in Miph (miles per hour).
|
||||||
-- @param #VELOCITY self
|
-- @param #VELOCITY self
|
||||||
-- @return #number The velocity in miles per hour.
|
-- @return #number The velocity in miles per hour.
|
||||||
@@ -95,8 +95,7 @@ do -- Velocity
|
|||||||
return UTILS.MpsToMiph( self.Velocity )
|
return UTILS.MpsToMiph( self.Velocity )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get the velocity in text, according the player @{Core.Settings}.
|
||||||
--- Get the velocity in text, according the player @{Settings}.
|
|
||||||
-- @param #VELOCITY self
|
-- @param #VELOCITY self
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings
|
||||||
-- @return #string The velocity in text.
|
-- @return #string The velocity in text.
|
||||||
@@ -113,11 +112,11 @@ do -- Velocity
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the velocity in text, according the player or default @{Settings}.
|
--- Get the velocity in text, according the player or default @{Core.Settings}.
|
||||||
-- @param #VELOCITY self
|
-- @param #VELOCITY self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||||
-- @param Core.Settings#SETTINGS Settings
|
-- @param Core.Settings#SETTINGS Settings
|
||||||
-- @return #string The velocity in text according the player or default @{Settings}
|
-- @return #string The velocity in text according the player or default @{Core.Settings}
|
||||||
function VELOCITY:ToString( VelocityGroup, Settings ) -- R2.3
|
function VELOCITY:ToString( VelocityGroup, Settings ) -- R2.3
|
||||||
self:F( { Group = VelocityGroup and VelocityGroup:GetName() } )
|
self:F( { Group = VelocityGroup and VelocityGroup:GetName() } )
|
||||||
local Settings = Settings or ( VelocityGroup and _DATABASE:GetPlayerSettings( VelocityGroup:GetPlayerName() ) ) or _SETTINGS
|
local Settings = Settings or ( VelocityGroup and _DATABASE:GetPlayerSettings( VelocityGroup:GetPlayerName() ) ) or _SETTINGS
|
||||||
@@ -134,7 +133,7 @@ do -- VELOCITY_POSITIONABLE
|
|||||||
|
|
||||||
--- # VELOCITY_POSITIONABLE class, extends @{Core.Base#BASE}
|
--- # VELOCITY_POSITIONABLE class, extends @{Core.Base#BASE}
|
||||||
--
|
--
|
||||||
-- VELOCITY_POSITIONABLE monitors the speed of an @{Positionable} in the simulation, which can be expressed in various formats according the Settings.
|
-- @{#VELOCITY_POSITIONABLE} monitors the speed of a @{Wrapper.Positionable#POSITIONABLE} in the simulation, which can be expressed in various formats according the Settings.
|
||||||
--
|
--
|
||||||
-- ## 1. VELOCITY_POSITIONABLE constructor
|
-- ## 1. VELOCITY_POSITIONABLE constructor
|
||||||
--
|
--
|
||||||
@@ -167,7 +166,7 @@ do -- VELOCITY_POSITIONABLE
|
|||||||
-- @param #VELOCITY_POSITIONABLE self
|
-- @param #VELOCITY_POSITIONABLE self
|
||||||
-- @return #number The velocity in kilometers per hour.
|
-- @return #number The velocity in kilometers per hour.
|
||||||
function VELOCITY_POSITIONABLE:GetKmph()
|
function VELOCITY_POSITIONABLE:GetKmph()
|
||||||
|
|
||||||
return UTILS.MpsToKmph( self.Positionable:GetVelocityMPS() or 0)
|
return UTILS.MpsToKmph( self.Positionable:GetVelocityMPS() or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -178,9 +177,9 @@ do -- VELOCITY_POSITIONABLE
|
|||||||
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
|
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the velocity in text, according the player or default @{Settings}.
|
--- Get the velocity in text, according the player or default @{Core.Settings}.
|
||||||
-- @param #VELOCITY_POSITIONABLE self
|
-- @param #VELOCITY_POSITIONABLE self
|
||||||
-- @return #string The velocity in text according the player or default @{Settings}
|
-- @return #string The velocity in text according the player or default @{Core.Settings}
|
||||||
function VELOCITY_POSITIONABLE:ToString() -- R2.3
|
function VELOCITY_POSITIONABLE:ToString() -- R2.3
|
||||||
self:F( { Group = self.Positionable and self.Positionable:GetName() } )
|
self:F( { Group = self.Positionable and self.Positionable:GetName() } )
|
||||||
local Settings = Settings or ( self.Positionable and _DATABASE:GetPlayerSettings( self.Positionable:GetPlayerName() ) ) or _SETTINGS
|
local Settings = Settings or ( self.Positionable and _DATABASE:GetPlayerSettings( self.Positionable:GetPlayerName() ) ) or _SETTINGS
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
|
--- **Core** - The ZONE_DETECTION class, defined by a zone name, a detection object and a radius.
|
||||||
|
-- @module Core.Zone_Detection
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
--- The ZONE_DETECTION class, defined by a zone name, a detection object and a radius.
|
--- @type ZONE_DETECTION
|
||||||
-- @type ZONE_DETECTION
|
|
||||||
-- @field DCS#Vec2 Vec2 The current location of the zone.
|
-- @field DCS#Vec2 Vec2 The current location of the zone.
|
||||||
-- @field DCS#Distance Radius The radius of the zone.
|
-- @field DCS#Distance Radius The radius of the zone.
|
||||||
-- @extends #ZONE_BASE
|
-- @extends #ZONE_BASE
|
||||||
@@ -29,7 +31,7 @@ function ZONE_DETECTION:New( ZoneName, Detection, Radius )
|
|||||||
|
|
||||||
self.Detection = Detection
|
self.Detection = Detection
|
||||||
self.Radius = Radius
|
self.Radius = Radius
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -48,15 +50,14 @@ function ZONE_DETECTION:BoundZone( Points, CountryID, UnBound )
|
|||||||
|
|
||||||
local Angle
|
local Angle
|
||||||
local RadialBase = math.pi*2
|
local RadialBase = math.pi*2
|
||||||
|
|
||||||
--
|
|
||||||
for Angle = 0, 360, (360 / Points ) do
|
for Angle = 0, 360, (360 / Points ) do
|
||||||
local Radial = Angle * RadialBase / 360
|
local Radial = Angle * RadialBase / 360
|
||||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||||
|
|
||||||
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
|
local CountryName = _DATABASE.COUNTRY_NAME[CountryID]
|
||||||
|
|
||||||
local Tire = {
|
local Tire = {
|
||||||
["country"] = CountryName,
|
["country"] = CountryName,
|
||||||
["category"] = "Fortifications",
|
["category"] = "Fortifications",
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
--- **DCS API** Prototypes
|
--- **DCS API** Prototypes.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
--
|
--
|
||||||
-- See the [Simulator Scripting Engine Documentation](https://wiki.hoggitworld.com/view/Simulator_Scripting_Engine_Documentation) on Hoggit for further explanation and examples.
|
-- See the [Simulator Scripting Engine Documentation](https://wiki.hoggitworld.com/view/Simulator_Scripting_Engine_Documentation) on Hoggit for further explanation and examples.
|
||||||
--
|
--
|
||||||
@@ -471,6 +473,22 @@ do -- Types
|
|||||||
--@field #boolean lateActivated
|
--@field #boolean lateActivated
|
||||||
--@field #boolean uncontrolled
|
--@field #boolean uncontrolled
|
||||||
|
|
||||||
|
--- DCS template data structure.
|
||||||
|
-- @type Template
|
||||||
|
-- @field #boolean uncontrolled Aircraft is uncontrolled.
|
||||||
|
-- @field #boolean lateActivation Group is late activated.
|
||||||
|
-- @field #number x 2D Position on x-axis in meters.
|
||||||
|
-- @field #number y 2D Position on y-axis in meters.
|
||||||
|
-- @field #table units Unit list.
|
||||||
|
--
|
||||||
|
|
||||||
|
--- Unit data structure.
|
||||||
|
--@type Template.Unit
|
||||||
|
--@field #string name Name of the unit.
|
||||||
|
--@field #number x
|
||||||
|
--@field #number y
|
||||||
|
--@field #number alt
|
||||||
|
|
||||||
end --
|
end --
|
||||||
|
|
||||||
|
|
||||||
@@ -487,8 +505,9 @@ do -- Object
|
|||||||
-- @field UNIT
|
-- @field UNIT
|
||||||
-- @field WEAPON
|
-- @field WEAPON
|
||||||
-- @field STATIC
|
-- @field STATIC
|
||||||
-- @field SCENERY
|
|
||||||
-- @field BASE
|
-- @field BASE
|
||||||
|
-- @field SCENERY
|
||||||
|
-- @field CARGO
|
||||||
|
|
||||||
--- @type Object.Desc
|
--- @type Object.Desc
|
||||||
-- @extends #Desc
|
-- @extends #Desc
|
||||||
@@ -498,6 +517,10 @@ do -- Object
|
|||||||
--- @function [parent=#Object] isExist
|
--- @function [parent=#Object] isExist
|
||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- @function [parent=#Object] isActive
|
||||||
|
-- @param #Object self
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
--- @function [parent=#Object] destroy
|
--- @function [parent=#Object] destroy
|
||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
@@ -1130,6 +1153,11 @@ do -- Unit
|
|||||||
-- @function [parent=#Unit] getAmmo
|
-- @function [parent=#Unit] getAmmo
|
||||||
-- @param #Unit self
|
-- @param #Unit self
|
||||||
-- @return #Unit.Ammo
|
-- @return #Unit.Ammo
|
||||||
|
|
||||||
|
--- Returns the number of infantry that can be embark onto the aircraft. Only returns a value if run on airplanes or helicopters. Returns nil if run on ground or ship units.
|
||||||
|
-- @function [parent=#Unit] getDescentCapacity
|
||||||
|
-- @param #Unit self
|
||||||
|
-- @return #number Number of soldiers that embark.
|
||||||
|
|
||||||
--- Returns the unit sensors.
|
--- Returns the unit sensors.
|
||||||
-- @function [parent=#Unit] getSensors
|
-- @function [parent=#Unit] getSensors
|
||||||
@@ -1348,7 +1376,9 @@ do -- AI
|
|||||||
--- @type AI.Option.Ground
|
--- @type AI.Option.Ground
|
||||||
-- @field #AI.Option.Ground.id id
|
-- @field #AI.Option.Ground.id id
|
||||||
-- @field #AI.Option.Ground.val val
|
-- @field #AI.Option.Ground.val val
|
||||||
|
-- @field #AI.Option.Ground.mid mid
|
||||||
|
-- @field #AI.Option.Ground.mval mval
|
||||||
|
--
|
||||||
--- @type AI.Option.Naval
|
--- @type AI.Option.Naval
|
||||||
-- @field #AI.Option.Naval.id id
|
-- @field #AI.Option.Naval.id id
|
||||||
-- @field #AI.Option.Naval.val val
|
-- @field #AI.Option.Naval.val val
|
||||||
@@ -1371,6 +1401,11 @@ do -- AI
|
|||||||
-- @field PROHIBIT_AG
|
-- @field PROHIBIT_AG
|
||||||
-- @field MISSILE_ATTACK
|
-- @field MISSILE_ATTACK
|
||||||
-- @field PROHIBIT_WP_PASS_REPORT
|
-- @field PROHIBIT_WP_PASS_REPORT
|
||||||
|
-- @field OPTION_RADIO_USAGE_CONTACT
|
||||||
|
-- @field OPTION_RADIO_USAGE_ENGAGE
|
||||||
|
-- @field OPTION_RADIO_USAGE_KILL
|
||||||
|
-- @field JETT_TANKS_IF_EMPTY
|
||||||
|
-- @field FORCED_ATTACK
|
||||||
|
|
||||||
--- @type AI.Option.Air.id.FORMATION
|
--- @type AI.Option.Air.id.FORMATION
|
||||||
-- @field LINE_ABREAST
|
-- @field LINE_ABREAST
|
||||||
@@ -1440,19 +1475,35 @@ do -- AI
|
|||||||
--- @type AI.Option.Ground.id
|
--- @type AI.Option.Ground.id
|
||||||
-- @field NO_OPTION
|
-- @field NO_OPTION
|
||||||
-- @field ROE @{#AI.Option.Ground.val.ROE}
|
-- @field ROE @{#AI.Option.Ground.val.ROE}
|
||||||
|
-- @field FORMATION
|
||||||
-- @field DISPERSE_ON_ATTACK true or false
|
-- @field DISPERSE_ON_ATTACK true or false
|
||||||
-- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE}
|
-- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE}
|
||||||
-- @field ENGAGE_AIR_WEAPONS
|
-- @field ENGAGE_AIR_WEAPONS
|
||||||
|
-- @field AC_ENGAGEMENT_RANGE_RESTRICTION
|
||||||
|
|
||||||
|
--- @type AI.Option.Ground.mid -- Moose added
|
||||||
|
-- @field RESTRICT_AAA_MIN 27
|
||||||
|
-- @field RESTRICT_AAA_MAX 29
|
||||||
|
-- @field RESTRICT_TARGETS @{#AI.Option.Ground.mval.ENGAGE_TARGETS} 28
|
||||||
|
|
||||||
--- @type AI.Option.Ground.val
|
--- @type AI.Option.Ground.val
|
||||||
-- @field #AI.Option.Ground.val.ROE ROE
|
-- @field #AI.Option.Ground.val.ROE ROE
|
||||||
-- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE
|
-- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE
|
||||||
|
-- @field #AI.Option.Ground.val.ENGAGE_TARGETS RESTRICT_TARGETS
|
||||||
|
|
||||||
--- @type AI.Option.Ground.val.ROE
|
--- @type AI.Option.Ground.val.ROE
|
||||||
-- @field OPEN_FIRE
|
-- @field OPEN_FIRE
|
||||||
-- @field RETURN_FIRE
|
-- @field RETURN_FIRE
|
||||||
-- @field WEAPON_HOLD
|
-- @field WEAPON_HOLD
|
||||||
|
|
||||||
|
--- @type AI.Option.Ground.mval -- Moose added
|
||||||
|
-- @field #AI.Option.Ground.mval.ENGAGE_TARGETS ENGAGE_TARGETS
|
||||||
|
|
||||||
|
--- @type AI.Option.Ground.mval.ENGAGE_TARGETS -- Moose added
|
||||||
|
-- @field ANY_TARGET -- 0
|
||||||
|
-- @field AIR_UNITS_ONLY -- 1
|
||||||
|
-- @field GROUND_UNITS_ONLY -- 2
|
||||||
|
|
||||||
--- @type AI.Option.Ground.val.ALARM_STATE
|
--- @type AI.Option.Ground.val.ALARM_STATE
|
||||||
-- @field AUTO
|
-- @field AUTO
|
||||||
-- @field GREEN
|
-- @field GREEN
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@
|
|||||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
|
||||||
--
|
--
|
||||||
-- ====
|
-- ====
|
||||||
-- @module Functional.Arty
|
-- @module Functional.Artillery
|
||||||
-- @image Artillery.JPG
|
-- @image Artillery.JPG
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
--- Enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can
|
--- Enables mission designers easily to assign targets for artillery units. Since the implementation is based on a Finite State Model (FSM), the mission designer can
|
||||||
-- interact with the process at certain events or states.
|
-- interact with the process at certain events or states.
|
||||||
--
|
--
|
||||||
-- A new ARTY object can be created with the @{#ARTY.New}(*group*) contructor.
|
-- A new ARTY object can be created with the @{#ARTY.New}(*group*) constructor.
|
||||||
-- The parameter *group* has to be a MOOSE Group object and defines ARTY group.
|
-- The parameter *group* has to be a MOOSE Group object and defines ARTY group.
|
||||||
--
|
--
|
||||||
-- The ARTY FSM process can be started by the @{#ARTY.Start}() command.
|
-- The ARTY FSM process can be started by the @{#ARTY.Start}() command.
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
-- When a new target is assigned via the @{#ARTY.AssignTargetCoord}() function (see below), the **NewTarget** event is triggered.
|
-- When a new target is assigned via the @{#ARTY.AssignTargetCoord}() function (see below), the **NewTarget** event is triggered.
|
||||||
--
|
--
|
||||||
-- ## Assigning Targets
|
-- ## Assigning Targets
|
||||||
-- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultanioulsly and are put into a queue.
|
-- Assigning targets is a central point of the ARTY class. Multiple targets can be assigned simultaneously and are put into a queue.
|
||||||
-- Of course, targets can be added at any time during the mission. For example, once they are detected by a reconnaissance unit.
|
-- Of course, targets can be added at any time during the mission. For example, once they are detected by a reconnaissance unit.
|
||||||
--
|
--
|
||||||
-- In order to add a target, the function @{#ARTY.AssignTargetCoord}(*coord*, *prio*, *radius*, *nshells*, *maxengage*, *time*, *weapontype*, *name*) has to be used.
|
-- In order to add a target, the function @{#ARTY.AssignTargetCoord}(*coord*, *prio*, *radius*, *nshells*, *maxengage*, *time*, *weapontype*, *name*) has to be used.
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
-- * *maxengage*: Number of times a target is engaged.
|
-- * *maxengage*: Number of times a target is engaged.
|
||||||
-- * *time*: Time of day the engagement is schedule in the format "hh:mm:ss" for hh=hours, mm=minutes, ss=seconds.
|
-- * *time*: Time of day the engagement is schedule in the format "hh:mm:ss" for hh=hours, mm=minutes, ss=seconds.
|
||||||
-- For example "10:15:35". In the case the attack will be executed at a quarter past ten in the morning at the day the mission started.
|
-- For example "10:15:35". In the case the attack will be executed at a quarter past ten in the morning at the day the mission started.
|
||||||
-- If the engagement should start on the following day the format can be specified as "10:15:35+1", where the +1 denots the following day.
|
-- If the engagement should start on the following day the format can be specified as "10:15:35+1", where the +1 denotes the following day.
|
||||||
-- This is useful for longer running missions or if the mission starts at 23:00 hours and the attack should be scheduled at 01:00 hours on the following day.
|
-- This is useful for longer running missions or if the mission starts at 23:00 hours and the attack should be scheduled at 01:00 hours on the following day.
|
||||||
-- Of course, later days are also possible by appending "+2", "+3", etc.
|
-- Of course, later days are also possible by appending "+2", "+3", etc.
|
||||||
-- **Note** that the time has to be given as a string. So the enclosing quotation marks "" are important.
|
-- **Note** that the time has to be given as a string. So the enclosing quotation marks "" are important.
|
||||||
@@ -179,7 +179,7 @@
|
|||||||
-- Let's first consider the case that none of the targets is scheduled to be executed at a certain time (*time*=nil).
|
-- Let's first consider the case that none of the targets is scheduled to be executed at a certain time (*time*=nil).
|
||||||
-- The ARTY group will first engage the target with higher priority (*prio*=10). After the engagement is finished, the target with lower priority is attacked.
|
-- The ARTY group will first engage the target with higher priority (*prio*=10). After the engagement is finished, the target with lower priority is attacked.
|
||||||
-- This is because the target with lower prio has been attacked one time less. After the attack on the lower priority task is finished and both targets
|
-- This is because the target with lower prio has been attacked one time less. After the attack on the lower priority task is finished and both targets
|
||||||
-- have been engaged equally often, the target with the higher priority is engaged again. This coninues until a target has engaged three times.
|
-- have been engaged equally often, the target with the higher priority is engaged again. This continues until a target has engaged three times.
|
||||||
-- Once the maximum number of engagements is reached, the target is deleted from the queue.
|
-- Once the maximum number of engagements is reached, the target is deleted from the queue.
|
||||||
--
|
--
|
||||||
-- In other words, the queue is first sorted with respect to the number of engagements and targets with the same number of engagements are sorted with
|
-- In other words, the queue is first sorted with respect to the number of engagements and targets with the same number of engagements are sorted with
|
||||||
@@ -190,7 +190,7 @@
|
|||||||
-- As mentioned above, targets can be engaged at a specific time of the day via the *time* parameter.
|
-- As mentioned above, targets can be engaged at a specific time of the day via the *time* parameter.
|
||||||
--
|
--
|
||||||
-- If the *time* parameter is specified for a target, the first engagement of that target will happen at that time of the day and not before.
|
-- If the *time* parameter is specified for a target, the first engagement of that target will happen at that time of the day and not before.
|
||||||
-- This also applies when multiple engagements are requested via the *maxengage* parameter. The first attack will not happen before the specifed time.
|
-- This also applies when multiple engagements are requested via the *maxengage* parameter. The first attack will not happen before the specified time.
|
||||||
-- When that timed attack is finished, the *time* parameter is deleted and the remaining engagements are carried out in the same manner as for untimed targets (described above).
|
-- When that timed attack is finished, the *time* parameter is deleted and the remaining engagements are carried out in the same manner as for untimed targets (described above).
|
||||||
--
|
--
|
||||||
-- Of course, it can happen that a scheduled task should be executed at a time, when another target is already under attack.
|
-- Of course, it can happen that a scheduled task should be executed at a time, when another target is already under attack.
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Determining the Amount of Ammo
|
-- ## Determining the Amount of Ammo
|
||||||
--
|
--
|
||||||
-- In order to determin when a unit is out of ammo and possible initiate the rearming process it is necessary to know which types of weapons have to be counted.
|
-- In order to determine when a unit is out of ammo and possible initiate the rearming process it is necessary to know which types of weapons have to be counted.
|
||||||
-- For most artillery unit types, this is simple because they only have one type of weapon and hence ammunition.
|
-- For most artillery unit types, this is simple because they only have one type of weapon and hence ammunition.
|
||||||
--
|
--
|
||||||
-- However, there are more complex scenarios. For example, naval units carry a big arsenal of different ammunition types ranging from various cannon shell types
|
-- However, there are more complex scenarios. For example, naval units carry a big arsenal of different ammunition types ranging from various cannon shell types
|
||||||
@@ -217,7 +217,7 @@
|
|||||||
-- **Note** that the default parameters "weapons.shells", "weapons.nurs", "weapons.missiles" **should in priciple** capture all the corresponding ammo types.
|
-- **Note** that the default parameters "weapons.shells", "weapons.nurs", "weapons.missiles" **should in priciple** capture all the corresponding ammo types.
|
||||||
-- However, the logic searches for the string "weapon.missies" in the ammo type. Especially for missiles, this string is often not contained in the ammo type descriptor.
|
-- However, the logic searches for the string "weapon.missies" in the ammo type. Especially for missiles, this string is often not contained in the ammo type descriptor.
|
||||||
--
|
--
|
||||||
-- One way to determin which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}().
|
-- One way to determine which types of ammo the unit carries, one can use the debug mode of the arty class via @{#ARTY.SetDebugON}().
|
||||||
-- In debug mode, the all ammo types of the group are printed to the monitor as message and can be found in the DCS.log file.
|
-- In debug mode, the all ammo types of the group are printed to the monitor as message and can be found in the DCS.log file.
|
||||||
--
|
--
|
||||||
-- ## Employing Selected Weapons
|
-- ## Employing Selected Weapons
|
||||||
@@ -274,7 +274,7 @@
|
|||||||
--
|
--
|
||||||
-- ## Simulated Weapons
|
-- ## Simulated Weapons
|
||||||
--
|
--
|
||||||
-- In addtion to the standard weapons a group has available some special weapon types that are not possible to use in the native DCS environment are simulated.
|
-- In addition to the standard weapons a group has available some special weapon types that are not possible to use in the native DCS environment are simulated.
|
||||||
--
|
--
|
||||||
-- ### Tactical Nukes
|
-- ### Tactical Nukes
|
||||||
--
|
--
|
||||||
@@ -283,9 +283,9 @@
|
|||||||
--
|
--
|
||||||
-- By default, they group does not have any nukes available. To give the group the ability the function @{#ARTY.SetTacNukeShells}(*n*) can be used.
|
-- By default, they group does not have any nukes available. To give the group the ability the function @{#ARTY.SetTacNukeShells}(*n*) can be used.
|
||||||
-- This supplies the group with *n* nuclear shells, where *n* is restricted to the number of conventional shells the group can carry.
|
-- This supplies the group with *n* nuclear shells, where *n* is restricted to the number of conventional shells the group can carry.
|
||||||
-- Note that the group must always have convenctional shells left in order to fire a nuclear shell.
|
-- Note that the group must always have conventional shells left in order to fire a nuclear shell.
|
||||||
--
|
--
|
||||||
-- The default explostion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT.
|
-- The default explosion strength is 0.075 kilo tons TNT. The can be changed with the @{#ARTY.SetTacNukeWarhead}(*strength*), where *strength* is given in kilo tons TNT.
|
||||||
--
|
--
|
||||||
-- ### Illumination Shells
|
-- ### Illumination Shells
|
||||||
--
|
--
|
||||||
@@ -301,12 +301,12 @@
|
|||||||
--
|
--
|
||||||
-- ### Smoke Shells
|
-- ### Smoke Shells
|
||||||
--
|
--
|
||||||
-- In a similar way to illumination shells, ARTY groups can also employ smoke shells. The numer of smoke shells the group has available is set by the function
|
-- In a similar way to illumination shells, ARTY groups can also employ smoke shells. The number of smoke shells the group has available is set by the function
|
||||||
-- @{#ARTY.SetSmokeShells}(*n*, *color*), where *n* is the number of shells and *color* defines the smoke color. Default is SMOKECOLOR.Red.
|
-- @{#ARTY.SetSmokeShells}(*n*, *color*), where *n* is the number of shells and *color* defines the smoke color. Default is SMOKECOLOR.Red.
|
||||||
--
|
--
|
||||||
-- The weapon type to be used in the @{#ARTY.AssignTargetCoord}() function is *ARTY.WeaponType.SmokeShells*.
|
-- The weapon type to be used in the @{#ARTY.AssignTargetCoord}() function is *ARTY.WeaponType.SmokeShells*.
|
||||||
--
|
--
|
||||||
-- The explosive shell the group fired is destroyed shortly before its impact on the ground and smoke of the speficied color is triggered at that position.
|
-- The explosive shell the group fired is destroyed shortly before its impact on the ground and smoke of the specified color is triggered at that position.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- ## Assignments via Markers on F10 Map
|
-- ## Assignments via Markers on F10 Map
|
||||||
@@ -320,15 +320,15 @@
|
|||||||
-- ### Target Assignments
|
-- ### Target Assignments
|
||||||
-- A new target can be assigned by writing **arty engage** in the marker text.
|
-- A new target can be assigned by writing **arty engage** in the marker text.
|
||||||
-- This is followed by a **comma separated list** of (optional) keywords and parameters.
|
-- This is followed by a **comma separated list** of (optional) keywords and parameters.
|
||||||
-- First, it is important to address the ARTY group or groups that should engage. This can be done in numrous ways. The keywords are *battery*, *alias*, *cluster*.
|
-- First, it is important to address the ARTY group or groups that should engage. This can be done in numerous ways. The keywords are *battery*, *alias*, *cluster*.
|
||||||
-- It is also possible to address all ARTY groups by the keyword *everyone* or *allbatteries*. These two can be used synonymously.
|
-- It is also possible to address all ARTY groups by the keyword *everyone* or *allbatteries*. These two can be used synonymously.
|
||||||
-- **Note that**, if no battery is assigned nothing will happen.
|
-- **Note that**, if no battery is assigned nothing will happen.
|
||||||
--
|
--
|
||||||
-- * *everyone* or *allbatteries* The target is assigned to all batteries.
|
-- * *everyone* or *allbatteries* The target is assigned to all batteries.
|
||||||
-- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition.
|
-- * *battery* Name of the ARTY group that the target is assigned to. Note that **the name is case sensitive** and has to be given in quotation marks. Default is all ARTY groups of the right coalition.
|
||||||
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
|
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
|
||||||
-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
-- * *cluster* The cluster of ARTY groups that is addressed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
||||||
-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement.
|
-- * *key* A number to authorize the target assignment. Only specifying the correct number will trigger an engagement.
|
||||||
-- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible.
|
-- * *time* Time for which which the engagement is schedules, e.g. 08:42. Default is as soon as possible.
|
||||||
-- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50, i.e. medium priority.
|
-- * *prio* Priority of the engagement as number between 1 (high prio) and 100 (low prio). Default is 50, i.e. medium priority.
|
||||||
-- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5.
|
-- * *shots* Number of shots (shells, rockets or missiles) fired at each engagement. Default is 5.
|
||||||
@@ -353,8 +353,8 @@
|
|||||||
-- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15
|
-- arty engage, battery "Paladin Alpha", weapon nukes, shots 1, time 20:15
|
||||||
-- arty engage, battery "Horwitzer 1", lldms 41:51:00N 41:47:58E
|
-- arty engage, battery "Horwitzer 1", lldms 41:51:00N 41:47:58E
|
||||||
--
|
--
|
||||||
-- Note that the keywords and parameters are *case insensitve*. Only exception are the battery, alias and cluster names.
|
-- Note that the keywords and parameters are *case insensitive*. Only exception are the battery, alias and cluster names.
|
||||||
-- These must be exactly the same as the names of the goups defined in the mission editor or the aliases and cluster names defined in the script.
|
-- These must be exactly the same as the names of the groups defined in the mission editor or the aliases and cluster names defined in the script.
|
||||||
--
|
--
|
||||||
-- ### Relocation Assignments
|
-- ### Relocation Assignments
|
||||||
--
|
--
|
||||||
@@ -363,11 +363,11 @@
|
|||||||
-- * *time* Time for which which the relocation/move is schedules, e.g. 08:42. Default is as soon as possible.
|
-- * *time* Time for which which the relocation/move is schedules, e.g. 08:42. Default is as soon as possible.
|
||||||
-- * *speed* The speed in km/h the group will drive at. Default is 70% of its max possible speed.
|
-- * *speed* The speed in km/h the group will drive at. Default is 70% of its max possible speed.
|
||||||
-- * *on road* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate.
|
-- * *on road* Group will use mainly roads. Default is off, i.e. it will go in a straight line from its current position to the assigned coordinate.
|
||||||
-- * *canceltarget* Group will cancel all running firing engagements and immidiately start to move. Default is that group will wait until is current assignment is over.
|
-- * *canceltarget* Group will cancel all running firing engagements and immediately start to move. Default is that group will wait until is current assignment is over.
|
||||||
-- * *battery* Name of the ARTY group that the relocation is assigned to.
|
-- * *battery* Name of the ARTY group that the relocation is assigned to.
|
||||||
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
|
-- * *alias* Alias of the ARTY group that the target is assigned to. The alias is **case sensitive** and needs to be in quotation marks.
|
||||||
-- * *cluster* The cluster of ARTY groups that is addessed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
-- * *cluster* The cluster of ARTY groups that is addressed. Clusters can be defined by the function @{#ARTY.AddToCluster}(*clusters*). Names are **case sensitive** and need to be in quotation marks.
|
||||||
-- * *key* A number to authorize the target assignment. Only specifing the correct number will trigger an engagement.
|
-- * *key* A number to authorize the target assignment. Only specifying the correct number will trigger an engagement.
|
||||||
-- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant. The group will move to the coordinates given in the lldms keyword.
|
-- * *lldms* Specify the coordinates in Lat/Long degrees, minutes and seconds format. The actual location of the marker is unimportant. The group will move to the coordinates given in the lldms keyword.
|
||||||
-- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below.
|
-- Format is DD:MM:SS[N,S] DD:MM:SS[W,E]. See example below.
|
||||||
-- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker.
|
-- * *readonly* Marker cannot be deleted by users any more. Hence, assignment cannot be cancelled by removing the marker.
|
||||||
@@ -410,12 +410,12 @@
|
|||||||
--
|
--
|
||||||
-- A few options can be set by marks. The corresponding keyword is **arty set**. This can be used to define the rearming place and group for a battery.
|
-- A few options can be set by marks. The corresponding keyword is **arty set**. This can be used to define the rearming place and group for a battery.
|
||||||
--
|
--
|
||||||
-- To set the reamring place of a group at the marker position type
|
-- To set the rearming place of a group at the marker position type
|
||||||
-- arty set, battery "Paladin Alpha", rearming place
|
-- arty set, battery "Paladin Alpha", rearming place
|
||||||
--
|
--
|
||||||
-- Setting the rearming group is independent of the position of the mark. Just create one anywhere on the map and type
|
-- Setting the rearming group is independent of the position of the mark. Just create one anywhere on the map and type
|
||||||
-- arty set, battery "Mortar Bravo", rearming group "Ammo Truck M818"
|
-- arty set, battery "Mortar Bravo", rearming group "Ammo Truck M818"
|
||||||
-- Note that the name of the rearming group has to be given in quotation marks and spellt exactly as the group name defined in the mission editor.
|
-- Note that the name of the rearming group has to be given in quotation marks and spelt exactly as the group name defined in the mission editor.
|
||||||
--
|
--
|
||||||
-- ## Transporting
|
-- ## Transporting
|
||||||
--
|
--
|
||||||
@@ -3422,7 +3422,7 @@ function ARTY:onafterMove(Controllable, From, Event, To, move)
|
|||||||
-- Set current move.
|
-- Set current move.
|
||||||
self.currentMove=move
|
self.currentMove=move
|
||||||
|
|
||||||
-- Route group to coodinate.
|
-- Route group to coordinate.
|
||||||
self:_Move(self.Controllable, move.coord, move.speed, move.onroad)
|
self:_Move(self.Controllable, move.coord, move.speed, move.onroad)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
|
--- **Functional** - Keep airbases clean of crashing or colliding airplanes, and kill missiles when being fired at airbases.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Management of target **Designation**. Lase, smoke and illuminate targets.
|
--- **Functional** - Management of target **Designation**. Lase, smoke and illuminate targets.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- A typical mission setup would require Recce (a @{Set} of Recce) to be detecting potential targets.
|
-- A typical mission setup would require Recce (a @{Core.Set} of Recce) to be detecting potential targets.
|
||||||
-- The DetectionObject will group the detected targets based on the detection method being used.
|
-- The DetectionObject will group the detected targets based on the detection method being used.
|
||||||
-- Possible detection methods could be by Area, by Type or by Unit.
|
-- Possible detection methods could be by Area, by Type or by Unit.
|
||||||
-- Each grouping will result in a **TargetGroup**, for terminology and clarity we will use this term throughout the document.
|
-- Each grouping will result in a **TargetGroup**, for terminology and clarity we will use this term throughout the document.
|
||||||
@@ -213,7 +213,7 @@ do -- DESIGNATE
|
|||||||
-- In order to prevent an overflow of designations due to many Detected Targets, there is a
|
-- In order to prevent an overflow of designations due to many Detected Targets, there is a
|
||||||
-- Maximum Designations scope that is set in the DesignationObject.
|
-- Maximum Designations scope that is set in the DesignationObject.
|
||||||
--
|
--
|
||||||
-- The method @{#DESIGNATE.SetMaximumDesignations}() will put a limit on the amount of designations put in scope of the DesignationObject.
|
-- The method @{#DESIGNATE.SetMaximumDesignations}() will put a limit on the amount of designations (target groups) put in scope of the DesignationObject.
|
||||||
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
||||||
--
|
--
|
||||||
-- # 4. Laser codes
|
-- # 4. Laser codes
|
||||||
@@ -276,7 +276,7 @@ do -- DESIGNATE
|
|||||||
-- # 7. Designate Menu Location for a Mission
|
-- # 7. Designate Menu Location for a Mission
|
||||||
--
|
--
|
||||||
-- You can make DESIGNATE work for a @{Tasking.Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission.
|
-- You can make DESIGNATE work for a @{Tasking.Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission.
|
||||||
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Mission} object for the designate function.
|
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Tasking.Mission} object for the designate function.
|
||||||
--
|
--
|
||||||
-- # 8. Status Report
|
-- # 8. Status Report
|
||||||
--
|
--
|
||||||
@@ -562,7 +562,8 @@ do -- DESIGNATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the maximum amount of designations.
|
--- Set the maximum amount of designations (target groups). This will put a limit on the amount of designations in scope.
|
||||||
|
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @param #number MaximumDesignations
|
-- @param #number MaximumDesignations
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
@@ -602,7 +603,7 @@ do -- DESIGNATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the maximum amount of markings FACs will do, per designated target group.
|
--- Set the maximum amount of markings FACs will do, per designated target group. This will limit the number of parallelly marked units of a target group.
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @param #number MaximumMarkings Maximum markings FACs will do, per designated target group.
|
-- @param #number MaximumMarkings Maximum markings FACs will do, per designated target group.
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
@@ -911,8 +912,8 @@ do -- DESIGNATE
|
|||||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||||
local DetectedItem = DetectedItems[DesignateIndex]
|
local DetectedItem = DetectedItems[DesignateIndex]
|
||||||
if DetectedItem then
|
if DetectedItem then
|
||||||
local Report = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
local Report = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup, nil, true ):Text( ", " )
|
||||||
DetectedReport:Add( string.rep( "-", 140 ) )
|
DetectedReport:Add( string.rep( "-", 40 ) )
|
||||||
DetectedReport:Add( " - " .. Report )
|
DetectedReport:Add( " - " .. Report )
|
||||||
if string.find( Designating, "L" ) then
|
if string.find( Designating, "L" ) then
|
||||||
DetectedReport:Add( " - " .. "Lasing Targets" )
|
DetectedReport:Add( " - " .. "Lasing Targets" )
|
||||||
@@ -1192,8 +1193,8 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
local MarkingCount = 0
|
local MarkingCount = 0
|
||||||
local MarkedTypes = {}
|
local MarkedTypes = {}
|
||||||
local ReportTypes = REPORT:New()
|
--local ReportTypes = REPORT:New()
|
||||||
local ReportLaserCodes = REPORT:New()
|
--local ReportLaserCodes = REPORT:New()
|
||||||
|
|
||||||
TargetSetUnit:Flush( self )
|
TargetSetUnit:Flush( self )
|
||||||
|
|
||||||
@@ -1243,8 +1244,8 @@ do -- DESIGNATE
|
|||||||
if not Recce then
|
if not Recce then
|
||||||
|
|
||||||
self:F( "Lasing..." )
|
self:F( "Lasing..." )
|
||||||
self.RecceSet:Flush( self)
|
--self.RecceSet:Flush( self)
|
||||||
|
|
||||||
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
||||||
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
||||||
|
|
||||||
@@ -1282,13 +1283,13 @@ do -- DESIGNATE
|
|||||||
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
||||||
MarkingCount = MarkingCount + 1
|
MarkingCount = MarkingCount + 1
|
||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
--RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
||||||
-- 5, self.AttackSet, DesignateName )
|
10, self.AttackSet, DesignateName )
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
ReportTypes:Add(TargetUnitType)
|
--ReportTypes:Add(TargetUnitType)
|
||||||
end
|
end
|
||||||
ReportLaserCodes:Add(RecceUnit.LaserCode)
|
--ReportLaserCodes:Add(RecceUnit.LaserCode)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1303,16 +1304,16 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
if Recce then
|
if Recce then
|
||||||
Recce:LaseOff()
|
Recce:LaseOff()
|
||||||
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet, self.DesignateName )
|
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 10, self.AttackSet, self.DesignateName )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
--MarkingCount = MarkingCount + 1
|
--MarkingCount = MarkingCount + 1
|
||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
ReportTypes:Add(TargetUnitType)
|
--ReportTypes:Add(TargetUnitType)
|
||||||
end
|
end
|
||||||
ReportLaserCodes:Add(RecceUnit.LaserCode)
|
--ReportLaserCodes:Add(RecceUnit.LaserCode)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1322,19 +1323,19 @@ do -- DESIGNATE
|
|||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
ReportTypes:Add(TargetUnitType)
|
--ReportTypes:Add(TargetUnitType)
|
||||||
end
|
end
|
||||||
ReportLaserCodes:Add(Recce.LaserCode)
|
--ReportLaserCodes:Add(Recce.LaserCode)
|
||||||
--Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 5, self.AttackSet )
|
Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 10, self.AttackSet )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
local MarkedTypesText = ReportTypes:Text(', ')
|
--local MarkedTypesText = ReportTypes:Text(', ')
|
||||||
local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
--local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
||||||
self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. ", code " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
--self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. ", code " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
||||||
|
|
||||||
self:__Lasing( -self.LaseDuration, Index, Duration, LaserCodeRequested )
|
self:__Lasing( -self.LaseDuration, Index, Duration, LaserCodeRequested )
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Models the detection of enemy units by FACs or RECCEs and group them according various methods.
|
--- **Functional** - Models the detection of enemy units by FACs or RECCEs and group them according various methods.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
do -- DETECTION_BASE
|
do -- DETECTION_BASE
|
||||||
|
|
||||||
--- @type DETECTION_BASE
|
--- @type DETECTION_BASE
|
||||||
-- @field Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
-- @field Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
||||||
-- @field DCS#Distance DetectionRange The range till which targets are accepted to be detected.
|
-- @field DCS#Distance DetectionRange The range till which targets are accepted to be detected.
|
||||||
-- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects.
|
-- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects.
|
||||||
-- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified.
|
-- @field #table DetectedObjectsIdentified Map of the DetectedObjects identified.
|
||||||
@@ -318,7 +318,7 @@ do -- DETECTION_BASE
|
|||||||
|
|
||||||
--- DETECTION constructor.
|
--- DETECTION constructor.
|
||||||
-- @param #DETECTION_BASE self
|
-- @param #DETECTION_BASE self
|
||||||
-- @param Core.Set#SET_GROUP DetectionSet The @{Set} of @{Group}s that is used to detect the units.
|
-- @param Core.Set#SET_GROUP DetectionSet The @{Core.Set} of @{Wrapper.Group}s that is used to detect the units.
|
||||||
-- @return #DETECTION_BASE self
|
-- @return #DETECTION_BASE self
|
||||||
function DETECTION_BASE:New( DetectionSet )
|
function DETECTION_BASE:New( DetectionSet )
|
||||||
|
|
||||||
@@ -591,7 +591,7 @@ do -- DETECTION_BASE
|
|||||||
-- @param #string From The From State string.
|
-- @param #string From The From State string.
|
||||||
-- @param #string Event The Event string.
|
-- @param #string Event The Event string.
|
||||||
-- @param #string To The To State string.
|
-- @param #string To The To State string.
|
||||||
-- @param Wrapper.Group#GROUP DetectionGroup The Group detecting.
|
-- @param Wrapper.Group#GROUP Detection The Group detecting.
|
||||||
-- @param #number DetectionTimeStamp Time stamp of detection event.
|
-- @param #number DetectionTimeStamp Time stamp of detection event.
|
||||||
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
|
function DETECTION_BASE:onafterDetection( From, Event, To, Detection, DetectionTimeStamp )
|
||||||
|
|
||||||
@@ -653,131 +653,132 @@ do -- DETECTION_BASE
|
|||||||
-- self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } )
|
-- self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } )
|
||||||
|
|
||||||
-- Only process if the target is visible. Detection also returns invisible units.
|
-- Only process if the target is visible. Detection also returns invisible units.
|
||||||
-- if Detection.visible == true then
|
--if Detection.visible == true then
|
||||||
|
|
||||||
local DetectionAccepted = true
|
local DetectionAccepted = true
|
||||||
|
|
||||||
local DetectedObjectName = DetectedObject:getName()
|
local DetectedObjectName = DetectedObject:getName()
|
||||||
local DetectedObjectType = DetectedObject:getTypeName()
|
local DetectedObjectType = DetectedObject:getTypeName()
|
||||||
|
|
||||||
local DetectedObjectVec3 = DetectedObject:getPoint()
|
local DetectedObjectVec3 = DetectedObject:getPoint()
|
||||||
local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z }
|
local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z }
|
||||||
local DetectionGroupVec3 = Detection:GetVec3()
|
local DetectionGroupVec3 = Detection:GetVec3() or {x=0,y=0,z=0}
|
||||||
local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z }
|
local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z }
|
||||||
|
|
||||||
local Distance = ((DetectedObjectVec3.x - DetectionGroupVec3.x) ^ 2 +
|
local Distance = ( ( DetectedObjectVec3.x - DetectionGroupVec3.x )^2 +
|
||||||
(DetectedObjectVec3.y - DetectionGroupVec3.y) ^ 2 +
|
( DetectedObjectVec3.y - DetectionGroupVec3.y )^2 +
|
||||||
(DetectedObjectVec3.z - DetectionGroupVec3.z) ^ 2) ^ 0.5 / 1000
|
( DetectedObjectVec3.z - DetectionGroupVec3.z )^2
|
||||||
|
) ^ 0.5 / 1000
|
||||||
local DetectedUnitCategory = DetectedObject:getDesc().category
|
|
||||||
|
local DetectedUnitCategory = DetectedObject:getDesc().category
|
||||||
-- self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } )
|
|
||||||
|
--self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } )
|
||||||
-- Calculate Acceptance
|
|
||||||
|
-- Calculate Acceptance
|
||||||
DetectionAccepted = self._.FilterCategories[DetectedUnitCategory] ~= nil and DetectionAccepted or false
|
|
||||||
|
DetectionAccepted = self._.FilterCategories[DetectedUnitCategory] ~= nil and DetectionAccepted or false
|
||||||
-- if Distance > 15000 then
|
|
||||||
-- if DetectedUnitCategory == Unit.Category.GROUND_UNIT or DetectedUnitCategory == Unit.Category.SHIP then
|
-- if Distance > 15000 then
|
||||||
-- if DetectedObject:hasSensors( Unit.SensorType.RADAR, Unit.RadarType.AS ) == false then
|
-- if DetectedUnitCategory == Unit.Category.GROUND_UNIT or DetectedUnitCategory == Unit.Category.SHIP then
|
||||||
-- DetectionAccepted = false
|
-- if DetectedObject:hasSensors( Unit.SensorType.RADAR, Unit.RadarType.AS ) == false then
|
||||||
-- end
|
-- DetectionAccepted = false
|
||||||
-- end
|
-- end
|
||||||
-- end
|
-- end
|
||||||
|
-- end
|
||||||
if self.AcceptRange and Distance * 1000 > self.AcceptRange then
|
|
||||||
DetectionAccepted = false
|
if self.AcceptRange and Distance * 1000 > self.AcceptRange then
|
||||||
end
|
DetectionAccepted = false
|
||||||
|
end
|
||||||
if self.AcceptZones then
|
|
||||||
local AnyZoneDetection = false
|
if self.AcceptZones then
|
||||||
for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do
|
local AnyZoneDetection = false
|
||||||
local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE
|
for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do
|
||||||
if AcceptZone:IsVec2InZone( DetectedObjectVec2 ) then
|
local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE
|
||||||
AnyZoneDetection = true
|
if AcceptZone:IsVec2InZone( DetectedObjectVec2 ) then
|
||||||
|
AnyZoneDetection = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not AnyZoneDetection then
|
||||||
|
DetectionAccepted = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not AnyZoneDetection then
|
|
||||||
DetectionAccepted = false
|
if self.RejectZones then
|
||||||
end
|
for RejectZoneID, RejectZone in pairs( self.RejectZones ) do
|
||||||
end
|
local RejectZone = RejectZone -- Core.Zone#ZONE_BASE
|
||||||
|
if RejectZone:IsVec2InZone( DetectedObjectVec2 ) == true then
|
||||||
if self.RejectZones then
|
|
||||||
for RejectZoneID, RejectZone in pairs( self.RejectZones ) do
|
|
||||||
local RejectZone = RejectZone -- Core.Zone#ZONE_BASE
|
|
||||||
if RejectZone:IsVec2InZone( DetectedObjectVec2 ) == true then
|
|
||||||
DetectionAccepted = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Calculate additional probabilities
|
|
||||||
|
|
||||||
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then
|
|
||||||
local DistanceFactor = Distance / 4
|
|
||||||
local DistanceProbabilityReversed = (1 - self.DistanceProbability) * DistanceFactor
|
|
||||||
local DistanceProbability = 1 - DistanceProbabilityReversed
|
|
||||||
DistanceProbability = DistanceProbability * 30 / 300
|
|
||||||
local Probability = math.random() -- Selects a number between 0 and 1
|
|
||||||
-- self:T( { Probability, DistanceProbability } )
|
|
||||||
if Probability > DistanceProbability then
|
|
||||||
DetectionAccepted = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.AlphaAngleProbability then
|
|
||||||
local NormalVec2 = { x = DetectedObjectVec2.x - DetectionGroupVec2.x, y = DetectedObjectVec2.y - DetectionGroupVec2.y }
|
|
||||||
local AlphaAngle = math.atan2( NormalVec2.y, NormalVec2.x )
|
|
||||||
local Sinus = math.sin( AlphaAngle )
|
|
||||||
local AlphaAngleProbabilityReversed = (1 - self.AlphaAngleProbability) * (1 - Sinus)
|
|
||||||
local AlphaAngleProbability = 1 - AlphaAngleProbabilityReversed
|
|
||||||
|
|
||||||
AlphaAngleProbability = AlphaAngleProbability * 30 / 300
|
|
||||||
|
|
||||||
local Probability = math.random() -- Selects a number between 0 and 1
|
|
||||||
-- self:T( { Probability, AlphaAngleProbability } )
|
|
||||||
if Probability > AlphaAngleProbability then
|
|
||||||
DetectionAccepted = false
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.ZoneProbability then
|
|
||||||
|
|
||||||
for ZoneDataID, ZoneData in pairs( self.ZoneProbability ) do
|
|
||||||
self:F( { ZoneData } )
|
|
||||||
local ZoneObject = ZoneData[1] -- Core.Zone#ZONE_BASE
|
|
||||||
local ZoneProbability = ZoneData[2] -- #number
|
|
||||||
ZoneProbability = ZoneProbability * 30 / 300
|
|
||||||
|
|
||||||
if ZoneObject:IsVec2InZone( DetectedObjectVec2 ) == true then
|
|
||||||
local Probability = math.random() -- Selects a number between 0 and 1
|
|
||||||
-- self:T( { Probability, ZoneProbability } )
|
|
||||||
if Probability > ZoneProbability then
|
|
||||||
DetectionAccepted = false
|
DetectionAccepted = false
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
-- Calculate additional probabilities
|
||||||
if DetectionAccepted then
|
|
||||||
|
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then
|
||||||
HasDetectedObjects = true
|
local DistanceFactor = Distance / 4
|
||||||
|
local DistanceProbabilityReversed = ( 1 - self.DistanceProbability ) * DistanceFactor
|
||||||
self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {}
|
local DistanceProbability = 1 - DistanceProbabilityReversed
|
||||||
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
|
DistanceProbability = DistanceProbability * 30 / 300
|
||||||
|
local Probability = math.random() -- Selects a number between 0 and 1
|
||||||
if TargetIsDetected and TargetIsDetected == true then
|
--self:T( { Probability, DistanceProbability } )
|
||||||
self.DetectedObjects[DetectedObjectName].IsDetected = TargetIsDetected
|
if Probability > DistanceProbability then
|
||||||
|
DetectionAccepted = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if TargetIsDetected and TargetIsVisible and TargetIsVisible == true then
|
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.AlphaAngleProbability then
|
||||||
self.DetectedObjects[DetectedObjectName].IsVisible = TargetIsDetected and TargetIsVisible
|
local NormalVec2 = { x = DetectedObjectVec2.x - DetectionGroupVec2.x, y = DetectedObjectVec2.y - DetectionGroupVec2.y }
|
||||||
|
local AlphaAngle = math.atan2( NormalVec2.y, NormalVec2.x )
|
||||||
|
local Sinus = math.sin( AlphaAngle )
|
||||||
|
local AlphaAngleProbabilityReversed = ( 1 - self.AlphaAngleProbability ) * ( 1 - Sinus )
|
||||||
|
local AlphaAngleProbability = 1 - AlphaAngleProbabilityReversed
|
||||||
|
|
||||||
|
AlphaAngleProbability = AlphaAngleProbability * 30 / 300
|
||||||
|
|
||||||
|
local Probability = math.random() -- Selects a number between 0 and 1
|
||||||
|
--self:T( { Probability, AlphaAngleProbability } )
|
||||||
|
if Probability > AlphaAngleProbability then
|
||||||
|
DetectionAccepted = false
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if TargetIsDetected and not self.DetectedObjects[DetectedObjectName].KnowType then
|
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.ZoneProbability then
|
||||||
self.DetectedObjects[DetectedObjectName].KnowType = TargetIsDetected and TargetKnowType
|
|
||||||
|
for ZoneDataID, ZoneData in pairs( self.ZoneProbability ) do
|
||||||
|
self:F({ZoneData})
|
||||||
|
local ZoneObject = ZoneData[1] -- Core.Zone#ZONE_BASE
|
||||||
|
local ZoneProbability = ZoneData[2] -- #number
|
||||||
|
ZoneProbability = ZoneProbability * 30 / 300
|
||||||
|
|
||||||
|
if ZoneObject:IsVec2InZone( DetectedObjectVec2 ) == true then
|
||||||
|
local Probability = math.random() -- Selects a number between 0 and 1
|
||||||
|
--self:T( { Probability, ZoneProbability } )
|
||||||
|
if Probability > ZoneProbability then
|
||||||
|
DetectionAccepted = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if DetectionAccepted then
|
||||||
|
|
||||||
|
HasDetectedObjects = true
|
||||||
|
|
||||||
|
self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {}
|
||||||
|
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
|
||||||
|
|
||||||
|
if TargetIsDetected and TargetIsDetected == true then
|
||||||
|
self.DetectedObjects[DetectedObjectName].IsDetected = TargetIsDetected
|
||||||
|
end
|
||||||
|
|
||||||
|
if TargetIsDetected and TargetIsVisible and TargetIsVisible == true then
|
||||||
|
self.DetectedObjects[DetectedObjectName].IsVisible = TargetIsDetected and TargetIsVisible
|
||||||
|
end
|
||||||
|
|
||||||
|
if TargetIsDetected and not self.DetectedObjects[DetectedObjectName].KnowType then
|
||||||
|
self.DetectedObjects[DetectedObjectName].KnowType = TargetIsDetected and TargetKnowType
|
||||||
end
|
end
|
||||||
self.DetectedObjects[DetectedObjectName].KnowDistance = TargetKnowDistance -- Detection.distance -- TargetKnowDistance
|
self.DetectedObjects[DetectedObjectName].KnowDistance = TargetKnowDistance -- Detection.distance -- TargetKnowDistance
|
||||||
self.DetectedObjects[DetectedObjectName].LastTime = (TargetIsDetected and TargetIsVisible == false) and TargetLastTime
|
self.DetectedObjects[DetectedObjectName].LastTime = (TargetIsDetected and TargetIsVisible == false) and TargetLastTime
|
||||||
@@ -1981,7 +1982,7 @@ do -- DETECTION_UNITS
|
|||||||
|
|
||||||
--- Will detect units within the battle zone.
|
--- Will detect units within the battle zone.
|
||||||
--
|
--
|
||||||
-- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference.
|
-- It will build a DetectedItems list filled with DetectedItems. Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{Wrapper.Unit#UNIT} object reference.
|
||||||
-- Beware that when the amount of units detected is large, the DetectedItems list will be large also.
|
-- Beware that when the amount of units detected is large, the DetectedItems list will be large also.
|
||||||
--
|
--
|
||||||
-- @field #DETECTION_UNITS
|
-- @field #DETECTION_UNITS
|
||||||
@@ -1992,7 +1993,7 @@ do -- DETECTION_UNITS
|
|||||||
|
|
||||||
--- DETECTION_UNITS constructor.
|
--- DETECTION_UNITS constructor.
|
||||||
-- @param Functional.Detection#DETECTION_UNITS self
|
-- @param Functional.Detection#DETECTION_UNITS self
|
||||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
||||||
-- @return Functional.Detection#DETECTION_UNITS self
|
-- @return Functional.Detection#DETECTION_UNITS self
|
||||||
function DETECTION_UNITS:New( DetectionSetGroup )
|
function DETECTION_UNITS:New( DetectionSetGroup )
|
||||||
|
|
||||||
@@ -2151,8 +2152,9 @@ do -- DETECTION_UNITS
|
|||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
||||||
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
||||||
-- @param Core.Settings#SETTINGS Settings Message formatting settings to use.
|
-- @param Core.Settings#SETTINGS Settings Message formatting settings to use.
|
||||||
|
-- @param #boolean ForceA2GCoordinate Set creation of A2G coordinate
|
||||||
-- @return Core.Report#REPORT The report of the detection items.
|
-- @return Core.Report#REPORT The report of the detection items.
|
||||||
function DETECTION_UNITS:DetectedItemReportSummary( DetectedItem, AttackGroup, Settings )
|
function DETECTION_UNITS:DetectedItemReportSummary( DetectedItem, AttackGroup, Settings, ForceA2GCoordinate )
|
||||||
self:F( { DetectedItem = DetectedItem } )
|
self:F( { DetectedItem = DetectedItem } )
|
||||||
|
|
||||||
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
|
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
|
||||||
@@ -2187,7 +2189,11 @@ do -- DETECTION_UNITS
|
|||||||
-- TODO: solve Index reference
|
-- TODO: solve Index reference
|
||||||
local DetectedItemCoordinate = self:GetDetectedItemCoordinate( DetectedItem )
|
local DetectedItemCoordinate = self:GetDetectedItemCoordinate( DetectedItem )
|
||||||
local DetectedItemCoordText = DetectedItemCoordinate:ToString( AttackGroup, Settings )
|
local DetectedItemCoordText = DetectedItemCoordinate:ToString( AttackGroup, Settings )
|
||||||
|
|
||||||
|
if ForceA2GCoordinate then
|
||||||
|
DetectedItemCoordText = DetectedItemCoordinate:ToStringA2G(AttackGroup,Settings)
|
||||||
|
end
|
||||||
|
|
||||||
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
|
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
|
||||||
|
|
||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
@@ -2231,7 +2237,7 @@ do -- DETECTION_TYPES
|
|||||||
|
|
||||||
--- Will detect units within the battle zone.
|
--- Will detect units within the battle zone.
|
||||||
-- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected.
|
-- It will build a DetectedItems[] list filled with DetectedItems, grouped by the type of units detected.
|
||||||
-- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{UNIT} object reference.
|
-- Each DetectedItem will contain a field Set, which contains a @{Core.Set#SET_UNIT} containing ONE @{Wrapper.Unit#UNIT} object reference.
|
||||||
-- Beware that when the amount of different types detected is large, the DetectedItems[] list will be large also.
|
-- Beware that when the amount of different types detected is large, the DetectedItems[] list will be large also.
|
||||||
--
|
--
|
||||||
-- @field #DETECTION_TYPES
|
-- @field #DETECTION_TYPES
|
||||||
@@ -2242,7 +2248,7 @@ do -- DETECTION_TYPES
|
|||||||
|
|
||||||
--- DETECTION_TYPES constructor.
|
--- DETECTION_TYPES constructor.
|
||||||
-- @param Functional.Detection#DETECTION_TYPES self
|
-- @param Functional.Detection#DETECTION_TYPES self
|
||||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Recce role.
|
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Recce role.
|
||||||
-- @return Functional.Detection#DETECTION_TYPES self
|
-- @return Functional.Detection#DETECTION_TYPES self
|
||||||
function DETECTION_TYPES:New( DetectionSetGroup )
|
function DETECTION_TYPES:New( DetectionSetGroup )
|
||||||
|
|
||||||
@@ -2430,7 +2436,7 @@ do -- DETECTION_AREAS
|
|||||||
|
|
||||||
--- @type DETECTION_AREAS
|
--- @type DETECTION_AREAS
|
||||||
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||||
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||||
-- @extends Functional.Detection#DETECTION_BASE
|
-- @extends Functional.Detection#DETECTION_BASE
|
||||||
|
|
||||||
--- Detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s),
|
--- Detect units within the battle zone for a list of @{Wrapper.Group}s detecting targets following (a) detection method(s),
|
||||||
@@ -2439,16 +2445,16 @@ do -- DETECTION_AREAS
|
|||||||
-- A set with multiple detected zones will be created as there are groups of units detected.
|
-- A set with multiple detected zones will be created as there are groups of units detected.
|
||||||
--
|
--
|
||||||
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
|
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
|
||||||
--
|
--
|
||||||
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DETECTION_BASE} and
|
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DECTECTION_BASE} and
|
||||||
-- the methods to manage the DetectedItems[].Zone(s) are implemented in @{Functional.Detection#DETECTION_AREAS}.
|
-- the methods to manage the DetectedItems[].Zone(s) are implemented in @{Functional.Detection#DETECTION_AREAS}.
|
||||||
--
|
--
|
||||||
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
||||||
--
|
--
|
||||||
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZones}().
|
-- Retrieve the formed @{Zone@ZONE_UNIT}s as a result of the grouping the detected units within the DetectionZoneRange, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZones}().
|
||||||
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneCount}().
|
-- To understand the amount of zones created, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneCount}().
|
||||||
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneByID}() with a given index.
|
-- If you want to obtain a specific zone from the DetectedZones, use the method @{Functional.Detection#DETECTION_AREAS.GetDetectionZoneByID}() with a given index.
|
||||||
--
|
--
|
||||||
-- ## 4.4) Flare or Smoke detected units
|
-- ## 4.4) Flare or Smoke detected units
|
||||||
--
|
--
|
||||||
-- Use the methods @{Functional.Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Functional.Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place.
|
-- Use the methods @{Functional.Detection#DETECTION_AREAS.FlareDetectedUnits}() or @{Functional.Detection#DETECTION_AREAS.SmokeDetectedUnits}() to flare or smoke the detected units when a new detection has taken place.
|
||||||
@@ -2471,7 +2477,7 @@ do -- DETECTION_AREAS
|
|||||||
|
|
||||||
--- DETECTION_AREAS constructor.
|
--- DETECTION_AREAS constructor.
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Set} of GROUPs in the Forward Air Controller role.
|
-- @param Core.Set#SET_GROUP DetectionSetGroup The @{Core.Set} of GROUPs in the Forward Air Controller role.
|
||||||
-- @param DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
-- @param DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||||
-- @return #DETECTION_AREAS
|
-- @return #DETECTION_AREAS
|
||||||
function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange )
|
function DETECTION_AREAS:New( DetectionSetGroup, DetectionZoneRange )
|
||||||
@@ -2489,10 +2495,10 @@ do -- DETECTION_AREAS
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Retrieve set of detected zones.
|
--- Retrieve set of detected zones.
|
||||||
-- @param #DETECTION_AREAS self
|
-- @param #DETECTION_AREAS self
|
||||||
-- @return Core.Set#SET_ZONE The @{Set} of ZONE_UNIT objects detected.
|
-- @return Core.Set#SET_ZONE The @{Core.Set} of ZONE_UNIT objects detected.
|
||||||
function DETECTION_AREAS:GetDetectionZones()
|
function DETECTION_AREAS:GetDetectionZones()
|
||||||
local zoneset = SET_ZONE:New()
|
local zoneset = SET_ZONE:New()
|
||||||
for _ID,_Item in pairs (self.DetectedItems) do
|
for _ID,_Item in pairs (self.DetectedItems) do
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
--- **Functional** - Captures the class DETECTION_ZONES.
|
||||||
|
-- @module Functional.DetectionZones
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
do -- DETECTION_ZONES
|
do -- DETECTION_ZONES
|
||||||
|
|
||||||
--- @type DETECTION_ZONES
|
--- @type DETECTION_ZONES
|
||||||
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
-- @field DCS#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
|
||||||
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
-- @field #DETECTION_BASE.DetectedItems DetectedItems A list of areas containing the set of @{Wrapper.Unit}s, @{Core.Zone}s, the center @{Wrapper.Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
|
||||||
-- @extends Functional.Detection#DETECTION_BASE
|
-- @extends Functional.Detection#DETECTION_BASE
|
||||||
|
|
||||||
--- (old, to be revised ) Detect units within the battle zone for a list of @{Core.Zone}s detecting targets following (a) detection method(s),
|
--- (old, to be revised ) Detect units within the battle zone for a list of @{Core.Zone}s detecting targets following (a) detection method(s),
|
||||||
@@ -40,27 +44,27 @@ do -- DETECTION_ZONES
|
|||||||
ClassName = "DETECTION_ZONES",
|
ClassName = "DETECTION_ZONES",
|
||||||
DetectionZoneRange = nil,
|
DetectionZoneRange = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--- DETECTION_ZONES constructor.
|
--- DETECTION_ZONES constructor.
|
||||||
-- @param #DETECTION_ZONES self
|
-- @param #DETECTION_ZONES self
|
||||||
-- @param Core.Set#SET_ZONE DetectionSetZone The @{Set} of ZONE_RADIUS.
|
-- @param Core.Set#SET_ZONE DetectionSetZone The @{Core.Set} of ZONE_RADIUS.
|
||||||
-- @param DCS#Coalition.side DetectionCoalition The coalition of the detection.
|
-- @param DCS#Coalition.side DetectionCoalition The coalition of the detection.
|
||||||
-- @return #DETECTION_ZONES
|
-- @return #DETECTION_ZONES
|
||||||
function DETECTION_ZONES:New( DetectionSetZone, DetectionCoalition )
|
function DETECTION_ZONES:New( DetectionSetZone, DetectionCoalition )
|
||||||
|
|
||||||
-- Inherits from DETECTION_BASE
|
-- Inherits from DETECTION_BASE
|
||||||
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetZone ) ) -- #DETECTION_ZONES
|
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionSetZone ) ) -- #DETECTION_ZONES
|
||||||
|
|
||||||
self.DetectionSetZone = DetectionSetZone -- Core.Set#SET_ZONE
|
self.DetectionSetZone = DetectionSetZone -- Core.Set#SET_ZONE
|
||||||
self.DetectionCoalition = DetectionCoalition
|
self.DetectionCoalition = DetectionCoalition
|
||||||
|
|
||||||
self._SmokeDetectedUnits = false
|
self._SmokeDetectedUnits = false
|
||||||
self._FlareDetectedUnits = false
|
self._FlareDetectedUnits = false
|
||||||
self._SmokeDetectedZones = false
|
self._SmokeDetectedZones = false
|
||||||
self._FlareDetectedZones = false
|
self._FlareDetectedZones = false
|
||||||
self._BoundDetectedZones = false
|
self._BoundDetectedZones = false
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Taking the lead of AI escorting your flight.
|
--- **Functional** - Taking the lead of AI escorting your flight.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** - (R2.5) - Yet Another Missile Trainer.
|
--- **Functional** - Yet Another Missile Trainer.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- Practice to evade missiles without being destroyed.
|
-- Practice to evade missiles without being destroyed.
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky**
|
||||||
-- @module Functional.FOX
|
-- @module Functional.Fox
|
||||||
-- @image Functional_FOX.png
|
-- @image Functional_FOX.png
|
||||||
|
|
||||||
--- FOX class.
|
--- FOX class.
|
||||||
@@ -492,7 +492,6 @@ end
|
|||||||
|
|
||||||
--- Disable F10 menu for all players.
|
--- Disable F10 menu for all players.
|
||||||
-- @param #FOX self
|
-- @param #FOX self
|
||||||
-- @param #boolean switch If true debug mode on. If false/nil debug mode off
|
|
||||||
-- @return #FOX self
|
-- @return #FOX self
|
||||||
function FOX:SetDisableF10Menu()
|
function FOX:SetDisableF10Menu()
|
||||||
|
|
||||||
@@ -501,6 +500,16 @@ function FOX:SetDisableF10Menu()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Enable F10 menu for all players.
|
||||||
|
-- @param #FOX self
|
||||||
|
-- @return #FOX self
|
||||||
|
function FOX:SetEnableF10Menu()
|
||||||
|
|
||||||
|
self.menudisabled=false
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set default player setting for missile destruction.
|
--- Set default player setting for missile destruction.
|
||||||
-- @param #FOX self
|
-- @param #FOX self
|
||||||
-- @param #boolean switch If true missiles are destroyed. If false/nil missiles are not destroyed.
|
-- @param #boolean switch If true missiles are destroyed. If false/nil missiles are not destroyed.
|
||||||
@@ -792,7 +801,7 @@ function FOX:onafterMissileLaunch(From, Event, To, missile)
|
|||||||
local text=string.format("Missile launch detected! Distance %.1f NM, bearing %03d°.", UTILS.MetersToNM(distance), bearing)
|
local text=string.format("Missile launch detected! Distance %.1f NM, bearing %03d°.", UTILS.MetersToNM(distance), bearing)
|
||||||
|
|
||||||
-- Say notching headings.
|
-- Say notching headings.
|
||||||
BASE:ScheduleOnce(5, FOX._SayNotchingHeadings, self, player, missile.weapon)
|
self:ScheduleOnce(5, FOX._SayNotchingHeadings, self, player, missile.weapon)
|
||||||
|
|
||||||
--TODO: ALERT or INFO depending on whether this is a direct target.
|
--TODO: ALERT or INFO depending on whether this is a direct target.
|
||||||
--TODO: lauchalertall option.
|
--TODO: lauchalertall option.
|
||||||
@@ -1114,6 +1123,13 @@ end
|
|||||||
-- Event Functions
|
-- Event Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- FOX event handler for event birth.
|
||||||
|
-- @param #FOX self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function FOX:OnEventPlayerEnterAircraft(EventData)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- FOX event handler for event birth.
|
--- FOX event handler for event birth.
|
||||||
-- @param #FOX self
|
-- @param #FOX self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
@@ -1155,7 +1171,7 @@ function FOX:OnEventBirth(EventData)
|
|||||||
|
|
||||||
-- Add F10 radio menu for player.
|
-- Add F10 radio menu for player.
|
||||||
if not self.menudisabled then
|
if not self.menudisabled then
|
||||||
SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
|
self:ScheduleOnce(0.1, self._AddF10Commands, self, _unitName)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Player data.
|
-- Player data.
|
||||||
@@ -1422,10 +1438,10 @@ function FOX:_AddF10Commands(_unitName)
|
|||||||
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName))
|
self:E(self.lid..string.format("ERROR: Could not find group or group ID in AddF10Menu() function. Unit name: %s.", _unitName or "unknown"))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self:E(self.lid..string.format("ERROR: Player unit does not exist in AddF10Menu() function. Unit name: %s.", _unitName))
|
self:E(self.lid..string.format("ERROR: Player unit does not exist in AddF10Menu() function. Unit name: %s.", _unitName or "unknown"))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,41 +1,41 @@
|
|||||||
--- **Functional** -- Train missile defence and deflection.
|
--- **Functional** - Train missile defence and deflection.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes.
|
-- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes.
|
||||||
-- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range °
|
-- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range
|
||||||
-- * Provide alerts when a missile would have killed your aircraft.
|
-- * Provide alerts when a missile would have killed your aircraft.
|
||||||
-- * Provide alerts when the missile self destructs.
|
-- * Provide alerts when the missile self destructs.
|
||||||
-- * Enable / Disable and Configure the Missile Trainer using the various menu options.
|
-- * Enable / Disable and Configure the Missile Trainer using the various menu options.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Missions:
|
-- ## Missions:
|
||||||
--
|
--
|
||||||
-- [MIT - Missile Trainer](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/MIT%20-%20Missile%20Trainer)
|
-- [MIT - Missile Trainer](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/MIT%20-%20Missile%20Trainer)
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- Uses the MOOSE messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft,
|
-- Uses the MOOSE messaging system to be alerted of any missiles fired, and when a missile would hit your aircraft,
|
||||||
-- the class will destroy the missile within a certain range, to avoid damage to your aircraft.
|
-- the class will destroy the missile within a certain range, to avoid damage to your aircraft.
|
||||||
--
|
--
|
||||||
-- When running a mission where the missile trainer is used, the following radio menu structure ( 'Radio Menu' -> 'Other (F10)' -> 'MissileTrainer' ) options are available for the players:
|
-- When running a mission where the missile trainer is used, the following radio menu structure ( 'Radio Menu' -> 'Other (F10)' -> 'MissileTrainer' ) options are available for the players:
|
||||||
--
|
--
|
||||||
-- * **Messages**: Menu to configure all messages.
|
-- * **Messages**: Menu to configure all messages.
|
||||||
-- * **Messages On**: Show all messages.
|
-- * **Messages On**: Show all messages.
|
||||||
-- * **Messages Off**: Disable all messages.
|
-- * **Messages Off**: Disable all messages.
|
||||||
-- * **Tracking**: Menu to configure missile tracking messages.
|
-- * **Tracking**: Menu to configure missile tracking messages.
|
||||||
-- * **To All**: Shows missile tracking messages to all players.
|
-- * **To All**: Shows missile tracking messages to all players.
|
||||||
-- * **To Target**: Shows missile tracking messages only to the player where the missile is targetted at.
|
-- * **To Target**: Shows missile tracking messages only to the player where the missile is targeted at.
|
||||||
-- * **Tracking On**: Show missile tracking messages.
|
-- * **Tracking On**: Show missile tracking messages.
|
||||||
-- * **Tracking Off**: Disable missile tracking messages.
|
-- * **Tracking Off**: Disable missile tracking messages.
|
||||||
-- * **Frequency Increase**: Increases the missile tracking message frequency with one second.
|
-- * **Frequency Increase**: Increases the missile tracking message frequency with one second.
|
||||||
-- * **Frequency Decrease**: Decreases the missile tracking message frequency with one second.
|
-- * **Frequency Decrease**: Decreases the missile tracking message frequency with one second.
|
||||||
-- * **Alerts**: Menu to configure alert messages.
|
-- * **Alerts**: Menu to configure alert messages.
|
||||||
-- * **To All**: Shows alert messages to all players.
|
-- * **To All**: Shows alert messages to all players.
|
||||||
-- * **To Target**: Shows alert messages only to the player where the missile is (was) targetted at.
|
-- * **To Target**: Shows alert messages only to the player where the missile is (was) targeted at.
|
||||||
-- * **Hits On**: Show missile hit alert messages.
|
-- * **Hits On**: Show missile hit alert messages.
|
||||||
-- * **Hits Off**: Disable missile hit alert messages.
|
-- * **Hits Off**: Disable missile hit alert messages.
|
||||||
-- * **Launches On**: Show missile launch messages.
|
-- * **Launches On**: Show missile launch messages.
|
||||||
@@ -45,23 +45,23 @@
|
|||||||
-- * **Range Off**: Disable range information when a missile is fired to a target.
|
-- * **Range Off**: Disable range information when a missile is fired to a target.
|
||||||
-- * **Bearing On**: Shows bearing information when a missile is fired to a target.
|
-- * **Bearing On**: Shows bearing information when a missile is fired to a target.
|
||||||
-- * **Bearing Off**: Disable bearing information when a missile is fired to a target.
|
-- * **Bearing Off**: Disable bearing information when a missile is fired to a target.
|
||||||
-- * **Distance**: Menu to configure the distance when a missile needs to be destroyed when near to a player, during tracking. This will improve/influence hit calculation accuracy, but has the risk of damaging the aircraft when the missile reaches the aircraft before the distance is measured.
|
-- * **Distance**: Menu to configure the distance when a missile needs to be destroyed when near to a player, during tracking. This will improve/influence hit calculation accuracy, but has the risk of damaging the aircraft when the missile reaches the aircraft before the distance is measured.
|
||||||
-- * **50 meter**: Destroys the missile when the distance to the aircraft is below or equal to 50 meter.
|
-- * **50 meter**: Destroys the missile when the distance to the aircraft is below or equal to 50 meter.
|
||||||
-- * **100 meter**: Destroys the missile when the distance to the aircraft is below or equal to 100 meter.
|
-- * **100 meter**: Destroys the missile when the distance to the aircraft is below or equal to 100 meter.
|
||||||
-- * **150 meter**: Destroys the missile when the distance to the aircraft is below or equal to 150 meter.
|
-- * **150 meter**: Destroys the missile when the distance to the aircraft is below or equal to 150 meter.
|
||||||
-- * **200 meter**: Destroys the missile when the distance to the aircraft is below or equal to 200 meter.
|
-- * **200 meter**: Destroys the missile when the distance to the aircraft is below or equal to 200 meter.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Authors: **FlightControl**
|
-- ### Authors: **FlightControl**
|
||||||
--
|
--
|
||||||
-- ### Contributions:
|
-- ### Contributions:
|
||||||
--
|
--
|
||||||
-- * **Stuka (Danny)**: Who you can search on the Eagle Dynamics Forums. Working together with Danny has resulted in the MISSILETRAINER class.
|
-- * **Stuka (Danny)**: Who you can search on the Eagle Dynamics Forums. Working together with Danny has resulted in the MISSILETRAINER class.
|
||||||
-- Danny has shared his ideas and together we made a design.
|
-- Danny has shared his ideas and together we made a design.
|
||||||
-- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback!
|
-- Together with the **476 virtual team**, we tested the MISSILETRAINER class, and got much positive feedback!
|
||||||
-- * **132nd Squadron**: Testing and optimizing the logic.
|
-- * **132nd Squadron**: Testing and optimizing the logic.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Functional.MissileTrainer
|
-- @module Functional.MissileTrainer
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
---
|
---
|
||||||
--
|
--
|
||||||
-- # Constructor:
|
-- # Constructor:
|
||||||
--
|
--
|
||||||
-- Create a new MISSILETRAINER object with the @{#MISSILETRAINER.New} method:
|
-- Create a new MISSILETRAINER object with the @{#MISSILETRAINER.New} method:
|
||||||
--
|
--
|
||||||
-- * @{#MISSILETRAINER.New}: Creates a new MISSILETRAINER object taking the maximum distance to your aircraft to evaluate when a missile needs to be destroyed.
|
-- * @{#MISSILETRAINER.New}: Creates a new MISSILETRAINER object taking the maximum distance to your aircraft to evaluate when a missile needs to be destroyed.
|
||||||
@@ -84,11 +84,11 @@
|
|||||||
-- MISSILETRAINER will collect each unit declared in the mission with a skill level "Client" and "Player", and will monitor the missiles shot at those.
|
-- MISSILETRAINER will collect each unit declared in the mission with a skill level "Client" and "Player", and will monitor the missiles shot at those.
|
||||||
--
|
--
|
||||||
-- # Initialization:
|
-- # Initialization:
|
||||||
--
|
--
|
||||||
-- A MISSILETRAINER object will behave differently based on the usage of initialization methods:
|
-- A MISSILETRAINER object will behave differently based on the usage of initialization methods:
|
||||||
--
|
--
|
||||||
-- * @{#MISSILETRAINER.InitMessagesOnOff}: Sets by default the display of any message to be ON or OFF.
|
-- * @{#MISSILETRAINER.InitMessagesOnOff}: Sets by default the display of any message to be ON or OFF.
|
||||||
-- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targetted to you.
|
-- * @{#MISSILETRAINER.InitTrackingToAll}: Sets by default the missile tracking report for all players or only for those missiles targeted to you.
|
||||||
-- * @{#MISSILETRAINER.InitTrackingOnOff}: Sets by default the display of missile tracking report to be ON or OFF.
|
-- * @{#MISSILETRAINER.InitTrackingOnOff}: Sets by default the display of missile tracking report to be ON or OFF.
|
||||||
-- * @{#MISSILETRAINER.InitTrackingFrequency}: Increases, decreases the missile tracking message display frequency with the provided time interval in seconds.
|
-- * @{#MISSILETRAINER.InitTrackingFrequency}: Increases, decreases the missile tracking message display frequency with the provided time interval in seconds.
|
||||||
-- * @{#MISSILETRAINER.InitAlertsToAll}: Sets by default the display of alerts to be shown to all players or only to you.
|
-- * @{#MISSILETRAINER.InitAlertsToAll}: Sets by default the display of alerts to be shown to all players or only to you.
|
||||||
@@ -97,8 +97,8 @@
|
|||||||
-- * @{#MISSILETRAINER.InitRangeOnOff}: Sets by default the display of range information of missiles ON of OFF.
|
-- * @{#MISSILETRAINER.InitRangeOnOff}: Sets by default the display of range information of missiles ON of OFF.
|
||||||
-- * @{#MISSILETRAINER.InitBearingOnOff}: Sets by default the display of bearing information of missiles ON of OFF.
|
-- * @{#MISSILETRAINER.InitBearingOnOff}: Sets by default the display of bearing information of missiles ON of OFF.
|
||||||
-- * @{#MISSILETRAINER.InitMenusOnOff}: Allows to configure the options through the radio menu.
|
-- * @{#MISSILETRAINER.InitMenusOnOff}: Allows to configure the options through the radio menu.
|
||||||
--
|
--
|
||||||
-- @field #MISSILETRAINER
|
-- @field #MISSILETRAINER
|
||||||
MISSILETRAINER = {
|
MISSILETRAINER = {
|
||||||
ClassName = "MISSILETRAINER",
|
ClassName = "MISSILETRAINER",
|
||||||
TrackingMissiles = {},
|
TrackingMissiles = {},
|
||||||
@@ -167,7 +167,7 @@ end
|
|||||||
-- When a missile is fired a SCHEDULER is set off that follows the missile. When near a certain a client player, the missile will be destroyed.
|
-- When a missile is fired a SCHEDULER is set off that follows the missile. When near a certain a client player, the missile will be destroyed.
|
||||||
-- @param #MISSILETRAINER self
|
-- @param #MISSILETRAINER self
|
||||||
-- @param #number Distance The distance in meters when a tracked missile needs to be destroyed when close to a player.
|
-- @param #number Distance The distance in meters when a tracked missile needs to be destroyed when close to a player.
|
||||||
-- @param #string Briefing (Optional) Will show a text to the players when starting their mission. Can be used for briefing purposes.
|
-- @param #string Briefing (Optional) Will show a text to the players when starting their mission. Can be used for briefing purposes.
|
||||||
-- @return #MISSILETRAINER
|
-- @return #MISSILETRAINER
|
||||||
function MISSILETRAINER:New( Distance, Briefing )
|
function MISSILETRAINER:New( Distance, Briefing )
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, BASE:New() )
|
||||||
@@ -194,8 +194,8 @@ function MISSILETRAINER:New( Distance, Briefing )
|
|||||||
-- self:F( "ForEach:" .. Client.UnitName )
|
-- self:F( "ForEach:" .. Client.UnitName )
|
||||||
-- Client:Alive( self._Alive, self )
|
-- Client:Alive( self._Alive, self )
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
self.DBClients:ForEachClient(
|
self.DBClients:ForEachClient(
|
||||||
function( Client )
|
function( Client )
|
||||||
self:F( "ForEach:" .. Client.UnitName )
|
self:F( "ForEach:" .. Client.UnitName )
|
||||||
Client:Alive( self._Alive, self )
|
Client:Alive( self._Alive, self )
|
||||||
@@ -207,9 +207,9 @@ function MISSILETRAINER:New( Distance, Briefing )
|
|||||||
-- self.DB:ForEachClient(
|
-- self.DB:ForEachClient(
|
||||||
-- --- @param Wrapper.Client#CLIENT Client
|
-- --- @param Wrapper.Client#CLIENT Client
|
||||||
-- function( Client )
|
-- function( Client )
|
||||||
--
|
--
|
||||||
-- ... actions ...
|
-- ... actions ...
|
||||||
--
|
--
|
||||||
-- end
|
-- end
|
||||||
-- )
|
-- )
|
||||||
|
|
||||||
@@ -225,7 +225,7 @@ function MISSILETRAINER:New( Distance, Briefing )
|
|||||||
|
|
||||||
self.DetailsRangeOnOff = true
|
self.DetailsRangeOnOff = true
|
||||||
self.DetailsBearingOnOff = true
|
self.DetailsBearingOnOff = true
|
||||||
|
|
||||||
self.MenusOnOff = true
|
self.MenusOnOff = true
|
||||||
|
|
||||||
self.TrackingMissiles = {}
|
self.TrackingMissiles = {}
|
||||||
@@ -256,7 +256,7 @@ function MISSILETRAINER:InitMessagesOnOff( MessagesOnOff )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets by default the missile tracking report for all players or only for those missiles targetted to you.
|
--- Sets by default the missile tracking report for all players or only for those missiles targeted to you.
|
||||||
-- @param #MISSILETRAINER self
|
-- @param #MISSILETRAINER self
|
||||||
-- @param #boolean TrackingToAll true or false
|
-- @param #boolean TrackingToAll true or false
|
||||||
-- @return #MISSILETRAINER self
|
-- @return #MISSILETRAINER self
|
||||||
@@ -293,7 +293,7 @@ end
|
|||||||
--- Increases, decreases the missile tracking message display frequency with the provided time interval in seconds.
|
--- Increases, decreases the missile tracking message display frequency with the provided time interval in seconds.
|
||||||
-- The default frequency is a 3 second interval, so the Tracking Frequency parameter specifies the increase or decrease from the default 3 seconds or the last frequency update.
|
-- The default frequency is a 3 second interval, so the Tracking Frequency parameter specifies the increase or decrease from the default 3 seconds or the last frequency update.
|
||||||
-- @param #MISSILETRAINER self
|
-- @param #MISSILETRAINER self
|
||||||
-- @param #number TrackingFrequency Provide a negative or positive value in seconds to incraese or decrease the display frequency.
|
-- @param #number TrackingFrequency Provide a negative or positive value in seconds to incraese or decrease the display frequency.
|
||||||
-- @return #MISSILETRAINER self
|
-- @return #MISSILETRAINER self
|
||||||
function MISSILETRAINER:InitTrackingFrequency( TrackingFrequency )
|
function MISSILETRAINER:InitTrackingFrequency( TrackingFrequency )
|
||||||
self:F( TrackingFrequency )
|
self:F( TrackingFrequency )
|
||||||
@@ -478,30 +478,30 @@ function MISSILETRAINER:OnEventShot( EVentData )
|
|||||||
if TrainerTargetDCSUnit then
|
if TrainerTargetDCSUnit then
|
||||||
local TrainerTargetDCSUnitName = Unit.getName( TrainerTargetDCSUnit )
|
local TrainerTargetDCSUnitName = Unit.getName( TrainerTargetDCSUnit )
|
||||||
local TrainerTargetSkill = _DATABASE.Templates.Units[TrainerTargetDCSUnitName].Template.skill
|
local TrainerTargetSkill = _DATABASE.Templates.Units[TrainerTargetDCSUnitName].Template.skill
|
||||||
|
|
||||||
self:T(TrainerTargetDCSUnitName )
|
self:T(TrainerTargetDCSUnitName )
|
||||||
|
|
||||||
local Client = self.DBClients:FindClient( TrainerTargetDCSUnitName )
|
local Client = self.DBClients:FindClient( TrainerTargetDCSUnitName )
|
||||||
if Client then
|
if Client then
|
||||||
|
|
||||||
local TrainerSourceUnit = UNIT:Find( TrainerSourceDCSUnit )
|
local TrainerSourceUnit = UNIT:Find( TrainerSourceDCSUnit )
|
||||||
local TrainerTargetUnit = UNIT:Find( TrainerTargetDCSUnit )
|
local TrainerTargetUnit = UNIT:Find( TrainerTargetDCSUnit )
|
||||||
|
|
||||||
if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then
|
if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then
|
||||||
|
|
||||||
local Message = MESSAGE:New(
|
local Message = MESSAGE:New(
|
||||||
string.format( "%s launched a %s",
|
string.format( "%s launched a %s",
|
||||||
TrainerSourceUnit:GetTypeName(),
|
TrainerSourceUnit:GetTypeName(),
|
||||||
TrainerWeaponName
|
TrainerWeaponName
|
||||||
) .. self:_AddRange( Client, TrainerWeapon ) .. self:_AddBearing( Client, TrainerWeapon ), 5, "Launch Alert" )
|
) .. self:_AddRange( Client, TrainerWeapon ) .. self:_AddBearing( Client, TrainerWeapon ), 5, "Launch Alert" )
|
||||||
|
|
||||||
if self.AlertsToAll then
|
if self.AlertsToAll then
|
||||||
Message:ToAll()
|
Message:ToAll()
|
||||||
else
|
else
|
||||||
Message:ToClient( Client )
|
Message:ToClient( Client )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local ClientID = Client:GetID()
|
local ClientID = Client:GetID()
|
||||||
self:T( ClientID )
|
self:T( ClientID )
|
||||||
local MissileData = {}
|
local MissileData = {}
|
||||||
@@ -579,52 +579,52 @@ function MISSILETRAINER:_TrackMissiles()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- ALERTS PART
|
-- ALERTS PART
|
||||||
|
|
||||||
-- Loop for all Player Clients to check the alerts and deletion of missiles.
|
-- Loop for all Player Clients to check the alerts and deletion of missiles.
|
||||||
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
|
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
|
||||||
|
|
||||||
local Client = ClientData.Client
|
local Client = ClientData.Client
|
||||||
|
|
||||||
if Client and Client:IsAlive() then
|
if Client and Client:IsAlive() then
|
||||||
|
|
||||||
for MissileDataID, MissileData in pairs( ClientData.MissileData ) do
|
for MissileDataID, MissileData in pairs( ClientData.MissileData ) do
|
||||||
self:T3( MissileDataID )
|
self:T3( MissileDataID )
|
||||||
|
|
||||||
local TrainerSourceUnit = MissileData.TrainerSourceUnit
|
local TrainerSourceUnit = MissileData.TrainerSourceUnit
|
||||||
local TrainerWeapon = MissileData.TrainerWeapon
|
local TrainerWeapon = MissileData.TrainerWeapon
|
||||||
local TrainerTargetUnit = MissileData.TrainerTargetUnit
|
local TrainerTargetUnit = MissileData.TrainerTargetUnit
|
||||||
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
|
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
|
||||||
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
|
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
|
||||||
|
|
||||||
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
|
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
|
||||||
local PositionMissile = TrainerWeapon:getPosition().p
|
local PositionMissile = TrainerWeapon:getPosition().p
|
||||||
local TargetVec3 = Client:GetVec3()
|
local TargetVec3 = Client:GetVec3()
|
||||||
|
|
||||||
local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 +
|
local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 +
|
||||||
( PositionMissile.y - TargetVec3.y )^2 +
|
( PositionMissile.y - TargetVec3.y )^2 +
|
||||||
( PositionMissile.z - TargetVec3.z )^2
|
( PositionMissile.z - TargetVec3.z )^2
|
||||||
) ^ 0.5 / 1000
|
) ^ 0.5 / 1000
|
||||||
|
|
||||||
if Distance <= self.Distance then
|
if Distance <= self.Distance then
|
||||||
-- Hit alert
|
-- Hit alert
|
||||||
TrainerWeapon:destroy()
|
TrainerWeapon:destroy()
|
||||||
if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then
|
if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then
|
||||||
|
|
||||||
self:T( "killed" )
|
self:T( "killed" )
|
||||||
|
|
||||||
local Message = MESSAGE:New(
|
local Message = MESSAGE:New(
|
||||||
string.format( "%s launched by %s killed %s",
|
string.format( "%s launched by %s killed %s",
|
||||||
TrainerWeapon:getTypeName(),
|
TrainerWeapon:getTypeName(),
|
||||||
TrainerSourceUnit:GetTypeName(),
|
TrainerSourceUnit:GetTypeName(),
|
||||||
TrainerTargetUnit:GetPlayerName()
|
TrainerTargetUnit:GetPlayerName()
|
||||||
), 15, "Hit Alert" )
|
), 15, "Hit Alert" )
|
||||||
|
|
||||||
if self.AlertsToAll == true then
|
if self.AlertsToAll == true then
|
||||||
Message:ToAll()
|
Message:ToAll()
|
||||||
else
|
else
|
||||||
Message:ToClient( Client )
|
Message:ToClient( Client )
|
||||||
end
|
end
|
||||||
|
|
||||||
MissileData = nil
|
MissileData = nil
|
||||||
table.remove( ClientData.MissileData, MissileDataID )
|
table.remove( ClientData.MissileData, MissileDataID )
|
||||||
self:T(ClientData.MissileData)
|
self:T(ClientData.MissileData)
|
||||||
@@ -639,7 +639,7 @@ function MISSILETRAINER:_TrackMissiles()
|
|||||||
TrainerWeaponTypeName,
|
TrainerWeaponTypeName,
|
||||||
TrainerSourceUnit:GetTypeName()
|
TrainerSourceUnit:GetTypeName()
|
||||||
), 5, "Tracking" )
|
), 5, "Tracking" )
|
||||||
|
|
||||||
if self.AlertsToAll == true then
|
if self.AlertsToAll == true then
|
||||||
Message:ToAll()
|
Message:ToAll()
|
||||||
else
|
else
|
||||||
@@ -660,41 +660,41 @@ function MISSILETRAINER:_TrackMissiles()
|
|||||||
if ShowMessages == true and self.MessagesOnOff == true and self.TrackingOnOff == true then -- Only do this when tracking information needs to be displayed.
|
if ShowMessages == true and self.MessagesOnOff == true and self.TrackingOnOff == true then -- Only do this when tracking information needs to be displayed.
|
||||||
|
|
||||||
-- TRACKING PART
|
-- TRACKING PART
|
||||||
|
|
||||||
-- For the current client, the missile range and bearing details are displayed To the Player Client.
|
-- For the current client, the missile range and bearing details are displayed To the Player Client.
|
||||||
-- For the other clients, the missile range and bearing details are displayed To the other Player Clients.
|
-- For the other clients, the missile range and bearing details are displayed To the other Player Clients.
|
||||||
-- To achieve this, a cross loop is done for each Player Client <-> Other Player Client missile information.
|
-- To achieve this, a cross loop is done for each Player Client <-> Other Player Client missile information.
|
||||||
|
|
||||||
-- Main Player Client loop
|
-- Main Player Client loop
|
||||||
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
|
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
|
||||||
|
|
||||||
local Client = ClientData.Client
|
local Client = ClientData.Client
|
||||||
--self:T2( { Client:GetName() } )
|
--self:T2( { Client:GetName() } )
|
||||||
|
|
||||||
|
|
||||||
ClientData.MessageToClient = ""
|
ClientData.MessageToClient = ""
|
||||||
ClientData.MessageToAll = ""
|
ClientData.MessageToAll = ""
|
||||||
|
|
||||||
-- Other Players Client loop
|
-- Other Players Client loop
|
||||||
for TrackingDataID, TrackingData in pairs( self.TrackingMissiles ) do
|
for TrackingDataID, TrackingData in pairs( self.TrackingMissiles ) do
|
||||||
|
|
||||||
for MissileDataID, MissileData in pairs( TrackingData.MissileData ) do
|
for MissileDataID, MissileData in pairs( TrackingData.MissileData ) do
|
||||||
--self:T3( MissileDataID )
|
--self:T3( MissileDataID )
|
||||||
|
|
||||||
local TrainerSourceUnit = MissileData.TrainerSourceUnit
|
local TrainerSourceUnit = MissileData.TrainerSourceUnit
|
||||||
local TrainerWeapon = MissileData.TrainerWeapon
|
local TrainerWeapon = MissileData.TrainerWeapon
|
||||||
local TrainerTargetUnit = MissileData.TrainerTargetUnit
|
local TrainerTargetUnit = MissileData.TrainerTargetUnit
|
||||||
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
|
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
|
||||||
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
|
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
|
||||||
|
|
||||||
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
|
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
|
||||||
|
|
||||||
if ShowMessages == true then
|
if ShowMessages == true then
|
||||||
local TrackingTo
|
local TrackingTo
|
||||||
TrackingTo = string.format( " -> %s",
|
TrackingTo = string.format( " -> %s",
|
||||||
TrainerWeaponTypeName
|
TrainerWeaponTypeName
|
||||||
)
|
)
|
||||||
|
|
||||||
if ClientDataID == TrackingDataID then
|
if ClientDataID == TrackingDataID then
|
||||||
if ClientData.MessageToClient == "" then
|
if ClientData.MessageToClient == "" then
|
||||||
ClientData.MessageToClient = "Missiles to You:\n"
|
ClientData.MessageToClient = "Missiles to You:\n"
|
||||||
@@ -712,7 +712,7 @@ function MISSILETRAINER:_TrackMissiles()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Once the Player Client and the Other Player Client tracking messages are prepared, show them.
|
-- Once the Player Client and the Other Player Client tracking messages are prepared, show them.
|
||||||
if ClientData.MessageToClient ~= "" or ClientData.MessageToAll ~= "" then
|
if ClientData.MessageToClient ~= "" or ClientData.MessageToAll ~= "" then
|
||||||
local Message = MESSAGE:New( ClientData.MessageToClient .. ClientData.MessageToAll, 1, "Tracking" ):ToClient( Client )
|
local Message = MESSAGE:New( ClientData.MessageToClient .. ClientData.MessageToAll, 1, "Tracking" ):ToClient( Client )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Limit the movement of simulaneous moving ground vehicles.
|
--- **Functional** - Limit the movement of simulaneous moving ground vehicles.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -30,23 +30,23 @@ MOVEMENT = {
|
|||||||
function MOVEMENT:New( MovePrefixes, MoveMaximum )
|
function MOVEMENT:New( MovePrefixes, MoveMaximum )
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #MOVEMENT
|
local self = BASE:Inherit( self, BASE:New() ) -- #MOVEMENT
|
||||||
self:F( { MovePrefixes, MoveMaximum } )
|
self:F( { MovePrefixes, MoveMaximum } )
|
||||||
|
|
||||||
if type( MovePrefixes ) == 'table' then
|
if type( MovePrefixes ) == 'table' then
|
||||||
self.MovePrefixes = MovePrefixes
|
self.MovePrefixes = MovePrefixes
|
||||||
else
|
else
|
||||||
self.MovePrefixes = { MovePrefixes }
|
self.MovePrefixes = { MovePrefixes }
|
||||||
end
|
end
|
||||||
self.MoveCount = 0 -- The internal counter of the amount of Moveing the has happened since MoveStart.
|
self.MoveCount = 0 -- The internal counter of the amount of Moving the has happened since MoveStart.
|
||||||
self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move...
|
self.MoveMaximum = MoveMaximum -- Contains the Maximum amount of units that are allowed to move.
|
||||||
self.AliveUnits = 0 -- Contains the counter how many units are currently alive
|
self.AliveUnits = 0 -- Contains the counter how many units are currently alive.
|
||||||
self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not.
|
self.MoveUnits = {} -- Reflects if the Moving for this MovePrefixes is going to be scheduled or not.
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Birth )
|
self:HandleEvent( EVENTS.Birth )
|
||||||
|
|
||||||
-- self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth )
|
-- self:AddEvent( world.event.S_EVENT_BIRTH, self.OnBirth )
|
||||||
--
|
--
|
||||||
-- self:EnableEvents()
|
-- self:EnableEvents()
|
||||||
|
|
||||||
self:ScheduleStart()
|
self:ScheduleStart()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -67,7 +67,7 @@ function MOVEMENT:ScheduleStop()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Captures the birth events when new Units were spawned.
|
--- Captures the birth events when new Units were spawned.
|
||||||
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
|
-- @todo This method should become obsolete. The global _DATABASE object (an instance of @{Core.Database#DATABASE}) will handle the collection administration.
|
||||||
-- @param #MOVEMENT self
|
-- @param #MOVEMENT self
|
||||||
-- @param Core.Event#EVENTDATA self
|
-- @param Core.Event#EVENTDATA self
|
||||||
function MOVEMENT:OnEventBirth( EventData )
|
function MOVEMENT:OnEventBirth( EventData )
|
||||||
@@ -86,14 +86,14 @@ function MOVEMENT:OnEventBirth( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
EventData.IniUnit:HandleEvent( EVENTS.DEAD, self.OnDeadOrCrash )
|
EventData.IniUnit:HandleEvent( EVENTS.DEAD, self.OnDeadOrCrash )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Captures the Dead or Crash events when Units crash or are destroyed.
|
--- Captures the Dead or Crash events when Units crash or are destroyed.
|
||||||
-- @todo This method should become obsolete. The new @{DATABASE} class will handle the collection administration.
|
-- @todo This method should become obsolete. The global _DATABASE object (an instance of @{Core.Database#DATABASE}) will handle the collection administration.
|
||||||
function MOVEMENT:OnDeadOrCrash( Event )
|
function MOVEMENT:OnDeadOrCrash( Event )
|
||||||
self:F( { Event } )
|
self:F( { Event } )
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** - Rudimentary ATC.
|
--- **Functional** - Basic ATC.
|
||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
@@ -949,11 +949,14 @@ function PSEUDOATC:LocalAirports(GID, UID)
|
|||||||
for _,airbase in pairs(airports) do
|
for _,airbase in pairs(airports) do
|
||||||
|
|
||||||
local name=airbase:getName()
|
local name=airbase:getName()
|
||||||
local q=AIRBASE:FindByName(name):GetCoordinate()
|
local a=AIRBASE:FindByName(name)
|
||||||
local d=q:Get2DDistance(pos)
|
if a then
|
||||||
|
local q=a:GetCoordinate()
|
||||||
|
local d=q:Get2DDistance(pos)
|
||||||
|
|
||||||
-- Add to table.
|
-- Add to table.
|
||||||
table.insert(self.group[GID].player[UID].airports, {distance=d, name=name})
|
table.insert(self.group[GID].player[UID].airports, {distance=d, name=name})
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1041,6 +1044,3 @@ function PSEUDOATC:_myname(unitname)
|
|||||||
|
|
||||||
return string.format("%s (%s)", csign, pname)
|
return string.format("%s (%s)", csign, pname)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** - Administer the scoring of player achievements, and create a CSV file logging the scoring events for use at team or squadron websites.
|
--- **Functional** - Administer the scoring of player achievements, file and log the scoring events for use at websites.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
-- * Score the hits and destroys of units.
|
-- * Score the hits and destroys of units.
|
||||||
-- * Score the hits and destroys of statics.
|
-- * Score the hits and destroys of statics.
|
||||||
-- * Score the hits and destroys of scenery.
|
-- * Score the hits and destroys of scenery.
|
||||||
-- * Log scores into a CSV file.
|
-- * (optional) Log scores into a CSV file.
|
||||||
-- * Connect to a remote server using JSON and IP.
|
-- * Connect to a remote server using JSON and IP.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
--
|
--
|
||||||
-- 
|
-- 
|
||||||
--
|
--
|
||||||
-- Various @{Zone}s can be defined for which scores are also granted when objects in that @{Zone} are destroyed.
|
-- Various @{Core.Zone}s can be defined for which scores are also granted when objects in that @{Core.Zone} are destroyed.
|
||||||
-- This is **specifically useful** to designate **scenery targets on the map** that will generate points when destroyed.
|
-- This is **specifically useful** to designate **scenery targets on the map** that will generate points when destroyed.
|
||||||
--
|
--
|
||||||
-- With a small change in MissionScripting.lua, the scoring results can also be logged in a **CSV file**.
|
-- With a small change in MissionScripting.lua, the scoring results can also be logged in a **CSV file**.
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
--
|
--
|
||||||
-- Special targets can be set that will give extra scores to the players when these are destroyed.
|
-- Special targets can be set that will give extra scores to the players when these are destroyed.
|
||||||
-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s.
|
-- Use the methods @{#SCORING.AddUnitScore}() and @{#SCORING.RemoveUnitScore}() to specify a special additional score for a specific @{Wrapper.Unit}s.
|
||||||
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Static}s.
|
-- Use the methods @{#SCORING.AddStaticScore}() and @{#SCORING.RemoveStaticScore}() to specify a special additional score for a specific @{Wrapper.Static}s.
|
||||||
-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s.
|
-- Use the method @{#SCORING.SetGroupGroup}() to specify a special additional score for a specific @{Wrapper.Group}s.
|
||||||
--
|
--
|
||||||
-- local Scoring = SCORING:New( "Scoring File" )
|
-- local Scoring = SCORING:New( "Scoring File" )
|
||||||
@@ -131,11 +131,11 @@
|
|||||||
-- # Define destruction zones that will give extra scores:
|
-- # Define destruction zones that will give extra scores:
|
||||||
--
|
--
|
||||||
-- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points.
|
-- Define zones of destruction. Any object destroyed within the zone of the given category will give extra points.
|
||||||
-- Use the method @{#SCORING.AddZoneScore}() to add a @{Zone} for additional scoring.
|
-- Use the method @{#SCORING.AddZoneScore}() to add a @{Core.Zone} for additional scoring.
|
||||||
-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Zone} for additional scoring.
|
-- Use the method @{#SCORING.RemoveZoneScore}() to remove a @{Core.Zone} for additional scoring.
|
||||||
-- There are interesting variations that can be achieved with this functionality. For example, if the @{Zone} is a @{Core.Zone#ZONE_UNIT},
|
-- There are interesting variations that can be achieved with this functionality. For example, if the @{Core.Zone} is a @{Core.Zone#ZONE_UNIT},
|
||||||
-- then the zone is a moving zone, and anything destroyed within that @{Zone} will generate points.
|
-- then the zone is a moving zone, and anything destroyed within that @{Core.Zone} will generate points.
|
||||||
-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Zone},
|
-- The other implementation could be to designate a scenery target (a building) in the mission editor surrounded by a @{Core.Zone},
|
||||||
-- just large enough around that building.
|
-- just large enough around that building.
|
||||||
--
|
--
|
||||||
-- # Add extra Goal scores upon an event or a condition:
|
-- # Add extra Goal scores upon an event or a condition:
|
||||||
@@ -225,6 +225,7 @@ SCORING = {
|
|||||||
ClassName = "SCORING",
|
ClassName = "SCORING",
|
||||||
ClassID = 0,
|
ClassID = 0,
|
||||||
Players = {},
|
Players = {},
|
||||||
|
AutoSave = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
local _SCORINGCoalition = {
|
local _SCORINGCoalition = {
|
||||||
@@ -280,11 +281,11 @@ function SCORING:New( GameName )
|
|||||||
-- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked).
|
-- Default fratricide penalty level (maximum penalty that can be assigned to a player before he gets kicked).
|
||||||
self:SetFratricide( self.ScaleDestroyPenalty * 3 )
|
self:SetFratricide( self.ScaleDestroyPenalty * 3 )
|
||||||
self.penaltyonfratricide = true
|
self.penaltyonfratricide = true
|
||||||
|
|
||||||
-- Default penalty when a player changes coalition.
|
-- Default penalty when a player changes coalition.
|
||||||
self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty )
|
self:SetCoalitionChangePenalty( self.ScaleDestroyPenalty )
|
||||||
self.penaltyoncoalitionchange = true
|
self.penaltyoncoalitionchange = true
|
||||||
|
|
||||||
self:SetDisplayMessagePrefix()
|
self:SetDisplayMessagePrefix()
|
||||||
|
|
||||||
-- Event handlers
|
-- Event handlers
|
||||||
@@ -306,6 +307,7 @@ function SCORING:New( GameName )
|
|||||||
end )
|
end )
|
||||||
|
|
||||||
-- Create the CSV file.
|
-- Create the CSV file.
|
||||||
|
self.AutoSave = true
|
||||||
self:OpenCSV( GameName )
|
self:OpenCSV( GameName )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -373,11 +375,11 @@ function SCORING:RemoveUnitScore( ScoreUnit )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a @{Static} for additional scoring when the @{Static} is destroyed.
|
--- Add a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
|
||||||
-- Note that if there was already a @{Static} declared within the scoring with the same name,
|
-- Note that if there was already a @{Wrapper.Static} declared within the scoring with the same name,
|
||||||
-- then the old @{Static} will be replaced with the new @{Static}.
|
-- then the old @{Wrapper.Static} will be replaced with the new @{Wrapper.Static}.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given.
|
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||||
-- @param #number Score The Score value.
|
-- @param #number Score The Score value.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
function SCORING:AddStaticScore( ScoreStatic, Score )
|
function SCORING:AddStaticScore( ScoreStatic, Score )
|
||||||
@@ -389,9 +391,9 @@ function SCORING:AddStaticScore( ScoreStatic, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a @{Static} for additional scoring when the @{Static} is destroyed.
|
--- Removes a @{Wrapper.Static} for additional scoring when the @{Wrapper.Static} is destroyed.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Wrapper.Static#UNIT ScoreStatic The @{Static} for which the Score needs to be given.
|
-- @param Wrapper.Static#UNIT ScoreStatic The @{Wrapper.Static} for which the Score needs to be given.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
function SCORING:RemoveStaticScore( ScoreStatic )
|
function SCORING:RemoveStaticScore( ScoreStatic )
|
||||||
|
|
||||||
@@ -419,11 +421,11 @@ function SCORING:AddScoreGroup( ScoreGroup, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a @{Zone} to define additional scoring when any object is destroyed in that zone.
|
--- Add a @{Core.Zone} to define additional scoring when any object is destroyed in that zone.
|
||||||
-- Note that if a @{Zone} with the same name is already within the scoring added, the @{Zone} (type) and Score will be replaced!
|
-- Note that if a @{Core.Zone} with the same name is already within the scoring added, the @{Core.Zone} (type) and Score will be replaced!
|
||||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters.
|
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Core.Zone} which defines the destruction score perimeters.
|
||||||
-- Note that a zone can be a polygon or a moving zone.
|
-- Note that a zone can be a polygon or a moving zone.
|
||||||
-- @param #number Score The Score value.
|
-- @param #number Score The Score value.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
@@ -438,11 +440,11 @@ function SCORING:AddZoneScore( ScoreZone, Score )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove a @{Zone} for additional scoring.
|
--- Remove a @{Core.Zone} for additional scoring.
|
||||||
-- The scoring will search if any @{Zone} is added with the given name, and will remove that zone from the scoring.
|
-- The scoring will search if any @{Core.Zone} is added with the given name, and will remove that zone from the scoring.
|
||||||
-- This allows for a dynamic destruction zone evolution within your mission.
|
-- This allows for a dynamic destruction zone evolution within your mission.
|
||||||
-- @param #SCORING self
|
-- @param #SCORING self
|
||||||
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Zone} which defines the destruction score perimeters.
|
-- @param Core.Zone#ZONE_BASE ScoreZone The @{Core.Zone} which defines the destruction score perimeters.
|
||||||
-- Note that a zone can be a polygon or a moving zone.
|
-- Note that a zone can be a polygon or a moving zone.
|
||||||
-- @return #SCORING
|
-- @return #SCORING
|
||||||
function SCORING:RemoveZoneScore( ScoreZone )
|
function SCORING:RemoveZoneScore( ScoreZone )
|
||||||
@@ -656,11 +658,12 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition and self.penaltyoncoalitionchange then
|
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition and self.penaltyoncoalitionchange then
|
||||||
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + self.CoalitionChangePenalty or 50
|
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + self.CoalitionChangePenalty or 50
|
||||||
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
|
||||||
self.CoalitionChangePenalty .. "Penalty points added.",
|
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). ".. self.CoalitionChangePenalty .."Penalty points added.",
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information
|
||||||
:ToAll()
|
):ToAll()
|
||||||
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -1 * self.CoalitionChangePenalty, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -1*self.CoalitionChangePenalty, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
|
||||||
|
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -671,7 +674,7 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
self.Players[PlayerName].UNIT = UnitData
|
self.Players[PlayerName].UNIT = UnitData
|
||||||
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
|
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
|
||||||
self.Players[PlayerName].ThreatType = UnitThreatType
|
self.Players[PlayerName].ThreatType = UnitThreatType
|
||||||
|
|
||||||
-- TODO: make fratricide switchable
|
-- TODO: make fratricide switchable
|
||||||
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 and self.penaltyonfratricide then
|
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 and self.penaltyonfratricide then
|
||||||
if self.Players[PlayerName].PenaltyWarning < 1 then
|
if self.Players[PlayerName].PenaltyWarning < 1 then
|
||||||
@@ -1112,16 +1115,18 @@ function SCORING:_EventOnHit( Event )
|
|||||||
if InitCoalition then -- A coalition object was hit, probably a static.
|
if InitCoalition then -- A coalition object was hit, probably a static.
|
||||||
if InitCoalition == TargetCoalition then
|
if InitCoalition == TargetCoalition then
|
||||||
-- TODO: Penalty according scale
|
-- TODO: Penalty according scale
|
||||||
Player.Penalty = Player.Penalty + 10 -- * self.ScaleDestroyPenalty
|
Player.Penalty = Player.Penalty + 10 --* self.ScaleDestroyPenalty
|
||||||
PlayerHit.Penalty = PlayerHit.Penalty + 10 -- * self.ScaleDestroyPenalty
|
PlayerHit.Penalty = PlayerHit.Penalty + 10 --* self.ScaleDestroyPenalty
|
||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
MESSAGE
|
||||||
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
|
||||||
MESSAGE.Type.Update )
|
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
MESSAGE.Type.Update
|
||||||
|
)
|
||||||
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
|
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
else
|
else
|
||||||
Player.Score = Player.Score + 1
|
Player.Score = Player.Score + 1
|
||||||
@@ -1651,18 +1656,19 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
|
|||||||
|
|
||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
||||||
|
|
||||||
PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s",
|
PlayerMessage =
|
||||||
PlayerName,
|
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s",
|
||||||
PlayerScore - PlayerPenalty,
|
PlayerName,
|
||||||
PlayerScore,
|
PlayerScore - PlayerPenalty,
|
||||||
PlayerPenalty,
|
PlayerScore,
|
||||||
ReportHits,
|
PlayerPenalty,
|
||||||
ReportDestroys,
|
ReportHits,
|
||||||
ReportCoalitionChanges,
|
ReportDestroys,
|
||||||
ReportGoals,
|
ReportCoalitionChanges,
|
||||||
ReportMissions
|
ReportGoals,
|
||||||
)
|
ReportMissions
|
||||||
|
)
|
||||||
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
|
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1706,13 +1712,14 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
|
|||||||
|
|
||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
||||||
|
|
||||||
PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
PlayerMessage =
|
||||||
PlayerName,
|
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
||||||
PlayerScore - PlayerPenalty,
|
PlayerName,
|
||||||
PlayerScore,
|
PlayerScore - PlayerPenalty,
|
||||||
PlayerPenalty
|
PlayerScore,
|
||||||
)
|
PlayerPenalty
|
||||||
|
)
|
||||||
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup )
|
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1743,7 +1750,7 @@ end
|
|||||||
function SCORING:OpenCSV( ScoringCSV )
|
function SCORING:OpenCSV( ScoringCSV )
|
||||||
self:F( ScoringCSV )
|
self:F( ScoringCSV )
|
||||||
|
|
||||||
if lfs and io and os then
|
if lfs and io and os and self.AutoSave then
|
||||||
if ScoringCSV then
|
if ScoringCSV then
|
||||||
self.ScoringCSV = ScoringCSV
|
self.ScoringCSV = ScoringCSV
|
||||||
local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
|
local fdir = lfs.writedir() .. [[Logs\]] .. self.ScoringCSV .. " " .. os.date( "%Y-%m-%d %H-%M-%S" ) .. ".csv"
|
||||||
@@ -1823,7 +1830,7 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
|||||||
TargetUnitType = TargetUnitType or ""
|
TargetUnitType = TargetUnitType or ""
|
||||||
TargetUnitName = TargetUnitName or ""
|
TargetUnitName = TargetUnitName or ""
|
||||||
|
|
||||||
if lfs and io and os then
|
if lfs and io and os and self.AutoSave then
|
||||||
self.CSVFile:write(
|
self.CSVFile:write(
|
||||||
'"' .. self.GameName .. '"' .. ',' ..
|
'"' .. self.GameName .. '"' .. ',' ..
|
||||||
'"' .. self.RunTime .. '"' .. ',' ..
|
'"' .. self.RunTime .. '"' .. ',' ..
|
||||||
@@ -1847,9 +1854,20 @@ function SCORING:ScoreCSV( PlayerName, TargetPlayerName, ScoreType, ScoreTimes,
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Close CSV file
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @return #SCORING self
|
||||||
function SCORING:CloseCSV()
|
function SCORING:CloseCSV()
|
||||||
if lfs and io and os then
|
if lfs and io and os and self.AutoSave then
|
||||||
self.CSVFile:close()
|
self.CSVFile:close()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Registers a score for a player.
|
||||||
|
-- @param #SCORING self
|
||||||
|
-- @param #boolean OnOff Switch saving to CSV on = true or off = false
|
||||||
|
-- @return #SCORING self
|
||||||
|
function SCORING:SwitchAutoSave(OnOff)
|
||||||
|
self.AutoSave = OnOff
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
--- **Functional** - Make SAM sites execute evasive and defensive behaviour when being fired upon.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -79,6 +79,7 @@ SEAD = {
|
|||||||
["Kh25"] = "Kh25",
|
["Kh25"] = "Kh25",
|
||||||
["BGM_109"] = "BGM_109",
|
["BGM_109"] = "BGM_109",
|
||||||
["AGM_154"] = "AGM_154",
|
["AGM_154"] = "AGM_154",
|
||||||
|
["HY-2"] = "HY-2",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Missile enumerators - from DCS ME and Wikipedia
|
--- Missile enumerators - from DCS ME and Wikipedia
|
||||||
@@ -98,6 +99,7 @@ SEAD = {
|
|||||||
["Kh25"] = {25, 0.8},
|
["Kh25"] = {25, 0.8},
|
||||||
["BGM_109"] = {460, 0.705}, --in-game ~465kn
|
["BGM_109"] = {460, 0.705}, --in-game ~465kn
|
||||||
["AGM_154"] = {130, 0.61},
|
["AGM_154"] = {130, 0.61},
|
||||||
|
["HY-2"] = {90,1},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
--- **Functional** -- Short Range Air Defense System
|
--- **Functional** - Short Range Air Defense System.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- **SHORAD** - Short Range Air Defense System
|
-- * Short Range Air Defense System
|
||||||
-- Controls a network of short range air/missile defense groups.
|
-- * Controls a network of short range air/missile defense groups.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -18,7 +20,7 @@
|
|||||||
-- @module Functional.Shorad
|
-- @module Functional.Shorad
|
||||||
-- @image Functional.Shorad.jpg
|
-- @image Functional.Shorad.jpg
|
||||||
--
|
--
|
||||||
-- Date: July 2021
|
-- Date: Nov 2021
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **SHORAD** class, extends Core.Base#BASE
|
--- **SHORAD** class, extends Core.Base#BASE
|
||||||
@@ -41,6 +43,7 @@
|
|||||||
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green.
|
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie)
|
--- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie)
|
||||||
--
|
--
|
||||||
-- Simple Class for a more intelligent Short Range Air Defense System
|
-- Simple Class for a more intelligent Short Range Air Defense System
|
||||||
@@ -131,6 +134,7 @@ do
|
|||||||
["Kh29"] = "Kh29",
|
["Kh29"] = "Kh29",
|
||||||
["Kh31"] = "Kh31",
|
["Kh31"] = "Kh31",
|
||||||
["Kh66"] = "Kh66",
|
["Kh66"] = "Kh66",
|
||||||
|
--["BGM_109"] = "BGM_109",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Instantiates a new SHORAD object
|
--- Instantiates a new SHORAD object
|
||||||
@@ -138,13 +142,13 @@ do
|
|||||||
-- @param #string Name Name of this SHORAD
|
-- @param #string Name Name of this SHORAD
|
||||||
-- @param #string ShoradPrefix Filter for the Shorad #SET_GROUP
|
-- @param #string ShoradPrefix Filter for the Shorad #SET_GROUP
|
||||||
-- @param Core.Set#SET_GROUP Samset The #SET_GROUP of SAM sites to defend
|
-- @param Core.Set#SET_GROUP Samset The #SET_GROUP of SAM sites to defend
|
||||||
-- @param #number Radius Defense radius in meters, used to switch on groups
|
-- @param #number Radius Defense radius in meters, used to switch on SHORAD groups **within** this radius
|
||||||
-- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call
|
-- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call
|
||||||
-- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral"
|
-- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral"
|
||||||
-- @param #boolean UseEmOnOff Use Emissions On/Off rather than Alarm State Red/Green (default: use Emissions switch)
|
-- @param #boolean UseEmOnOff Use Emissions On/Off rather than Alarm State Red/Green (default: use Emissions switch)
|
||||||
-- @retunr #SHORAD self
|
-- @retunr #SHORAD self
|
||||||
function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition, UseEmOnOff)
|
function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition, UseEmOnOff)
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, FSM:New() )
|
||||||
self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
||||||
|
|
||||||
local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart()
|
local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart()
|
||||||
@@ -162,11 +166,17 @@ do
|
|||||||
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
||||||
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
||||||
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||||
self:I("*** SHORAD - Started Version 0.2.8")
|
self:I("*** SHORAD - Started Version 0.3.1")
|
||||||
-- Set the string id for output to DCS.log file.
|
-- Set the string id for output to DCS.log file.
|
||||||
self.lid=string.format("SHORAD %s | ", self.name)
|
self.lid=string.format("SHORAD %s | ", self.name)
|
||||||
self:_InitState()
|
self:_InitState()
|
||||||
self:HandleEvent(EVENTS.Shot, self.HandleEventShot)
|
self:HandleEvent(EVENTS.Shot, self.HandleEventShot)
|
||||||
|
|
||||||
|
-- Start State.
|
||||||
|
self:SetStartState("Running")
|
||||||
|
self:AddTransition("*", "WakeUpShorad", "*")
|
||||||
|
self:AddTransition("*", "CalculateHitZone", "*")
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -310,7 +320,7 @@ do
|
|||||||
local hit = false
|
local hit = false
|
||||||
if self.DefendHarms then
|
if self.DefendHarms then
|
||||||
for _,_name in pairs (SHORAD.Harms) do
|
for _,_name in pairs (SHORAD.Harms) do
|
||||||
if string.find(WeaponName,_name,1) then hit = true end
|
if string.find(WeaponName,_name,1,true) then hit = true end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return hit
|
return hit
|
||||||
@@ -326,7 +336,7 @@ do
|
|||||||
local hit = false
|
local hit = false
|
||||||
if self.DefendMavs then
|
if self.DefendMavs then
|
||||||
for _,_name in pairs (SHORAD.Mavs) do
|
for _,_name in pairs (SHORAD.Mavs) do
|
||||||
if string.find(WeaponName,_name,1) then hit = true end
|
if string.find(WeaponName,_name,1,true) then hit = true end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return hit
|
return hit
|
||||||
@@ -367,7 +377,7 @@ do
|
|||||||
local returnname = false
|
local returnname = false
|
||||||
for _,_groups in pairs (shoradset) do
|
for _,_groups in pairs (shoradset) do
|
||||||
local groupname = _groups:GetName()
|
local groupname = _groups:GetName()
|
||||||
if string.find(groupname, tgtgrp, 1) then
|
if string.find(groupname, tgtgrp, 1, true) then
|
||||||
returnname = true
|
returnname = true
|
||||||
--_groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive
|
--_groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive
|
||||||
end
|
end
|
||||||
@@ -388,7 +398,7 @@ do
|
|||||||
local returnname = false
|
local returnname = false
|
||||||
for _,_groups in pairs (shoradset) do
|
for _,_groups in pairs (shoradset) do
|
||||||
local groupname = _groups:GetName()
|
local groupname = _groups:GetName()
|
||||||
if string.find(groupname, tgtgrp, 1) then
|
if string.find(groupname, tgtgrp, 1, true) then
|
||||||
returnname = true
|
returnname = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -400,6 +410,7 @@ do
|
|||||||
-- @return #boolean Returns true for a detection, else false
|
-- @return #boolean Returns true for a detection, else false
|
||||||
function SHORAD:_ShotIsDetected()
|
function SHORAD:_ShotIsDetected()
|
||||||
self:T(self.lid .. " _ShotIsDetected")
|
self:T(self.lid .. " _ShotIsDetected")
|
||||||
|
if self.debug then return true end
|
||||||
local IsDetected = false
|
local IsDetected = false
|
||||||
local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value
|
local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value
|
||||||
local ActualDetection = math.random(1,100) -- value for this shot
|
local ActualDetection = math.random(1,100) -- value for this shot
|
||||||
@@ -423,7 +434,7 @@ do
|
|||||||
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||||
-- mymantis:AddShorad(myshorad,720)
|
-- mymantis:AddShorad(myshorad,720)
|
||||||
-- mymantis:Start()
|
-- mymantis:Start()
|
||||||
function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer, TargetCat)
|
function SHORAD:onafterWakeUpShorad(From, Event, To, TargetGroup, Radius, ActiveTimer, TargetCat)
|
||||||
self:T(self.lid .. " WakeUpShorad")
|
self:T(self.lid .. " WakeUpShorad")
|
||||||
self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
||||||
local targetcat = TargetCat or Object.Category.UNIT
|
local targetcat = TargetCat or Object.Category.UNIT
|
||||||
@@ -477,6 +488,76 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Calculate hit zone of an AGM-88
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #table SEADWeapon DCS.Weapon object
|
||||||
|
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||||
|
-- @param #number height Height when the missile was fired
|
||||||
|
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||||
|
-- @return #SHORAD self
|
||||||
|
function SHORAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup)
|
||||||
|
self:T("**** Calculating hit zone")
|
||||||
|
if SEADWeapon and SEADWeapon:isExist() then
|
||||||
|
--local pos = SEADWeapon:getPoint()
|
||||||
|
|
||||||
|
-- postion and height
|
||||||
|
local position = SEADWeapon:getPosition()
|
||||||
|
local mheight = height
|
||||||
|
-- heading
|
||||||
|
local wph = math.atan2(position.x.z, position.x.x)
|
||||||
|
if wph < 0 then
|
||||||
|
wph=wph+2*math.pi
|
||||||
|
end
|
||||||
|
wph=math.deg(wph)
|
||||||
|
|
||||||
|
-- velocity
|
||||||
|
local wpndata = SEAD.HarmData["AGM_88"]
|
||||||
|
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||||
|
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||||
|
local c2 = (mveloc^2) / 9.81
|
||||||
|
local Ropt = c2 * math.sqrt(c1+1)
|
||||||
|
if height <= 5000 then
|
||||||
|
Ropt = Ropt * 0.72
|
||||||
|
elseif height <= 7500 then
|
||||||
|
Ropt = Ropt * 0.82
|
||||||
|
elseif height <= 10000 then
|
||||||
|
Ropt = Ropt * 0.87
|
||||||
|
elseif height <= 12500 then
|
||||||
|
Ropt = Ropt * 0.98
|
||||||
|
end
|
||||||
|
|
||||||
|
-- look at a couple of zones across the trajectory
|
||||||
|
for n=1,3 do
|
||||||
|
local dist = Ropt - ((n-1)*20000)
|
||||||
|
local predpos= pos0:Translate(dist,wph)
|
||||||
|
if predpos then
|
||||||
|
|
||||||
|
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||||
|
|
||||||
|
if self.debug then
|
||||||
|
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||||
|
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local seadset = self.Groupset
|
||||||
|
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||||
|
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local _targetgroup = nil
|
||||||
|
local _targetgroupname = "none"
|
||||||
|
local _targetskill = "Random"
|
||||||
|
if tgtgrp and tgtgrp:IsAlive() then
|
||||||
|
_targetgroup = tgtgrp
|
||||||
|
_targetgroupname = tgtgrp:GetName() -- group name
|
||||||
|
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||||
|
self:T("*** Found Target = ".. _targetgroupname)
|
||||||
|
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Main function - work on the EventData
|
--- Main function - work on the EventData
|
||||||
-- @param #SHORAD self
|
-- @param #SHORAD self
|
||||||
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
||||||
@@ -504,13 +585,48 @@ do
|
|||||||
if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then
|
if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then
|
||||||
-- get target data
|
-- get target data
|
||||||
local targetdata = EventData.Weapon:getTarget() -- Identify target
|
local targetdata = EventData.Weapon:getTarget() -- Identify target
|
||||||
|
-- Is there target data?
|
||||||
|
if not targetdata or self.debug then
|
||||||
|
if string.find(ShootingWeaponName,"AGM_88",1,true) then
|
||||||
|
self:I("**** Tracking AGM-88 with no target data.")
|
||||||
|
local pos0 = EventData.IniUnit:GetCoordinate()
|
||||||
|
local fheight = EventData.IniUnit:GetHeight()
|
||||||
|
self:__CalculateHitZone(20,ShootingWeapon,pos0,fheight,EventData.IniGroup)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
local targetcat = targetdata:getCategory() -- Identify category
|
local targetcat = targetdata:getCategory() -- Identify category
|
||||||
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
||||||
|
self:T({targetdata})
|
||||||
local targetunit = nil
|
local targetunit = nil
|
||||||
if targetcat == Object.Category.UNIT then -- UNIT
|
if targetcat == Object.Category.UNIT then -- UNIT
|
||||||
targetunit = UNIT:Find(targetdata)
|
targetunit = UNIT:Find(targetdata)
|
||||||
elseif targetcat == Object.Category.STATIC then -- STATIC
|
elseif targetcat == Object.Category.STATIC then -- STATIC
|
||||||
targetunit = STATIC:Find(targetdata)
|
--self:T("Static Target Data")
|
||||||
|
--self:T({targetdata:isExist()})
|
||||||
|
--self:T({targetdata:getPoint()})
|
||||||
|
local tgtcoord = COORDINATE:NewFromVec3(targetdata:getPoint())
|
||||||
|
--tgtcoord:MarkToAll("Missile Target",true)
|
||||||
|
|
||||||
|
local tgtgrp1 = self.Samset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local tgtcoord1 = tgtgrp1:GetCoordinate()
|
||||||
|
--tgtcoord1:MarkToAll("Close target SAM",true)
|
||||||
|
|
||||||
|
local tgtgrp2 = self.Groupset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local tgtcoord2 = tgtgrp2:GetCoordinate()
|
||||||
|
--tgtcoord2:MarkToAll("Close target SHORAD",true)
|
||||||
|
|
||||||
|
local dist1 = tgtcoord:Get2DDistance(tgtcoord1)
|
||||||
|
local dist2 = tgtcoord:Get2DDistance(tgtcoord2)
|
||||||
|
|
||||||
|
if dist1 < dist2 then
|
||||||
|
targetunit = tgtgrp1
|
||||||
|
targetcat = Object.Category.UNIT
|
||||||
|
else
|
||||||
|
targetunit = tgtgrp2
|
||||||
|
targetcat = Object.Category.UNIT
|
||||||
|
end
|
||||||
end
|
end
|
||||||
--local targetunitname = Unit.getName(targetdata) -- Unit name
|
--local targetunitname = Unit.getName(targetdata) -- Unit name
|
||||||
if targetunit and targetunit:IsAlive() then
|
if targetunit and targetunit:IsAlive() then
|
||||||
@@ -519,7 +635,11 @@ do
|
|||||||
local targetgroup = nil
|
local targetgroup = nil
|
||||||
local targetgroupname = "none"
|
local targetgroupname = "none"
|
||||||
if targetcat == Object.Category.UNIT then
|
if targetcat == Object.Category.UNIT then
|
||||||
targetgroup = targetunit:GetGroup()
|
if targetunit.ClassName == "UNIT" then
|
||||||
|
targetgroup = targetunit:GetGroup()
|
||||||
|
elseif targetunit.ClassName == "GROUP" then
|
||||||
|
targetgroup = targetunit
|
||||||
|
end
|
||||||
targetgroupname = targetgroup:GetName() -- group name
|
targetgroupname = targetgroup:GetName() -- group name
|
||||||
elseif targetcat == Object.Category.STATIC then
|
elseif targetcat == Object.Category.STATIC then
|
||||||
targetgroup = targetunit
|
targetgroup = targetunit
|
||||||
@@ -540,6 +660,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
--
|
--
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional** -- Models the process to zone guarding and capturing.
|
--- **Functional** - Models the process to zone guarding and capturing.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -68,9 +68,9 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
--
|
--
|
||||||
-- In order to use ZONE_CAPTURE_COALITION, you need to:
|
-- In order to use ZONE_CAPTURE_COALITION, you need to:
|
||||||
--
|
--
|
||||||
-- * Create a @{Zone} object from one of the ZONE_ classes.
|
-- * Create a @{Core.Zone} object from one of the ZONE_ classes.
|
||||||
-- Note that ZONE_POLYGON_ classes are not yet functional.
|
-- The functional ZONE_ classses are those derived from a ZONE_RADIUS.
|
||||||
-- The only functional ZONE_ classses are those derived from a ZONE_RADIUS.
|
-- In order to use a ZONE_POLYGON, hand over the **GROUP name** of a late activated group forming a polygon with it's waypoints.
|
||||||
-- * Set the state of the zone. Most of the time, Guarded would be the initial state.
|
-- * Set the state of the zone. Most of the time, Guarded would be the initial state.
|
||||||
-- * Start the zone capturing **monitoring process**.
|
-- * Start the zone capturing **monitoring process**.
|
||||||
-- This will check the presence of friendly and/or enemy units within the zone and will transition the state of the zone when the tactical situation changed.
|
-- This will check the presence of friendly and/or enemy units within the zone and will transition the state of the zone when the tactical situation changed.
|
||||||
@@ -363,7 +363,7 @@ do -- ZONE_CAPTURE_COALITION
|
|||||||
|
|
||||||
--- ZONE_CAPTURE_COALITION Constructor.
|
--- ZONE_CAPTURE_COALITION Constructor.
|
||||||
-- @param #ZONE_CAPTURE_COALITION self
|
-- @param #ZONE_CAPTURE_COALITION self
|
||||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a @{ZONE_POLYGON} with its waypoints.
|
||||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||||
-- @param #table ObjectCategories Table of unit categories. See [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object). Default {Object.Category.UNIT, Object.Category.STATIC}, i.e. all UNITS and STATICS.
|
-- @param #table ObjectCategories Table of unit categories. See [DCS Class Object](https://wiki.hoggitworld.com/view/DCS_Class_Object). Default {Object.Category.UNIT, Object.Category.STATIC}, i.e. all UNITS and STATICS.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone.
|
--- **Functional** - Base class that models processes to achieve goals involving a Zone.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **FlightControl**
|
-- ### Author: **FlightControl**
|
||||||
-- ### Contributions: **funkyfranky**
|
-- ### Contributions: **funkyfranky**, **Applevangelist**
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -26,7 +26,6 @@ do -- Zone
|
|||||||
-- @field #boolean SmokeZone If true, smoke zone.
|
-- @field #boolean SmokeZone If true, smoke zone.
|
||||||
-- @extends Core.Zone#ZONE_RADIUS
|
-- @extends Core.Zone#ZONE_RADIUS
|
||||||
|
|
||||||
|
|
||||||
--- Models processes that have a Goal with a defined achievement involving a Zone.
|
--- Models processes that have a Goal with a defined achievement involving a Zone.
|
||||||
-- Derived classes implement the ways how the achievements can be realized.
|
-- Derived classes implement the ways how the achievements can be realized.
|
||||||
--
|
--
|
||||||
@@ -53,21 +52,26 @@ do -- Zone
|
|||||||
SmokeColor = nil,
|
SmokeColor = nil,
|
||||||
SmokeZone = nil,
|
SmokeZone = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- ZONE_GOAL Constructor.
|
--- ZONE_GOAL Constructor.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
-- @param Core.Zone#ZONE_RADIUS Zone A @{Zone} object with the goal to be achieved.
|
-- @param Core.Zone#ZONE_RADIUS Zone A @{Core.Zone} object with the goal to be achieved. Alternatively, can be handed as the name of late activated group describing a ZONE_POLYGON with its waypoints.
|
||||||
-- @return #ZONE_GOAL
|
-- @return #ZONE_GOAL
|
||||||
function ZONE_GOAL:New( Zone )
|
function ZONE_GOAL:New( Zone )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
|
|
||||||
self:F( { Zone = Zone } )
|
|
||||||
|
|
||||||
|
BASE:I({Zone=Zone})
|
||||||
|
local self = BASE:Inherit( self, BASE:New())
|
||||||
|
if type(Zone) == "string" then
|
||||||
|
self = BASE:Inherit( self, ZONE_POLYGON:NewFromGroupName(Zone) )
|
||||||
|
else
|
||||||
|
self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
|
||||||
|
self:F( { Zone = Zone } )
|
||||||
|
end
|
||||||
-- Goal object.
|
-- Goal object.
|
||||||
self.Goal = GOAL:New()
|
self.Goal = GOAL:New()
|
||||||
|
|
||||||
self.SmokeTime = nil
|
self.SmokeTime = nil
|
||||||
|
|
||||||
-- Set smoke ON.
|
-- Set smoke ON.
|
||||||
self:SetSmokeZone(true)
|
self:SetSmokeZone(true)
|
||||||
|
|
||||||
@@ -81,7 +85,7 @@ do -- Zone
|
|||||||
-- @function [parent=#ZONE_GOAL] __DestroyedUnit
|
-- @function [parent=#ZONE_GOAL] __DestroyedUnit
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
-- @param #number delay Delay in seconds.
|
-- @param #number delay Delay in seconds.
|
||||||
|
|
||||||
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
|
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
|
||||||
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
|
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
@@ -93,15 +97,15 @@ do -- Zone
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get the Zone.
|
--- Get the Zone.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
-- @return #ZONE_GOAL
|
-- @return #ZONE_GOAL
|
||||||
function ZONE_GOAL:GetZone()
|
function ZONE_GOAL:GetZone()
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the name of the Zone.
|
--- Get the name of the Zone.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
-- @return #string
|
-- @return #string
|
||||||
@@ -109,7 +113,6 @@ do -- Zone
|
|||||||
return self:GetName()
|
return self:GetName()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Activate smoking of zone with the color or the current owner.
|
--- Activate smoking of zone with the color or the current owner.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
-- @param #boolean switch If *true* or *nil* activate smoke. If *false* or *nil*, no smoke.
|
-- @param #boolean switch If *true* or *nil* activate smoke. If *false* or *nil*, no smoke.
|
||||||
@@ -131,11 +134,10 @@ do -- Zone
|
|||||||
-- @param DCS#SMOKECOLOR.Color SmokeColor
|
-- @param DCS#SMOKECOLOR.Color SmokeColor
|
||||||
function ZONE_GOAL:Smoke( SmokeColor )
|
function ZONE_GOAL:Smoke( SmokeColor )
|
||||||
self:F( { SmokeColor = SmokeColor} )
|
self:F( { SmokeColor = SmokeColor} )
|
||||||
|
|
||||||
self.SmokeColor = SmokeColor
|
self.SmokeColor = SmokeColor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Flare the zone boundary.
|
--- Flare the zone boundary.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
-- @param DCS#SMOKECOLOR.Color FlareColor
|
-- @param DCS#SMOKECOLOR.Color FlareColor
|
||||||
@@ -143,7 +145,6 @@ do -- Zone
|
|||||||
self:FlareZone( FlareColor, 30)
|
self:FlareZone( FlareColor, 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- When started, check the Smoke and the Zone status.
|
--- When started, check the Smoke and the Zone status.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
function ZONE_GOAL:onafterGuard()
|
function ZONE_GOAL:onafterGuard()
|
||||||
@@ -155,17 +156,16 @@ do -- Zone
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Check status Smoke.
|
--- Check status Smoke.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
function ZONE_GOAL:StatusSmoke()
|
function ZONE_GOAL:StatusSmoke()
|
||||||
self:F({self.SmokeTime, self.SmokeColor})
|
self:F({self.SmokeTime, self.SmokeColor})
|
||||||
|
|
||||||
if self.SmokeZone then
|
if self.SmokeZone then
|
||||||
|
|
||||||
-- Current time.
|
-- Current time.
|
||||||
local CurrentTime = timer.getTime()
|
local CurrentTime = timer.getTime()
|
||||||
|
|
||||||
-- Restart smoke every 5 min.
|
-- Restart smoke every 5 min.
|
||||||
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||||
if self.SmokeColor then
|
if self.SmokeColor then
|
||||||
@@ -173,11 +173,10 @@ do -- Zone
|
|||||||
self.SmokeTime = CurrentTime
|
self.SmokeTime = CurrentTime
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- @param #ZONE_GOAL self
|
--- @param #ZONE_GOAL self
|
||||||
-- @param Core.Event#EVENTDATA EventData Event data table.
|
-- @param Core.Event#EVENTDATA EventData Event data table.
|
||||||
@@ -185,38 +184,37 @@ do -- Zone
|
|||||||
self:F( { "EventDead", EventData } )
|
self:F( { "EventDead", EventData } )
|
||||||
|
|
||||||
self:F( { EventData.IniUnit } )
|
self:F( { EventData.IniUnit } )
|
||||||
|
|
||||||
if EventData.IniDCSUnit then
|
if EventData.IniDCSUnit then
|
||||||
|
|
||||||
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
||||||
self:F( { Vec3 = Vec3 } )
|
self:F( { Vec3 = Vec3 } )
|
||||||
|
|
||||||
if Vec3 and self:IsVec3InZone(Vec3) then
|
if Vec3 and self:IsVec3InZone(Vec3) then
|
||||||
|
|
||||||
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
|
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
|
||||||
|
|
||||||
if PlayerHits then
|
if PlayerHits then
|
||||||
|
|
||||||
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
|
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
|
||||||
self.Goal:AddPlayerContribution( PlayerName )
|
self.Goal:AddPlayerContribution( PlayerName )
|
||||||
self:DestroyedUnit( EventData.IniUnitName, PlayerName )
|
self:DestroyedUnit( EventData.IniUnitName, PlayerName )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Activate the event UnitDestroyed to be fired when a unit is destroyed in the zone.
|
--- Activate the event UnitDestroyed to be fired when a unit is destroyed in the zone.
|
||||||
-- @param #ZONE_GOAL self
|
-- @param #ZONE_GOAL self
|
||||||
function ZONE_GOAL:MonitorDestroyedUnits()
|
function ZONE_GOAL:MonitorDestroyedUnits()
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Dead, self.__Destroyed )
|
self:HandleEvent( EVENTS.Dead, self.__Destroyed )
|
||||||
self:HandleEvent( EVENTS.Crash, self.__Destroyed )
|
self:HandleEvent( EVENTS.Crash, self.__Destroyed )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone and Cargo.
|
--- **Functional** - Base class that models processes to achieve goals involving a Zone and Cargo.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -55,7 +55,7 @@ do -- ZoneGoal
|
|||||||
|
|
||||||
--- ZONE_GOAL_CARGO Constructor.
|
--- ZONE_GOAL_CARGO Constructor.
|
||||||
-- @param #ZONE_GOAL_CARGO self
|
-- @param #ZONE_GOAL_CARGO self
|
||||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved.
|
||||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||||
-- @return #ZONE_GOAL_CARGO
|
-- @return #ZONE_GOAL_CARGO
|
||||||
function ZONE_GOAL_CARGO:New( Zone, Coalition )
|
function ZONE_GOAL_CARGO:New( Zone, Coalition )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone for a Coalition.
|
--- **Functional** - Base class that models processes to achieve goals involving a Zone for a Coalition.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -53,7 +53,7 @@ do -- ZoneGoal
|
|||||||
|
|
||||||
--- ZONE_GOAL_COALITION Constructor.
|
--- ZONE_GOAL_COALITION Constructor.
|
||||||
-- @param #ZONE_GOAL_COALITION self
|
-- @param #ZONE_GOAL_COALITION self
|
||||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
-- @param Core.Zone#ZONE Zone A @{Core.Zone} object with the goal to be achieved.
|
||||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone. Default coalition.side.NEUTRAL.
|
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone. Default coalition.side.NEUTRAL.
|
||||||
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
-- @param #table UnitCategories Table of unit categories. See [DCS Class Unit](https://wiki.hoggitworld.com/view/DCS_Class_Unit). Default {Unit.Category.GROUND_UNIT}.
|
||||||
-- @return #ZONE_GOAL_COALITION
|
-- @return #ZONE_GOAL_COALITION
|
||||||
|
|||||||
@@ -22,25 +22,37 @@ _DATABASE:_RegisterAirbases()
|
|||||||
|
|
||||||
--- Check if os etc is available.
|
--- Check if os etc is available.
|
||||||
BASE:I("Checking de-sanitization of os, io and lfs:")
|
BASE:I("Checking de-sanitization of os, io and lfs:")
|
||||||
local __na=false
|
local __na = false
|
||||||
if os then
|
if os then
|
||||||
BASE:I("- os available")
|
BASE:I("- os available")
|
||||||
else
|
else
|
||||||
BASE:I("- os NOT available! Some functions may not work.")
|
BASE:I("- os NOT available! Some functions may not work.")
|
||||||
__na=true
|
__na = true
|
||||||
end
|
end
|
||||||
if io then
|
if io then
|
||||||
BASE:I("- io available")
|
BASE:I("- io available")
|
||||||
else
|
else
|
||||||
BASE:I("- io NOT available! Some functions may not work.")
|
BASE:I("- io NOT available! Some functions may not work.")
|
||||||
__na=true
|
__na = true
|
||||||
end
|
end
|
||||||
if lfs then
|
if lfs then
|
||||||
BASE:I("- lfs available")
|
BASE:I("- lfs available")
|
||||||
else
|
else
|
||||||
BASE:I("- lfs NOT available! Some functions may not work.")
|
BASE:I("- lfs NOT available! Some functions may not work.")
|
||||||
__na=true
|
__na = true
|
||||||
end
|
end
|
||||||
if __na then
|
if __na then
|
||||||
BASE:I("Check <DCS install folder>/Scripts/MissionScripting.lua and comment out the lines with sanitizeModule(''). Use at your own risk!)")
|
BASE:I("Check <DCS install folder>/Scripts/MissionScripting.lua and comment out the lines with sanitizeModule(''). Use at your own risk!)")
|
||||||
end
|
end
|
||||||
|
BASE.ServerName = "Unknown"
|
||||||
|
if lfs and loadfile then
|
||||||
|
local serverfile = lfs.writedir() .. 'Config/serverSettings.lua'
|
||||||
|
if UTILS.FileExists(serverfile) then
|
||||||
|
loadfile(serverfile)()
|
||||||
|
if cfg and cfg.name then
|
||||||
|
BASE.ServerName = cfg.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
BASE.ServerName = BASE.ServerName or "Unknown"
|
||||||
|
BASE:I("Server Name: " .. tostring(BASE.ServerName))
|
||||||
|
end
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ __Moose.Include( 'Scripts/Moose/Utilities/Utils.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Utilities/Socket.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/Astar.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/Condition.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Report.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Report.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Scheduler.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Scheduler.lua' )
|
||||||
@@ -27,6 +31,8 @@ __Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Core/Timer.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Timer.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/MarkerOps_Base.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/TextAndSound.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Object.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Object.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Identifiable.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Identifiable.lua' )
|
||||||
|
|||||||
@@ -46,13 +46,12 @@
|
|||||||
--
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky**
|
||||||
--
|
--
|
||||||
-- @module Ops.Atis
|
-- @module Ops.ATIS
|
||||||
-- @image OPS_ATIS.png
|
-- @image OPS_ATIS.png
|
||||||
|
|
||||||
--- ATIS class.
|
--- ATIS class.
|
||||||
-- @type ATIS
|
-- @type ATIS
|
||||||
-- @field #string ClassName Name of the class.
|
-- @field #string ClassName Name of the class.
|
||||||
-- @field #boolean Debug Debug mode. Messages to all about status.
|
|
||||||
-- @field #string lid Class id string for output to DCS log file.
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
-- @field #string theatre DCS map name.
|
-- @field #string theatre DCS map name.
|
||||||
-- @field #string airbasename The name of the airbase.
|
-- @field #string airbasename The name of the airbase.
|
||||||
@@ -92,6 +91,8 @@
|
|||||||
-- @field #boolean useSRS If true, use SRS for transmission.
|
-- @field #boolean useSRS If true, use SRS for transmission.
|
||||||
-- @field Sound.SRS#MSRS msrs Moose SRS object.
|
-- @field Sound.SRS#MSRS msrs Moose SRS object.
|
||||||
-- @field #number dTQueueCheck Time interval to check the radio queue. Default 5 sec or 90 sec if SRS is used.
|
-- @field #number dTQueueCheck Time interval to check the radio queue. Default 5 sec or 90 sec if SRS is used.
|
||||||
|
-- @field #boolean ReportmBar Report mBar/hpa even if not metric, i.e. for Mirage flights
|
||||||
|
-- @field #boolean TransmitOnlyWithPlayers For SRS - If true, only transmit if there are alive Players.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
||||||
@@ -121,7 +122,7 @@
|
|||||||
-- The @{#ATIS.New}(*airbasename*, *frequency*) creates a new ATIS object. The parameter *airbasename* is the name of the airbase or airport. Note that this has to be spelled exactly as in the DCS mission editor.
|
-- The @{#ATIS.New}(*airbasename*, *frequency*) creates a new ATIS object. The parameter *airbasename* is the name of the airbase or airport. Note that this has to be spelled exactly as in the DCS mission editor.
|
||||||
-- The parameter *frequency* is the frequency the ATIS broadcasts in MHz.
|
-- The parameter *frequency* is the frequency the ATIS broadcasts in MHz.
|
||||||
--
|
--
|
||||||
-- Broadcasting is started via the @{#ATIS.Start}() function. The start can be delayed by useing @{#ATIS.__Start}(*delay*), where *delay* is the delay in seconds.
|
-- Broadcasting is started via the @{#ATIS.Start}() function. The start can be delayed by using @{#ATIS.__Start}(*delay*), where *delay* is the delay in seconds.
|
||||||
--
|
--
|
||||||
-- ## Subtitles
|
-- ## Subtitles
|
||||||
--
|
--
|
||||||
@@ -309,7 +310,6 @@
|
|||||||
-- @field #ATIS
|
-- @field #ATIS
|
||||||
ATIS = {
|
ATIS = {
|
||||||
ClassName = "ATIS",
|
ClassName = "ATIS",
|
||||||
Debug = false,
|
|
||||||
lid = nil,
|
lid = nil,
|
||||||
theatre = nil,
|
theatre = nil,
|
||||||
airbasename = nil,
|
airbasename = nil,
|
||||||
@@ -346,6 +346,8 @@ ATIS = {
|
|||||||
usemarker = nil,
|
usemarker = nil,
|
||||||
markerid = nil,
|
markerid = nil,
|
||||||
relHumidity = nil,
|
relHumidity = nil,
|
||||||
|
ReportmBar = false,
|
||||||
|
TransmitOnlyWithPlayers = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- NATO alphabet.
|
--- NATO alphabet.
|
||||||
@@ -588,15 +590,18 @@ _ATIS = {}
|
|||||||
|
|
||||||
--- ATIS class version.
|
--- ATIS class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ATIS.version = "0.9.6"
|
ATIS.version = "0.9.10"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: Add new Normany airfields.
|
-- TODO: Add new Normandy airfields.
|
||||||
-- TODO: Zulu time --> Zulu in output.
|
-- TODO: Zulu time --> Zulu in output.
|
||||||
-- TODO: Correct fog for elevation.
|
-- TODO: Correct fog for elevation.
|
||||||
|
-- DONE: Use new AIRBASE system to set start/landing runway
|
||||||
|
-- DONE: SetILS doesn't work
|
||||||
|
-- DONE: Visibility reported twice over SRS
|
||||||
-- DONE: Add text report for output.
|
-- DONE: Add text report for output.
|
||||||
-- DONE: Add stop FMS functions.
|
-- DONE: Add stop FMS functions.
|
||||||
-- NOGO: Use local time. Not realisitc!
|
-- NOGO: Use local time. Not realisitc!
|
||||||
@@ -613,26 +618,26 @@ ATIS.version = "0.9.6"
|
|||||||
|
|
||||||
--- Create a new ATIS class object for a specific aircraft carrier unit.
|
--- Create a new ATIS class object for a specific aircraft carrier unit.
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @param #string airbasename Name of the airbase.
|
-- @param #string AirbaseName Name of the airbase.
|
||||||
-- @param #number frequency Radio frequency in MHz. Default 143.00 MHz.
|
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz.
|
||||||
-- @param #number modulation Radio modulation: 0=AM, 1=FM. Default 0=AM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators
|
-- @param #number Modulation Radio modulation: 0=AM, 1=FM. Default 0=AM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators.
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:New( airbasename, frequency, modulation )
|
function ATIS:New(AirbaseName, Frequency, Modulation)
|
||||||
|
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self = BASE:Inherit( self, FSM:New() ) -- #ATIS
|
local self = BASE:Inherit( self, FSM:New() ) -- #ATIS
|
||||||
|
|
||||||
self.airbasename = airbasename
|
self.airbasename=AirbaseName
|
||||||
self.airbase = AIRBASE:FindByName( airbasename )
|
self.airbase=AIRBASE:FindByName(AirbaseName)
|
||||||
|
|
||||||
if self.airbase == nil then
|
if self.airbase==nil then
|
||||||
self:E( "ERROR: Airbase %s for ATIS could not be found!", tostring( airbasename ) )
|
self:E("ERROR: Airbase %s for ATIS could not be found!", tostring(AirbaseName))
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Default freq and modulation.
|
-- Default freq and modulation.
|
||||||
self.frequency = frequency or 143.00
|
self.frequency=Frequency or 143.00
|
||||||
self.modulation = modulation or 0
|
self.modulation=Modulation or 0
|
||||||
|
|
||||||
-- Get map.
|
-- Get map.
|
||||||
self.theatre = env.mission.theatre
|
self.theatre = env.mission.theatre
|
||||||
@@ -653,6 +658,7 @@ function ATIS:New( airbasename, frequency, modulation )
|
|||||||
self:SetMapMarks( false )
|
self:SetMapMarks( false )
|
||||||
self:SetRelativeHumidity()
|
self:SetRelativeHumidity()
|
||||||
self:SetQueueUpdateTime()
|
self:SetQueueUpdateTime()
|
||||||
|
self:SetReportmBar(false)
|
||||||
|
|
||||||
-- Start State.
|
-- Start State.
|
||||||
self:SetStartState( "Stopped" )
|
self:SetStartState( "Stopped" )
|
||||||
@@ -734,14 +740,6 @@ function ATIS:New( airbasename, frequency, modulation )
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #string Text Report text.
|
-- @param #string Text Report text.
|
||||||
|
|
||||||
-- Debug trace.
|
|
||||||
if false then
|
|
||||||
self.Debug = true
|
|
||||||
BASE:TraceOnOff( true )
|
|
||||||
BASE:TraceClass( self.ClassName )
|
|
||||||
BASE:TraceLevel( 1 )
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -755,7 +753,7 @@ end
|
|||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetSoundfilesPath( path )
|
function ATIS:SetSoundfilesPath( path )
|
||||||
self.soundpath = tostring( path or "ATIS Soundfiles/" )
|
self.soundpath = tostring( path or "ATIS Soundfiles/" )
|
||||||
self:I( self.lid .. string.format( "Setting sound files path to %s", self.soundpath ) )
|
self:T( self.lid .. string.format( "Setting sound files path to %s", self.soundpath ) )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -766,7 +764,7 @@ end
|
|||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetRadioRelayUnitName( unitname )
|
function ATIS:SetRadioRelayUnitName( unitname )
|
||||||
self.relayunitname = unitname
|
self.relayunitname = unitname
|
||||||
self:I( self.lid .. string.format( "Setting radio relay unit to %s", self.relayunitname ) )
|
self:T( self.lid .. string.format( "Setting radio relay unit to %s", self.relayunitname ) )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -784,13 +782,52 @@ function ATIS:SetTowerFrequencies( freqs )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Set active runway. This can be used if the automatic runway determination via the wind direction gives incorrect results.
|
--- For SRS - Switch to only transmit if there are players on the server.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #boolean Switch If true, only send SRS if there are alive Players.
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetTransmitOnlyWithPlayers(Switch)
|
||||||
|
self.TransmitOnlyWithPlayers = Switch
|
||||||
|
if self.msrsQ then
|
||||||
|
self.msrsQ:SetTransmitOnlyWithPlayers(Switch)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set active runway for **landing** operations. This can be used if the automatic runway determination via the wind direction gives incorrect results.
|
||||||
-- For example, use this if there are two runways with the same directions.
|
-- For example, use this if there are two runways with the same directions.
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @param #string runway Active runway, *e.g.* "31L".
|
-- @param #string runway Active runway, *e.g.* "31L".
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetActiveRunway( runway )
|
function ATIS:SetActiveRunway( runway )
|
||||||
self.activerunway = tostring( runway )
|
self.activerunway = tostring( runway )
|
||||||
|
local prefer = nil
|
||||||
|
if string.find(string.lower(runway),"l") then
|
||||||
|
prefer = true
|
||||||
|
elseif string.find(string.lower(runway),"r") then
|
||||||
|
prefer = false
|
||||||
|
end
|
||||||
|
self.airbase:SetActiveRunway(runway,prefer)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the active runway for landing.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #string runway : Name of the runway, e.g. "31" or "02L" or "90R". If not given, the runway is determined from the wind direction.
|
||||||
|
-- @param #boolean preferleft : If true, perfer the left runway. If false, prefer the right runway. If nil (default), do not care about left or right.
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetActiveRunwayLanding(runway, preferleft)
|
||||||
|
self.airbase:SetActiveRunwayLanding(runway,preferleft)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the active runway for take-off.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #string runway : Name of the runway, e.g. "31" or "02L" or "90R". If not given, the runway is determined from the wind direction.
|
||||||
|
-- @param #boolean preferleft : If true, perfer the left runway. If false, prefer the right runway. If nil (default), do not care about left or right.
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetActiveRunwayTakeoff(runway,preferleft)
|
||||||
|
self.airbase:SetActiveRunwayTakeoff(runway,preferleft)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -802,6 +839,15 @@ function ATIS:SetRunwayLength()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Give information on runway length.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetRunwayLength()
|
||||||
|
self.rwylength=true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Give information on airfield elevation
|
--- Give information on airfield elevation
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
@@ -852,7 +898,7 @@ function ATIS:SetRunwayHeadingsMagnetic( headings )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Add runway heading to table.
|
-- Add runway heading to table.
|
||||||
self:I( self.lid .. string.format( "Adding user specified magnetic runway heading %s", heading ) )
|
self:T( self.lid .. string.format( "Adding user specified magnetic runway heading %s", heading ) )
|
||||||
table.insert( self.runwaymag, heading )
|
table.insert( self.runwaymag, heading )
|
||||||
|
|
||||||
local h = self:GetRunwayWithoutLR( heading )
|
local h = self:GetRunwayWithoutLR( heading )
|
||||||
@@ -874,7 +920,7 @@ function ATIS:SetRunwayHeadingsMagnetic( headings )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Add inverse runway heading to table.
|
-- Add inverse runway heading to table.
|
||||||
self:I( self.lid .. string.format( "Adding user specified magnetic runway heading %s (inverse)", head2 ) )
|
self:T( self.lid .. string.format( "Adding user specified magnetic runway heading %s (inverse)", head2 ) )
|
||||||
table.insert( self.runwaymag, head2 )
|
table.insert( self.runwaymag, head2 )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -948,6 +994,28 @@ function ATIS:SetAltimeterQNH( switch )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Additionally report altimeter QNH/QFE in hPa, even if not set to metric.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #boolean switch If true or nil, report mBar/hPa in addition.
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetReportmBar(switch)
|
||||||
|
if switch == true or switch == nil then
|
||||||
|
self.ReportmBar = true
|
||||||
|
else
|
||||||
|
self.ReportmBar = false
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Additionally report free text, only working with SRS(!)
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @param #string text The text to report at the end of the ATIS message, e.g. runway closure, warnings, etc.
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetAdditionalInformation(text)
|
||||||
|
self.AdditionalInformation = text
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Suppresses QFE readout. Default is to report both QNH and QFE.
|
--- Suppresses QFE readout. Default is to report both QNH and QFE.
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
@@ -979,7 +1047,7 @@ end
|
|||||||
-- Or you make your life simple and just include the sign so you don't have to bother about East/West.
|
-- Or you make your life simple and just include the sign so you don't have to bother about East/West.
|
||||||
--
|
--
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @param #number magvar Magnetic variation in degrees. Positive for easterly and negative for westerly variation. Default is magnatic declinaton of the used map, c.f. @{Utilities.UTils#UTILS.GetMagneticDeclination}.
|
-- @param #number magvar Magnetic variation in degrees. Positive for easterly and negative for westerly variation. Default is magnatic declinaton of the used map, c.f. @{Utilities.Utils#UTILS.GetMagneticDeclination}.
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetMagneticDeclination( magvar )
|
function ATIS:SetMagneticDeclination( magvar )
|
||||||
self.magvar = magvar or UTILS.GetMagneticDeclination()
|
self.magvar = magvar or UTILS.GetMagneticDeclination()
|
||||||
@@ -1127,17 +1195,26 @@ end
|
|||||||
-- @param #string Culture Culture, e.g. "en-GB" (default).
|
-- @param #string Culture Culture, e.g. "en-GB" (default).
|
||||||
-- @param #string Voice Specific voice. Overrides `Gender` and `Culture`.
|
-- @param #string Voice Specific voice. Overrides `Gender` and `Culture`.
|
||||||
-- @param #number Port SRS port. Default 5002.
|
-- @param #number Port SRS port. Default 5002.
|
||||||
|
-- @param #string GoogleKey Path to Google JSON-Key.
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetSRS( PathToSRS, Gender, Culture, Voice, Port )
|
function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port, GoogleKey)
|
||||||
self.useSRS = true
|
if PathToSRS then
|
||||||
self.msrs = MSRS:New( PathToSRS, self.frequency, self.modulation )
|
self.useSRS=true
|
||||||
self.msrs:SetGender( Gender )
|
self.msrs=MSRS:New(PathToSRS, self.frequency, self.modulation)
|
||||||
self.msrs:SetCulture( Culture )
|
self.msrs:SetGender(Gender)
|
||||||
self.msrs:SetVoice( Voice )
|
self.msrs:SetCulture(Culture)
|
||||||
self.msrs:SetPort( Port )
|
self.msrs:SetVoice(Voice)
|
||||||
self.msrs:SetCoalition( self:GetCoalition() )
|
self.msrs:SetPort(Port)
|
||||||
if self.dTQueueCheck <= 10 then
|
self.msrs:SetCoalition(self:GetCoalition())
|
||||||
self:SetQueueUpdateTime( 90 )
|
self.msrs:SetLabel("ATIS")
|
||||||
|
self.msrs:SetGoogle(GoogleKey)
|
||||||
|
self.msrsQ = MSRSQUEUE:New("ATIS")
|
||||||
|
self.msrsQ:SetTransmitOnlyWithPlayers(self.TransmitOnlyWithPlayers)
|
||||||
|
if self.dTQueueCheck<=10 then
|
||||||
|
self:SetQueueUpdateTime(90)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:E(self.lid..string.format("ERROR: No SRS path specified!"))
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1179,31 +1256,33 @@ function ATIS:onafterStart( From, Event, To )
|
|||||||
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) )
|
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) )
|
||||||
|
|
||||||
-- Start radio queue.
|
-- Start radio queue.
|
||||||
self.radioqueue = RADIOQUEUE:New( self.frequency, self.modulation, string.format( "ATIS %s", self.airbasename ) )
|
if not self.useSRS then
|
||||||
|
self.radioqueue = RADIOQUEUE:New( self.frequency, self.modulation, string.format( "ATIS %s", self.airbasename ) )
|
||||||
|
|
||||||
-- Send coordinate is airbase coord.
|
-- Send coordinate is airbase coord.
|
||||||
self.radioqueue:SetSenderCoordinate( self.airbase:GetCoordinate() )
|
self.radioqueue:SetSenderCoordinate( self.airbase:GetCoordinate() )
|
||||||
|
|
||||||
-- Set relay unit if we have one.
|
-- Set relay unit if we have one.
|
||||||
self.radioqueue:SetSenderUnitName( self.relayunitname )
|
self.radioqueue:SetSenderUnitName( self.relayunitname )
|
||||||
|
|
||||||
-- Set radio power.
|
-- Set radio power.
|
||||||
self.radioqueue:SetRadioPower( self.power )
|
self.radioqueue:SetRadioPower( self.power )
|
||||||
|
|
||||||
-- Init numbers.
|
-- Init numbers.
|
||||||
self.radioqueue:SetDigit( 0, ATIS.Sound.N0.filename, ATIS.Sound.N0.duration, self.soundpath )
|
self.radioqueue:SetDigit( 0, ATIS.Sound.N0.filename, ATIS.Sound.N0.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 1, ATIS.Sound.N1.filename, ATIS.Sound.N1.duration, self.soundpath )
|
self.radioqueue:SetDigit( 1, ATIS.Sound.N1.filename, ATIS.Sound.N1.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 2, ATIS.Sound.N2.filename, ATIS.Sound.N2.duration, self.soundpath )
|
self.radioqueue:SetDigit( 2, ATIS.Sound.N2.filename, ATIS.Sound.N2.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 3, ATIS.Sound.N3.filename, ATIS.Sound.N3.duration, self.soundpath )
|
self.radioqueue:SetDigit( 3, ATIS.Sound.N3.filename, ATIS.Sound.N3.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 4, ATIS.Sound.N4.filename, ATIS.Sound.N4.duration, self.soundpath )
|
self.radioqueue:SetDigit( 4, ATIS.Sound.N4.filename, ATIS.Sound.N4.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 5, ATIS.Sound.N5.filename, ATIS.Sound.N5.duration, self.soundpath )
|
self.radioqueue:SetDigit( 5, ATIS.Sound.N5.filename, ATIS.Sound.N5.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 6, ATIS.Sound.N6.filename, ATIS.Sound.N6.duration, self.soundpath )
|
self.radioqueue:SetDigit( 6, ATIS.Sound.N6.filename, ATIS.Sound.N6.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 7, ATIS.Sound.N7.filename, ATIS.Sound.N7.duration, self.soundpath )
|
self.radioqueue:SetDigit( 7, ATIS.Sound.N7.filename, ATIS.Sound.N7.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 8, ATIS.Sound.N8.filename, ATIS.Sound.N8.duration, self.soundpath )
|
self.radioqueue:SetDigit( 8, ATIS.Sound.N8.filename, ATIS.Sound.N8.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 9, ATIS.Sound.N9.filename, ATIS.Sound.N9.duration, self.soundpath )
|
self.radioqueue:SetDigit( 9, ATIS.Sound.N9.filename, ATIS.Sound.N9.duration, self.soundpath )
|
||||||
|
|
||||||
-- Start radio queue.
|
-- Start radio queue.
|
||||||
self.radioqueue:Start( 1, 0.1 )
|
self.radioqueue:Start( 1, 0.1 )
|
||||||
|
end
|
||||||
|
|
||||||
-- Handle airbase capture
|
-- Handle airbase capture
|
||||||
-- Handle events.
|
-- Handle events.
|
||||||
@@ -1239,7 +1318,7 @@ function ATIS:onafterStatus( From, Event, To )
|
|||||||
else
|
else
|
||||||
text = text .. string.format( ", Relay unit=%s (alive=%s)", tostring( self.relayunitname ), relayunitstatus )
|
text = text .. string.format( ", Relay unit=%s (alive=%s)", tostring( self.relayunitname ), relayunitstatus )
|
||||||
end
|
end
|
||||||
self:I( self.lid .. text )
|
self:T( self.lid .. text )
|
||||||
|
|
||||||
self:__Status( -60 )
|
self:__Status( -60 )
|
||||||
end
|
end
|
||||||
@@ -1319,6 +1398,9 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local mBarqnh = qnh
|
||||||
|
local mBarqfe = qfe
|
||||||
|
|
||||||
-- Convert to inHg.
|
-- Convert to inHg.
|
||||||
if self.PmmHg then
|
if self.PmmHg then
|
||||||
qfe = UTILS.hPa2mmHg( qfe )
|
qfe = UTILS.hPa2mmHg( qfe )
|
||||||
@@ -1378,7 +1460,8 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
--- Runway ---
|
--- Runway ---
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
local runway, rwyLeft = self:GetActiveRunway()
|
local runwayLanding, rwyLandingLeft=self:GetActiveRunway()
|
||||||
|
local runwayTakeoff, rwyTakeoffLeft=self:GetActiveRunway(true)
|
||||||
|
|
||||||
------------
|
------------
|
||||||
--- Time ---
|
--- Time ---
|
||||||
@@ -1444,8 +1527,8 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
-- Convert to °F.
|
-- Convert to °F.
|
||||||
if self.TDegF then
|
if self.TDegF then
|
||||||
temperature = UTILS.CelsiusToFahrenheit( temperature )
|
temperature=UTILS.CelsiusToFahrenheit(temperature)
|
||||||
dewpoint = UTILS.CelsiusToFahrenheit( dewpoint )
|
dewpoint=UTILS.CelsiusToFahrenheit(dewpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
local TEMPERATURE = string.format( "%d", math.abs( temperature ) )
|
local TEMPERATURE = string.format( "%d", math.abs( temperature ) )
|
||||||
@@ -1740,6 +1823,10 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Wind
|
-- Wind
|
||||||
|
-- Adding a space after each digit of WINDFROM to convert this to aviation-speak for TTS via SRS
|
||||||
|
if self.useSRS then
|
||||||
|
WINDFROM = string.gsub(WINDFROM,".", "%1 ")
|
||||||
|
end
|
||||||
if self.metric then
|
if self.metric then
|
||||||
subtitle = string.format( "Wind from %s at %s m/s", WINDFROM, WINDSPEED )
|
subtitle = string.format( "Wind from %s at %s m/s", WINDFROM, WINDSPEED )
|
||||||
else
|
else
|
||||||
@@ -1764,7 +1851,9 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
--self:I("Line 1811")
|
||||||
|
--self:I(alltext)
|
||||||
|
|
||||||
-- Visibility
|
-- Visibility
|
||||||
if self.metric then
|
if self.metric then
|
||||||
subtitle = string.format( "Visibility %s km", VISIBILITY )
|
subtitle = string.format( "Visibility %s km", VISIBILITY )
|
||||||
@@ -1781,7 +1870,10 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
--self:I("Line 1830")
|
||||||
|
--self:I(alltext)
|
||||||
|
|
||||||
|
subtitle = ""
|
||||||
-- Weather phenomena
|
-- Weather phenomena
|
||||||
local wp = false
|
local wp = false
|
||||||
local wpsub = ""
|
local wpsub = ""
|
||||||
@@ -1881,8 +1973,11 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
--self:I("Line 1932")
|
||||||
|
|
||||||
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
--self:I(alltext)
|
||||||
|
subtitle = ""
|
||||||
-- Temperature
|
-- Temperature
|
||||||
if self.TDegF then
|
if self.TDegF then
|
||||||
if temperature < 0 then
|
if temperature < 0 then
|
||||||
@@ -1910,8 +2005,10 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 )
|
self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--self:I("Line 1962")
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
--self:I(alltext)
|
||||||
|
|
||||||
-- Dew point
|
-- Dew point
|
||||||
if self.TDegF then
|
if self.TDegF then
|
||||||
if dewpoint < 0 then
|
if dewpoint < 0 then
|
||||||
@@ -1939,6 +2036,8 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 )
|
self:Transmission( ATIS.Sound.DegreesCelsius, 0.2 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--self:I("Line 1992")
|
||||||
|
--self:I(alltext)
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
|
||||||
-- Altimeter QNH/QFE.
|
-- Altimeter QNH/QFE.
|
||||||
@@ -1963,6 +2062,15 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.ReportmBar and not self.metric then
|
||||||
|
if self.qnhonly then
|
||||||
|
subtitle = string.format( "%s;\nAltimeter %d hPa", subtitle, mBarqnh )
|
||||||
|
else
|
||||||
|
subtitle = string.format( "%s;\nAltimeter: QNH %d, QFE %d hPa", subtitle, mBarqnh, mBarqfe)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local _ALTIMETER = subtitle
|
local _ALTIMETER = subtitle
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
self:Transmission( ATIS.Sound.Altimeter, 1.0, subtitle )
|
self:Transmission( ATIS.Sound.Altimeter, 1.0, subtitle )
|
||||||
@@ -1995,23 +2103,25 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--self:I("Line 2049")
|
||||||
|
--self:I(alltext)
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
|
||||||
-- Active runway.
|
-- Active runway.
|
||||||
local subtitle = string.format( "Active runway %s", runway )
|
local subtitle=string.format("Active runway %s", runwayLanding)
|
||||||
if rwyLeft == true then
|
if rwyLandingLeft==true then
|
||||||
subtitle = subtitle .. " Left"
|
subtitle=subtitle.." Left"
|
||||||
elseif rwyLeft == false then
|
elseif rwyLandingLeft==false then
|
||||||
subtitle = subtitle .. " Right"
|
subtitle=subtitle.." Right"
|
||||||
end
|
end
|
||||||
local _RUNACT = subtitle
|
local _RUNACT = subtitle
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
self:Transmission( ATIS.Sound.ActiveRunway, 1.0, subtitle )
|
self:Transmission(ATIS.Sound.ActiveRunway, 1.0, subtitle)
|
||||||
self.radioqueue:Number2Transmission( runway )
|
self.radioqueue:Number2Transmission(runwayLanding)
|
||||||
if rwyLeft == true then
|
if rwyLandingLeft==true then
|
||||||
self:Transmission( ATIS.Sound.Left, 0.2 )
|
self:Transmission(ATIS.Sound.Left, 0.2)
|
||||||
elseif rwyLeft == false then
|
elseif rwyLandingLeft==false then
|
||||||
self:Transmission( ATIS.Sound.Right, 0.2 )
|
self:Transmission(ATIS.Sound.Right, 0.2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
@@ -2122,7 +2232,9 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- ILS
|
-- ILS
|
||||||
local ils = self:GetNavPoint( self.ils, runway, rwyLeft )
|
--self:I({ils=self.ils})
|
||||||
|
local ils=self:GetNavPoint(self.ils, runwayLanding, rwyLandingLeft)
|
||||||
|
--self:I({ils=ils,runwayLanding=runwayLanding, rwyLandingLeft=rwyLandingLeft})
|
||||||
if ils then
|
if ils then
|
||||||
subtitle = string.format( "ILS frequency %.2f MHz", ils.frequency )
|
subtitle = string.format( "ILS frequency %.2f MHz", ils.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2137,10 +2249,11 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
self:Transmission( ATIS.Sound.MegaHertz, 0.2 )
|
self:Transmission( ATIS.Sound.MegaHertz, 0.2 )
|
||||||
end
|
end
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
--self:I(alltext)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Outer NDB
|
-- Outer NDB
|
||||||
local ndb = self:GetNavPoint( self.ndbouter, runway, rwyLeft )
|
local ndb=self:GetNavPoint(self.ndbouter, runwayLanding, rwyLandingLeft)
|
||||||
if ndb then
|
if ndb then
|
||||||
subtitle = string.format( "Outer NDB frequency %.2f MHz", ndb.frequency )
|
subtitle = string.format( "Outer NDB frequency %.2f MHz", ndb.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2158,7 +2271,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Inner NDB
|
-- Inner NDB
|
||||||
local ndb = self:GetNavPoint( self.ndbinner, runway, rwyLeft )
|
local ndb=self:GetNavPoint(self.ndbinner, runwayLanding, rwyLandingLeft)
|
||||||
if ndb then
|
if ndb then
|
||||||
subtitle = string.format( "Inner NDB frequency %.2f MHz", ndb.frequency )
|
subtitle = string.format( "Inner NDB frequency %.2f MHz", ndb.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2197,7 +2310,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
-- TACAN
|
-- TACAN
|
||||||
if self.tacan then
|
if self.tacan then
|
||||||
subtitle = string.format( "TACAN channel %dX", self.tacan )
|
subtitle=string.format("TACAN channel %dX Ray", self.tacan)
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
self:Transmission( ATIS.Sound.TACANChannel, 1.0, subtitle )
|
self:Transmission( ATIS.Sound.TACANChannel, 1.0, subtitle )
|
||||||
self.radioqueue:Number2Transmission( tostring( self.tacan ), nil, 0.2 )
|
self.radioqueue:Number2Transmission( tostring( self.tacan ), nil, 0.2 )
|
||||||
@@ -2217,7 +2330,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- PRMG
|
-- PRMG
|
||||||
local ndb = self:GetNavPoint( self.prmg, runway, rwyLeft )
|
local ndb=self:GetNavPoint(self.prmg, runwayLanding, rwyLandingLeft)
|
||||||
if ndb then
|
if ndb then
|
||||||
subtitle = string.format( "PRMG channel %d", ndb.frequency )
|
subtitle = string.format( "PRMG channel %d", ndb.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2226,7 +2339,12 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- additional info, if any
|
||||||
|
if self.useSRS and self.AdditionalInformation then
|
||||||
|
alltext = alltext .. ";\n"..self.AdditionalInformation
|
||||||
|
end
|
||||||
|
|
||||||
-- Advice on initial...
|
-- Advice on initial...
|
||||||
subtitle = string.format( "Advise on initial contact, you have information %s", NATO )
|
subtitle = string.format( "Advise on initial contact, you have information %s", NATO )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2274,8 +2392,10 @@ function ATIS:onafterReport( From, Event, To, Text )
|
|||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T( "SRS TTS: " .. text )
|
self:T( "SRS TTS: " .. text )
|
||||||
|
|
||||||
-- Play text-to-speech report.
|
-- Play text-to-speech report.
|
||||||
self.msrs:PlayText( text )
|
local duration = STTS.getSpeechTime(text,0.95)
|
||||||
|
self.msrsQ:NewTransmission(text,duration,self.msrs,nil,2)
|
||||||
|
--self.msrs:PlayText( text )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2344,39 +2464,19 @@ end
|
|||||||
|
|
||||||
--- Get active runway runway.
|
--- Get active runway runway.
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
|
-- @param #boolean Takeoff If `true`, get runway for takeoff. Default is for landing.
|
||||||
-- @return #string Active runway, e.g. "31" for 310 deg.
|
-- @return #string Active runway, e.g. "31" for 310 deg.
|
||||||
-- @return #boolean Use Left=true, Right=false, or nil.
|
-- @return #boolean Use Left=true, Right=false, or nil.
|
||||||
function ATIS:GetActiveRunway()
|
function ATIS:GetActiveRunway(Takeoff)
|
||||||
|
|
||||||
local coord = self.airbase:GetCoordinate()
|
local runway=nil --Wrapper.Airbase#AIRBASE.Runway
|
||||||
local height = coord:GetLandHeight()
|
if Takeoff then
|
||||||
|
runway=self.airbase:GetActiveRunwayTakeoff()
|
||||||
-- Get wind direction and speed in m/s.
|
else
|
||||||
local windFrom, windSpeed = coord:GetWind( height + 10 )
|
runway=self.airbase:GetActiveRunwayLanding()
|
||||||
|
|
||||||
-- Get active runway data based on wind direction.
|
|
||||||
local runact = self.airbase:GetActiveRunway( self.runwaym2t )
|
|
||||||
|
|
||||||
-- Active runway "31".
|
|
||||||
local runway = self:GetMagneticRunway( windFrom ) or runact.idx
|
|
||||||
|
|
||||||
-- Left or right in case there are two runways with the same heading.
|
|
||||||
local rwyLeft = nil
|
|
||||||
|
|
||||||
-- Check if user explicitly specified a runway.
|
|
||||||
if self.activerunway then
|
|
||||||
|
|
||||||
-- Get explicit runway heading if specified.
|
|
||||||
local runwayno = self:GetRunwayWithoutLR( self.activerunway )
|
|
||||||
if runwayno ~= "" then
|
|
||||||
runway = runwayno
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Was "L"eft or "R"ight given?
|
|
||||||
rwyLeft = self:GetRunwayLR( self.activerunway )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return runway, rwyLeft
|
return runway.name, runway.isLeft
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get runway from user supplied magnetic heading.
|
--- Get runway from user supplied magnetic heading.
|
||||||
@@ -2442,7 +2542,7 @@ end
|
|||||||
-- @return #string Runway heading without left or right, *e.g.* "31".
|
-- @return #string Runway heading without left or right, *e.g.* "31".
|
||||||
function ATIS:GetRunwayWithoutLR( runway )
|
function ATIS:GetRunwayWithoutLR( runway )
|
||||||
local rwywo = runway:gsub( "%D+", "" )
|
local rwywo = runway:gsub( "%D+", "" )
|
||||||
-- self:I(string.format("FF runway=%s ==> rwywo=%s", runway, rwywo))
|
-- self:T(string.format("FF runway=%s ==> rwywo=%s", runway, rwywo))
|
||||||
return rwywo
|
return rwywo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
--- **Ops** -- Combat Search and Rescue.
|
--- **Ops** - Combat Search and Rescue.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
-- @module Ops.CSAR
|
-- @module Ops.CSAR
|
||||||
-- @image OPS_CSAR.jpg
|
-- @image OPS_CSAR.jpg
|
||||||
|
|
||||||
-- Date: Feb 2022
|
-- Date: October 2022
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
--- **CSAR** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
-- @field #number verbose Verbosity level.
|
-- @field #number verbose Verbosity level.
|
||||||
-- @field #string lid Class id string for output to DCS log file.
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
-- @field #number coalition Coalition side number, e.g. `coalition.side.RED`.
|
-- @field #number coalition Coalition side number, e.g. `coalition.side.RED`.
|
||||||
|
-- @field Core.Set#SET_GROUP allheligroupset Set of CSAR heli groups.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Combat search and rescue (CSAR) are search and rescue operations that are carried out during war that are within or near combat zones.* (Wikipedia)
|
--- *Combat search and rescue (CSAR) are search and rescue operations that are carried out during war that are within or near combat zones.* (Wikipedia)
|
||||||
@@ -76,64 +77,70 @@
|
|||||||
--
|
--
|
||||||
-- The following options are available (with their defaults). Only set the ones you want changed:
|
-- The following options are available (with their defaults). Only set the ones you want changed:
|
||||||
--
|
--
|
||||||
-- self.allowDownedPilotCAcontrol = false -- Set to false if you don\'t want to allow control by Combined Arms.
|
-- mycsar.allowDownedPilotCAcontrol = false -- Set to false if you don\'t want to allow control by Combined Arms.
|
||||||
-- self.allowFARPRescue = true -- allows pilots to be rescued by landing at a FARP or Airbase. Else MASH only!
|
-- mycsar.allowFARPRescue = true -- allows pilots to be rescued by landing at a FARP or Airbase. Else MASH only!
|
||||||
-- self.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued.
|
-- mycsar.FARPRescueDistance = 1000 -- you need to be this close to a FARP or Airport for the pilot to be rescued.
|
||||||
-- self.autosmoke = false -- automatically smoke a downed pilot\'s location when a heli is near.
|
-- mycsar.autosmoke = false -- automatically smoke a downed pilot\'s location when a heli is near.
|
||||||
-- self.autosmokedistance = 1000 -- distance for autosmoke
|
-- mycsar.autosmokedistance = 1000 -- distance for autosmoke
|
||||||
-- self.coordtype = 1 -- Use Lat/Long DDM (0), Lat/Long DMS (1), MGRS (2), Bullseye imperial (3) or Bullseye metric (4) for coordinates.
|
-- mycsar.coordtype = 1 -- Use Lat/Long DDM (0), Lat/Long DMS (1), MGRS (2), Bullseye imperial (3) or Bullseye metric (4) for coordinates.
|
||||||
-- self.csarOncrash = false -- (WIP) If set to true, will generate a downed pilot when a plane crashes as well.
|
-- mycsar.csarOncrash = false -- (WIP) If set to true, will generate a downed pilot when a plane crashes as well.
|
||||||
-- self.enableForAI = false -- set to false to disable AI pilots from being rescued.
|
-- mycsar.enableForAI = false -- set to false to disable AI pilots from being rescued.
|
||||||
-- self.pilotRuntoExtractPoint = true -- Downed pilot will run to the rescue helicopter up to self.extractDistance in meters.
|
-- mycsar.pilotRuntoExtractPoint = true -- Downed pilot will run to the rescue helicopter up to mycsar.extractDistance in meters.
|
||||||
-- self.extractDistance = 500 -- Distance the downed pilot will start to run to the rescue helicopter.
|
-- mycsar.extractDistance = 500 -- Distance the downed pilot will start to run to the rescue helicopter.
|
||||||
-- self.immortalcrew = true -- Set to true to make wounded crew immortal.
|
-- mycsar.immortalcrew = true -- Set to true to make wounded crew immortal.
|
||||||
-- self.invisiblecrew = false -- Set to true to make wounded crew insvisible.
|
-- mycsar.invisiblecrew = false -- Set to true to make wounded crew insvisible.
|
||||||
-- self.loadDistance = 75 -- configure distance for pilots to get into helicopter in meters.
|
-- mycsar.loadDistance = 75 -- configure distance for pilots to get into helicopter in meters.
|
||||||
-- self.mashprefix = {"MASH"} -- prefixes of #GROUP objects used as MASHes.
|
-- mycsar.mashprefix = {"MASH"} -- prefixes of #GROUP objects used as MASHes.
|
||||||
-- self.max_units = 6 -- max number of pilots that can be carried if #CSAR.AircraftType is undefined.
|
-- mycsar.max_units = 6 -- max number of pilots that can be carried if #CSAR.AircraftType is undefined.
|
||||||
-- self.messageTime = 15 -- Time to show messages for in seconds. Doubled for long messages.
|
-- mycsar.messageTime = 15 -- Time to show messages for in seconds. Doubled for long messages.
|
||||||
-- self.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons.
|
-- mycsar.radioSound = "beacon.ogg" -- the name of the sound file to use for the pilots\' radio beacons.
|
||||||
-- self.smokecolor = 4 -- Color of smokemarker, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue.
|
-- mycsar.smokecolor = 4 -- Color of smokemarker, 0 is green, 1 is red, 2 is white, 3 is orange and 4 is blue.
|
||||||
-- self.useprefix = true -- Requires CSAR helicopter #GROUP names to have the prefix(es) defined below.
|
-- mycsar.useprefix = true -- Requires CSAR helicopter #GROUP names to have the prefix(es) defined below.
|
||||||
-- self.csarPrefix = { "helicargo", "MEDEVAC"} -- #GROUP name prefixes used for useprefix=true - DO NOT use # in helicopter names in the Mission Editor!
|
-- mycsar.csarPrefix = { "helicargo", "MEDEVAC"} -- #GROUP name prefixes used for useprefix=true - DO NOT use # in helicopter names in the Mission Editor!
|
||||||
-- self.verbose = 0 -- set to > 1 for stats output for debugging.
|
-- mycsar.verbose = 0 -- set to > 1 for stats output for debugging.
|
||||||
-- -- (added 0.1.4) limit amount of downed pilots spawned by **ejection** events
|
-- -- limit amount of downed pilots spawned by **ejection** events
|
||||||
-- self.limitmaxdownedpilots = true
|
-- mycsar.limitmaxdownedpilots = true
|
||||||
-- self.maxdownedpilots = 10
|
-- mycsar.maxdownedpilots = 10
|
||||||
-- -- (added 0.1.8) - allow to set far/near distance for approach and optionally pilot must open doors
|
-- -- allow to set far/near distance for approach and optionally pilot must open doors
|
||||||
-- self.approachdist_far = 5000 -- switch do 10 sec interval approach mode, meters
|
-- mycsar.approachdist_far = 5000 -- switch do 10 sec interval approach mode, meters
|
||||||
-- self.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters
|
-- mycsar.approachdist_near = 3000 -- switch to 5 sec interval approach mode, meters
|
||||||
-- self.pilotmustopendoors = false -- switch to true to enable check of open doors
|
-- mycsar.pilotmustopendoors = false -- switch to true to enable check of open doors
|
||||||
-- -- (added 0.1.9)
|
-- mycsar.suppressmessages = false -- switch off all messaging if you want to do your own
|
||||||
-- self.suppressmessages = false -- switch off all messaging if you want to do your own
|
-- mycsar.rescuehoverheight = 20 -- max height for a hovering rescue in meters
|
||||||
-- -- (added 0.1.11)
|
-- mycsar.rescuehoverdistance = 10 -- max distance for a hovering rescue in meters
|
||||||
-- self.rescuehoverheight = 20 -- max height for a hovering rescue in meters
|
|
||||||
-- self.rescuehoverdistance = 10 -- max distance for a hovering rescue in meters
|
|
||||||
-- -- (added 0.1.12)
|
|
||||||
-- -- Country codes for spawned pilots
|
-- -- Country codes for spawned pilots
|
||||||
-- self.countryblue= country.id.USA
|
-- mycsar.countryblue= country.id.USA
|
||||||
-- self.countryred = country.id.RUSSIA
|
-- mycsar.countryred = country.id.RUSSIA
|
||||||
-- self.countryneutral = country.id.UN_PEACEKEEPERS
|
-- mycsar.countryneutral = country.id.UN_PEACEKEEPERS
|
||||||
|
-- mycsar.topmenuname = "CSAR" -- set the menu entry name
|
||||||
|
-- mycsar.ADFRadioPwr = 1000 -- ADF Beacons sending with 1KW as default
|
||||||
--
|
--
|
||||||
-- ## 2.1 Experimental Features
|
-- ## 2.1 Experimental Features
|
||||||
--
|
--
|
||||||
-- WARNING - Here\'ll be dragons!
|
-- WARNING - Here\'ll be dragons!
|
||||||
-- DANGER - For this to work you need to de-sanitize your mission environment (all three entries) in <DCS root>\Scripts\MissionScripting.lua
|
-- DANGER - For this to work you need to de-sanitize your mission environment (all three entries) in <DCS root>\Scripts\MissionScripting.lua
|
||||||
-- Needs SRS => 1.9.6 to work (works on the **server** side of SRS)
|
-- Needs SRS => 1.9.6 to work (works on the **server** side of SRS)
|
||||||
-- self.useSRS = false -- Set true to use FF\'s SRS integration
|
-- mycsar.useSRS = false -- Set true to use FF\'s SRS integration
|
||||||
-- self.SRSPath = "E:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
|
-- mycsar.SRSPath = "C:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your SRS installation -- server(!)
|
||||||
-- self.SRSchannel = 300 -- radio channel
|
-- mycsar.SRSchannel = 300 -- radio channel
|
||||||
-- self.SRSModulation = radio.modulation.AM -- modulation
|
-- mycsar.SRSModulation = radio.modulation.AM -- modulation
|
||||||
|
-- mycsar.SRSport = 5002 -- and SRS Server port
|
||||||
|
-- mycsar.SRSCulture = "en-GB" -- SRS voice culture
|
||||||
|
-- mycsar.SRSVoice = nil -- SRS voice, relevant for Google TTS
|
||||||
|
-- mycsar.SRSGPathToCredentials = nil -- Path to your Google credentials json file, set this if you want to use Google TTS
|
||||||
|
-- mycsar.SRSVolume = 1 -- Volume, between 0 and 1
|
||||||
|
-- mycsar.SRSGender = "male" -- male or female voice
|
||||||
-- --
|
-- --
|
||||||
-- self.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection --shagrat
|
-- mycsar.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection. Requires mycsar.enableForAI to be set to true. --shagrat
|
||||||
-- self.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
|
-- mycsar.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
|
||||||
|
-- mycsar.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
||||||
--
|
--
|
||||||
-- ## 3. Results
|
-- ## 3. Results
|
||||||
--
|
--
|
||||||
-- Number of successful landings with save pilots and aggregated number of saved pilots is stored in these variables in the object:
|
-- Number of successful landings with save pilots and aggregated number of saved pilots is stored in these variables in the object:
|
||||||
--
|
--
|
||||||
-- self.rescues -- number of successful landings *with* saved pilots
|
-- mycsar.rescues -- number of successful landings *with* saved pilots
|
||||||
-- self.rescuedpilots -- aggregated number of pilots rescued from the field (of *all* players)
|
-- mycsar.rescuedpilots -- aggregated number of pilots rescued from the field (of *all* players)
|
||||||
--
|
--
|
||||||
-- ## 4. Events
|
-- ## 4. Events
|
||||||
--
|
--
|
||||||
@@ -160,7 +167,7 @@
|
|||||||
--
|
--
|
||||||
-- The pilot has been boarded to the helicopter. Use e.g. `function my_csar:OnAfterBoarded(...)` to link into this event:
|
-- The pilot has been boarded to the helicopter. Use e.g. `function my_csar:OnAfterBoarded(...)` to link into this event:
|
||||||
--
|
--
|
||||||
-- function my_csar:OnAfterBoarded(from, event, to, heliname, groupname)
|
-- function my_csar:OnAfterBoarded(from, event, to, heliname, groupname, description)
|
||||||
-- ... your code here ...
|
-- ... your code here ...
|
||||||
-- end
|
-- end
|
||||||
--
|
--
|
||||||
@@ -210,7 +217,7 @@ CSAR = {
|
|||||||
smokeMarkers = {}, -- tracks smoke markers for groups
|
smokeMarkers = {}, -- tracks smoke markers for groups
|
||||||
heliVisibleMessage = {}, -- tracks if the first message has been sent of the heli being visible
|
heliVisibleMessage = {}, -- tracks if the first message has been sent of the heli being visible
|
||||||
heliCloseMessage = {}, -- tracks heli close message ie heli < 500m distance
|
heliCloseMessage = {}, -- tracks heli close message ie heli < 500m distance
|
||||||
max_units = 6, --number of pilots that can be carried
|
max_units = 6, -- number of pilots that can be carried
|
||||||
hoverStatus = {}, -- tracks status of a helis hover above a downed pilot
|
hoverStatus = {}, -- tracks status of a helis hover above a downed pilot
|
||||||
pilotDisabled = {}, -- tracks what aircraft a pilot is disabled for
|
pilotDisabled = {}, -- tracks what aircraft a pilot is disabled for
|
||||||
pilotLives = {}, -- tracks how many lives a pilot has
|
pilotLives = {}, -- tracks how many lives a pilot has
|
||||||
@@ -223,6 +230,9 @@ CSAR = {
|
|||||||
rescuedpilots = 0,
|
rescuedpilots = 0,
|
||||||
limitmaxdownedpilots = true,
|
limitmaxdownedpilots = true,
|
||||||
maxdownedpilots = 10,
|
maxdownedpilots = 10,
|
||||||
|
allheligroupset = nil,
|
||||||
|
topmenuname = "CSAR",
|
||||||
|
ADFRadioPwr = 1000,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Downed pilots info.
|
--- Downed pilots info.
|
||||||
@@ -254,12 +264,13 @@ CSAR.AircraftType["Mi-8MT"] = 12
|
|||||||
CSAR.AircraftType["Mi-24P"] = 8
|
CSAR.AircraftType["Mi-24P"] = 8
|
||||||
CSAR.AircraftType["Mi-24V"] = 8
|
CSAR.AircraftType["Mi-24V"] = 8
|
||||||
CSAR.AircraftType["Bell-47"] = 2
|
CSAR.AircraftType["Bell-47"] = 2
|
||||||
CSAR.AircraftType["UH-60L"] = 10
|
CSAR.AircraftType["UH-60L"] = 10
|
||||||
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
||||||
|
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="1.0.4d"
|
CSAR.version="1.0.15"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -328,6 +339,7 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
self:AddTransition("*", "Status", "*") -- CSAR status update.
|
self:AddTransition("*", "Status", "*") -- CSAR status update.
|
||||||
self:AddTransition("*", "PilotDown", "*") -- Downed Pilot added
|
self:AddTransition("*", "PilotDown", "*") -- Downed Pilot added
|
||||||
self:AddTransition("*", "Approach", "*") -- CSAR heli closing in.
|
self:AddTransition("*", "Approach", "*") -- CSAR heli closing in.
|
||||||
|
self:AddTransition("*", "Landed", "*") -- CSAR heli landed
|
||||||
self:AddTransition("*", "Boarded", "*") -- Pilot boarded.
|
self:AddTransition("*", "Boarded", "*") -- Pilot boarded.
|
||||||
self:AddTransition("*", "Returning", "*") -- CSAR able to return to base.
|
self:AddTransition("*", "Returning", "*") -- CSAR able to return to base.
|
||||||
self:AddTransition("*", "Rescued", "*") -- Pilot at MASH.
|
self:AddTransition("*", "Rescued", "*") -- Pilot at MASH.
|
||||||
@@ -405,14 +417,25 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
-- added 0.1.4
|
-- added 0.1.4
|
||||||
self.wetfeettemplate = nil
|
self.wetfeettemplate = nil
|
||||||
self.usewetfeet = false
|
self.usewetfeet = false
|
||||||
|
|
||||||
|
-- added 0.1.8
|
||||||
|
self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
||||||
|
|
||||||
|
self.ADFRadioPwr = 1000
|
||||||
|
|
||||||
-- WARNING - here\'ll be dragons
|
-- WARNING - here\'ll be dragons
|
||||||
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
||||||
-- needs SRS => 1.9.6 to work (works on the *server* side)
|
-- needs SRS => 1.9.6 to work (works on the *server* side)
|
||||||
self.useSRS = false -- Use FF\'s SRS integration
|
self.useSRS = false -- Use FF\'s SRS integration
|
||||||
self.SRSPath = "E:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your server(!)
|
self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone" -- adjust your own path in your server(!)
|
||||||
self.SRSchannel = 300 -- radio channel
|
self.SRSchannel = 300 -- radio channel
|
||||||
self.SRSModulation = radio.modulation.AM -- modulation
|
self.SRSModulation = radio.modulation.AM -- modulation
|
||||||
|
self.SRSport = 5002 -- port
|
||||||
|
self.SRSCulture = "en-GB"
|
||||||
|
self.SRSVoice = nil
|
||||||
|
self.SRSGPathToCredentials = nil
|
||||||
|
self.SRSVolume = 1.0 -- volume 0.0 to 1.0
|
||||||
|
self.SRSGender = "male" -- male or female
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
--- Pseudo Functions ---
|
--- Pseudo Functions ---
|
||||||
@@ -464,7 +487,16 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
-- @param #string Heliname Name of the helicopter group.
|
-- @param #string Heliname Name of the helicopter group.
|
||||||
-- @param #string Woundedgroupname Name of the downed pilot\'s group.
|
-- @param #string Woundedgroupname Name of the downed pilot\'s group.
|
||||||
|
|
||||||
--- On After "Boarded" event. Downed pilot boarded heli.
|
--- On After "Landed" event. Heli landed at an airbase.
|
||||||
|
-- @function [parent=#CSAR] OnAfterLanded
|
||||||
|
-- @param #CSAR self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string HeliName Name of the #UNIT which has landed.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where the heli landed.
|
||||||
|
|
||||||
|
--- On After "Boarded" event. Downed pilot boarded heli.
|
||||||
-- @function [parent=#CSAR] OnAfterBoarded
|
-- @function [parent=#CSAR] OnAfterBoarded
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param #string From From state.
|
-- @param #string From From state.
|
||||||
@@ -472,6 +504,7 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #string Heliname Name of the helicopter group.
|
-- @param #string Heliname Name of the helicopter group.
|
||||||
-- @param #string Woundedgroupname Name of the downed pilot\'s group.
|
-- @param #string Woundedgroupname Name of the downed pilot\'s group.
|
||||||
|
-- @param #string Description Descriptive name of the group.
|
||||||
|
|
||||||
--- On After "Returning" event. Heli can return home with downed pilot(s).
|
--- On After "Returning" event. Heli can return home with downed pilot(s).
|
||||||
-- @function [parent=#CSAR] OnAfterReturning
|
-- @function [parent=#CSAR] OnAfterReturning
|
||||||
@@ -580,6 +613,19 @@ function CSAR:_DoubleEjection(_unitname)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (User) Add a PLAYERTASK - FSM events will check success
|
||||||
|
-- @param #CSAR self
|
||||||
|
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
|
||||||
|
-- @return #CSAR self
|
||||||
|
function CSAR:AddPlayerTask(PlayerTask)
|
||||||
|
self:T(self.lid .. " AddPlayerTask")
|
||||||
|
if not self.PlayerTaskQueue then
|
||||||
|
self.PlayerTaskQueue = FIFO:New()
|
||||||
|
end
|
||||||
|
self.PlayerTaskQueue:Push(PlayerTask,PlayerTask.PlayerTaskNr)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Spawn a downed pilot
|
--- (Internal) Spawn a downed pilot
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param #number country Country for template.
|
-- @param #number country Country for template.
|
||||||
@@ -859,12 +905,12 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
-- no Player
|
-- no Player
|
||||||
if self.enableForAI == false and _event.IniPlayerName == nil then
|
if self.enableForAI == false and _event.IniPlayerName == nil then
|
||||||
return
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- no event
|
-- no event
|
||||||
if _event == nil or _event.initiator == nil then
|
if _event == nil or _event.initiator == nil then
|
||||||
return false
|
return self
|
||||||
|
|
||||||
-- take off
|
-- take off
|
||||||
elseif _event.id == EVENTS.Takeoff then -- taken off
|
elseif _event.id == EVENTS.Takeoff then -- taken off
|
||||||
@@ -872,35 +918,52 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
local _coalition = _event.IniCoalition
|
local _coalition = _event.IniCoalition
|
||||||
if _coalition ~= self.coalition then
|
if _coalition ~= self.coalition then
|
||||||
return --ignore!
|
return self --ignore!
|
||||||
end
|
end
|
||||||
|
|
||||||
if _event.IniGroupName then
|
if _event.IniGroupName then
|
||||||
self.takenOff[_event.IniUnitName] = true
|
self.takenOff[_event.IniUnitName] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return self
|
||||||
|
|
||||||
-- player enter unit
|
-- player enter unit
|
||||||
elseif _event.id == EVENTS.PlayerEnterAircraft or _event.id == EVENTS.PlayerEnterUnit then --player entered unit
|
elseif _event.id == EVENTS.PlayerEnterAircraft or _event.id == EVENTS.PlayerEnterUnit then --player entered unit
|
||||||
self:T(self.lid .. " Event unit - Player Enter")
|
self:T(self.lid .. " Event unit - Player Enter")
|
||||||
|
|
||||||
local _coalition = _event.IniCoalition
|
local _coalition = _event.IniCoalition
|
||||||
|
self:T("Coalition = "..UTILS.GetCoalitionName(_coalition))
|
||||||
if _coalition ~= self.coalition then
|
if _coalition ~= self.coalition then
|
||||||
return --ignore!
|
return self --ignore!
|
||||||
end
|
end
|
||||||
|
|
||||||
if _event.IniPlayerName then
|
if _event.IniPlayerName then
|
||||||
self.takenOff[_event.IniPlayerName] = nil
|
self.takenOff[_event.IniPlayerName] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- jumped into flying plane?
|
||||||
|
self:T("Taken Off: "..tostring(_event.IniUnit:InAir(true)))
|
||||||
|
|
||||||
|
if _event.IniUnit:InAir(true) then
|
||||||
|
self.takenOff[_event.IniPlayerName] = true
|
||||||
|
end
|
||||||
|
|
||||||
local _unit = _event.IniUnit
|
local _unit = _event.IniUnit
|
||||||
local _group = _event.IniGroup
|
local _group = _event.IniGroup
|
||||||
if _unit:IsHelicopter() or _group:IsHelicopter() then
|
|
||||||
|
local function IsBronco(Group)
|
||||||
|
local grp = Group -- Wrapper.Group#GROUP
|
||||||
|
local typename = grp:GetTypeName()
|
||||||
|
self:T(typename)
|
||||||
|
if typename == "Bronco-OV-10A" then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if _unit:IsHelicopter() or _group:IsHelicopter() or IsBronco(_group) then
|
||||||
self:_AddMedevacMenuItem()
|
self:_AddMedevacMenuItem()
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return self
|
||||||
|
|
||||||
elseif (_event.id == EVENTS.PilotDead and self.csarOncrash == false) then
|
elseif (_event.id == EVENTS.PilotDead and self.csarOncrash == false) then
|
||||||
-- Pilot dead
|
-- Pilot dead
|
||||||
@@ -912,57 +975,68 @@ function CSAR:_EventHandler(EventData)
|
|||||||
local _group = _event.IniGroup
|
local _group = _event.IniGroup
|
||||||
|
|
||||||
if _unit == nil then
|
if _unit == nil then
|
||||||
return -- error!
|
return self -- error!
|
||||||
end
|
end
|
||||||
|
|
||||||
local _coalition = _event.IniCoalition
|
local _coalition = _event.IniCoalition
|
||||||
if _coalition ~= self.coalition then
|
if _coalition ~= self.coalition then
|
||||||
return --ignore!
|
return self --ignore!
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Catch multiple events here?
|
-- Catch multiple events here?
|
||||||
if self.takenOff[_event.IniUnitName] == true or _group:IsAirborne() then
|
if self.takenOff[_event.IniUnitName] == true or _group:IsAirborne() then
|
||||||
if self:_DoubleEjection(_unitname) then
|
if self:_DoubleEjection(_unitname) then
|
||||||
return
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
self:T(self.lid .. " Pilot has not taken off, ignore")
|
self:T(self.lid .. " Pilot has not taken off, ignore")
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return self
|
||||||
|
|
||||||
elseif _event.id == EVENTS.PilotDead or _event.id == EVENTS.Ejection then
|
elseif _event.id == EVENTS.PilotDead or _event.id == EVENTS.Ejection then
|
||||||
if _event.id == EVENTS.PilotDead and self.csarOncrash == false then
|
if _event.id == EVENTS.PilotDead and self.csarOncrash == false then
|
||||||
return
|
return self
|
||||||
end
|
end
|
||||||
self:T(self.lid .. " Event unit - Pilot Ejected")
|
self:T(self.lid .. " Event unit - Pilot Ejected")
|
||||||
|
|
||||||
local _unit = _event.IniUnit
|
local _unit = _event.IniUnit
|
||||||
local _unitname = _event.IniUnitName
|
local _unitname = _event.IniUnitName
|
||||||
local _group = _event.IniGroup
|
local _group = _event.IniGroup
|
||||||
|
|
||||||
|
self:T({_unit.UnitName, _unitname, _group.GroupName})
|
||||||
|
|
||||||
if _unit == nil then
|
if _unit == nil then
|
||||||
return -- error!
|
self:T("Unit NIL!")
|
||||||
|
return self -- error!
|
||||||
end
|
end
|
||||||
|
|
||||||
local _coalition = _unit:GetCoalition()
|
--local _coalition = _unit:GetCoalition() -- nil now for some reason
|
||||||
|
local _coalition = _group:GetCoalition()
|
||||||
if _coalition ~= self.coalition then
|
if _coalition ~= self.coalition then
|
||||||
return --ignore!
|
self:T("Wrong coalition! Coalition = "..UTILS.GetCoalitionName(_coalition))
|
||||||
|
return self --ignore!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
self:T("Airborne: "..tostring(_group:IsAirborne()))
|
||||||
|
self:T("Taken Off: "..tostring(self.takenOff[_event.IniUnitName]))
|
||||||
|
|
||||||
if not self.takenOff[_event.IniUnitName] and not _group:IsAirborne() then
|
if not self.takenOff[_event.IniUnitName] and not _group:IsAirborne() then
|
||||||
self:T(self.lid .. " Pilot has not taken off, ignore")
|
self:T(self.lid .. " Pilot has not taken off, ignore")
|
||||||
return -- give up, pilot hasnt taken off
|
-- return self -- give up, pilot hasnt taken off
|
||||||
end
|
end
|
||||||
|
|
||||||
if self:_DoubleEjection(_unitname) then
|
if self:_DoubleEjection(_unitname) then
|
||||||
return
|
self:T("Double Ejection!")
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- limit no of pilots in the field.
|
-- limit no of pilots in the field.
|
||||||
if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then
|
if self.limitmaxdownedpilots and self:_ReachedPilotLimit() then
|
||||||
return
|
self:T("Maxed Downed Pilot!")
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -971,33 +1045,31 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
local wetfeet = false
|
local wetfeet = false
|
||||||
|
|
||||||
local surface = _unit:GetCoordinate():GetSurfaceType()
|
local initdcscoord = nil
|
||||||
|
local initcoord = nil
|
||||||
|
if _event.id == EVENTS.Ejection then
|
||||||
|
initdcscoord = _event.TgtDCSUnit:getPoint()
|
||||||
|
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
||||||
|
self:T({initdcscoord})
|
||||||
|
else
|
||||||
|
initdcscoord = _event.IniDCSUnit:getPoint()
|
||||||
|
initcoord = COORDINATE:NewFromVec3(initdcscoord)
|
||||||
|
self:T({initdcscoord})
|
||||||
|
end
|
||||||
|
|
||||||
|
--local surface = _unit:GetCoordinate():GetSurfaceType()
|
||||||
|
local surface = initcoord:GetSurfaceType()
|
||||||
|
|
||||||
if surface == land.SurfaceType.WATER then
|
if surface == land.SurfaceType.WATER then
|
||||||
|
self:T("Wet feet!")
|
||||||
wetfeet = true
|
wetfeet = true
|
||||||
end
|
end
|
||||||
-- all checks passed, get going.
|
-- all checks passed, get going.
|
||||||
if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land
|
if self.csarUsePara == false or (self.csarUsePara and wetfeet ) then --shagrat check parameter LandingAfterEjection, if true don't spawn a Pilot from EJECTION event, wait for the Chute to land
|
||||||
local _freq = self:_GenerateADFFrequency()
|
|
||||||
self:_AddCsar(_coalition, _unit:GetCountry(), _unit:GetCoordinate() , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none")
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location
|
|
||||||
elseif (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then
|
|
||||||
self:I({EVENT=_event})
|
|
||||||
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
|
||||||
local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute'
|
|
||||||
local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot"
|
|
||||||
local _country = _event.initiator:getCountry()
|
|
||||||
local _coalition = coalition.getCountryCoalition( _country )
|
|
||||||
if _coalition == self.coalition then
|
|
||||||
local _freq = self:_GenerateADFFrequency()
|
local _freq = self:_GenerateADFFrequency()
|
||||||
self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq})
|
self:_AddCsar(_coalition, _unit:GetCountry(), initcoord , _unit:GetTypeName(), _unit:GetName(), _event.IniPlayerName, _freq, false, "none")
|
||||||
self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location.
|
return self
|
||||||
|
end
|
||||||
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
|
|
||||||
elseif _event.id == EVENTS.Land then
|
elseif _event.id == EVENTS.Land then
|
||||||
self:T(self.lid .. " Landing")
|
self:T(self.lid .. " Landing")
|
||||||
@@ -1012,38 +1084,60 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
if _unit == nil then
|
if _unit == nil then
|
||||||
self:T(self.lid .. " Unit nil on landing")
|
self:T(self.lid .. " Unit nil on landing")
|
||||||
return -- error!
|
return self -- error!
|
||||||
end
|
end
|
||||||
|
|
||||||
local _coalition = _event.IniCoalition
|
--local _coalition = _event.IniCoalition
|
||||||
|
local _coalition = _event.IniGroup:GetCoalition()
|
||||||
if _coalition ~= self.coalition then
|
if _coalition ~= self.coalition then
|
||||||
return --ignore!
|
self:T(self.lid .. " Wrong coalition")
|
||||||
|
return self --ignore!
|
||||||
end
|
end
|
||||||
|
|
||||||
self.takenOff[_event.IniUnitName] = nil
|
self.takenOff[_event.IniUnitName] = nil
|
||||||
|
|
||||||
local _place = _event.Place -- Wrapper.Airbase#AIRBASE
|
local _place = _event.Place -- Wrapper.Airbase#AIRBASE
|
||||||
|
|
||||||
if _place == nil then
|
if _place == nil then
|
||||||
self:T(self.lid .. " Landing Place Nil")
|
self:T(self.lid .. " Landing Place Nil")
|
||||||
return -- error!
|
return self -- error!
|
||||||
end
|
end
|
||||||
|
|
||||||
-- anyone on board?
|
-- anyone on board?
|
||||||
if self.inTransitGroups[_event.IniUnitName] == nil then
|
if self.inTransitGroups[_event.IniUnitName] == nil then
|
||||||
-- ignore
|
-- ignore
|
||||||
return
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
if _place:GetCoalition() == self.coalition or _place:GetCoalition() == coalition.side.NEUTRAL then
|
||||||
|
self:__Landed(2,_event.IniUnitName, _place)
|
||||||
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
|
self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
|
||||||
else
|
else
|
||||||
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
self:T(string.format("Airfield %d, Unit %d", _place:GetCoalition(), _unit:GetCoalition()))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---- shagrat on event LANDING_AFTER_EJECTION spawn pilot at parachute location
|
||||||
|
if (_event.id == EVENTS.LandingAfterEjection and self.csarUsePara == true) then
|
||||||
|
self:T("LANDING_AFTER_EJECTION")
|
||||||
|
local _LandingPos = COORDINATE:NewFromVec3(_event.initiator:getPosition().p)
|
||||||
|
local _unitname = "Aircraft" --_event.initiator:getName() or "Aircraft" --shagrat Optional use of Object name which is unfortunately 'f15_Pilot_Parachute'
|
||||||
|
local _typename = "Ejected Pilot" --_event.Initiator.getTypeName() or "Ejected Pilot"
|
||||||
|
local _country = _event.initiator:getCountry()
|
||||||
|
local _coalition = coalition.getCountryCoalition( _country )
|
||||||
|
self:T("Country = ".._country.." Coalition = ".._coalition)
|
||||||
|
if _coalition == self.coalition then
|
||||||
|
local _freq = self:_GenerateADFFrequency()
|
||||||
|
self:I({coalition=_coalition,country= _country, coord=_LandingPos, name=_unitname, player=_event.IniPlayerName, freq=_freq})
|
||||||
|
self:_AddCsar(_coalition, _country, _LandingPos, nil, _unitname, _event.IniPlayerName, _freq, false, "none")--shagrat add CSAR at Parachute location.
|
||||||
|
|
||||||
|
Unit.destroy(_event.initiator) -- shagrat remove static Pilot model
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1116,6 +1210,38 @@ function CSAR:_RemoveNameFromDownedPilots(name,force)
|
|||||||
return found
|
return found
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- [User] Set callsign options for TTS output. See @{Wrapper.Group#GROUP.GetCustomCallSign}() on how to set customized callsigns.
|
||||||
|
-- @param #CSAR self
|
||||||
|
-- @param #boolean ShortCallsign If true, only call out the major flight number
|
||||||
|
-- @param #boolean Keepnumber If true, keep the **customized callsign** in the #GROUP name for players as-is, no amendments or numbers.
|
||||||
|
-- @param #table CallsignTranslations (optional) Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized
|
||||||
|
-- callsigns from playername or group name.
|
||||||
|
-- @return #CSAR self
|
||||||
|
function CSAR:SetCallSignOptions(ShortCallsign,Keepnumber,CallsignTranslations)
|
||||||
|
if not ShortCallsign or ShortCallsign == false then
|
||||||
|
self.ShortCallsign = false
|
||||||
|
else
|
||||||
|
self.ShortCallsign = true
|
||||||
|
end
|
||||||
|
self.Keepnumber = Keepnumber or false
|
||||||
|
self.CallsignTranslations = CallsignTranslations
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Check if a name is in downed pilot table and remove it.
|
||||||
|
-- @param #CSAR self
|
||||||
|
-- @param #string UnitName
|
||||||
|
-- @return #string CallSign
|
||||||
|
function CSAR:_GetCustomCallSign(UnitName)
|
||||||
|
local callsign = Unitname
|
||||||
|
local unit = UNIT:FindByName(UnitName)
|
||||||
|
if unit and unit:IsAlive() then
|
||||||
|
local group = unit:GetGroup()
|
||||||
|
callsign = group:GetCustomCallSign(self.ShortCallsign,self.Keepnumber,self.CallsignTranslations)
|
||||||
|
end
|
||||||
|
return callsign
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Check state of wounded group.
|
--- (Internal) Check state of wounded group.
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param #string heliname heliname
|
-- @param #string heliname heliname
|
||||||
@@ -1143,7 +1269,7 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname)
|
|||||||
self.heliVisibleMessage[_lookupKeyHeli] = nil
|
self.heliVisibleMessage[_lookupKeyHeli] = nil
|
||||||
self.heliCloseMessage[_lookupKeyHeli] = nil
|
self.heliCloseMessage[_lookupKeyHeli] = nil
|
||||||
self.landedStatus[_lookupKeyHeli] = nil
|
self.landedStatus[_lookupKeyHeli] = nil
|
||||||
self:T("...helinunit nil!")
|
self:T("...heliunit nil!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1172,9 +1298,9 @@ function CSAR:_CheckWoundedGroupStatus(heliname,woundedgroupname)
|
|||||||
local dist = UTILS.MetersToNM(self.autosmokedistance)
|
local dist = UTILS.MetersToNM(self.autosmokedistance)
|
||||||
disttext = string.format("%.0fnm",dist)
|
disttext = string.format("%.0fnm",dist)
|
||||||
end
|
end
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", _heliName, _pilotName, disttext), self.messageTime,false,true)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nI'll pop a smoke when you are %s away.\nLand or hover by the smoke.", self:_GetCustomCallSign(_heliName), _pilotName, disttext), self.messageTime,false,true)
|
||||||
else
|
else
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", _heliName, _pilotName), self.messageTime,false,true)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. I hear you! Finally, that is music in my ears!\nRequest a flare or smoke if you need.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
|
||||||
end
|
end
|
||||||
--mark as shown for THIS heli and THIS group
|
--mark as shown for THIS heli and THIS group
|
||||||
self.heliVisibleMessage[_lookupKeyHeli] = true
|
self.heliVisibleMessage[_lookupKeyHeli] = true
|
||||||
@@ -1238,8 +1364,8 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
|
|||||||
_maxUnits = self.max_units
|
_maxUnits = self.max_units
|
||||||
end
|
end
|
||||||
if _unitsInHelicopter + 1 > _maxUnits then
|
if _unitsInHelicopter + 1 > _maxUnits then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, _heliName, _unitsInHelicopter, _unitsInHelicopter), self.messageTime)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s, %s. We\'re already crammed with %d guys! Sorry!", _pilotName, self:_GetCustomCallSign(_heliName), _unitsInHelicopter, _unitsInHelicopter), self.messageTime,false,false,true)
|
||||||
return true
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
local found,downedgrouptable = self:_CheckNameInDownedPilots(_woundedGroupName)
|
local found,downedgrouptable = self:_CheckNameInDownedPilots(_woundedGroupName)
|
||||||
@@ -1256,11 +1382,27 @@ function CSAR:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupNam
|
|||||||
_woundedGroup:Destroy(false)
|
_woundedGroup:Destroy(false)
|
||||||
self:_RemoveNameFromDownedPilots(_woundedGroupName,true)
|
self:_RemoveNameFromDownedPilots(_woundedGroupName,true)
|
||||||
|
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", _heliName, _pilotName), self.messageTime,true,true)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s I\'m in! Get to the MASH ASAP! ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,true,true)
|
||||||
|
|
||||||
self:__Boarded(5,_heliName,_woundedGroupName)
|
self:_UpdateUnitCargoMass(_heliName)
|
||||||
|
|
||||||
return true
|
self:__Boarded(5,_heliName,_woundedGroupName,grouptable.desc)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to calculate and set Unit internal cargo mass
|
||||||
|
-- @param #CSAR self
|
||||||
|
-- @param #string _heliName Unit name
|
||||||
|
-- @return #CSAR self
|
||||||
|
function CSAR:_UpdateUnitCargoMass(_heliName)
|
||||||
|
self:T(self.lid .. " _UpdateUnitCargoMass")
|
||||||
|
local calculatedMass = self:_PilotsOnboard(_heliName)*80
|
||||||
|
local Unit = UNIT:FindByName(_heliName)
|
||||||
|
if Unit then
|
||||||
|
Unit:SetUnitInternalCargo(calculatedMass)
|
||||||
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) Move group to destination.
|
--- (Internal) Move group to destination.
|
||||||
@@ -1277,7 +1419,6 @@ function CSAR:_OrderGroupToMoveToPoint(_leader, _destination)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (internal) Function to check if the heli door(s) are open. Thanks to Shadowze.
|
--- (internal) Function to check if the heli door(s) are open. Thanks to Shadowze.
|
||||||
-- @param #CSAR self
|
-- @param #CSAR self
|
||||||
-- @param #string unit_name Name of unit.
|
-- @param #string unit_name Name of unit.
|
||||||
@@ -1311,9 +1452,9 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
|
|
||||||
if self.heliCloseMessage[_lookupKeyHeli] == nil then
|
if self.heliCloseMessage[_lookupKeyHeli] == nil then
|
||||||
if self.autosmoke == true then
|
if self.autosmoke == true then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", _heliName, _pilotName), self.messageTime,false,true)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land or hover at the smoke.", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
|
||||||
else
|
else
|
||||||
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", _heliName, _pilotName), self.messageTime,false,true)
|
self:_DisplayMessageToSAR(_heliUnit, string.format("%s: %s. You\'re close now! Land in a safe place, I will go there ", self:_GetCustomCallSign(_heliName), _pilotName), self.messageTime,false,true)
|
||||||
end
|
end
|
||||||
self.heliCloseMessage[_lookupKeyHeli] = true
|
self.heliCloseMessage[_lookupKeyHeli] = true
|
||||||
end
|
end
|
||||||
@@ -1326,7 +1467,8 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
local _time = self.landedStatus[_lookupKeyHeli]
|
local _time = self.landedStatus[_lookupKeyHeli]
|
||||||
if _time == nil then
|
if _time == nil then
|
||||||
self.landedStatus[_lookupKeyHeli] = math.floor( (_distance - self.loadDistance) / 3.6 )
|
self.landedStatus[_lookupKeyHeli] = math.floor( (_distance - self.loadDistance) / 3.6 )
|
||||||
_time = self.landedStatus[_lookupKeyHeli]
|
_time = self.landedStatus[_lookupKeyHeli]
|
||||||
|
_woundedGroup:OptionAlarmStateGreen()
|
||||||
self:_OrderGroupToMoveToPoint(_woundedGroup, _heliUnit:GetCoordinate())
|
self:_OrderGroupToMoveToPoint(_woundedGroup, _heliUnit:GetCoordinate())
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Wait till " .. _pilotName .. " gets in. \nETA " .. _time .. " more seconds.", self.messageTime, false)
|
self:_DisplayMessageToSAR(_heliUnit, "Wait till " .. _pilotName .. " gets in. \nETA " .. _time .. " more seconds.", self.messageTime, false)
|
||||||
else
|
else
|
||||||
@@ -1335,24 +1477,24 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
end
|
end
|
||||||
--if _time <= 0 or _distance < self.loadDistance then
|
--if _time <= 0 or _distance < self.loadDistance then
|
||||||
if _distance < self.loadDistance + 5 or _distance <= 13 then
|
if _distance < self.loadDistance + 5 or _distance <= 13 then
|
||||||
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
|
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||||
return true
|
return false
|
||||||
else
|
else
|
||||||
self.landedStatus[_lookupKeyHeli] = nil
|
self.landedStatus[_lookupKeyHeli] = nil
|
||||||
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
||||||
return false
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if (_distance < self.loadDistance) then
|
if (_distance < self.loadDistance) then
|
||||||
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
|
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||||
return true
|
return false
|
||||||
else
|
else
|
||||||
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
||||||
return false
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1365,7 +1507,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
end
|
end
|
||||||
|
|
||||||
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
|
if _heliUnit:InAir() and _unitsInHelicopter + 1 <= _maxUnits then
|
||||||
-- TODO - make variable
|
-- DONE - make variable
|
||||||
if _distance < self.rescuehoverdistance then
|
if _distance < self.rescuehoverdistance then
|
||||||
|
|
||||||
--check height!
|
--check height!
|
||||||
@@ -1373,7 +1515,7 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
if leaderheight < 0 then leaderheight = 0 end
|
if leaderheight < 0 then leaderheight = 0 end
|
||||||
local _height = _heliUnit:GetHeight() - leaderheight
|
local _height = _heliUnit:GetHeight() - leaderheight
|
||||||
|
|
||||||
-- TODO - make variable
|
-- DONE - make variable
|
||||||
if _height <= self.rescuehoverheight then
|
if _height <= self.rescuehoverheight then
|
||||||
|
|
||||||
local _time = self.hoverStatus[_lookupKeyHeli]
|
local _time = self.hoverStatus[_lookupKeyHeli]
|
||||||
@@ -1389,18 +1531,19 @@ function CSAR:_CheckCloseWoundedGroup(_distance, _heliUnit, _heliName, _woundedG
|
|||||||
if _time > 0 then
|
if _time > 0 then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Hovering above " .. _pilotName .. ". \n\nHold hover for " .. _time .. " seconds to winch them up. \n\nIf the countdown stops you\'re too far away!", self.messageTime, true)
|
||||||
else
|
else
|
||||||
if self.pilotmustopendoors and not self:_IsLoadingDoorOpen(_heliName) then
|
if self.pilotmustopendoors and (self:_IsLoadingDoorOpen(_heliName) == false) then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me in!", self.messageTime, true, true)
|
||||||
return true
|
return false
|
||||||
else
|
else
|
||||||
self.hoverStatus[_lookupKeyHeli] = nil
|
self.hoverStatus[_lookupKeyHeli] = nil
|
||||||
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
self:_PickupUnit(_heliUnit, _pilotName, _woundedGroup, _woundedGroupName)
|
||||||
return false
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
_reset = false
|
_reset = false
|
||||||
else
|
else
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true)
|
self:_DisplayMessageToSAR(_heliUnit, "Too high to winch " .. _pilotName .. " \nReduce height and hover for 10 seconds!", self.messageTime, true,true)
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1449,7 +1592,7 @@ function CSAR:_ScheduledSARFlight(heliname,groupname, isairport)
|
|||||||
|
|
||||||
if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then
|
if ( _dist < self.FARPRescueDistance or isairport ) and _heliUnit:InAir() == false then
|
||||||
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
|
if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname) == false then
|
||||||
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true)
|
self:_DisplayMessageToSAR(_heliUnit, "Open the door to let me out!", self.messageTime, true, true)
|
||||||
else
|
else
|
||||||
self:_RescuePilots(_heliUnit)
|
self:_RescuePilots(_heliUnit)
|
||||||
return
|
return
|
||||||
@@ -1478,9 +1621,12 @@ function CSAR:_RescuePilots(_heliUnit)
|
|||||||
|
|
||||||
self.inTransitGroups[_heliName] = nil
|
self.inTransitGroups[_heliName] = nil
|
||||||
|
|
||||||
local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", _heliName, PilotsSaved)
|
local _txt = string.format("%s: The %d pilot(s) have been taken to the\nmedical clinic. Good job!", self:_GetCustomCallSign(_heliName), PilotsSaved)
|
||||||
|
|
||||||
self:_DisplayMessageToSAR(_heliUnit, _txt, self.messageTime)
|
self:_DisplayMessageToSAR(_heliUnit, _txt, self.messageTime)
|
||||||
|
|
||||||
|
self:_UpdateUnitCargoMass(_heliName)
|
||||||
|
|
||||||
-- trigger event
|
-- trigger event
|
||||||
self:__Rescued(-1,_heliUnit,_heliName, PilotsSaved)
|
self:__Rescued(-1,_heliUnit,_heliName, PilotsSaved)
|
||||||
return self
|
return self
|
||||||
@@ -1514,16 +1660,11 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
|
|||||||
local _clear = _clear or nil
|
local _clear = _clear or nil
|
||||||
local _time = _time or self.messageTime
|
local _time = _time or self.messageTime
|
||||||
if _override or not self.suppressmessages then
|
if _override or not self.suppressmessages then
|
||||||
local m = MESSAGE:New(_text,_time,"Info",_clear):ToGroup(group)
|
local m = MESSAGE:New(_text,_time,"CSAR",_clear):ToGroup(group)
|
||||||
end
|
end
|
||||||
-- integrate SRS
|
-- integrate SRS
|
||||||
if _speak and self.useSRS then
|
if _speak and self.useSRS then
|
||||||
local srstext = SOUNDTEXT:New(_text)
|
self.SRSQueue:NewTransmission(_text,nil,self.msrs,nil,2)
|
||||||
local path = self.SRSPath
|
|
||||||
local modulation = self.SRSModulation
|
|
||||||
local channel = self.SRSchannel
|
|
||||||
local msrs = MSRS:New(path,channel,modulation)
|
|
||||||
msrs:PlaySoundText(srstext, 2)
|
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1668,7 +1809,7 @@ function CSAR:_SignalFlare(_unitName)
|
|||||||
else
|
else
|
||||||
_distance = string.format("%.1fkm",_closest.distance)
|
_distance = string.format("%.1fkm",_closest.distance)
|
||||||
end
|
end
|
||||||
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
|
local _msg = string.format("%s - Popping signal flare at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
|
||||||
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
|
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
|
||||||
|
|
||||||
local _coord = _closest.pilot:GetCoordinate()
|
local _coord = _closest.pilot:GetCoordinate()
|
||||||
@@ -1722,7 +1863,7 @@ function CSAR:_Reqsmoke( _unitName )
|
|||||||
else
|
else
|
||||||
_distance = string.format("%.1fkm",_closest.distance/1000)
|
_distance = string.format("%.1fkm",_closest.distance/1000)
|
||||||
end
|
end
|
||||||
local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", _unitName, _clockDir, _distance)
|
local _msg = string.format("%s - Popping smoke at your %s o\'clock. Distance %s", self:_GetCustomCallSign(_unitName), _clockDir, _distance)
|
||||||
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
|
self:_DisplayMessageToSAR(_heli, _msg, self.messageTime, false, true, true)
|
||||||
local _coord = _closest.pilot:GetCoordinate()
|
local _coord = _closest.pilot:GetCoordinate()
|
||||||
local color = self.smokecolor
|
local color = self.smokecolor
|
||||||
@@ -1773,7 +1914,7 @@ function CSAR:_GetClosestMASH(_heli)
|
|||||||
|
|
||||||
if self.allowFARPRescue then
|
if self.allowFARPRescue then
|
||||||
local position = _heli:GetCoordinate()
|
local position = _heli:GetCoordinate()
|
||||||
local afb,distance = position:GetClosestAirbase2(nil,self.coalition)
|
local afb,distance = position:GetClosestAirbase(nil,self.coalition)
|
||||||
_shortestDistance = distance
|
_shortestDistance = distance
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1823,7 +1964,7 @@ function CSAR:_AddMedevacMenuItem()
|
|||||||
self:T(self.lid .. " _AddMedevacMenuItem")
|
self:T(self.lid .. " _AddMedevacMenuItem")
|
||||||
|
|
||||||
local coalition = self.coalition
|
local coalition = self.coalition
|
||||||
local allheligroupset = self.allheligroupset
|
local allheligroupset = self.allheligroupset -- Core.Set#SET_GROUP
|
||||||
local _allHeliGroups = allheligroupset:GetSetObjects()
|
local _allHeliGroups = allheligroupset:GetSetObjects()
|
||||||
|
|
||||||
-- rebuild units table
|
-- rebuild units table
|
||||||
@@ -1848,7 +1989,8 @@ function CSAR:_AddMedevacMenuItem()
|
|||||||
local groupname = _group:GetName()
|
local groupname = _group:GetName()
|
||||||
if self.addedTo[groupname] == nil then
|
if self.addedTo[groupname] == nil then
|
||||||
self.addedTo[groupname] = true
|
self.addedTo[groupname] = true
|
||||||
local _rootPath = MENU_GROUP:New(_group,"CSAR")
|
local menuname = self.topmenuname or "CSAR"
|
||||||
|
local _rootPath = MENU_GROUP:New(_group,menuname)
|
||||||
local _rootMenu1 = MENU_GROUP_COMMAND:New(_group,"List Active CSAR",_rootPath, self._DisplayActiveSAR,self,_unitName)
|
local _rootMenu1 = MENU_GROUP_COMMAND:New(_group,"List Active CSAR",_rootPath, self._DisplayActiveSAR,self,_unitName)
|
||||||
local _rootMenu2 = MENU_GROUP_COMMAND:New(_group,"Check Onboard",_rootPath, self._CheckOnboard,self,_unitName)
|
local _rootMenu2 = MENU_GROUP_COMMAND:New(_group,"Check Onboard",_rootPath, self._CheckOnboard,self,_unitName)
|
||||||
local _rootMenu3 = MENU_GROUP_COMMAND:New(_group,"Request Signal Flare",_rootPath, self._SignalFlare,self,_unitName)
|
local _rootMenu3 = MENU_GROUP_COMMAND:New(_group,"Request Signal Flare",_rootPath, self._SignalFlare,self,_unitName)
|
||||||
@@ -1925,13 +2067,17 @@ function CSAR:_GetClockDirection(_heli, _group)
|
|||||||
local DirectionVec3 = _playerPosition:GetDirectionVec3( _targetpostions )
|
local DirectionVec3 = _playerPosition:GetDirectionVec3( _targetpostions )
|
||||||
local Angle = _playerPosition:GetAngleDegrees( DirectionVec3 )
|
local Angle = _playerPosition:GetAngleDegrees( DirectionVec3 )
|
||||||
self:T(self.lid .. " _GetClockDirection"..tostring(Angle).." "..tostring(_heading))
|
self:T(self.lid .. " _GetClockDirection"..tostring(Angle).." "..tostring(_heading))
|
||||||
local clock = 12
|
local hours = 0
|
||||||
if _heading then
|
local clock = 12
|
||||||
local Aspect = Angle - _heading
|
if _heading and Angle then
|
||||||
if Aspect == 0 then Aspect = 360 end
|
clock = 12
|
||||||
clock = math.abs(UTILS.Round((Aspect / 30),0))
|
--if angle == 0 then angle = 360 end
|
||||||
if clock == 0 then clock = 12 end
|
clock = _heading-Angle
|
||||||
end
|
hours = (clock/30)*-1
|
||||||
|
clock = 12+hours
|
||||||
|
clock = UTILS.Round(clock,0)
|
||||||
|
if clock > 12 then clock = clock-12 end
|
||||||
|
end
|
||||||
return clock
|
return clock
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1954,10 +2100,13 @@ function CSAR:_AddBeaconToGroup(_group, _freq)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if _group:IsAlive() then
|
if _group:IsAlive() then
|
||||||
local _radioUnit = _group:GetUnit(1)
|
local _radioUnit = _group:GetUnit(1)
|
||||||
local Frequency = _freq -- Freq in Hertz
|
if _radioUnit then
|
||||||
local Sound = "l10n/DEFAULT/"..self.radioSound
|
local Frequency = _freq -- Freq in Hertz
|
||||||
trigger.action.radioTransmission(Sound, _radioUnit:GetPositionVec3(), 0, false, Frequency, 1000) -- Beacon in MP only runs for exactly 30secs straight
|
local Sound = "l10n/DEFAULT/"..self.radioSound
|
||||||
|
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
|
||||||
|
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, self.ADFRadioPwr or 1000) -- Beacon in MP only runs for exactly 30secs straight
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2023,7 +2172,7 @@ end
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
function CSAR:onafterStart(From, Event, To)
|
function CSAR:onafterStart(From, Event, To)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
self:I(self.lid .. "Started.")
|
self:I(self.lid .. "Started ("..self.version..")")
|
||||||
-- event handler
|
-- event handler
|
||||||
self:HandleEvent(EVENTS.Takeoff, self._EventHandler)
|
self:HandleEvent(EVENTS.Takeoff, self._EventHandler)
|
||||||
self:HandleEvent(EVENTS.Land, self._EventHandler)
|
self:HandleEvent(EVENTS.Land, self._EventHandler)
|
||||||
@@ -2032,7 +2181,11 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
||||||
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
|
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
|
||||||
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
|
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
|
||||||
if self.useprefix then
|
|
||||||
|
if self.allowbronco then
|
||||||
|
local prefixes = self.csarPrefix or {}
|
||||||
|
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(prefixes):FilterStart()
|
||||||
|
elseif self.useprefix then
|
||||||
local prefixes = self.csarPrefix or {}
|
local prefixes = self.csarPrefix or {}
|
||||||
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(prefixes):FilterCategoryHelicopter():FilterStart()
|
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(prefixes):FilterCategoryHelicopter():FilterStart()
|
||||||
else
|
else
|
||||||
@@ -2042,6 +2195,24 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
if self.wetfeettemplate then
|
if self.wetfeettemplate then
|
||||||
self.usewetfeet = true
|
self.usewetfeet = true
|
||||||
end
|
end
|
||||||
|
if self.useSRS then
|
||||||
|
local path = self.SRSPath
|
||||||
|
local modulation = self.SRSModulation
|
||||||
|
local channel = self.SRSchannel
|
||||||
|
self.msrs = MSRS:New(path,channel,modulation)
|
||||||
|
self.msrs:SetPort(self.SRSport)
|
||||||
|
self.msrs:SetLabel("CSAR")
|
||||||
|
self.msrs:SetCulture(self.SRSCulture)
|
||||||
|
self.msrs:SetCoalition(self.coalition)
|
||||||
|
self.msrs:SetVoice(self.SRSVoice)
|
||||||
|
self.msrs:SetGender(self.SRSGender)
|
||||||
|
if self.SRSGPathToCredentials then
|
||||||
|
self.msrs:SetGoogle(self.SRSGPathToCredentials)
|
||||||
|
end
|
||||||
|
self.msrs:SetVolume(self.SRSVolume)
|
||||||
|
self.msrs:SetLabel("CSAR")
|
||||||
|
self.SRSQueue = MSRSQUEUE:New("CSAR")
|
||||||
|
end
|
||||||
self:__Status(-10)
|
self:__Status(-10)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2178,6 +2349,29 @@ end
|
|||||||
function CSAR:onbeforeBoarded(From, Event, To, Heliname, Woundedgroupname)
|
function CSAR:onbeforeBoarded(From, Event, To, Heliname, Woundedgroupname)
|
||||||
self:T({From, Event, To, Heliname, Woundedgroupname})
|
self:T({From, Event, To, Heliname, Woundedgroupname})
|
||||||
self:_ScheduledSARFlight(Heliname,Woundedgroupname)
|
self:_ScheduledSARFlight(Heliname,Woundedgroupname)
|
||||||
|
local Unit = UNIT:FindByName(Heliname)
|
||||||
|
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
|
||||||
|
local playername = Unit:GetPlayerName()
|
||||||
|
local dropcoord = Unit:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||||
|
local dropvec2 = dropcoord:GetVec2()
|
||||||
|
self.PlayerTaskQueue:ForEach(
|
||||||
|
function (Task)
|
||||||
|
local task = Task -- Ops.PlayerTask#PLAYERTASK
|
||||||
|
local subtype = task:GetSubType()
|
||||||
|
-- right subtype?
|
||||||
|
if Event == subtype and not task:IsDone() then
|
||||||
|
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
|
||||||
|
if (targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2))
|
||||||
|
or (string.find(task.CSARPilotName,Woundedgroupname)) then
|
||||||
|
if task.Clients:HasUniqueID(playername) then
|
||||||
|
-- success
|
||||||
|
task:__Success(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2207,6 +2401,23 @@ function CSAR:onbeforeRescued(From, Event, To, HeliUnit, HeliName, PilotsSaved)
|
|||||||
self:T({From, Event, To, HeliName, HeliUnit})
|
self:T({From, Event, To, HeliName, HeliUnit})
|
||||||
self.rescues = self.rescues + 1
|
self.rescues = self.rescues + 1
|
||||||
self.rescuedpilots = self.rescuedpilots + PilotsSaved
|
self.rescuedpilots = self.rescuedpilots + PilotsSaved
|
||||||
|
local Unit = HeliUnit or UNIT:FindByName(HeliName)
|
||||||
|
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
|
||||||
|
local playername = Unit:GetPlayerName()
|
||||||
|
self.PlayerTaskQueue:ForEach(
|
||||||
|
function (Task)
|
||||||
|
local task = Task -- Ops.PlayerTask#PLAYERTASK
|
||||||
|
local subtype = task:GetSubType()
|
||||||
|
-- right subtype?
|
||||||
|
if Event == subtype and not task:IsDone() then
|
||||||
|
if task.Clients:HasUniqueID(playername) then
|
||||||
|
-- success
|
||||||
|
task:__Success(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2223,6 +2434,18 @@ function CSAR:onbeforePilotDown(From, Event, To, Group, Frequency, Leadername, C
|
|||||||
self:T({From, Event, To, Group, Frequency, Leadername, CoordinatesText})
|
self:T({From, Event, To, Group, Frequency, Leadername, CoordinatesText})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function called before Landed() event.
|
||||||
|
-- @param #CSAR self.
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event triggered.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #string HeliName Name of the #UNIT which has landed.
|
||||||
|
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where the heli landed.
|
||||||
|
function CSAR:onbeforeLanded(From, Event, To, HeliName, Airbase)
|
||||||
|
self:T({From, Event, To, HeliName, Airbase})
|
||||||
|
return self
|
||||||
|
end
|
||||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- End Ops.CSAR
|
-- End Ops.CSAR
|
||||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Ops** -- Combat Troops & Logistics Department.
|
--- **Ops** - Combat Troops & Logistics Department.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -22,13 +22,13 @@
|
|||||||
-- @module Ops.CTLD
|
-- @module Ops.CTLD
|
||||||
-- @image OPS_CTLD.jpg
|
-- @image OPS_CTLD.jpg
|
||||||
|
|
||||||
-- Date: Feb 2022
|
-- Last Update October 2022
|
||||||
|
|
||||||
do
|
do
|
||||||
|
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
--- **CTLD_ENGINEERING** class, extends Core.Base#BASE
|
--- **CTLD_ENGINEERING** class, extends Core.Base#BASE
|
||||||
--- @type CTLD_ENGINEERING
|
-- @type CTLD_ENGINEERING
|
||||||
-- @field #string ClassName
|
-- @field #string ClassName
|
||||||
-- @field #string lid
|
-- @field #string lid
|
||||||
-- @field #string Name
|
-- @field #string Name
|
||||||
@@ -74,29 +74,13 @@ CTLD_ENGINEERING = {
|
|||||||
self.Name = Name or "Engineer Squad" -- #string
|
self.Name = Name or "Engineer Squad" -- #string
|
||||||
self.Group = GROUP:FindByName(GroupName) -- Wrapper.Group#GROUP
|
self.Group = GROUP:FindByName(GroupName) -- Wrapper.Group#GROUP
|
||||||
self.Unit = self.Group:GetUnit(1) -- Wrapper.Unit#UNIT
|
self.Unit = self.Group:GetUnit(1) -- Wrapper.Unit#UNIT
|
||||||
--self.C_Ops = C_Ops -- Ops.CTLD#CTLD
|
|
||||||
self.HeliGroup = HeliGroup -- Wrapper.Group#GROUP
|
self.HeliGroup = HeliGroup -- Wrapper.Group#GROUP
|
||||||
self.HeliUnit = HeliUnit -- Wrapper.Unit#UNIT
|
self.HeliUnit = HeliUnit -- Wrapper.Unit#UNIT
|
||||||
--self.distance = Distance or UTILS.NMToMeters(1)
|
|
||||||
self.currwpt = nil -- Core.Point#COORDINATE
|
self.currwpt = nil -- Core.Point#COORDINATE
|
||||||
self.lid = string.format("%s (%s) | ",self.Name, self.Version)
|
self.lid = string.format("%s (%s) | ",self.Name, self.Version)
|
||||||
-- Start State.
|
-- Start State.
|
||||||
self.State = "Stopped"
|
self.State = "Stopped"
|
||||||
self.marktimer = 300 -- wait this many secs before trying a crate again
|
self.marktimer = 300 -- wait this many secs before trying a crate again
|
||||||
|
|
||||||
--[[ Add FSM transitions.
|
|
||||||
-- From State --> Event --> To State
|
|
||||||
self:AddTransition("Stopped", "Start", "Running") -- Start FSM.
|
|
||||||
self:AddTransition("*", "Status", "*")
|
|
||||||
self:AddTransition("*", "Search", "Searching")
|
|
||||||
self:AddTransition("*", "Move", "Moving")
|
|
||||||
self:AddTransition("*", "Arrive", "Arrived")
|
|
||||||
self:AddTransition("*", "Build", "Building")
|
|
||||||
self:AddTransition("*", "Done", "Running")
|
|
||||||
self:AddTransition("*", "Stop", "Stopped") -- Stop FSM.
|
|
||||||
|
|
||||||
self:__Start(5)
|
|
||||||
--]]
|
|
||||||
self:Start()
|
self:Start()
|
||||||
local parent = self:GetParent(self)
|
local parent = self:GetParent(self)
|
||||||
return self
|
return self
|
||||||
@@ -200,10 +184,8 @@ CTLD_ENGINEERING = {
|
|||||||
-- have we tried this cargo recently?
|
-- have we tried this cargo recently?
|
||||||
local tag = chalk.tag or "none"
|
local tag = chalk.tag or "none"
|
||||||
local timestamp = chalk.timestamp or 0
|
local timestamp = chalk.timestamp or 0
|
||||||
--self:I({chalk})
|
|
||||||
-- enough time gone?
|
-- enough time gone?
|
||||||
local gone = timer.getAbsTime() - timestamp
|
local gone = timer.getAbsTime() - timestamp
|
||||||
--self:I({time=gone})
|
|
||||||
if gone >= self.marktimer then
|
if gone >= self.marktimer then
|
||||||
ok = true
|
ok = true
|
||||||
_cargo:WipeMark()
|
_cargo:WipeMark()
|
||||||
@@ -287,7 +269,6 @@ CTLD_ENGINEERING = {
|
|||||||
if _point1 and _point2 then
|
if _point1 and _point2 then
|
||||||
local distance1 = _point1:Get2DDistance(_point2)
|
local distance1 = _point1:Get2DDistance(_point2)
|
||||||
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
||||||
--self:I({dist1=distance1, dist2=distance2})
|
|
||||||
if distance1 and type(distance1) == "number" then
|
if distance1 and type(distance1) == "number" then
|
||||||
return distance1
|
return distance1
|
||||||
elseif distance2 and type(distance2) == "number" then
|
elseif distance2 and type(distance2) == "number" then
|
||||||
@@ -306,6 +287,7 @@ CTLD_ENGINEERING = {
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
--- **CTLD_CARGO** class, extends Core.Base#BASE
|
--- **CTLD_CARGO** class, extends Core.Base#BASE
|
||||||
@@ -314,7 +296,7 @@ do
|
|||||||
-- @field #number ID ID of this cargo.
|
-- @field #number ID ID of this cargo.
|
||||||
-- @field #string Name Name for menu.
|
-- @field #string Name Name for menu.
|
||||||
-- @field #table Templates Table of #POSITIONABLE objects.
|
-- @field #table Templates Table of #POSITIONABLE objects.
|
||||||
-- @field #CTLD_CARGO.Enum CargoType Enumerator of Type.
|
-- @field #string CargoType Enumerator of Type.
|
||||||
-- @field #boolean HasBeenMoved Flag for moving.
|
-- @field #boolean HasBeenMoved Flag for moving.
|
||||||
-- @field #boolean LoadDirectly Flag for direct loading.
|
-- @field #boolean LoadDirectly Flag for direct loading.
|
||||||
-- @field #number CratesNeeded Crates needed to build.
|
-- @field #number CratesNeeded Crates needed to build.
|
||||||
@@ -326,7 +308,7 @@ do
|
|||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @field #CTLD_CARGO
|
-- @field #CTLD_CARGO CTLD_CARGO
|
||||||
CTLD_CARGO = {
|
CTLD_CARGO = {
|
||||||
ClassName = "CTLD_CARGO",
|
ClassName = "CTLD_CARGO",
|
||||||
ID = 0,
|
ID = 0,
|
||||||
@@ -343,9 +325,15 @@ CTLD_CARGO = {
|
|||||||
Mark = nil,
|
Mark = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
|
||||||
--- Define cargo types.
|
--- Define cargo types.
|
||||||
-- @field Enum
|
-- @type CTLD_CARGO.Enum
|
||||||
|
-- @field #string VEHICLE
|
||||||
|
-- @field #string TROOPS
|
||||||
|
-- @field #string FOB
|
||||||
|
-- @field #string CRATE
|
||||||
|
-- @field #string REPAIR
|
||||||
|
-- @field #string ENGINEERS
|
||||||
|
-- @field #string STATIC
|
||||||
CTLD_CARGO.Enum = {
|
CTLD_CARGO.Enum = {
|
||||||
VEHICLE = "Vehicle", -- #string vehicles
|
VEHICLE = "Vehicle", -- #string vehicles
|
||||||
TROOPS = "Troops", -- #string troops
|
TROOPS = "Troops", -- #string troops
|
||||||
@@ -353,7 +341,7 @@ CTLD_CARGO = {
|
|||||||
CRATE = "Crate", -- #string crate
|
CRATE = "Crate", -- #string crate
|
||||||
REPAIR = "Repair", -- #string repair
|
REPAIR = "Repair", -- #string repair
|
||||||
ENGINEERS = "Engineers", -- #string engineers
|
ENGINEERS = "Engineers", -- #string engineers
|
||||||
STATIC = "Static", -- #string engineers
|
STATIC = "Static", -- #string statics
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Function to create new CTLD_CARGO object.
|
--- Function to create new CTLD_CARGO object.
|
||||||
@@ -542,7 +530,7 @@ CTLD_CARGO = {
|
|||||||
|
|
||||||
--- Query crate type for STATIC
|
--- Query crate type for STATIC
|
||||||
-- @param #CTLD_CARGO self
|
-- @param #CTLD_CARGO self
|
||||||
-- @param #boolean
|
-- @return #boolean
|
||||||
function CTLD_CARGO:IsStatic()
|
function CTLD_CARGO:IsStatic()
|
||||||
if self.CargoType == "Static" then
|
if self.CargoType == "Static" then
|
||||||
return true
|
return true
|
||||||
@@ -551,23 +539,43 @@ CTLD_CARGO = {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add mark
|
||||||
|
-- @param #CTLD_CARGO self
|
||||||
|
-- @return #CTLD_CARGO self
|
||||||
function CTLD_CARGO:AddMark(Mark)
|
function CTLD_CARGO:AddMark(Mark)
|
||||||
self.Mark = Mark
|
self.Mark = Mark
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get mark
|
||||||
|
-- @param #CTLD_CARGO self
|
||||||
|
-- @return #string Mark
|
||||||
function CTLD_CARGO:GetMark(Mark)
|
function CTLD_CARGO:GetMark(Mark)
|
||||||
return self.Mark
|
return self.Mark
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Wipe mark
|
||||||
|
-- @param #CTLD_CARGO self
|
||||||
|
-- @return #CTLD_CARGO self
|
||||||
function CTLD_CARGO:WipeMark()
|
function CTLD_CARGO:WipeMark()
|
||||||
self.Mark = nil
|
self.Mark = nil
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get overall mass of a cargo object, i.e. crates needed x mass per crate
|
||||||
|
-- @param #CTLD_CARGO self
|
||||||
|
-- @return #number mass
|
||||||
|
function CTLD_CARGO:GetNetMass()
|
||||||
|
return self.CratesNeeded * self.PerCrateMass
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO CTLD
|
||||||
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **CTLD** class, extends Core.Base#BASE, Core.Fsm#FSM
|
--- **CTLD** class, extends Core.Base#BASE, Core.Fsm#FSM
|
||||||
-- @type CTLD
|
-- @type CTLD
|
||||||
@@ -691,6 +699,7 @@ do
|
|||||||
-- my_ctld.smokedistance = 2000 -- Only smoke or flare zones if requesting player unit is this far away (in meters)
|
-- my_ctld.smokedistance = 2000 -- Only smoke or flare zones if requesting player unit is this far away (in meters)
|
||||||
-- my_ctld.suppressmessages = false -- Set to true if you want to script your own messages.
|
-- my_ctld.suppressmessages = false -- Set to true if you want to script your own messages.
|
||||||
-- my_ctld.repairtime = 300 -- Number of seconds it takes to repair a unit.
|
-- my_ctld.repairtime = 300 -- Number of seconds it takes to repair a unit.
|
||||||
|
-- my_ctld.buildtime = 300 -- Number of seconds it takes to build a unit. Set to zero or nil to build instantly.
|
||||||
-- my_ctld.cratecountry = country.id.GERMANY -- ID of crates. Will default to country.id.RUSSIA for RED coalition setups.
|
-- my_ctld.cratecountry = country.id.GERMANY -- ID of crates. Will default to country.id.RUSSIA for RED coalition setups.
|
||||||
-- my_ctld.allowcratepickupagain = true -- allow re-pickup crates that were dropped.
|
-- my_ctld.allowcratepickupagain = true -- allow re-pickup crates that were dropped.
|
||||||
-- my_ctld.enableslingload = false -- allow cargos to be slingloaded - might not work for all cargo types
|
-- my_ctld.enableslingload = false -- allow cargos to be slingloaded - might not work for all cargo types
|
||||||
@@ -700,6 +709,7 @@ do
|
|||||||
-- my_ctld.basetype = "container_cargo" -- default shape of the cargo container
|
-- my_ctld.basetype = "container_cargo" -- default shape of the cargo container
|
||||||
-- my_ctld.droppedbeacontimeout = 600 -- dropped beacon lasts 10 minutes
|
-- my_ctld.droppedbeacontimeout = 600 -- dropped beacon lasts 10 minutes
|
||||||
-- my_ctld.usesubcats = false -- use sub-category names for crates, adds an extra menu layer in "Get Crates", useful if you have > 10 crate types.
|
-- my_ctld.usesubcats = false -- use sub-category names for crates, adds an extra menu layer in "Get Crates", useful if you have > 10 crate types.
|
||||||
|
-- my_ctld.placeCratesAhead = false -- place crates straight ahead of the helicopter, in a random way. If true, crates are more neatly sorted.
|
||||||
--
|
--
|
||||||
-- ## 2.1 User functions
|
-- ## 2.1 User functions
|
||||||
--
|
--
|
||||||
@@ -722,7 +732,8 @@ do
|
|||||||
-- ["Mi-24P"] = {type="Mi-24P", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
|
-- ["Mi-24P"] = {type="Mi-24P", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
|
||||||
-- ["Mi-24V"] = {type="Mi-24V", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
|
-- ["Mi-24V"] = {type="Mi-24V", crates=true, troops=true, cratelimit = 2, trooplimit = 8, length = 18, cargoweightlimit = 700},
|
||||||
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000},
|
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 25, cargoweightlimit = 19000},
|
||||||
-- ["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500},
|
-- ["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500},
|
||||||
|
-- ["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200},
|
||||||
--
|
--
|
||||||
-- ### 2.1.2 Activate and deactivate zones
|
-- ### 2.1.2 Activate and deactivate zones
|
||||||
--
|
--
|
||||||
@@ -817,6 +828,8 @@ do
|
|||||||
--
|
--
|
||||||
-- To award player with points, using the SCORING Class (SCORING: my_Scoring, CTLD: CTLD_Cargotransport)
|
-- To award player with points, using the SCORING Class (SCORING: my_Scoring, CTLD: CTLD_Cargotransport)
|
||||||
--
|
--
|
||||||
|
-- my_scoring = SCORING:New("Combat Transport")
|
||||||
|
--
|
||||||
-- function CTLD_Cargotransport:OnAfterCratesDropped(From, Event, To, Group, Unit, Cargotable)
|
-- function CTLD_Cargotransport:OnAfterCratesDropped(From, Event, To, Group, Unit, Cargotable)
|
||||||
-- local points = 10
|
-- local points = 10
|
||||||
-- if Unit then
|
-- if Unit then
|
||||||
@@ -870,8 +883,13 @@ do
|
|||||||
--
|
--
|
||||||
-- ## 5. Support for Hercules mod by Anubis
|
-- ## 5. Support for Hercules mod by Anubis
|
||||||
--
|
--
|
||||||
-- Basic support for the Hercules mod By Anubis has been build into CTLD. Currently this does **not** cover objects and troops which can
|
-- Basic support for the Hercules mod By Anubis has been build into CTLD - that is you can load/drop/build the same way and for the same objects as
|
||||||
-- be loaded from the Rearm/Refuel menu, i.e. you can drop them into the field, but you cannot use them in functions scripted with this class.
|
-- the helicopters (main method).
|
||||||
|
-- To cover objects and troops which can be loaded from the groud crew Rearm/Refuel menu (F8), you need to use @{#CTLD_HERCULES.New}() and link
|
||||||
|
-- this object to your CTLD setup (alternative method). In this case, do **not** use the `Hercules_Cargo.lua` or `Hercules_Cargo_CTLD.lua` which are part of the mod
|
||||||
|
-- in your mission!
|
||||||
|
--
|
||||||
|
-- ### 5.1 Create an own CTLD instance and allow the usage of the Hercules mod (main method)
|
||||||
--
|
--
|
||||||
-- local my_ctld = CTLD:New(coalition.side.BLUE,{"Helicargo", "Hercules"},"Lufttransportbrigade I")
|
-- local my_ctld = CTLD:New(coalition.side.BLUE,{"Helicargo", "Hercules"},"Lufttransportbrigade I")
|
||||||
--
|
--
|
||||||
@@ -882,10 +900,47 @@ do
|
|||||||
-- my_ctld.HercMaxAngels = 2000 -- for troop/cargo drop via chute in meters, ca 6000 ft
|
-- my_ctld.HercMaxAngels = 2000 -- for troop/cargo drop via chute in meters, ca 6000 ft
|
||||||
-- my_ctld.HercMaxSpeed = 77 -- 77mps or 270kph or 150kn
|
-- my_ctld.HercMaxSpeed = 77 -- 77mps or 270kph or 150kn
|
||||||
--
|
--
|
||||||
|
-- Hint: you can **only** airdrop from the Hercules if you are "in parameters", i.e. at or below `HercMaxSpeed` and in the AGL bracket between
|
||||||
|
-- `HercMinAngels` and `HercMaxAngels`!
|
||||||
|
--
|
||||||
-- Also, the following options need to be set to `true`:
|
-- Also, the following options need to be set to `true`:
|
||||||
--
|
--
|
||||||
-- my_ctld.useprefix = true -- this is true by default and MUST BE ON.
|
-- my_ctld.useprefix = true -- this is true by default and MUST BE ON.
|
||||||
--
|
--
|
||||||
|
-- ### 5.2 Integrate Hercules ground crew (F8 Menu) loadable objects (alternative method, use either the above OR this method, NOT both!)
|
||||||
|
--
|
||||||
|
-- Integrate to your CTLD instance like so, where `my_ctld` is a previously created CTLD instance:
|
||||||
|
--
|
||||||
|
-- my_ctld.enableHercules = false -- avoid dual loading via CTLD F10 and F8 ground crew
|
||||||
|
-- local herccargo = CTLD_HERCULES:New("blue", "Hercules Test", my_ctld)
|
||||||
|
--
|
||||||
|
-- You also need:
|
||||||
|
--
|
||||||
|
-- * A template called "Infantry" for 10 Paratroopers (as set via herccargo.infantrytemplate).
|
||||||
|
-- * Depending on what you are loading with the help of the ground crew, there are 42 more templates for the various vehicles that are loadable.
|
||||||
|
--
|
||||||
|
-- There's a **quick check output in the `dcs.log`** which tells you what's there and what not.
|
||||||
|
-- E.g.:
|
||||||
|
--
|
||||||
|
-- ...Checking template for APC BTR-82A Air [24998lb] (BTR-82A) ... MISSING)
|
||||||
|
-- ...Checking template for ART 2S9 NONA Skid [19030lb] (SAU 2-C9) ... MISSING)
|
||||||
|
-- ...Checking template for EWR SBORKA Air [21624lb] (Dog Ear radar) ... MISSING)
|
||||||
|
-- ...Checking template for Transport Tigr Air [15900lb] (Tigr_233036) ... OK)
|
||||||
|
--
|
||||||
|
-- Expected template names are the ones in the rounded brackets.
|
||||||
|
--
|
||||||
|
-- ### 5.2.1 Hints
|
||||||
|
--
|
||||||
|
-- The script works on the EVENTS.Shot trigger, which is used by the mod when you **drop cargo from the Hercules while flying**. Unloading on the ground does
|
||||||
|
-- not achieve anything here. If you just want to unload on the ground, use the normal Moose CTLD (see 5.1).
|
||||||
|
--
|
||||||
|
-- DO NOT use the "splash damage" script together with this method! Your cargo will explode on the ground!
|
||||||
|
--
|
||||||
|
-- There are two ways of airdropping:
|
||||||
|
--
|
||||||
|
-- 1) Very low and very slow (>5m and <10m AGL) - here you can drop stuff which has "Skid" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||||
|
-- 2) Higher up and slow (>100m AGL) - here you can drop paratroopers and cargo which has "Air" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||||
|
--
|
||||||
-- Standard transport capabilities as per the real Hercules are:
|
-- Standard transport capabilities as per the real Hercules are:
|
||||||
--
|
--
|
||||||
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64}, -- 19t cargo, 64 paratroopers
|
-- ["Hercules"] = {type="Hercules", crates=true, troops=true, cratelimit = 7, trooplimit = 64}, -- 19t cargo, 64 paratroopers
|
||||||
@@ -924,7 +979,6 @@ CTLD = {
|
|||||||
FreeUHFFrequencies = {}, -- Table of UHF
|
FreeUHFFrequencies = {}, -- Table of UHF
|
||||||
FreeFMFrequencies = {}, -- Table of FM
|
FreeFMFrequencies = {}, -- Table of FM
|
||||||
CargoCounter = 0,
|
CargoCounter = 0,
|
||||||
wpZones = {},
|
|
||||||
Cargo_Troops = {}, -- generic troops objects
|
Cargo_Troops = {}, -- generic troops objects
|
||||||
Cargo_Crates = {}, -- generic crate objects
|
Cargo_Crates = {}, -- generic crate objects
|
||||||
Loaded_Cargo = {}, -- cargo aboard units
|
Loaded_Cargo = {}, -- cargo aboard units
|
||||||
@@ -1018,11 +1072,12 @@ CTLD.UnitTypes = {
|
|||||||
--Actually it's longer, but the center coord is off-center of the model.
|
--Actually it's longer, but the center coord is off-center of the model.
|
||||||
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
|
||||||
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
|
||||||
|
["Bronco-OV-10A"] = {type="Bronco-OV-10A", crates= false, troops=true, cratelimit = 0, trooplimit = 5, length = 13, cargoweightlimit = 1450},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- CTLD class version.
|
--- CTLD class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CTLD.version="1.0.10"
|
CTLD.version="1.0.18"
|
||||||
|
|
||||||
--- Instantiate a new CTLD.
|
--- Instantiate a new CTLD.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
@@ -1138,7 +1193,6 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
|||||||
self.CrateDistance = 35 -- list/load crates in this radius
|
self.CrateDistance = 35 -- list/load crates in this radius
|
||||||
self.ExtractFactor = 3.33 -- factor for troops extraction, i.e. CrateDistance * Extractfactor
|
self.ExtractFactor = 3.33 -- factor for troops extraction, i.e. CrateDistance * Extractfactor
|
||||||
self.prefixes = Prefixes or {"Cargoheli"}
|
self.prefixes = Prefixes or {"Cargoheli"}
|
||||||
--self.I({prefixes = self.prefixes})
|
|
||||||
self.useprefix = true
|
self.useprefix = true
|
||||||
|
|
||||||
self.maximumHoverHeight = 15
|
self.maximumHoverHeight = 15
|
||||||
@@ -1161,8 +1215,9 @@ function CTLD:New(Coalition, Prefixes, Alias)
|
|||||||
-- message suppression
|
-- message suppression
|
||||||
self.suppressmessages = false
|
self.suppressmessages = false
|
||||||
|
|
||||||
-- time to repair a unit/group
|
-- time to repairor build a unit/group
|
||||||
self.repairtime = 300
|
self.repairtime = 300
|
||||||
|
self.buildtime = 300
|
||||||
|
|
||||||
-- place spawned crates in front of aircraft
|
-- place spawned crates in front of aircraft
|
||||||
self.placeCratesAhead = false
|
self.placeCratesAhead = false
|
||||||
@@ -1431,6 +1486,19 @@ function CTLD:SetTroopDropZoneRadius(Radius)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (User) Add a PLAYERTASK - FSM events will check success
|
||||||
|
-- @param #CTLD self
|
||||||
|
-- @param Ops.PlayerTask#PLAYERTASK PlayerTask
|
||||||
|
-- @return #CTLD self
|
||||||
|
function CTLD:AddPlayerTask(PlayerTask)
|
||||||
|
self:T(self.lid .. " AddPlayerTask")
|
||||||
|
if not self.PlayerTaskQueue then
|
||||||
|
self.PlayerTaskQueue = FIFO:New()
|
||||||
|
end
|
||||||
|
self.PlayerTaskQueue:Push(PlayerTask,PlayerTask.PlayerTaskNr)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Event handler function
|
--- (Internal) Event handler function
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
@@ -1451,8 +1519,7 @@ function CTLD:_EventHandler(EventData)
|
|||||||
self:_RefreshF10Menus()
|
self:_RefreshF10Menus()
|
||||||
end
|
end
|
||||||
-- Herc support
|
-- Herc support
|
||||||
--self:T_unit:GetTypeName())
|
if self:IsHercules(_unit) and self.enableHercules then
|
||||||
if _unit:GetTypeName() == "Hercules" and self.enableHercules then
|
|
||||||
local unitname = event.IniUnitName or "none"
|
local unitname = event.IniUnitName or "none"
|
||||||
self.Loaded_Cargo[unitname] = nil
|
self.Loaded_Cargo[unitname] = nil
|
||||||
self:_RefreshF10Menus()
|
self:_RefreshF10Menus()
|
||||||
@@ -1492,6 +1559,8 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype)
|
|||||||
local instock = Cargotype:GetStock()
|
local instock = Cargotype:GetStock()
|
||||||
local cgoname = Cargotype:GetName()
|
local cgoname = Cargotype:GetName()
|
||||||
local cgotype = Cargotype:GetType()
|
local cgotype = Cargotype:GetType()
|
||||||
|
local cgonetmass = Cargotype:GetNetMass()
|
||||||
|
local maxloadable = self:_GetMaxLoadableMass(Unit)
|
||||||
if type(instock) == "number" and tonumber(instock) <= 0 and tonumber(instock) ~= -1 then
|
if type(instock) == "number" and tonumber(instock) <= 0 and tonumber(instock) ~= -1 then
|
||||||
-- nothing left over
|
-- nothing left over
|
||||||
self:_SendMessage(string.format("Sorry, all %s are gone!", cgoname), 10, false, Group)
|
self:_SendMessage(string.format("Sorry, all %s are gone!", cgoname), 10, false, Group)
|
||||||
@@ -1543,6 +1612,9 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype)
|
|||||||
if troopsize + numberonboard > trooplimit then
|
if troopsize + numberonboard > trooplimit then
|
||||||
self:_SendMessage("Sorry, we\'re crammed already!", 10, false, Group)
|
self:_SendMessage("Sorry, we\'re crammed already!", 10, false, Group)
|
||||||
return
|
return
|
||||||
|
elseif maxloadable < cgonetmass then
|
||||||
|
self:_SendMessage("Sorry, that\'s too heavy to load!", 10, false, Group)
|
||||||
|
return
|
||||||
else
|
else
|
||||||
self.CargoCounter = self.CargoCounter + 1
|
self.CargoCounter = self.CargoCounter + 1
|
||||||
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, cgotype, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
|
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, cgotype, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
|
||||||
@@ -1570,7 +1642,6 @@ function CTLD:_FindRepairNearby(Group, Unit, Repairtype)
|
|||||||
local distance = self:_GetDistance(v:GetCoordinate(),unitcoord)
|
local distance = self:_GetDistance(v:GetCoordinate(),unitcoord)
|
||||||
local unit = v:GetUnit(1) -- Wrapper.Unit#UNIT
|
local unit = v:GetUnit(1) -- Wrapper.Unit#UNIT
|
||||||
local desc = unit:GetDesc() or nil
|
local desc = unit:GetDesc() or nil
|
||||||
--self:I({desc = desc.attributes})
|
|
||||||
if distance < nearestDistance and distance ~= -1 and not desc.attributes.Infantry then
|
if distance < nearestDistance and distance ~= -1 and not desc.attributes.Infantry then
|
||||||
nearestGroup = v
|
nearestGroup = v
|
||||||
nearestGroupIndex = k
|
nearestGroupIndex = k
|
||||||
@@ -1607,7 +1678,6 @@ function CTLD:_FindRepairNearby(Group, Unit, Repairtype)
|
|||||||
-- walk through generics and find matching type
|
-- walk through generics and find matching type
|
||||||
local Cargotype = nil
|
local Cargotype = nil
|
||||||
for k,v in pairs(self.Cargo_Crates) do
|
for k,v in pairs(self.Cargo_Crates) do
|
||||||
--self:I({groupname,v.Templates})
|
|
||||||
if matchstring(groupname,v.Templates) and matchstring(groupname,Repairtype) then
|
if matchstring(groupname,v.Templates) and matchstring(groupname,Repairtype) then
|
||||||
Cargotype = v -- #CTLD_CARGO
|
Cargotype = v -- #CTLD_CARGO
|
||||||
break
|
break
|
||||||
@@ -1615,7 +1685,6 @@ function CTLD:_FindRepairNearby(Group, Unit, Repairtype)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Cargotype == nil then
|
if Cargotype == nil then
|
||||||
--self:_SendMessage("Can't find a matching group for " .. Repairtype, 10, false, Group)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
else
|
else
|
||||||
return nearestGroup, Cargotype
|
return nearestGroup, Cargotype
|
||||||
@@ -1634,17 +1703,14 @@ end
|
|||||||
function CTLD:_RepairObjectFromCrates(Group,Unit,Crates,Build,Number,Engineering)
|
function CTLD:_RepairObjectFromCrates(Group,Unit,Crates,Build,Number,Engineering)
|
||||||
self:T(self.lid .. " _RepairObjectFromCrates")
|
self:T(self.lid .. " _RepairObjectFromCrates")
|
||||||
local build = Build -- -- #CTLD.Buildable
|
local build = Build -- -- #CTLD.Buildable
|
||||||
--self:I({Build=Build})
|
|
||||||
local Repairtype = build.Template -- #string
|
local Repairtype = build.Template -- #string
|
||||||
local NearestGroup, CargoType = self:_FindRepairNearby(Group,Unit,Repairtype) -- Wrapper.Group#GROUP, #CTLD_CARGO
|
local NearestGroup, CargoType = self:_FindRepairNearby(Group,Unit,Repairtype) -- Wrapper.Group#GROUP, #CTLD_CARGO
|
||||||
--self:I({Repairtype=Repairtype, CargoType=CargoType, NearestGroup=NearestGroup})
|
|
||||||
if NearestGroup ~= nil then
|
if NearestGroup ~= nil then
|
||||||
if self.repairtime < 2 then self.repairtime = 30 end -- noob catch
|
if self.repairtime < 2 then self.repairtime = 30 end -- noob catch
|
||||||
if not Engineering then
|
if not Engineering then
|
||||||
self:_SendMessage(string.format("Repair started using %s taking %d secs", build.Name, self.repairtime), 10, false, Group)
|
self:_SendMessage(string.format("Repair started using %s taking %d secs", build.Name, self.repairtime), 10, false, Group)
|
||||||
end
|
end
|
||||||
-- now we can build ....
|
-- now we can build ....
|
||||||
--NearestGroup:Destroy(false)
|
|
||||||
local name = CargoType:GetName()
|
local name = CargoType:GetName()
|
||||||
local required = CargoType:GetCratesNeeded()
|
local required = CargoType:GetCratesNeeded()
|
||||||
local template = CargoType:GetTemplates()
|
local template = CargoType:GetTemplates()
|
||||||
@@ -1661,7 +1727,6 @@ function CTLD:_RepairObjectFromCrates(Group,Unit,Crates,Build,Number,Engineering
|
|||||||
desttimer:Start(self.repairtime - 1)
|
desttimer:Start(self.repairtime - 1)
|
||||||
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,object,true,NearestGroup:GetCoordinate())
|
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,object,true,NearestGroup:GetCoordinate())
|
||||||
buildtimer:Start(self.repairtime)
|
buildtimer:Start(self.repairtime)
|
||||||
--self:_BuildObjectFromCrates(Group,Unit,object)
|
|
||||||
else
|
else
|
||||||
if not Engineering then
|
if not Engineering then
|
||||||
self:_SendMessage("Can't repair this unit with " .. build.Name, 10, false, Group)
|
self:_SendMessage("Can't repair this unit with " .. build.Name, 10, false, Group)
|
||||||
@@ -1773,9 +1838,7 @@ end
|
|||||||
self:__TroopsExtracted(1,Group, Unit, nearestGroup)
|
self:__TroopsExtracted(1,Group, Unit, nearestGroup)
|
||||||
|
|
||||||
-- clean up:
|
-- clean up:
|
||||||
--table.remove(self.DroppedTroops, nearestGroupIndex)
|
|
||||||
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
|
if type(Cargotype.Templates) == "table" and Cargotype.Templates[2] then
|
||||||
--self:I("*****This CargoType has multiple templates: "..Cargotype.Name)
|
|
||||||
for _,_key in pairs (Cargotype.Templates) do
|
for _,_key in pairs (Cargotype.Templates) do
|
||||||
table.insert(secondarygroups,_key)
|
table.insert(secondarygroups,_key)
|
||||||
end
|
end
|
||||||
@@ -1823,6 +1886,8 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop)
|
|||||||
local drop = drop or false
|
local drop = drop or false
|
||||||
local ship = nil
|
local ship = nil
|
||||||
local width = 20
|
local width = 20
|
||||||
|
local distance = nil
|
||||||
|
local zone = nil
|
||||||
if not drop then
|
if not drop then
|
||||||
inzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD)
|
inzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD)
|
||||||
if not inzone then
|
if not inzone then
|
||||||
@@ -1924,7 +1989,6 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop)
|
|||||||
local width = width / 2
|
local width = width / 2
|
||||||
local Offy = math.random(-width,width)
|
local Offy = math.random(-width,width)
|
||||||
self.Spawned_Crates[self.CrateCounter] = SPAWNSTATIC:NewFromType(basetype,"Cargos",self.cratecountry)
|
self.Spawned_Crates[self.CrateCounter] = SPAWNSTATIC:NewFromType(basetype,"Cargos",self.cratecountry)
|
||||||
--:InitCoordinate(cratecoord)
|
|
||||||
:InitCargoMass(cgomass)
|
:InitCargoMass(cgomass)
|
||||||
:InitCargo(self.enableslingload)
|
:InitCargo(self.enableslingload)
|
||||||
:InitLinkToUnit(Ship,dist,Offy,0)
|
:InitLinkToUnit(Ship,dist,Offy,0)
|
||||||
@@ -1934,7 +1998,6 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop)
|
|||||||
:InitCoordinate(cratecoord)
|
:InitCoordinate(cratecoord)
|
||||||
:InitCargoMass(cgomass)
|
:InitCargoMass(cgomass)
|
||||||
:InitCargo(self.enableslingload)
|
:InitCargo(self.enableslingload)
|
||||||
--:InitLinkToUnit(Unit,OffsetX,OffsetY,OffsetAngle)
|
|
||||||
:Spawn(270,cratealias)
|
:Spawn(270,cratealias)
|
||||||
end
|
end
|
||||||
local templ = cargotype:GetTemplates()
|
local templ = cargotype:GetTemplates()
|
||||||
@@ -2063,7 +2126,6 @@ function CTLD:_GetDistance(_point1, _point2)
|
|||||||
if _point1 and _point2 then
|
if _point1 and _point2 then
|
||||||
local distance1 = _point1:Get2DDistance(_point2)
|
local distance1 = _point1:Get2DDistance(_point2)
|
||||||
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
local distance2 = _point1:DistanceFromPointVec2(_point2)
|
||||||
--self:I({dist1=distance1, dist2=distance2})
|
|
||||||
if distance1 and type(distance1) == "number" then
|
if distance1 and type(distance1) == "number" then
|
||||||
return distance1
|
return distance1
|
||||||
elseif distance2 and type(distance2) == "number" then
|
elseif distance2 and type(distance2) == "number" then
|
||||||
@@ -2102,11 +2164,7 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight)
|
|||||||
local maxmass = 2000
|
local maxmass = 2000
|
||||||
local maxloadable = 2000
|
local maxloadable = 2000
|
||||||
if not _ignoreweight then
|
if not _ignoreweight then
|
||||||
loadedmass = self:_GetUnitCargoMass(_unit)
|
maxloadable = self:_GetMaxLoadableMass(_unit)
|
||||||
unittype = _unit:GetTypeName()
|
|
||||||
capabilities = self:_GetUnitCapabilities(_unit) -- #CTLD.UnitCapabilities
|
|
||||||
maxmass = capabilities.cargoweightlimit or 2000
|
|
||||||
maxloadable = maxmass - loadedmass
|
|
||||||
end
|
end
|
||||||
self:T(self.lid .. " Max loadable mass: " .. maxloadable)
|
self:T(self.lid .. " Max loadable mass: " .. maxloadable)
|
||||||
for _,_cargoobject in pairs (existingcrates) do
|
for _,_cargoobject in pairs (existingcrates) do
|
||||||
@@ -2284,6 +2342,21 @@ function CTLD:_GetUnitCargoMass(Unit)
|
|||||||
return loadedmass
|
return loadedmass
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Function to calculate max loadable mass left over.
|
||||||
|
-- @param #CTLD self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit
|
||||||
|
-- @return #number maxloadable Max loadable mass in kg
|
||||||
|
function CTLD:_GetMaxLoadableMass(Unit)
|
||||||
|
self:T(self.lid .. " _GetMaxLoadableMass")
|
||||||
|
if not Unit then return 0 end
|
||||||
|
local loadable = 0
|
||||||
|
local loadedmass = self:_GetUnitCargoMass(Unit)
|
||||||
|
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitCapabilities
|
||||||
|
local maxmass = capabilities.cargoweightlimit or 2000 -- max 2 tons
|
||||||
|
loadable = maxmass - loadedmass
|
||||||
|
return loadable
|
||||||
|
end
|
||||||
|
|
||||||
--- (Internal) Function to calculate and set Unit internal cargo mass
|
--- (Internal) Function to calculate and set Unit internal cargo mass
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param Wrapper.Unit#UNIT Unit
|
-- @param Wrapper.Unit#UNIT Unit
|
||||||
@@ -2291,9 +2364,6 @@ function CTLD:_UpdateUnitCargoMass(Unit)
|
|||||||
self:T(self.lid .. " _UpdateUnitCargoMass")
|
self:T(self.lid .. " _UpdateUnitCargoMass")
|
||||||
local calculatedMass = self:_GetUnitCargoMass(Unit)
|
local calculatedMass = self:_GetUnitCargoMass(Unit)
|
||||||
Unit:SetUnitInternalCargo(calculatedMass)
|
Unit:SetUnitInternalCargo(calculatedMass)
|
||||||
--local report = REPORT:New("Loadmaster report")
|
|
||||||
--report:Add("Carrying " .. calculatedMass .. "Kg")
|
|
||||||
--self:_SendMessage(report:Text(),10,false,Unit:GetGroup())
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2311,6 +2381,7 @@ function CTLD:_ListCargo(Group, Unit)
|
|||||||
local cratelimit = capabilities.cratelimit -- #number
|
local cratelimit = capabilities.cratelimit -- #number
|
||||||
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
|
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
|
||||||
local loadedmass = self:_GetUnitCargoMass(Unit) -- #number
|
local loadedmass = self:_GetUnitCargoMass(Unit) -- #number
|
||||||
|
local maxloadable = self:_GetMaxLoadableMass(Unit)
|
||||||
if self.Loaded_Cargo[unitname] then
|
if self.Loaded_Cargo[unitname] then
|
||||||
local no_troops = loadedcargo.Troopsloaded or 0
|
local no_troops = loadedcargo.Troopsloaded or 0
|
||||||
local no_crates = loadedcargo.Cratesloaded or 0
|
local no_crates = loadedcargo.Cratesloaded or 0
|
||||||
@@ -2345,11 +2416,11 @@ function CTLD:_ListCargo(Group, Unit)
|
|||||||
report:Add(" N O N E")
|
report:Add(" N O N E")
|
||||||
end
|
end
|
||||||
report:Add("------------------------------------------------------------")
|
report:Add("------------------------------------------------------------")
|
||||||
report:Add("Total Mass: ".. loadedmass .. " kg")
|
report:Add("Total Mass: ".. loadedmass .. " kg. Loadable: "..maxloadable.." kg.")
|
||||||
local text = report:Text()
|
local text = report:Text()
|
||||||
self:_SendMessage(text, 30, true, Group)
|
self:_SendMessage(text, 30, true, Group)
|
||||||
else
|
else
|
||||||
self:_SendMessage(string.format("Nothing loaded!\nTroop limit: %d | Crate limit %d",trooplimit,cratelimit), 10, false, Group)
|
self:_SendMessage(string.format("Nothing loaded!\nTroop limit: %d | Crate limit %d | Weight limit %d kgs",trooplimit,cratelimit,maxloadable), 10, false, Group)
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2453,7 +2524,7 @@ end
|
|||||||
-- @param Wrapper.Unit#UNIT Unit
|
-- @param Wrapper.Unit#UNIT Unit
|
||||||
-- @return #boolean Outcome
|
-- @return #boolean Outcome
|
||||||
function CTLD:IsHercules(Unit)
|
function CTLD:IsHercules(Unit)
|
||||||
if Unit:GetTypeName() == "Hercules" then
|
if Unit:GetTypeName() == "Hercules" or string.find(Unit:GetTypeName(),"Bronco") then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
@@ -2525,7 +2596,6 @@ function CTLD:_UnloadTroops(Group, Unit)
|
|||||||
end -- template loop
|
end -- template loop
|
||||||
cargo:SetWasDropped(true)
|
cargo:SetWasDropped(true)
|
||||||
-- engineering group?
|
-- engineering group?
|
||||||
--self:I("Dropped Troop Type: "..type)
|
|
||||||
if type == CTLD_CARGO.Enum.ENGINEERS then
|
if type == CTLD_CARGO.Enum.ENGINEERS then
|
||||||
self.Engineers = self.Engineers + 1
|
self.Engineers = self.Engineers + 1
|
||||||
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
||||||
@@ -2663,8 +2733,7 @@ end
|
|||||||
function CTLD:_BuildCrates(Group, Unit,Engineering)
|
function CTLD:_BuildCrates(Group, Unit,Engineering)
|
||||||
self:T(self.lid .. " _BuildCrates")
|
self:T(self.lid .. " _BuildCrates")
|
||||||
-- avoid users trying to build from flying Hercs
|
-- avoid users trying to build from flying Hercs
|
||||||
local type = Unit:GetTypeName()
|
if self:IsHercules(Unit) and self.enableHercules and not Engineering then
|
||||||
if type == "Hercules" and self.enableHercules and not Engineering then
|
|
||||||
local speed = Unit:GetVelocityKMH()
|
local speed = Unit:GetVelocityKMH()
|
||||||
if speed > 1 then
|
if speed > 1 then
|
||||||
self:_SendMessage("You need to land / stop to build something, Pilot!", 10, false, Group)
|
self:_SendMessage("You need to land / stop to build something, Pilot!", 10, false, Group)
|
||||||
@@ -2687,6 +2756,8 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
|
|||||||
local required = Crate:GetCratesNeeded()
|
local required = Crate:GetCratesNeeded()
|
||||||
local template = Crate:GetTemplates()
|
local template = Crate:GetTemplates()
|
||||||
local ctype = Crate:GetType()
|
local ctype = Crate:GetType()
|
||||||
|
local ccoord = Crate:GetPositionable():GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
--local testmarker = ccoord:MarkToAll("Crate found",true,"Build Position")
|
||||||
if not buildables[name] then
|
if not buildables[name] then
|
||||||
local object = {} -- #CTLD.Buildable
|
local object = {} -- #CTLD.Buildable
|
||||||
object.Name = name
|
object.Name = name
|
||||||
@@ -2695,6 +2766,7 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
|
|||||||
object.Template = template
|
object.Template = template
|
||||||
object.CanBuild = false
|
object.CanBuild = false
|
||||||
object.Type = ctype -- #CTLD_CARGO.Enum
|
object.Type = ctype -- #CTLD_CARGO.Enum
|
||||||
|
object.Coord = ccoord:GetVec2()
|
||||||
buildables[name] = object
|
buildables[name] = object
|
||||||
foundbuilds = true
|
foundbuilds = true
|
||||||
else
|
else
|
||||||
@@ -2738,7 +2810,13 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
|
|||||||
local build = _build -- #CTLD.Buildable
|
local build = _build -- #CTLD.Buildable
|
||||||
if build.CanBuild then
|
if build.CanBuild then
|
||||||
self:_CleanUpCrates(crates,build,number)
|
self:_CleanUpCrates(crates,build,number)
|
||||||
self:_BuildObjectFromCrates(Group,Unit,build)
|
if self.buildtime and self.buildtime > 0 then
|
||||||
|
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate())
|
||||||
|
buildtimer:Start(self.buildtime)
|
||||||
|
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
|
||||||
|
else
|
||||||
|
self:_BuildObjectFromCrates(Group,Unit,build)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2837,13 +2915,13 @@ end
|
|||||||
-- @param Wrapper.Group#UNIT Unit
|
-- @param Wrapper.Group#UNIT Unit
|
||||||
-- @param #CTLD.Buildable Build
|
-- @param #CTLD.Buildable Build
|
||||||
-- @param #boolean Repair If true this is a repair and not a new build
|
-- @param #boolean Repair If true this is a repair and not a new build
|
||||||
-- @param Core.Point#COORDINATE Coordinate Location for repair (e.g. where the destroyed unit was)
|
-- @param Core.Point#COORDINATE RepairLocation Location for repair (e.g. where the destroyed unit was)
|
||||||
function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
|
function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
|
||||||
self:T(self.lid .. " _BuildObjectFromCrates")
|
self:T(self.lid .. " _BuildObjectFromCrates")
|
||||||
-- Spawn-a-crate-content
|
-- Spawn-a-crate-content
|
||||||
if Group and Group:IsAlive() then
|
if Group and Group:IsAlive() or (RepairLocation and not Repair) then
|
||||||
local position = Unit:GetCoordinate() or Group:GetCoordinate()
|
--local position = Unit:GetCoordinate() or Group:GetCoordinate()
|
||||||
local unitname = Unit:GetName() or Group:GetName()
|
--local unitname = Unit:GetName() or Group:GetName() or "Unknown"
|
||||||
local name = Build.Name
|
local name = Build.Name
|
||||||
local ctype = Build.Type -- #CTLD_CARGO.Enum
|
local ctype = Build.Type -- #CTLD_CARGO.Enum
|
||||||
local canmove = false
|
local canmove = false
|
||||||
@@ -2855,8 +2933,15 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
|
|||||||
if type(temptable) == "string" then
|
if type(temptable) == "string" then
|
||||||
temptable = {temptable}
|
temptable = {temptable}
|
||||||
end
|
end
|
||||||
local zone = ZONE_GROUP:New(string.format("Unload zone-%s",unitname),Group,100)
|
local zone = nil
|
||||||
local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
|
if RepairLocation and not Repair then
|
||||||
|
-- timed build
|
||||||
|
zone = ZONE_RADIUS:New(string.format("Build zone-%d",math.random(1,10000)),RepairLocation:GetVec2(),100)
|
||||||
|
else
|
||||||
|
zone = ZONE_GROUP:New(string.format("Unload zone-%d",math.random(1,10000)),Group,100)
|
||||||
|
end
|
||||||
|
--local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
|
||||||
|
local randomcoord = Build.Coord or zone:GetRandomCoordinate(35):GetVec2()
|
||||||
if Repair then
|
if Repair then
|
||||||
randomcoord = RepairLocation:GetVec2()
|
randomcoord = RepairLocation:GetVec2()
|
||||||
end
|
end
|
||||||
@@ -2865,7 +2950,7 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
|
|||||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||||
if canmove then
|
if canmove then
|
||||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template,alias)
|
||||||
:InitRandomizeUnits(true,20,2)
|
--:InitRandomizeUnits(true,20,2)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
:SpawnFromVec2(randomcoord)
|
:SpawnFromVec2(randomcoord)
|
||||||
else -- don't random position of e.g. SAM units build as FOB
|
else -- don't random position of e.g. SAM units build as FOB
|
||||||
@@ -2897,7 +2982,6 @@ function CTLD:_MoveGroupToZone(Group)
|
|||||||
local groupcoord = Group:GetCoordinate()
|
local groupcoord = Group:GetCoordinate()
|
||||||
-- Get closest zone of type
|
-- Get closest zone of type
|
||||||
local outcome, name, zone, distance = self:IsUnitInZone(Group,CTLD.CargoZoneType.MOVE)
|
local outcome, name, zone, distance = self:IsUnitInZone(Group,CTLD.CargoZoneType.MOVE)
|
||||||
--self:Tstring.format("Closest WP zone %s is %d meters",name,distance))
|
|
||||||
if (distance <= self.movetroopsdistance) and zone then
|
if (distance <= self.movetroopsdistance) and zone then
|
||||||
-- yes, we can ;)
|
-- yes, we can ;)
|
||||||
local groupname = Group:GetName()
|
local groupname = Group:GetName()
|
||||||
@@ -2962,7 +3046,7 @@ function CTLD:_RefreshF10Menus()
|
|||||||
local _unit = _group:GetUnit(1) -- Wrapper.Unit#UNIT Asume that there is only one unit in the flight for players
|
local _unit = _group:GetUnit(1) -- Wrapper.Unit#UNIT Asume that there is only one unit in the flight for players
|
||||||
if _unit then
|
if _unit then
|
||||||
if _unit:IsAlive() and _unit:IsPlayer() then
|
if _unit:IsAlive() and _unit:IsPlayer() then
|
||||||
if _unit:IsHelicopter() or (_unit:GetTypeName() == "Hercules" and self.enableHercules) then --ensure no stupid unit entries here
|
if _unit:IsHelicopter() or (self:IsHercules(_unit) and self.enableHercules) then --ensure no stupid unit entries here
|
||||||
local unitName = _unit:GetName()
|
local unitName = _unit:GetName()
|
||||||
_UnitList[unitName] = unitName
|
_UnitList[unitName] = unitName
|
||||||
end
|
end
|
||||||
@@ -3061,7 +3145,7 @@ function CTLD:_RefreshF10Menus()
|
|||||||
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
|
local buildmenu = MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates, self._BuildCrates, self, _group, _unit)
|
||||||
local repairmenu = MENU_GROUP_COMMAND:New(_group,"Repair",topcrates, self._RepairCrates, self, _group, _unit):Refresh()
|
local repairmenu = MENU_GROUP_COMMAND:New(_group,"Repair",topcrates, self._RepairCrates, self, _group, _unit):Refresh()
|
||||||
end
|
end
|
||||||
if unittype == "Hercules" then
|
if self:IsHercules(_unit) then
|
||||||
local hoverpars = MENU_GROUP_COMMAND:New(_group,"Show flight parameters",topmenu, self._ShowFlightParams, self, _group, _unit):Refresh()
|
local hoverpars = MENU_GROUP_COMMAND:New(_group,"Show flight parameters",topmenu, self._ShowFlightParams, self, _group, _unit):Refresh()
|
||||||
else
|
else
|
||||||
local hoverpars = MENU_GROUP_COMMAND:New(_group,"Show hover parameters",topmenu, self._ShowHoverParams, self, _group, _unit):Refresh()
|
local hoverpars = MENU_GROUP_COMMAND:New(_group,"Show hover parameters",topmenu, self._ShowHoverParams, self, _group, _unit):Refresh()
|
||||||
@@ -3079,7 +3163,7 @@ function CTLD:_RefreshF10Menus()
|
|||||||
--- [Internal] Function to check if a template exists in the mission.
|
--- [Internal] Function to check if a template exists in the mission.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param #table temptable Table of string names
|
-- @param #table temptable Table of string names
|
||||||
-- @return #boolen outcome
|
-- @return #boolean outcome
|
||||||
function CTLD:_CheckTemplates(temptable)
|
function CTLD:_CheckTemplates(temptable)
|
||||||
self:T(self.lid .. " _CheckTemplates")
|
self:T(self.lid .. " _CheckTemplates")
|
||||||
local outcome = true
|
local outcome = true
|
||||||
@@ -3336,7 +3420,21 @@ end
|
|||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Shipwidth)
|
function CTLD:AddCTLDZone(Name, Type, Color, Active, HasBeacon, Shiplength, Shipwidth)
|
||||||
self:T(self.lid .. " AddCTLDZone")
|
self:T(self.lid .. " AddCTLDZone")
|
||||||
|
|
||||||
|
local zone = ZONE:FindByName(Name)
|
||||||
|
if not zone and Type ~= CTLD.CargoZoneType.SHIP then
|
||||||
|
self:E(self.lid.."**** Zone does not exist: "..Name)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
if Type == CTLD.CargoZoneType.SHIP then
|
||||||
|
local Ship = UNIT:FindByName(Name)
|
||||||
|
if not Ship then
|
||||||
|
self:E(self.lid.."**** Ship does not exist: "..Name)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local ctldzone = {} -- #CTLD.CargoZone
|
local ctldzone = {} -- #CTLD.CargoZone
|
||||||
ctldzone.active = Active or false
|
ctldzone.active = Active or false
|
||||||
ctldzone.color = Color or SMOKECOLOR.Red
|
ctldzone.color = Color or SMOKECOLOR.Red
|
||||||
@@ -3582,9 +3680,10 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
|
|||||||
local zoneret = nil
|
local zoneret = nil
|
||||||
local zonewret = nil
|
local zonewret = nil
|
||||||
local zonenameret = nil
|
local zonenameret = nil
|
||||||
|
local unitcoord = Unit:GetCoordinate()
|
||||||
|
local unitVec2 = unitcoord:GetVec2()
|
||||||
for _,_cargozone in pairs(zonetable) do
|
for _,_cargozone in pairs(zonetable) do
|
||||||
local czone = _cargozone -- #CTLD.CargoZone
|
local czone = _cargozone -- #CTLD.CargoZone
|
||||||
local unitcoord = Unit:GetCoordinate()
|
|
||||||
local zonename = czone.name
|
local zonename = czone.name
|
||||||
local active = czone.active
|
local active = czone.active
|
||||||
local color = czone.color
|
local color = czone.color
|
||||||
@@ -3593,25 +3692,26 @@ function CTLD:IsUnitInZone(Unit,Zonetype)
|
|||||||
local zonewidth = 20
|
local zonewidth = 20
|
||||||
if Zonetype == CTLD.CargoZoneType.SHIP then
|
if Zonetype == CTLD.CargoZoneType.SHIP then
|
||||||
self:T("Checking Type Ship: "..zonename)
|
self:T("Checking Type Ship: "..zonename)
|
||||||
zone = UNIT:FindByName(zonename)
|
local ZoneUNIT = UNIT:FindByName(zonename)
|
||||||
zonecoord = zone:GetCoordinate()
|
zonecoord = ZoneUNIT:GetCoordinate()
|
||||||
zoneradius = czone.shiplength
|
zoneradius = czone.shiplength
|
||||||
zonewidth = czone.shipwidth
|
zonewidth = czone.shipwidth
|
||||||
|
zone = ZONE_UNIT:New( ZoneUNIT:GetName(), ZoneUNIT, zoneradius/2)
|
||||||
elseif ZONE:FindByName(zonename) then
|
elseif ZONE:FindByName(zonename) then
|
||||||
zone = ZONE:FindByName(zonename)
|
zone = ZONE:FindByName(zonename)
|
||||||
self:T("Checking Zone: "..zonename)
|
self:T("Checking Zone: "..zonename)
|
||||||
zonecoord = zone:GetCoordinate()
|
zonecoord = zone:GetCoordinate()
|
||||||
zoneradius = zone:GetRadius()
|
--zoneradius = 1500
|
||||||
zonewidth = zoneradius
|
zonewidth = zoneradius
|
||||||
elseif AIRBASE:FindByName(zonename) then
|
elseif AIRBASE:FindByName(zonename) then
|
||||||
zone = AIRBASE:FindByName(zonename):GetZone()
|
zone = AIRBASE:FindByName(zonename):GetZone()
|
||||||
self:T("Checking Zone: "..zonename)
|
self:T("Checking Zone: "..zonename)
|
||||||
zonecoord = zone:GetCoordinate()
|
zonecoord = zone:GetCoordinate()
|
||||||
zoneradius = zone:GetRadius()
|
zoneradius = 2000
|
||||||
zonewidth = zoneradius
|
zonewidth = zoneradius
|
||||||
end
|
end
|
||||||
local distance = self:_GetDistance(zonecoord,unitcoord)
|
local distance = self:_GetDistance(zonecoord,unitcoord)
|
||||||
if distance <= zoneradius and active then
|
if zone:IsVec2InZone(unitVec2) and active then
|
||||||
outcome = true
|
outcome = true
|
||||||
end
|
end
|
||||||
if maxdist > distance then
|
if maxdist > distance then
|
||||||
@@ -3787,8 +3887,8 @@ end
|
|||||||
local ucoord = Unit:GetCoordinate()
|
local ucoord = Unit:GetCoordinate()
|
||||||
local gheight = ucoord:GetLandHeight()
|
local gheight = ucoord:GetLandHeight()
|
||||||
local aheight = uheight - gheight -- height above ground
|
local aheight = uheight - gheight -- height above ground
|
||||||
local maxh = self.HercMinAngels-- 1500m
|
local minh = self.HercMinAngels-- 1500m
|
||||||
local minh = self.HercMaxAngels -- 5000m
|
local maxh = self.HercMaxAngels -- 5000m
|
||||||
local maxspeed = self.HercMaxSpeed -- 77 mps
|
local maxspeed = self.HercMaxSpeed -- 77 mps
|
||||||
-- DONE: TEST - Speed test for Herc, should not be above 280kph/150kn
|
-- DONE: TEST - Speed test for Herc, should not be above 280kph/150kn
|
||||||
local kmspeed = uspeed * 3.6
|
local kmspeed = uspeed * 3.6
|
||||||
@@ -3816,7 +3916,7 @@ end
|
|||||||
else
|
else
|
||||||
local minheight = UTILS.MetersToFeet(self.minimumHoverHeight)
|
local minheight = UTILS.MetersToFeet(self.minimumHoverHeight)
|
||||||
local maxheight = UTILS.MetersToFeet(self.maximumHoverHeight)
|
local maxheight = UTILS.MetersToFeet(self.maximumHoverHeight)
|
||||||
text = string.format("Hover parameters (autoload/drop):\n - Min height %dm \n - Max height %dm \n - Max speed 6fts \n - In parameter: %s", minheight, maxheight, htxt)
|
text = string.format("Hover parameters (autoload/drop):\n - Min height %dft \n - Max height %dft \n - Max speed 6ftps \n - In parameter: %s", minheight, maxheight, htxt)
|
||||||
end
|
end
|
||||||
self:_SendMessage(text, 10, false, Group)
|
self:_SendMessage(text, 10, false, Group)
|
||||||
return self
|
return self
|
||||||
@@ -3843,8 +3943,7 @@ end
|
|||||||
self:_SendMessage(text, 10, false, Group)
|
self:_SendMessage(text, 10, false, Group)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (Internal) Check if a unit is in a load zone and is hovering in parameters.
|
--- (Internal) Check if a unit is in a load zone and is hovering in parameters.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param Wrapper.Unit#UNIT Unit
|
-- @param Wrapper.Unit#UNIT Unit
|
||||||
@@ -3866,7 +3965,7 @@ end
|
|||||||
function CTLD:IsUnitInAir(Unit)
|
function CTLD:IsUnitInAir(Unit)
|
||||||
-- get speed and height
|
-- get speed and height
|
||||||
local minheight = self.minimumHoverHeight
|
local minheight = self.minimumHoverHeight
|
||||||
if self.enableHercules and Unit:GetTypeName() == "Hercules" then
|
if self.enableHercules and self:IsHercules(Unit) then
|
||||||
minheight = 5.1 -- herc is 5m AGL on the ground
|
minheight = 5.1 -- herc is 5m AGL on the ground
|
||||||
end
|
end
|
||||||
local uheight = Unit:GetHeight()
|
local uheight = Unit:GetHeight()
|
||||||
@@ -4114,9 +4213,6 @@ end
|
|||||||
self.Engineers = self.Engineers + 1
|
self.Engineers = self.Engineers + 1
|
||||||
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
|
||||||
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
|
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
|
||||||
--self:I(string.format("%s Injected Engineers %s into action!",self.lid, name))
|
|
||||||
else
|
|
||||||
--self:I(string.format("%s Injected Troops %s into action!",self.lid, name))
|
|
||||||
end
|
end
|
||||||
if self.eventoninject then
|
if self.eventoninject then
|
||||||
self:__TroopsDeployed(1,nil,nil,self.DroppedTroops[self.TroopCounter])
|
self:__TroopsDeployed(1,nil,nil,self.DroppedTroops[self.TroopCounter])
|
||||||
@@ -4198,7 +4294,7 @@ end
|
|||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
-- FSM functions
|
-- TODO FSM functions
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
--- (Internal) FSM Function onafterStart.
|
--- (Internal) FSM Function onafterStart.
|
||||||
@@ -4371,6 +4467,27 @@ end
|
|||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:onbeforeTroopsDeployed(From, Event, To, Group, Unit, Troops)
|
function CTLD:onbeforeTroopsDeployed(From, Event, To, Group, Unit, Troops)
|
||||||
self:T({From, Event, To})
|
self:T({From, Event, To})
|
||||||
|
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
|
||||||
|
local playername = Unit:GetPlayerName()
|
||||||
|
local dropcoord = Troops:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||||
|
local dropvec2 = dropcoord:GetVec2()
|
||||||
|
self.PlayerTaskQueue:ForEach(
|
||||||
|
function (Task)
|
||||||
|
local task = Task -- Ops.PlayerTask#PLAYERTASK
|
||||||
|
local subtype = task:GetSubType()
|
||||||
|
-- right subtype?
|
||||||
|
if Event == subtype and not task:IsDone() then
|
||||||
|
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
|
||||||
|
if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2) then
|
||||||
|
if task.Clients:HasUniqueID(playername) then
|
||||||
|
-- success
|
||||||
|
task:__Success(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4398,10 +4515,31 @@ end
|
|||||||
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
|
-- @param Wrapper.Group#GROUP Vehicle The #GROUP object of the vehicle or FOB build.
|
||||||
-- @return #CTLD self
|
-- @return #CTLD self
|
||||||
function CTLD:onbeforeCratesBuild(From, Event, To, Group, Unit, Vehicle)
|
function CTLD:onbeforeCratesBuild(From, Event, To, Group, Unit, Vehicle)
|
||||||
self:T({From, Event, To})
|
self:I({From, Event, To})
|
||||||
|
if Unit and Unit:IsPlayer() and self.PlayerTaskQueue then
|
||||||
|
local playername = Unit:GetPlayerName()
|
||||||
|
local dropcoord = Vehicle:GetCoordinate() or COORDINATE:New(0,0,0)
|
||||||
|
local dropvec2 = dropcoord:GetVec2()
|
||||||
|
self.PlayerTaskQueue:ForEach(
|
||||||
|
function (Task)
|
||||||
|
local task = Task -- Ops.PlayerTask#PLAYERTASK
|
||||||
|
local subtype = task:GetSubType()
|
||||||
|
-- right subtype?
|
||||||
|
if Event == subtype and not task:IsDone() then
|
||||||
|
local targetzone = task.Target:GetObject() -- Core.Zone#ZONE should be a zone in this case ....
|
||||||
|
if targetzone and targetzone.ClassName and string.match(targetzone.ClassName,"ZONE") and targetzone:IsVec2InZone(dropvec2) then
|
||||||
|
if task.Clients:HasUniqueID(playername) then
|
||||||
|
-- success
|
||||||
|
task:__Success(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- (Internal) FSM Function onbeforeTroopsRTB.
|
--- (Internal) FSM Function onbeforeTroopsRTB.
|
||||||
-- @param #CTLD self
|
-- @param #CTLD self
|
||||||
-- @param #string From State.
|
-- @param #string From State.
|
||||||
@@ -4487,7 +4625,6 @@ end
|
|||||||
local cargo = _cargo -- #CTLD_CARGO
|
local cargo = _cargo -- #CTLD_CARGO
|
||||||
local object = cargo:GetPositionable() -- Wrapper.Static#STATIC
|
local object = cargo:GetPositionable() -- Wrapper.Static#STATIC
|
||||||
if object and object:IsAlive() and cargo:WasDropped() then
|
if object and object:IsAlive() and cargo:WasDropped() then
|
||||||
self:I({_cargo})
|
|
||||||
statics[#statics+1] = cargo
|
statics[#statics+1] = cargo
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4504,7 +4641,6 @@ end
|
|||||||
template = { template }
|
template = { template }
|
||||||
end
|
end
|
||||||
for _,_name in pairs (template) do
|
for _,_name in pairs (template) do
|
||||||
--self:I(string.format("*** Saving CTLD: Matching %s with %s",name,_name))
|
|
||||||
if string.find(name,_name) and _cargo:GetType() ~= CTLD_CARGO.Enum.REPAIR then
|
if string.find(name,_name) and _cargo:GetType() ~= CTLD_CARGO.Enum.REPAIR then
|
||||||
match = true
|
match = true
|
||||||
cargo = thiscargo
|
cargo = thiscargo
|
||||||
@@ -4699,7 +4835,6 @@ end
|
|||||||
|
|
||||||
local loadeddata = {}
|
local loadeddata = {}
|
||||||
for line in file:lines() do
|
for line in file:lines() do
|
||||||
--self:I({line=type(line)})
|
|
||||||
loadeddata[#loadeddata+1] = line
|
loadeddata[#loadeddata+1] = line
|
||||||
end
|
end
|
||||||
file:close()
|
file:close()
|
||||||
@@ -4723,7 +4858,6 @@ end
|
|||||||
cargotemplates = UTILS.Split(cargotemplates,";")
|
cargotemplates = UTILS.Split(cargotemplates,";")
|
||||||
local size = tonumber(dataset[8])
|
local size = tonumber(dataset[8])
|
||||||
local mass = tonumber(dataset[9])
|
local mass = tonumber(dataset[9])
|
||||||
--self:I({groupname,vec3,cargoname,cargotemplates,cargotype,size,mass})
|
|
||||||
-- inject at Vec2
|
-- inject at Vec2
|
||||||
local dropzone = ZONE_RADIUS:New("DropZone",vec2,20)
|
local dropzone = ZONE_RADIUS:New("DropZone",vec2,20)
|
||||||
if cargotype == CTLD_CARGO.Enum.VEHICLE or cargotype == CTLD_CARGO.Enum.FOB then
|
if cargotype == CTLD_CARGO.Enum.VEHICLE or cargotype == CTLD_CARGO.Enum.FOB then
|
||||||
@@ -4738,8 +4872,6 @@ end
|
|||||||
local size = tonumber(dataset[8])
|
local size = tonumber(dataset[8])
|
||||||
local mass = tonumber(dataset[9])
|
local mass = tonumber(dataset[9])
|
||||||
local dropzone = ZONE_RADIUS:New("DropZone",vec2,20)
|
local dropzone = ZONE_RADIUS:New("DropZone",vec2,20)
|
||||||
-- STATIC,-84037,154,834021,Humvee,{Humvee;},Vehicle,1,100
|
|
||||||
-- STATIC,-84036,154,834018,Ammunition-1,ammo_cargo,Static,1,500
|
|
||||||
local injectstatic = nil
|
local injectstatic = nil
|
||||||
if cargotype == CTLD_CARGO.Enum.VEHICLE or cargotype == CTLD_CARGO.Enum.FOB then
|
if cargotype == CTLD_CARGO.Enum.VEHICLE or cargotype == CTLD_CARGO.Enum.FOB then
|
||||||
cargotemplates = string.gsub(cargotemplates,"{","")
|
cargotemplates = string.gsub(cargotemplates,"{","")
|
||||||
@@ -4760,10 +4892,13 @@ end
|
|||||||
end -- end do
|
end -- end do
|
||||||
|
|
||||||
do
|
do
|
||||||
--- Hercules Cargo Drop Events by Anubis Yinepu
|
--- **Hercules Cargo AIR Drop Events** by Anubis Yinepu
|
||||||
-- Moose CTLD OO refactoring by Applevangelist
|
-- Moose CTLD OO refactoring by Applevangelist
|
||||||
--
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- This script will only work for the Herculus mod by Anubis
|
-- TODO CTLD_HERCULES
|
||||||
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- This script will only work for the Herculus mod by Anubis, and only for **Air Dropping** cargo from the Hercules.
|
||||||
|
-- Use the standard Moose CTLD if you want to unload on the ground.
|
||||||
-- Payloads carried by pylons 11, 12 and 13 need to be declared in the Herculus_Loadout.lua file
|
-- Payloads carried by pylons 11, 12 and 13 need to be declared in the Herculus_Loadout.lua file
|
||||||
-- Except for Ammo pallets, this script will spawn whatever payload gets launched from pylons 11, 12 and 13
|
-- Except for Ammo pallets, this script will spawn whatever payload gets launched from pylons 11, 12 and 13
|
||||||
-- Pylons 11, 12 and 13 are moveable within the Herculus cargobay area
|
-- Pylons 11, 12 and 13 are moveable within the Herculus cargobay area
|
||||||
@@ -4784,7 +4919,7 @@ CTLD_HERCULES = {
|
|||||||
ClassName = "CTLD_HERCULES",
|
ClassName = "CTLD_HERCULES",
|
||||||
lid = "",
|
lid = "",
|
||||||
Name = "",
|
Name = "",
|
||||||
Version = "0.0.1",
|
Version = "0.0.2",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Define cargo types.
|
--- Define cargo types.
|
||||||
@@ -4851,7 +4986,6 @@ CTLD_HERCULES.Types = {
|
|||||||
["ART GVOZDIKA [34720lb]"] = {['name'] = "SAU Gvozdika", ['container'] = false},
|
["ART GVOZDIKA [34720lb]"] = {['name'] = "SAU Gvozdika", ['container'] = false},
|
||||||
["APC MTLB Air [26400lb]"] = {['name'] = "MTLB", ['container'] = true},
|
["APC MTLB Air [26400lb]"] = {['name'] = "MTLB", ['container'] = true},
|
||||||
["APC MTLB Skid [26290lb]"] = {['name'] = "MTLB", ['container'] = false},
|
["APC MTLB Skid [26290lb]"] = {['name'] = "MTLB", ['container'] = false},
|
||||||
["Generic Crate [20000lb]"] = {['name'] = "Hercules_Container_Parachute", ['container'] = true} --nothing generic in Moose CTLD
|
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Cargo Object
|
--- Cargo Object
|
||||||
@@ -4876,7 +5010,8 @@ CTLD_HERCULES.Types = {
|
|||||||
-- @return #CTLD_HERCULES self
|
-- @return #CTLD_HERCULES self
|
||||||
-- @usage
|
-- @usage
|
||||||
-- Integrate to your CTLD instance like so, where `my_ctld` is a previously created CTLD instance:
|
-- Integrate to your CTLD instance like so, where `my_ctld` is a previously created CTLD instance:
|
||||||
--
|
--
|
||||||
|
-- my_ctld.enableHercules = false -- avoid dual loading via CTLD F10 and F8 ground crew
|
||||||
-- local herccargo = CTLD_HERCULES:New("blue", "Hercules Test", my_ctld)
|
-- local herccargo = CTLD_HERCULES:New("blue", "Hercules Test", my_ctld)
|
||||||
--
|
--
|
||||||
-- You also need:
|
-- You also need:
|
||||||
@@ -4890,6 +5025,22 @@ CTLD_HERCULES.Types = {
|
|||||||
-- ...Checking template for Transport Tigr Air [15900lb] (Tigr_233036) ... OK)
|
-- ...Checking template for Transport Tigr Air [15900lb] (Tigr_233036) ... OK)
|
||||||
--
|
--
|
||||||
-- Expected template names are the ones in the rounded brackets.
|
-- Expected template names are the ones in the rounded brackets.
|
||||||
|
--
|
||||||
|
-- ### HINTS
|
||||||
|
--
|
||||||
|
-- The script works on the EVENTS.Shot trigger, which is used by the mod when you **drop cargo from the Hercules while flying**. Unloading on the ground does
|
||||||
|
-- not achieve anything here. If you just want to unload on the ground, use the normal Moose CTLD.
|
||||||
|
-- **Do not use** the **splash damage** script together with this, your cargo will just explode when reaching the ground!
|
||||||
|
--
|
||||||
|
-- ### Airdrops
|
||||||
|
--
|
||||||
|
-- There are two ways of airdropping:
|
||||||
|
-- 1) Very low and very slow (>5m and <10m AGL) - here you can drop stuff which has "Skid" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||||
|
-- 2) Higher up and slow (>100m AGL) - here you can drop paratroopers and cargo which has "Air" at the end of the cargo name (loaded via F8 Ground Crew menu)
|
||||||
|
--
|
||||||
|
-- ### General
|
||||||
|
--
|
||||||
|
-- Use either this method to integrate the Hercules **or** the one from the "normal" CTLD. Never both!
|
||||||
function CTLD_HERCULES:New(Coalition, Alias, CtldObject)
|
function CTLD_HERCULES:New(Coalition, Alias, CtldObject)
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self=BASE:Inherit(self, FSM:New()) -- #CTLD_HERCULES
|
local self=BASE:Inherit(self, FSM:New()) -- #CTLD_HERCULES
|
||||||
@@ -4944,8 +5095,7 @@ function CTLD_HERCULES:New(Coalition, Alias, CtldObject)
|
|||||||
|
|
||||||
-- Set some string id for output to DCS.log file.
|
-- Set some string id for output to DCS.log file.
|
||||||
self.lid=string.format("%s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown")
|
self.lid=string.format("%s (%s) | ", self.alias, self.coalition and UTILS.GetCoalitionName(self.coalition) or "unknown")
|
||||||
|
|
||||||
--self:HandleEvent(EVENTS.Birth,self._HandleBirth)
|
|
||||||
self:HandleEvent(EVENTS.Shot, self._HandleShot)
|
self:HandleEvent(EVENTS.Shot, self._HandleShot)
|
||||||
|
|
||||||
self:I(self.lid .. "Started")
|
self:I(self.lid .. "Started")
|
||||||
@@ -5059,13 +5209,8 @@ function CTLD_HERCULES:Cargo_SpawnStatic(Cargo_Drop_initiator,Cargo_Drop_Positio
|
|||||||
local position = Cargo_Drop_Position:GetVec2()
|
local position = Cargo_Drop_Position:GetVec2()
|
||||||
local Zone = ZONE_RADIUS:New("Cargo Static " .. math.random(1,10000),position,100)
|
local Zone = ZONE_RADIUS:New("Cargo Static " .. math.random(1,10000),position,100)
|
||||||
if not dead then
|
if not dead then
|
||||||
-- CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock)
|
|
||||||
local injectstatic = CTLD_CARGO:New(nil,"Cargo Static Group "..math.random(1,10000),"iso_container",CTLD_CARGO.Enum.STATIC,true,false,1,nil,true,4500,1)
|
local injectstatic = CTLD_CARGO:New(nil,"Cargo Static Group "..math.random(1,10000),"iso_container",CTLD_CARGO.Enum.STATIC,true,false,1,nil,true,4500,1)
|
||||||
self.CTLD:InjectStatics(Zone,injectstatic,true)
|
self.CTLD:InjectStatics(Zone,injectstatic,true)
|
||||||
else
|
|
||||||
--local static = SPAWNSTATIC:NewFromType("iso_container","Cargos",Cargo_Country)
|
|
||||||
--static.InitDead = true
|
|
||||||
--static:SpawnFromZone(Zone,CargoHeading)
|
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -5089,7 +5234,6 @@ function CTLD_HERCULES:Cargo_SpawnObjects(Cargo_Drop_initiator,Cargo_Drop_Direct
|
|||||||
self:T(self.lid .. 'Cargo_SpawnObjects')
|
self:T(self.lid .. 'Cargo_SpawnObjects')
|
||||||
|
|
||||||
local CargoHeading = self.CargoHeading
|
local CargoHeading = self.CargoHeading
|
||||||
--local Cargo_Drop_Position = {}
|
|
||||||
|
|
||||||
if offload_cargo == true or ParatrooperGroupSpawn == true then
|
if offload_cargo == true or ParatrooperGroupSpawn == true then
|
||||||
if ParatrooperGroupSpawn == true then
|
if ParatrooperGroupSpawn == true then
|
||||||
@@ -5097,18 +5241,11 @@ function CTLD_HERCULES:Cargo_SpawnObjects(Cargo_Drop_initiator,Cargo_Drop_Direct
|
|||||||
self:Soldier_SpawnGroup(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, Cargo_Country, 5)
|
self:Soldier_SpawnGroup(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, Cargo_Country, 5)
|
||||||
self:Soldier_SpawnGroup(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, Cargo_Country, 10)
|
self:Soldier_SpawnGroup(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, Cargo_Country, 10)
|
||||||
else
|
else
|
||||||
self:Cargo_SpawnGroup(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, Cargo_Country, 0)
|
self:Cargo_SpawnGroup(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, Cargo_Country)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if all_cargo_gets_destroyed == true or Cargo_over_water == true then
|
if all_cargo_gets_destroyed == true or Cargo_over_water == true then
|
||||||
if Container_Enclosed == true then
|
|
||||||
--self:Cargo_SpawnStatic(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, true, Cargo_Country)
|
|
||||||
if ParatrooperGroupSpawn == false then
|
|
||||||
--self:Cargo_SpawnStatic(Cargo_Drop_initiator,Cargo_Content_position, "Hercules_Container_Parachute_Static", CargoHeading, true, Cargo_Country)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--self:Cargo_SpawnStatic(Cargo_Drop_initiator,Cargo_Content_position, Cargo_Type_name, CargoHeading, true, Cargo_Country)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
if all_cargo_survive_to_the_ground == true then
|
if all_cargo_survive_to_the_ground == true then
|
||||||
if ParatrooperGroupSpawn == true then
|
if ParatrooperGroupSpawn == true then
|
||||||
@@ -5153,14 +5290,12 @@ function CTLD_HERCULES:Calculate_Object_Height_AGL(group)
|
|||||||
return height - lheight
|
return height - lheight
|
||||||
else
|
else
|
||||||
-- DCS object
|
-- DCS object
|
||||||
--self:T({group})
|
|
||||||
if group:isExist() then
|
if group:isExist() then
|
||||||
local dcsposition = group:getPosition().p
|
local dcsposition = group:getPosition().p
|
||||||
local dcsvec2 = {x = dcsposition.x, y = dcsposition.z} -- Vec2
|
local dcsvec2 = {x = dcsposition.x, y = dcsposition.z} -- Vec2
|
||||||
local height = math.floor(group:getPosition().p.y - land.getHeight(dcsvec2))
|
local height = math.floor(group:getPosition().p.y - land.getHeight(dcsvec2))
|
||||||
self.ObjectTracker[group.id_] = dcsposition -- Vec3
|
self.ObjectTracker[group.id_] = dcsposition -- Vec3
|
||||||
self:T(self.lid .. "Height " .. height)
|
self:T(self.lid .. "Height " .. height)
|
||||||
--self:T({group.id_,self.ObjectTracker[group.id_]})
|
|
||||||
return height
|
return height
|
||||||
else
|
else
|
||||||
return 0
|
return 0
|
||||||
@@ -5195,7 +5330,7 @@ function CTLD_HERCULES:Cargo_Track(cargo, initiator)
|
|||||||
if self:Check_SurfaceType(cargo.Cargo_Contents) == 2 or self:Check_SurfaceType(cargo.Cargo_Contents) == 3 then
|
if self:Check_SurfaceType(cargo.Cargo_Contents) == 2 or self:Check_SurfaceType(cargo.Cargo_Contents) == 3 then
|
||||||
cargo.Cargo_over_water = true--pallets gets destroyed in water
|
cargo.Cargo_over_water = true--pallets gets destroyed in water
|
||||||
end
|
end
|
||||||
local dcsvec3 = self.ObjectTracker[cargo.Cargo_Contents.id_] -- last known position
|
local dcsvec3 = self.ObjectTracker[cargo.Cargo_Contents.id_] or initiator:GetVec3() -- last known position
|
||||||
self:T("SPAWNPOSITION: ")
|
self:T("SPAWNPOSITION: ")
|
||||||
self:T({dcsvec3})
|
self:T({dcsvec3})
|
||||||
local Vec2 = {
|
local Vec2 = {
|
||||||
@@ -5298,7 +5433,7 @@ function CTLD_HERCULES:Cargo_Initialize(Initiator, Cargo_Contents, Cargo_Type_na
|
|||||||
|
|
||||||
local timer = TIMER:New(self.Cargo_Track,self,self.Cargo[self.j],Initiator)
|
local timer = TIMER:New(self.Cargo_Track,self,self.Cargo[self.j],Initiator)
|
||||||
self.Cargo[self.j].scheduleFunctionID = timer
|
self.Cargo[self.j].scheduleFunctionID = timer
|
||||||
timer:Start(5,2,600)
|
timer:Start(1,1,600)
|
||||||
|
|
||||||
else
|
else
|
||||||
-- no paras
|
-- no paras
|
||||||
@@ -5323,7 +5458,7 @@ function CTLD_HERCULES:Cargo_Initialize(Initiator, Cargo_Contents, Cargo_Type_na
|
|||||||
|
|
||||||
local timer = TIMER:New(self.Cargo_Track,self,self.Cargo[self.j],Initiator)
|
local timer = TIMER:New(self.Cargo_Track,self,self.Cargo[self.j],Initiator)
|
||||||
self.Cargo[self.j].scheduleFunctionID = timer
|
self.Cargo[self.j].scheduleFunctionID = timer
|
||||||
timer:Start(5,2,600)
|
timer:Start(1,1,600)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -5381,27 +5516,6 @@ end
|
|||||||
function CTLD_HERCULES:_HandleBirth(event)
|
function CTLD_HERCULES:_HandleBirth(event)
|
||||||
-- not sure what this is needed for? I think this for setting generic crates "content" setting.
|
-- not sure what this is needed for? I think this for setting generic crates "content" setting.
|
||||||
self:T(self.lid .. "Birth Event ID:" .. event.id)
|
self:T(self.lid .. "Birth Event ID:" .. event.id)
|
||||||
--[[
|
|
||||||
if event.id == EVENTS.Birth then
|
|
||||||
local desc = event.initiator:getDesc()
|
|
||||||
if desc["displayName"] == "Hercules" then
|
|
||||||
local grpTab = {}
|
|
||||||
grpTab['object'] = event.IniGroup
|
|
||||||
grpTab['name'] = event.IniGroupName
|
|
||||||
grpTab['cargoType'] = 'Container red 1'
|
|
||||||
grpTab['cargoNum'] = 1
|
|
||||||
grpTab['key'] = #self.carrierGroups + 1
|
|
||||||
|
|
||||||
table.insert(self.carrierGroups,grpTab)
|
|
||||||
|
|
||||||
local hercCargoMenu = MENU_GROUP:New(event.IniGroup,"CargoTypes",nil)
|
|
||||||
local mlrs = MENU_GROUP_COMMAND:New(event.IniGroup,"MLRS",hercCargoMenu,self.SetType,self,grpTab['key'],'MLRS',1)
|
|
||||||
local mlrs = MENU_GROUP_COMMAND:New(event.IniGroup,"Mortar",hercCargoMenu,self.SetType,self,grpTab['key'],'2B11 mortar',8)
|
|
||||||
local mlrs = MENU_GROUP_COMMAND:New(event.IniGroup,"M-109",hercCargoMenu,self.SetType,self,grpTab['key'],'M-109',1)
|
|
||||||
local mlrs = MENU_GROUP_COMMAND:New(event.IniGroup,"FOB Crate",hercCargoMenu,self.SetType,self,grpTab['key'],'Container red 1',1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
--]]
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
-- @field #string tankergroupname Name of the late activated tanker template group.
|
-- @field #string tankergroupname Name of the late activated tanker template group.
|
||||||
-- @field Wrapper.Group#GROUP tanker Tanker group.
|
-- @field Wrapper.Group#GROUP tanker Tanker group.
|
||||||
-- @field Wrapper.Airbase#AIRBASE airbase The home airbase object of the tanker. Normally the aircraft carrier.
|
-- @field Wrapper.Airbase#AIRBASE airbase The home airbase object of the tanker. Normally the aircraft carrier.
|
||||||
-- @field Core.Radio#BEACON beacon Tanker TACAN beacon.
|
-- @field Core.Beacon#BEACON beacon Tanker TACAN beacon.
|
||||||
-- @field #number TACANchannel TACAN channel. Default 1.
|
-- @field #number TACANchannel TACAN channel. Default 1.
|
||||||
-- @field #string TACANmode TACAN mode, i.e. "X" or "Y". Default "Y". Use only "Y" for AA TACAN stations!
|
-- @field #string TACANmode TACAN mode, i.e. "X" or "Y". Default "Y". Use only "Y" for AA TACAN stations!
|
||||||
-- @field #string TACANmorse TACAN morse code. Three letters identifying the TACAN station. Default "TKR".
|
-- @field #string TACANmorse TACAN morse code. Three letters identifying the TACAN station. Default "TKR".
|
||||||
@@ -784,10 +784,11 @@ end
|
|||||||
-- @param #RECOVERYTANKER self
|
-- @param #RECOVERYTANKER self
|
||||||
-- @param #number channel TACAN channel. Default 1.
|
-- @param #number channel TACAN channel. Default 1.
|
||||||
-- @param #string morse TACAN morse code identifier. Three letters. Default "TKR".
|
-- @param #string morse TACAN morse code identifier. Three letters. Default "TKR".
|
||||||
|
-- @param #string mode TACAN mode, which can be either "Y" (default) or "X".
|
||||||
-- @return #RECOVERYTANKER self
|
-- @return #RECOVERYTANKER self
|
||||||
function RECOVERYTANKER:SetTACAN(channel, morse)
|
function RECOVERYTANKER:SetTACAN(channel, morse, mode)
|
||||||
self.TACANchannel=channel or 1
|
self.TACANchannel=channel or 1
|
||||||
self.TACANmode="Y"
|
self.TACANmode=mode or "Y"
|
||||||
self.TACANmorse=morse or "TKR"
|
self.TACANmorse=morse or "TKR"
|
||||||
self.TACANon=true
|
self.TACANon=true
|
||||||
return self
|
return self
|
||||||
@@ -1625,7 +1626,6 @@ function RECOVERYTANKER:_ActivateTACAN(delay)
|
|||||||
if delay and delay>0 then
|
if delay and delay>0 then
|
||||||
|
|
||||||
-- Schedule TACAN activation.
|
-- Schedule TACAN activation.
|
||||||
--SCHEDULER:New(nil, self._ActivateTACAN, {self}, delay)
|
|
||||||
self:ScheduleOnce(delay, RECOVERYTANKER._ActivateTACAN, self)
|
self:ScheduleOnce(delay, RECOVERYTANKER._ActivateTACAN, self)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
--- **Sound** - Radio transmissions.
|
--- **Sound** - Radio transmissions.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Provide radio functionality to broadcast radio transmissions.
|
-- * Provide radio functionality to broadcast radio transmissions.
|
||||||
--
|
--
|
||||||
-- What are radio communications in DCS?
|
-- What are radio communications in DCS?
|
||||||
--
|
--
|
||||||
-- * Radio transmissions consist of **sound files** that are broadcasted on a specific **frequency** (e.g. 115MHz) and **modulation** (e.g. AM),
|
-- * Radio transmissions consist of **sound files** that are broadcasted on a specific **frequency** (e.g. 115MHz) and **modulation** (e.g. AM),
|
||||||
-- * They can be **subtitled** for a specific **duration**, the **power** in Watts of the transmiter's antenna can be set, and the transmission can be **looped**.
|
-- * They can be **subtitled** for a specific **duration**, the **power** in Watts of the transmitter's antenna can be set, and the transmission can be **looped**.
|
||||||
--
|
--
|
||||||
-- How to supply DCS my own Sound Files?
|
-- How to supply DCS my own Sound Files?
|
||||||
--
|
--
|
||||||
-- * Your sound files need to be encoded in **.ogg** or .wav,
|
-- * Your sound files need to be encoded in **.ogg** or .wav,
|
||||||
-- * Your sound files should be **as tiny as possible**. It is suggested you encode in .ogg with low bitrate and sampling settings,
|
-- * Your sound files should be **as tiny as possible**. It is suggested you encode in .ogg with low bitrate and sampling settings,
|
||||||
-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (wich can be decompressed like a .zip file),
|
-- * They need to be added in .\l10n\DEFAULT\ in you .miz file (which can be decompressed like a .zip file),
|
||||||
-- * For simplicity sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
|
-- * For simplicity sake, you can **let DCS' Mission Editor add the file** itself, by creating a new Trigger with the action "Sound to Country", and choosing your sound file and a country you don't use in your mission.
|
||||||
--
|
--
|
||||||
-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Wrapper.Positionable#POSITIONABLE}
|
-- Due to weird DCS quirks, **radio communications behave differently** if sent by a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or by any other @{Wrapper.Positionable#POSITIONABLE}
|
||||||
--
|
--
|
||||||
-- * If the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically,
|
-- * If the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, DCS will set the power of the transmission automatically,
|
||||||
-- * If the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped.
|
-- * If the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}, the transmisison can't be subtitled or looped.
|
||||||
--
|
--
|
||||||
-- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft,
|
-- Note that obviously, the **frequency** and the **modulation** of the transmission are important only if the players are piloting an **Advanced System Modelling** enabled aircraft,
|
||||||
-- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below).
|
-- like the A10C or the Mirage 2000C. They will **hear the transmission** if they are tuned on the **right frequency and modulation** (and if they are close enough - more on that below).
|
||||||
-- If an FC3 aircraft is used, it will **hear every communication, whatever the frequency and the modulation** is set to. The same is true for TACAN beacons. If your aircraft isn't compatible,
|
-- If an FC3 aircraft is used, it will **hear every communication, whatever the frequency and the modulation** is set to. The same is true for TACAN beacons. If your aircraft isn't compatible,
|
||||||
-- you won't hear/be able to use the TACAN beacon informations.
|
-- you won't hear/be able to use the TACAN beacon information.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -37,41 +37,41 @@
|
|||||||
|
|
||||||
|
|
||||||
--- *It's not true I had nothing on, I had the radio on.* -- Marilyn Monroe
|
--- *It's not true I had nothing on, I had the radio on.* -- Marilyn Monroe
|
||||||
--
|
--
|
||||||
-- # RADIO usage
|
-- # RADIO usage
|
||||||
--
|
--
|
||||||
-- There are 3 steps to a successful radio transmission.
|
-- There are 3 steps to a successful radio transmission.
|
||||||
--
|
--
|
||||||
-- * First, you need to **"add a @{#RADIO} object** to your @{Wrapper.Positionable#POSITIONABLE}. This is done using the @{Wrapper.Positionable#POSITIONABLE.GetRadio}() function,
|
-- * First, you need to **"add a @{#RADIO} object** to your @{Wrapper.Positionable#POSITIONABLE}. This is done using the @{Wrapper.Positionable#POSITIONABLE.GetRadio}() function,
|
||||||
-- * Then, you will **set the relevant parameters** to the transmission (see below),
|
-- * Then, you will **set the relevant parameters** to the transmission (see below),
|
||||||
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function.
|
-- * When done, you can actually **broadcast the transmission** (i.e. play the sound) with the @{RADIO.Broadcast}() function.
|
||||||
--
|
--
|
||||||
-- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Wrapper.Positionable#POSITIONABLE}
|
-- Methods to set relevant parameters for both a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP} or any other @{Wrapper.Positionable#POSITIONABLE}
|
||||||
--
|
--
|
||||||
-- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"),
|
-- * @{#RADIO.SetFileName}() : Sets the file name of your sound file (e.g. "Noise.ogg"),
|
||||||
-- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission.
|
-- * @{#RADIO.SetFrequency}() : Sets the frequency of your transmission.
|
||||||
-- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission.
|
-- * @{#RADIO.SetModulation}() : Sets the modulation of your transmission.
|
||||||
-- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead...
|
-- * @{#RADIO.SetLoop}() : Choose if you want the transmission to be looped. If you need your transmission to be looped, you might need a @{#BEACON} instead...
|
||||||
--
|
--
|
||||||
-- Additional Methods to set relevant parameters if the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}
|
-- Additional Methods to set relevant parameters if the transmitter is a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}
|
||||||
--
|
--
|
||||||
-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration,
|
-- * @{#RADIO.SetSubtitle}() : Set both the subtitle and its duration,
|
||||||
-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call
|
-- * @{#RADIO.NewUnitTransmission}() : Shortcut to set all the relevant parameters in one method call
|
||||||
--
|
--
|
||||||
-- Additional Methods to set relevant parameters if the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}
|
-- Additional Methods to set relevant parameters if the transmitter is any other @{Wrapper.Positionable#POSITIONABLE}
|
||||||
--
|
--
|
||||||
-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts
|
-- * @{#RADIO.SetPower}() : Sets the power of the antenna in Watts
|
||||||
-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call
|
-- * @{#RADIO.NewGenericTransmission}() : Shortcut to set all the relevant parameters in one method call
|
||||||
--
|
--
|
||||||
-- What is this power thing?
|
-- What is this power thing?
|
||||||
--
|
--
|
||||||
-- * If your transmission is sent by a @{Wrapper.Positionable#POSITIONABLE} other than a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna,
|
-- * If your transmission is sent by a @{Wrapper.Positionable#POSITIONABLE} other than a @{Wrapper.Unit#UNIT} or a @{Wrapper.Group#GROUP}, you can set the power of the antenna,
|
||||||
-- * Otherwise, DCS sets it automatically, depending on what's available on your Unit,
|
-- * Otherwise, DCS sets it automatically, depending on what's available on your Unit,
|
||||||
-- * If the player gets **too far** from the transmitter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**,
|
-- * If the player gets **too far** from the transmitter, or if the antenna is **too weak**, the transmission will **fade** and **become noisyer**,
|
||||||
-- * This an automated DCS calculation you have no say on,
|
-- * This an automated DCS calculation you have no say on,
|
||||||
-- * For reference, a standard VOR station has a 100 W antenna, a standard AA TACAN has a 120 W antenna, and civilian ATC's antenna usually range between 300 and 500 W,
|
-- * For reference, a standard VOR station has a 100 W antenna, a standard AA TACAN has a 120 W antenna, and civilian ATC's antenna usually range between 300 and 500 W,
|
||||||
-- * Note that if the transmission has a subtitle, it will be readable, regardless of the quality of the transmission.
|
-- * Note that if the transmission has a subtitle, it will be readable, regardless of the quality of the transmission.
|
||||||
--
|
--
|
||||||
-- @type RADIO
|
-- @type RADIO
|
||||||
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will transmit the radio calls.
|
-- @field Wrapper.Controllable#CONTROLLABLE Positionable The @{#CONTROLLABLE} that will transmit the radio calls.
|
||||||
-- @field #string FileName Name of the sound file played.
|
-- @field #string FileName Name of the sound file played.
|
||||||
@@ -98,19 +98,19 @@ RADIO = {
|
|||||||
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast.
|
--- Create a new RADIO Object. This doesn't broadcast a transmission, though, use @{#RADIO.Broadcast} to actually broadcast.
|
||||||
-- If you want to create a RADIO, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetRadio}() instead.
|
-- If you want to create a RADIO, you probably should use @{Wrapper.Positionable#POSITIONABLE.GetRadio}() instead.
|
||||||
-- @param #RADIO self
|
-- @param #RADIO self
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Positionable} that will receive radio capabilities.
|
-- @param Wrapper.Positionable#POSITIONABLE Positionable The @{Wrapper.Positionable#POSITIONABLE} that will receive radio capabilities.
|
||||||
-- @return #RADIO The RADIO object or #nil if Positionable is invalid.
|
-- @return #RADIO The RADIO object or #nil if Positionable is invalid.
|
||||||
function RADIO:New(Positionable)
|
function RADIO:New(Positionable)
|
||||||
|
|
||||||
-- Inherit base
|
-- Inherit base
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- Core.Radio#RADIO
|
local self = BASE:Inherit( self, BASE:New() ) -- Sound.Radio#RADIO
|
||||||
self:F(Positionable)
|
self:F(Positionable)
|
||||||
|
|
||||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
||||||
self.Positionable = Positionable
|
self.Positionable = Positionable
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E({error="The passed positionable is invalid, no RADIO created!", positionable=Positionable})
|
self:E({error="The passed positionable is invalid, no RADIO created!", positionable=Positionable})
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -137,19 +137,19 @@ end
|
|||||||
-- @return #RADIO self
|
-- @return #RADIO self
|
||||||
function RADIO:SetFileName(FileName)
|
function RADIO:SetFileName(FileName)
|
||||||
self:F2(FileName)
|
self:F2(FileName)
|
||||||
|
|
||||||
if type(FileName) == "string" then
|
if type(FileName) == "string" then
|
||||||
|
|
||||||
if FileName:find(".ogg") or FileName:find(".wav") then
|
if FileName:find(".ogg") or FileName:find(".wav") then
|
||||||
if not FileName:find("l10n/DEFAULT/") then
|
if not FileName:find("l10n/DEFAULT/") then
|
||||||
FileName = "l10n/DEFAULT/" .. FileName
|
FileName = "l10n/DEFAULT/" .. FileName
|
||||||
end
|
end
|
||||||
|
|
||||||
self.FileName = FileName
|
self.FileName = FileName
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E({"File name invalid. Maybe something wrong with the extension?", FileName})
|
self:E({"File name invalid. Maybe something wrong with the extension?", FileName})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -161,34 +161,34 @@ end
|
|||||||
-- @return #RADIO self
|
-- @return #RADIO self
|
||||||
function RADIO:SetFrequency(Frequency)
|
function RADIO:SetFrequency(Frequency)
|
||||||
self:F2(Frequency)
|
self:F2(Frequency)
|
||||||
|
|
||||||
if type(Frequency) == "number" then
|
if type(Frequency) == "number" then
|
||||||
|
|
||||||
-- If frequency is in range
|
-- If frequency is in range
|
||||||
-- if (Frequency >= 30 and Frequency <= 87.995) or (Frequency >= 108 and Frequency <= 173.995) or (Frequency >= 225 and Frequency <= 399.975) then
|
--if (Frequency >= 30 and Frequency <= 87.995) or (Frequency >= 108 and Frequency <= 173.995) or (Frequency >= 225 and Frequency <= 399.975) then
|
||||||
|
|
||||||
-- Convert frequency from MHz to Hz
|
-- Convert frequency from MHz to Hz
|
||||||
self.Frequency = Frequency * 1000000
|
self.Frequency = Frequency * 1000000
|
||||||
|
|
||||||
-- If the RADIO is attached to a UNIT or a GROUP, we need to send the DCS Command "SetFrequency" to change the UNIT or GROUP frequency
|
-- If the RADIO is attached to a UNIT or a GROUP, we need to send the DCS Command "SetFrequency" to change the UNIT or GROUP frequency
|
||||||
if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then
|
if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then
|
||||||
|
|
||||||
local commandSetFrequency={
|
local commandSetFrequency={
|
||||||
id = "SetFrequency",
|
id = "SetFrequency",
|
||||||
params = {
|
params = {
|
||||||
frequency = self.Frequency,
|
frequency = self.Frequency,
|
||||||
modulation = self.Modulation,
|
modulation = self.Modulation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self:T2(commandSetFrequency)
|
self:T2(commandSetFrequency)
|
||||||
self.Positionable:SetCommand(commandSetFrequency)
|
self.Positionable:SetCommand(commandSetFrequency)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
-- end
|
--end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E({"Frequency is not a number. Frequency unchanged.", Frequency})
|
self:E({"Frequency is not a number. Frequency unchanged.", Frequency})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -215,13 +215,13 @@ end
|
|||||||
-- @return #RADIO self
|
-- @return #RADIO self
|
||||||
function RADIO:SetPower(Power)
|
function RADIO:SetPower(Power)
|
||||||
self:F2(Power)
|
self:F2(Power)
|
||||||
|
|
||||||
if type(Power) == "number" then
|
if type(Power) == "number" then
|
||||||
self.Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
|
self.Power = math.floor(math.abs(Power)) --TODO Find what is the maximum power allowed by DCS and limit power to that
|
||||||
else
|
else
|
||||||
self:E({"Power is invalid. Power unchanged.", self.Power})
|
self:E({"Power is invalid. Power unchanged.", self.Power})
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ end
|
|||||||
-- -- create the broadcaster and attaches it a RADIO
|
-- -- create the broadcaster and attaches it a RADIO
|
||||||
-- local MyUnit = UNIT:FindByName("MyUnit")
|
-- local MyUnit = UNIT:FindByName("MyUnit")
|
||||||
-- local MyUnitRadio = MyUnit:GetRadio()
|
-- local MyUnitRadio = MyUnit:GetRadio()
|
||||||
--
|
--
|
||||||
-- -- add a subtitle for the next transmission, which will be up for 10s
|
-- -- add a subtitle for the next transmission, which will be up for 10s
|
||||||
-- MyUnitRadio:SetSubtitle("My Subtitle, 10)
|
-- MyUnitRadio:SetSubtitle("My Subtitle, 10)
|
||||||
function RADIO:SetSubtitle(Subtitle, SubtitleDuration)
|
function RADIO:SetSubtitle(Subtitle, SubtitleDuration)
|
||||||
@@ -264,14 +264,14 @@ function RADIO:SetSubtitle(Subtitle, SubtitleDuration)
|
|||||||
self.SubtitleDuration = SubtitleDuration
|
self.SubtitleDuration = SubtitleDuration
|
||||||
else
|
else
|
||||||
self.SubtitleDuration = 0
|
self.SubtitleDuration = 0
|
||||||
self:E({"SubtitleDuration is invalid. SubtitleDuration reset.", self.SubtitleDuration})
|
self:E({"SubtitleDuration is invalid. SubtitleDuration reset.", self.SubtitleDuration})
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a new transmission, that is to say, populate the RADIO with relevant data
|
--- Create a new transmission, that is to say, populate the RADIO with relevant data
|
||||||
-- In this function the data is especially relevant if the broadcaster is anything but a UNIT or a GROUP,
|
-- In this function the data is especially relevant if the broadcaster is anything but a UNIT or a GROUP,
|
||||||
-- but it will work with a UNIT or a GROUP anyway.
|
-- but it will work with a UNIT or a GROUP anyway.
|
||||||
-- Only the #RADIO and the Filename are mandatory
|
-- Only the #RADIO and the Filename are mandatory
|
||||||
-- @param #RADIO self
|
-- @param #RADIO self
|
||||||
-- @param #string FileName Name of the sound file that will be transmitted.
|
-- @param #string FileName Name of the sound file that will be transmitted.
|
||||||
@@ -281,20 +281,20 @@ end
|
|||||||
-- @return #RADIO self
|
-- @return #RADIO self
|
||||||
function RADIO:NewGenericTransmission(FileName, Frequency, Modulation, Power, Loop)
|
function RADIO:NewGenericTransmission(FileName, Frequency, Modulation, Power, Loop)
|
||||||
self:F({FileName, Frequency, Modulation, Power})
|
self:F({FileName, Frequency, Modulation, Power})
|
||||||
|
|
||||||
self:SetFileName(FileName)
|
self:SetFileName(FileName)
|
||||||
if Frequency then self:SetFrequency(Frequency) end
|
if Frequency then self:SetFrequency(Frequency) end
|
||||||
if Modulation then self:SetModulation(Modulation) end
|
if Modulation then self:SetModulation(Modulation) end
|
||||||
if Power then self:SetPower(Power) end
|
if Power then self:SetPower(Power) end
|
||||||
if Loop then self:SetLoop(Loop) end
|
if Loop then self:SetLoop(Loop) end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Create a new transmission, that is to say, populate the RADIO with relevant data
|
--- Create a new transmission, that is to say, populate the RADIO with relevant data
|
||||||
-- In this function the data is especially relevant if the broadcaster is a UNIT or a GROUP,
|
-- In this function the data is especially relevant if the broadcaster is a UNIT or a GROUP,
|
||||||
-- but it will work for any @{Wrapper.Positionable#POSITIONABLE}.
|
-- but it will work for any @{Wrapper.Positionable#POSITIONABLE}.
|
||||||
-- Only the RADIO and the Filename are mandatory.
|
-- Only the RADIO and the Filename are mandatory.
|
||||||
-- @param #RADIO self
|
-- @param #RADIO self
|
||||||
-- @param #string FileName Name of sound file.
|
-- @param #string FileName Name of sound file.
|
||||||
@@ -316,20 +316,20 @@ function RADIO:NewUnitTransmission(FileName, Subtitle, SubtitleDuration, Frequen
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Set frequency.
|
-- Set frequency.
|
||||||
if Frequency then
|
if Frequency then
|
||||||
self:SetFrequency(Frequency)
|
self:SetFrequency(Frequency)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set subtitle.
|
-- Set subtitle.
|
||||||
if Subtitle then
|
if Subtitle then
|
||||||
self:SetSubtitle(Subtitle, SubtitleDuration or 0)
|
self:SetSubtitle(Subtitle, SubtitleDuration or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set Looping.
|
-- Set Looping.
|
||||||
if Loop then
|
if Loop then
|
||||||
self:SetLoop(Loop)
|
self:SetLoop(Loop)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ end
|
|||||||
-- @return #RADIO self
|
-- @return #RADIO self
|
||||||
function RADIO:Broadcast(viatrigger)
|
function RADIO:Broadcast(viatrigger)
|
||||||
self:F({viatrigger=viatrigger})
|
self:F({viatrigger=viatrigger})
|
||||||
|
|
||||||
-- If the POSITIONABLE is actually a UNIT or a GROUP, use the more complicated DCS command system.
|
-- If the POSITIONABLE is actually a UNIT or a GROUP, use the more complicated DCS command system.
|
||||||
if (self.Positionable.ClassName=="UNIT" or self.Positionable.ClassName=="GROUP") and (not viatrigger) then
|
if (self.Positionable.ClassName=="UNIT" or self.Positionable.ClassName=="GROUP") and (not viatrigger) then
|
||||||
self:T("Broadcasting from a UNIT or a GROUP")
|
self:T("Broadcasting from a UNIT or a GROUP")
|
||||||
@@ -359,7 +359,7 @@ function RADIO:Broadcast(viatrigger)
|
|||||||
subtitle = self.Subtitle,
|
subtitle = self.Subtitle,
|
||||||
loop = self.Loop,
|
loop = self.Loop,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
self:T3(commandTransmitMessage)
|
self:T3(commandTransmitMessage)
|
||||||
self.Positionable:SetCommand(commandTransmitMessage)
|
self.Positionable:SetCommand(commandTransmitMessage)
|
||||||
else
|
else
|
||||||
@@ -368,23 +368,23 @@ function RADIO:Broadcast(viatrigger)
|
|||||||
self:T("Broadcasting from a POSITIONABLE")
|
self:T("Broadcasting from a POSITIONABLE")
|
||||||
trigger.action.radioTransmission(self.FileName, self.Positionable:GetPositionVec3(), self.Modulation, self.Loop, self.Frequency, self.Power, tostring(self.ID))
|
trigger.action.radioTransmission(self.FileName, self.Positionable:GetPositionVec3(), self.Modulation, self.Loop, self.Frequency, self.Power, tostring(self.ID))
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--- Stops a transmission
|
--- Stops a transmission
|
||||||
-- This function is especially usefull to stop the broadcast of looped transmissions
|
-- This function is especially useful to stop the broadcast of looped transmissions
|
||||||
-- @param #RADIO self
|
-- @param #RADIO self
|
||||||
-- @return #RADIO self
|
-- @return #RADIO self
|
||||||
function RADIO:StopBroadcast()
|
function RADIO:StopBroadcast()
|
||||||
self:F()
|
self:F()
|
||||||
-- If the POSITIONABLE is a UNIT or a GROUP, stop the transmission with the DCS "StopTransmission" command
|
-- If the POSITIONABLE is a UNIT or a GROUP, stop the transmission with the DCS "StopTransmission" command
|
||||||
if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then
|
if self.Positionable.ClassName == "UNIT" or self.Positionable.ClassName == "GROUP" then
|
||||||
|
|
||||||
local commandStopTransmission={id="StopTransmission", params={}}
|
local commandStopTransmission={id="StopTransmission", params={}}
|
||||||
|
|
||||||
self.Positionable:SetCommand(commandStopTransmission)
|
self.Positionable:SetCommand(commandStopTransmission)
|
||||||
else
|
else
|
||||||
-- Else, we use the appropriate singleton funciton
|
-- Else, we use the appropriate singleton funciton
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
--- **Core** - Makes the radio talk.
|
--- **Core** - Makes the radio talk.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Send text strings using a vocabulary that is converted in spoken language.
|
-- * Send text strings using a vocabulary that is converted in spoken language.
|
||||||
-- * Possiblity to implement multiple language.
|
-- * Possiblity to implement multiple language.
|
||||||
--
|
--
|
||||||
@@ -15,10 +15,10 @@
|
|||||||
-- @image Core_Radio.JPG
|
-- @image Core_Radio.JPG
|
||||||
|
|
||||||
--- Makes the radio speak.
|
--- Makes the radio speak.
|
||||||
--
|
--
|
||||||
-- # RADIOSPEECH usage
|
-- # RADIOSPEECH usage
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- @type RADIOSPEECH
|
-- @type RADIOSPEECH
|
||||||
-- @extends Core.RadioQueue#RADIOQUEUE
|
-- @extends Core.RadioQueue#RADIOQUEUE
|
||||||
RADIOSPEECH = {
|
RADIOSPEECH = {
|
||||||
@@ -59,24 +59,24 @@ RADIOSPEECH.Vocabulary.EN = {
|
|||||||
["70"] = { "70", 0.48 },
|
["70"] = { "70", 0.48 },
|
||||||
["80"] = { "80", 0.26 },
|
["80"] = { "80", 0.26 },
|
||||||
["90"] = { "90", 0.36 },
|
["90"] = { "90", 0.36 },
|
||||||
["100"] = { "100", 0.55 },
|
["100"] = { "100", 0.55 },
|
||||||
["200"] = { "200", 0.55 },
|
["200"] = { "200", 0.55 },
|
||||||
["300"] = { "300", 0.61 },
|
["300"] = { "300", 0.61 },
|
||||||
["400"] = { "400", 0.60 },
|
["400"] = { "400", 0.60 },
|
||||||
["500"] = { "500", 0.61 },
|
["500"] = { "500", 0.61 },
|
||||||
["600"] = { "600", 0.65 },
|
["600"] = { "600", 0.65 },
|
||||||
["700"] = { "700", 0.70 },
|
["700"] = { "700", 0.70 },
|
||||||
["800"] = { "800", 0.54 },
|
["800"] = { "800", 0.54 },
|
||||||
["900"] = { "900", 0.60 },
|
["900"] = { "900", 0.60 },
|
||||||
["1000"] = { "1000", 0.60 },
|
["1000"] = { "1000", 0.60 },
|
||||||
["2000"] = { "2000", 0.61 },
|
["2000"] = { "2000", 0.61 },
|
||||||
["3000"] = { "3000", 0.64 },
|
["3000"] = { "3000", 0.64 },
|
||||||
["4000"] = { "4000", 0.62 },
|
["4000"] = { "4000", 0.62 },
|
||||||
["5000"] = { "5000", 0.69 },
|
["5000"] = { "5000", 0.69 },
|
||||||
["6000"] = { "6000", 0.69 },
|
["6000"] = { "6000", 0.69 },
|
||||||
["7000"] = { "7000", 0.75 },
|
["7000"] = { "7000", 0.75 },
|
||||||
["8000"] = { "8000", 0.59 },
|
["8000"] = { "8000", 0.59 },
|
||||||
["9000"] = { "9000", 0.65 },
|
["9000"] = { "9000", 0.65 },
|
||||||
|
|
||||||
["chevy"] = { "chevy", 0.35 },
|
["chevy"] = { "chevy", 0.35 },
|
||||||
["colt"] = { "colt", 0.35 },
|
["colt"] = { "colt", 0.35 },
|
||||||
@@ -94,10 +94,10 @@ RADIOSPEECH.Vocabulary.EN = {
|
|||||||
["meters"] = { "meters", 0.41 },
|
["meters"] = { "meters", 0.41 },
|
||||||
["mi"] = { "miles", 0.45 },
|
["mi"] = { "miles", 0.45 },
|
||||||
["feet"] = { "feet", 0.29 },
|
["feet"] = { "feet", 0.29 },
|
||||||
|
|
||||||
["br"] = { "br", 1.1 },
|
["br"] = { "br", 1.1 },
|
||||||
["bra"] = { "bra", 0.3 },
|
["bra"] = { "bra", 0.3 },
|
||||||
|
|
||||||
|
|
||||||
["returning to base"] = { "returning_to_base", 0.85 },
|
["returning to base"] = { "returning_to_base", 0.85 },
|
||||||
["on route to ground target"] = { "on_route_to_ground_target", 1.05 },
|
["on route to ground target"] = { "on_route_to_ground_target", 1.05 },
|
||||||
@@ -143,24 +143,24 @@ RADIOSPEECH.Vocabulary.RU = {
|
|||||||
["70"] = { "70", 0.68 },
|
["70"] = { "70", 0.68 },
|
||||||
["80"] = { "80", 0.84 },
|
["80"] = { "80", 0.84 },
|
||||||
["90"] = { "90", 0.71 },
|
["90"] = { "90", 0.71 },
|
||||||
["100"] = { "100", 0.35 },
|
["100"] = { "100", 0.35 },
|
||||||
["200"] = { "200", 0.59 },
|
["200"] = { "200", 0.59 },
|
||||||
["300"] = { "300", 0.53 },
|
["300"] = { "300", 0.53 },
|
||||||
["400"] = { "400", 0.70 },
|
["400"] = { "400", 0.70 },
|
||||||
["500"] = { "500", 0.50 },
|
["500"] = { "500", 0.50 },
|
||||||
["600"] = { "600", 0.58 },
|
["600"] = { "600", 0.58 },
|
||||||
["700"] = { "700", 0.64 },
|
["700"] = { "700", 0.64 },
|
||||||
["800"] = { "800", 0.77 },
|
["800"] = { "800", 0.77 },
|
||||||
["900"] = { "900", 0.75 },
|
["900"] = { "900", 0.75 },
|
||||||
["1000"] = { "1000", 0.87 },
|
["1000"] = { "1000", 0.87 },
|
||||||
["2000"] = { "2000", 0.83 },
|
["2000"] = { "2000", 0.83 },
|
||||||
["3000"] = { "3000", 0.84 },
|
["3000"] = { "3000", 0.84 },
|
||||||
["4000"] = { "4000", 1.00 },
|
["4000"] = { "4000", 1.00 },
|
||||||
["5000"] = { "5000", 0.77 },
|
["5000"] = { "5000", 0.77 },
|
||||||
["6000"] = { "6000", 0.90 },
|
["6000"] = { "6000", 0.90 },
|
||||||
["7000"] = { "7000", 0.77 },
|
["7000"] = { "7000", 0.77 },
|
||||||
["8000"] = { "8000", 0.92 },
|
["8000"] = { "8000", 0.92 },
|
||||||
["9000"] = { "9000", 0.87 },
|
["9000"] = { "9000", 0.87 },
|
||||||
|
|
||||||
["градусы"] = { "degrees", 0.5 },
|
["градусы"] = { "degrees", 0.5 },
|
||||||
["километры"] = { "kilometers", 0.65 },
|
["километры"] = { "kilometers", 0.65 },
|
||||||
@@ -170,10 +170,11 @@ RADIOSPEECH.Vocabulary.RU = {
|
|||||||
["метров"] = { "meters", 0.41 },
|
["метров"] = { "meters", 0.41 },
|
||||||
["m"] = { "meters", 0.41 },
|
["m"] = { "meters", 0.41 },
|
||||||
["ноги"] = { "feet", 0.37 },
|
["ноги"] = { "feet", 0.37 },
|
||||||
|
|
||||||
["br"] = { "br", 1.1 },
|
["br"] = { "br", 1.1 },
|
||||||
["bra"] = { "bra", 0.3 },
|
["bra"] = { "bra", 0.3 },
|
||||||
|
|
||||||
|
|
||||||
["возвращение на базу"] = { "returning_to_base", 1.40 },
|
["возвращение на базу"] = { "returning_to_base", 1.40 },
|
||||||
["на пути к наземной цели"] = { "on_route_to_ground_target", 1.45 },
|
["на пути к наземной цели"] = { "on_route_to_ground_target", 1.45 },
|
||||||
["перехват боги"] = { "intercepting_bogeys", 1.22 },
|
["перехват боги"] = { "intercepting_bogeys", 1.22 },
|
||||||
@@ -199,11 +200,11 @@ function RADIOSPEECH:New(frequency, modulation)
|
|||||||
|
|
||||||
-- Inherit base
|
-- Inherit base
|
||||||
local self = BASE:Inherit( self, RADIOQUEUE:New( frequency, modulation ) ) -- #RADIOSPEECH
|
local self = BASE:Inherit( self, RADIOQUEUE:New( frequency, modulation ) ) -- #RADIOSPEECH
|
||||||
|
|
||||||
self.Language = "EN"
|
self.Language = "EN"
|
||||||
|
|
||||||
self:BuildTree()
|
self:BuildTree()
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -261,7 +262,7 @@ end
|
|||||||
function RADIOSPEECH:BuildTree()
|
function RADIOSPEECH:BuildTree()
|
||||||
|
|
||||||
self.Speech = {}
|
self.Speech = {}
|
||||||
|
|
||||||
for Language, Sentences in pairs( self.Vocabulary ) do
|
for Language, Sentences in pairs( self.Vocabulary ) do
|
||||||
self:I( { Language = Language, Sentences = Sentences })
|
self:I( { Language = Language, Sentences = Sentences })
|
||||||
self.Speech[Language] = {}
|
self.Speech[Language] = {}
|
||||||
@@ -270,7 +271,7 @@ function RADIOSPEECH:BuildTree()
|
|||||||
self:AddSentenceToSpeech( Sentence, self.Speech[Language], Sentence, Data )
|
self:AddSentenceToSpeech( Sentence, self.Speech[Language], Sentence, Data )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:I( { Speech = self.Speech } )
|
self:I( { Speech = self.Speech } )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -289,7 +290,7 @@ function RADIOSPEECH:SpeakWords( Sentence, Speech, Language )
|
|||||||
local Word, RemainderSentence = Sentence:match( "^[., ]*([^ .,]+)(.*)" )
|
local Word, RemainderSentence = Sentence:match( "^[., ]*([^ .,]+)(.*)" )
|
||||||
|
|
||||||
self:I( { Word = Word, Speech = Speech[Word], RemainderSentence = RemainderSentence } )
|
self:I( { Word = Word, Speech = Speech[Word], RemainderSentence = RemainderSentence } )
|
||||||
|
|
||||||
|
|
||||||
if Word then
|
if Word then
|
||||||
if Word ~= "" and tonumber(Word) == nil then
|
if Word ~= "" and tonumber(Word) == nil then
|
||||||
@@ -301,7 +302,7 @@ function RADIOSPEECH:SpeakWords( Sentence, Speech, Language )
|
|||||||
if Speech[Word].Next == nil then
|
if Speech[Word].Next == nil then
|
||||||
self:I( { Sentence = Speech[Word].Sentence, Data = Speech[Word].Data } )
|
self:I( { Sentence = Speech[Word].Sentence, Data = Speech[Word].Data } )
|
||||||
self:NewTransmission( Speech[Word].Data[1] .. ".wav", Speech[Word].Data[2], Language .. "/" )
|
self:NewTransmission( Speech[Word].Data[1] .. ".wav", Speech[Word].Data[2], Language .. "/" )
|
||||||
else
|
else
|
||||||
if RemainderSentence and RemainderSentence ~= "" then
|
if RemainderSentence and RemainderSentence ~= "" then
|
||||||
return self:SpeakWords( RemainderSentence, Speech[Word].Next, Language )
|
return self:SpeakWords( RemainderSentence, Speech[Word].Next, Language )
|
||||||
end
|
end
|
||||||
@@ -309,11 +310,11 @@ function RADIOSPEECH:SpeakWords( Sentence, Speech, Language )
|
|||||||
end
|
end
|
||||||
return RemainderSentence
|
return RemainderSentence
|
||||||
end
|
end
|
||||||
return OriginalSentence
|
return OriginalSentence
|
||||||
else
|
else
|
||||||
return ""
|
return ""
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Speak a sentence.
|
--- Speak a sentence.
|
||||||
@@ -332,7 +333,7 @@ function RADIOSPEECH:SpeakDigits( Sentence, Speech, Langauge )
|
|||||||
|
|
||||||
if Digits then
|
if Digits then
|
||||||
if Digits ~= "" and tonumber( Digits ) ~= nil then
|
if Digits ~= "" and tonumber( Digits ) ~= nil then
|
||||||
|
|
||||||
-- Construct numbers
|
-- Construct numbers
|
||||||
local Number = tonumber( Digits )
|
local Number = tonumber( Digits )
|
||||||
local Multiple = nil
|
local Multiple = nil
|
||||||
@@ -356,7 +357,7 @@ function RADIOSPEECH:SpeakDigits( Sentence, Speech, Langauge )
|
|||||||
end
|
end
|
||||||
return RemainderSentence
|
return RemainderSentence
|
||||||
end
|
end
|
||||||
return OriginalSentence
|
return OriginalSentence
|
||||||
else
|
else
|
||||||
return ""
|
return ""
|
||||||
end
|
end
|
||||||
@@ -373,26 +374,26 @@ function RADIOSPEECH:Speak( Sentence, Language )
|
|||||||
self:I( { Sentence, Language } )
|
self:I( { Sentence, Language } )
|
||||||
|
|
||||||
local Language = Language or "EN"
|
local Language = Language or "EN"
|
||||||
|
|
||||||
self:I( { Language = Language } )
|
self:I( { Language = Language } )
|
||||||
|
|
||||||
-- If there is no node for Speech, then we start at the first nodes of the language.
|
-- If there is no node for Speech, then we start at the first nodes of the language.
|
||||||
local Speech = self.Speech[Language]
|
local Speech = self.Speech[Language]
|
||||||
|
|
||||||
self:I( { Speech = Speech, Language = Language } )
|
self:I( { Speech = Speech, Language = Language } )
|
||||||
|
|
||||||
self:NewTransmission( "_In.wav", 0.52, Language .. "/" )
|
self:NewTransmission( "_In.wav", 0.52, Language .. "/" )
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
|
|
||||||
Sentence = self:SpeakWords( Sentence, Speech, Language )
|
Sentence = self:SpeakWords( Sentence, Speech, Language )
|
||||||
|
|
||||||
self:I( { Sentence = Sentence } )
|
self:I( { Sentence = Sentence } )
|
||||||
|
|
||||||
Sentence = self:SpeakDigits( Sentence, Speech, Language )
|
Sentence = self:SpeakDigits( Sentence, Speech, Language )
|
||||||
|
|
||||||
self:I( { Sentence = Sentence } )
|
self:I( { Sentence = Sentence } )
|
||||||
|
|
||||||
-- Sentence = self:SpeakSymbols( Sentence, Speech )
|
-- Sentence = self:SpeakSymbols( Sentence, Speech )
|
||||||
--
|
--
|
||||||
-- self:I( { Sentence = Sentence } )
|
-- self:I( { Sentence = Sentence } )
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Sound** - Simple Radio Standalone (SRS) Integration.
|
--- **Sound** - Simple Radio Standalone (SRS) Integration and Text-to-Speech.
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky**
|
||||||
-- @module Sound.MSRS
|
-- @module Sound.SRS
|
||||||
-- @image Sound_MSRS.png
|
-- @image Sound_MSRS.png
|
||||||
|
|
||||||
--- MSRS class.
|
--- MSRS class.
|
||||||
@@ -45,14 +45,13 @@
|
|||||||
-- @field Core.Point#COORDINATE coordinate Coordinate from where the transmission is send.
|
-- @field Core.Point#COORDINATE coordinate Coordinate from where the transmission is send.
|
||||||
-- @field #string path Path to the SRS exe. This includes the final slash "/".
|
-- @field #string path Path to the SRS exe. This includes the final slash "/".
|
||||||
-- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json".
|
-- @field #string google Full path google credentials JSON file, e.g. "C:\Users\username\Downloads\service-account-file.json".
|
||||||
|
-- @field #string Label Label showing up on the SRS radio overlay. Default is "ROBOT". No spaces allowed.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
--- *It is a very sad thing that nowadays there is so little useless information.* - Oscar Wilde
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # The MSRS Concept
|
-- # The MSRS Concept
|
||||||
--
|
--
|
||||||
-- This class allows to broadcast sound files or text via Simple Radio Standalone (SRS).
|
-- This class allows to broadcast sound files or text via Simple Radio Standalone (SRS).
|
||||||
@@ -95,17 +94,35 @@
|
|||||||
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
|
-- For more information on setting up a cloud account, visit: https://cloud.google.com/text-to-speech
|
||||||
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
|
-- Google's supported SSML reference: https://cloud.google.com/text-to-speech/docs/ssml
|
||||||
--
|
--
|
||||||
|
--
|
||||||
|
-- **Pro-Tipp** - use the command line with power shell to call DCS-SR-ExternalAudio.exe - it will tell you what is missing.
|
||||||
|
-- and also the Google Console error, in case you have missed a step in setting up your Google TTS.
|
||||||
|
-- E.g. `.\DCS-SR-ExternalAudio.exe -t "Text Message" -f 255 -m AM -c 2 -s 2 -z -G "Path_To_You_Google.Json"`
|
||||||
|
-- Plays a message on 255AM for the blue coalition in-game.
|
||||||
|
--
|
||||||
-- ## Set Voice
|
-- ## Set Voice
|
||||||
--
|
--
|
||||||
-- Use a specifc voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
|
-- Use a specific voice with the @{#MSRS.SetVoice} function, e.g, `:SetVoice("Microsoft Hedda Desktop")`.
|
||||||
-- Note that this must be installed on your windows system.
|
-- Note that this must be installed on your windows system.
|
||||||
-- If enabling SetGoogle(), you can use voices provided by Google
|
-- If enabling SetGoogle(), you can use voices provided by Google
|
||||||
-- Google's supported voices: https://cloud.google.com/text-to-speech/docs/voices
|
-- Google's supported voices: https://cloud.google.com/text-to-speech/docs/voices
|
||||||
|
-- For voices there are enumerators in this class to help you out on voice names:
|
||||||
|
--
|
||||||
|
-- MSRS.Voices.Microsoft -- e.g. MSRS.Voices.Microsoft.Hedda - the Microsoft enumerator contains all voices known to work with SRS
|
||||||
|
-- MSRS.Voices.Google -- e.g. MSRS.Voices.Google.Standard.en_AU_Standard_A or MSRS.Voices.Google.Wavenet.de_DE_Wavenet_C - The Google enumerator contains voices for EN, DE, IT, FR and ES.
|
||||||
--
|
--
|
||||||
-- ## Set Coordinate
|
-- ## Set Coordinate
|
||||||
--
|
--
|
||||||
-- Use @{#MSRS.SetCoordinate} to define the origin from where the transmission is broadcasted.
|
-- Use @{#MSRS.SetCoordinate} to define the origin from where the transmission is broadcasted.
|
||||||
--
|
--
|
||||||
|
-- ## Set SRS Port
|
||||||
|
--
|
||||||
|
-- Use @{#MSRS.SetPort} to define the SRS port. Defaults to 5002.
|
||||||
|
--
|
||||||
|
-- ## Set SRS Volume
|
||||||
|
--
|
||||||
|
-- Use @{#MSRS.SetVolume} to define the SRS volume. Defaults to 1.0. Allowed values are between 0.0 and 1.0, from silent to loudest.
|
||||||
|
--
|
||||||
-- @field #MSRS
|
-- @field #MSRS
|
||||||
MSRS = {
|
MSRS = {
|
||||||
ClassName = "MSRS",
|
ClassName = "MSRS",
|
||||||
@@ -121,17 +138,119 @@ MSRS = {
|
|||||||
volume = 1,
|
volume = 1,
|
||||||
speed = 1,
|
speed = 1,
|
||||||
coordinate = nil,
|
coordinate = nil,
|
||||||
|
Label = "ROBOT",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- MSRS class version.
|
--- MSRS class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
MSRS.version="0.0.3"
|
MSRS.version="0.1.1"
|
||||||
|
|
||||||
|
--- Voices
|
||||||
|
-- @type Voices
|
||||||
|
MSRS.Voices = {
|
||||||
|
Microsoft = {
|
||||||
|
["Hedda"] = "Microsoft Hedda Desktop", -- de-DE
|
||||||
|
["Hazel"] = "Microsoft Hazel Desktop", -- en-GB
|
||||||
|
["David"] = "Microsoft David Desktop", -- en-US
|
||||||
|
["Zira"] = "Microsoft Zira Desktop", -- en-US
|
||||||
|
["Hortense"] = "Microsoft Hortense Desktop", --fr-FR
|
||||||
|
},
|
||||||
|
Google = {
|
||||||
|
Standard = {
|
||||||
|
["en_AU_Standard_A"] = 'en-AU-Standard-A', -- [1] FEMALE
|
||||||
|
["en_AU_Standard_B"] = 'en-AU-Standard-B', -- [2] MALE
|
||||||
|
["en_AU_Standard_C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
||||||
|
["en_AU_Standard_D"] = 'en-AU-Standard-D', -- [4] MALE
|
||||||
|
["en_IN_Standard_A"] = 'en-IN-Standard-A', -- [5] FEMALE
|
||||||
|
["en_IN_Standard_B"] = 'en-IN-Standard-B', -- [6] MALE
|
||||||
|
["en_IN_Standard_C"] = 'en-IN-Standard-C', -- [7] MALE
|
||||||
|
["en_IN_Standard_D"] = 'en-IN-Standard-D', -- [8] FEMALE
|
||||||
|
["en_GB_Standard_A"] = 'en-GB-Standard-A', -- [9] FEMALE
|
||||||
|
["en_GB_Standard_B"] = 'en-GB-Standard-B', -- [10] MALE
|
||||||
|
["en_GB_Standard_C"] = 'en-GB-Standard-C', -- [11] FEMALE
|
||||||
|
["en_GB_Standard_D"] = 'en-GB-Standard-D', -- [12] MALE
|
||||||
|
["en_GB_Standard_F"] = 'en-GB-Standard-F', -- [13] FEMALE
|
||||||
|
["en_US_Standard_A"] = 'en-US-Standard-A', -- [14] MALE
|
||||||
|
["en_US_Standard_B"] = 'en-US-Standard-B', -- [15] MALE
|
||||||
|
["en_US_Standard_C"] = 'en-US-Standard-C', -- [16] FEMALE
|
||||||
|
["en_US_Standard_D"] = 'en-US-Standard-D', -- [17] MALE
|
||||||
|
["en_US_Standard_E"] = 'en-US-Standard-E', -- [18] FEMALE
|
||||||
|
["en_US_Standard_F"] = 'en-US-Standard-F', -- [19] FEMALE
|
||||||
|
["en_US_Standard_G"] = 'en-US-Standard-G', -- [20] FEMALE
|
||||||
|
["en_US_Standard_H"] = 'en-US-Standard-H', -- [21] FEMALE
|
||||||
|
["en_US_Standard_I"] = 'en-US-Standard-I', -- [22] MALE
|
||||||
|
["en_US_Standard_J"] = 'en-US-Standard-J', -- [23] MALE
|
||||||
|
["fr_FR_Standard_A"] = "fr-FR-Standard-A", -- Female
|
||||||
|
["fr_FR_Standard_B"] = "fr-FR-Standard-B", -- Male
|
||||||
|
["fr_FR_Standard_C"] = "fr-FR-Standard-C", -- Female
|
||||||
|
["fr_FR_Standard_D"] = "fr-FR-Standard-D", -- Male
|
||||||
|
["fr_FR_Standard_E"] = "fr-FR-Standard-E", -- Female
|
||||||
|
["de_DE_Standard_A"] = "de-DE-Standard-A", -- Female
|
||||||
|
["de_DE_Standard_B"] = "de-DE-Standard-B", -- Male
|
||||||
|
["de_DE_Standard_C"] = "de-DE-Standard-C", -- Female
|
||||||
|
["de_DE_Standard_D"] = "de-DE-Standard-D", -- Male
|
||||||
|
["de_DE_Standard_E"] = "de-DE-Standard-E", -- Male
|
||||||
|
["de_DE_Standard_F"] = "de-DE-Standard-F", -- Female
|
||||||
|
["es_ES_Standard_A"] = "es-ES-Standard-A", -- Female
|
||||||
|
["es_ES_Standard_B"] = "es-ES-Standard-B", -- Male
|
||||||
|
["es_ES_Standard_C"] = "es-ES-Standard-C", -- Female
|
||||||
|
["es_ES_Standard_D"] = "es-ES-Standard-D", -- Female
|
||||||
|
["it_IT_Standard_A"] = "it-IT-Standard-A", -- Female
|
||||||
|
["it_IT_Standard_B"] = "it-IT-Standard-B", -- Female
|
||||||
|
["it_IT_Standard_C"] = "it-IT-Standard-C", -- Male
|
||||||
|
["it_IT_Standard_D"] = "it-IT-Standard-D", -- Male
|
||||||
|
},
|
||||||
|
Wavenet = {
|
||||||
|
["en_AU_Wavenet_A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
|
||||||
|
["en_AU_Wavenet_B"] = 'en-AU-Wavenet-B', -- [2] MALE
|
||||||
|
["en_AU_Wavenet_C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
|
||||||
|
["en_AU_Wavenet_D"] = 'en-AU-Wavenet-D', -- [4] MALE
|
||||||
|
["en_IN_Wavenet_A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
|
||||||
|
["en_IN_Wavenet_B"] = 'en-IN-Wavenet-B', -- [6] MALE
|
||||||
|
["en_IN_Wavenet_C"] = 'en-IN-Wavenet-C', -- [7] MALE
|
||||||
|
["en_IN_Wavenet_D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
|
||||||
|
["en_GB_Wavenet_A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
|
||||||
|
["en_GB_Wavenet_B"] = 'en-GB-Wavenet-B', -- [10] MALE
|
||||||
|
["en_GB_Wavenet_C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
|
||||||
|
["en_GB_Wavenet_D"] = 'en-GB-Wavenet-D', -- [12] MALE
|
||||||
|
["en_GB_Wavenet_F"] = 'en-GB-Wavenet-F', -- [13] FEMALE
|
||||||
|
["en_US_Wavenet_A"] = 'en-US-Wavenet-A', -- [14] MALE
|
||||||
|
["en_US_Wavenet_B"] = 'en-US-Wavenet-B', -- [15] MALE
|
||||||
|
["en_US_Wavenet_C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
||||||
|
["en_US_Wavenet_D"] = 'en-US-Wavenet-D', -- [17] MALE
|
||||||
|
["en_US_Wavenet_E"] = 'en-US-Wavenet-E', -- [18] FEMALE
|
||||||
|
["en_US_Wavenet_F"] = 'en-US-Wavenet-F', -- [19] FEMALE
|
||||||
|
["en_US_Wavenet_G"] = 'en-US-Wavenet-G', -- [20] FEMALE
|
||||||
|
["en_US_Wavenet_H"] = 'en-US-Wavenet-H', -- [21] FEMALE
|
||||||
|
["en_US_Wavenet_I"] = 'en-US-Wavenet-I', -- [22] MALE
|
||||||
|
["en_US_Wavenet_J"] = 'en-US-Wavenet-J', -- [23] MALE
|
||||||
|
["fr_FR_Wavenet_A"] = "fr-FR-Wavenet-A", -- Female
|
||||||
|
["fr_FR_Wavenet_B"] = "fr-FR-Wavenet-B", -- Male
|
||||||
|
["fr_FR_Wavenet_C"] = "fr-FR-Wavenet-C", -- Female
|
||||||
|
["fr_FR_Wavenet_D"] = "fr-FR-Wavenet-D", -- Male
|
||||||
|
["fr_FR_Wavenet_E"] = "fr-FR-Wavenet-E", -- Female
|
||||||
|
["de_DE_Wavenet_A"] = "de-DE-Wavenet-A", -- Female
|
||||||
|
["de_DE_Wavenet_B"] = "de-DE-Wavenet-B", -- Male
|
||||||
|
["de_DE_Wavenet_C"] = "de-DE-Wavenet-C", -- Female
|
||||||
|
["de_DE_Wavenet_D"] = "de-DE-Wavenet-D", -- Male
|
||||||
|
["de_DE_Wavenet_E"] = "de-DE-Wavenet-E", -- Male
|
||||||
|
["de_DE_Wavenet_F"] = "de-DE-Wavenet-F", -- Female
|
||||||
|
["es_ES_Wavenet_B"] = "es-ES-Wavenet-B", -- Male
|
||||||
|
["es_ES_Wavenet_C"] = "es-ES-Wavenet-C", -- Female
|
||||||
|
["es_ES_Wavenet_D"] = "es-ES-Wavenet-D", -- Female
|
||||||
|
["it_IT_Wavenet_A"] = "it-IT-Wavenet-A", -- Female
|
||||||
|
["it_IT_Wavenet_B"] = "it-IT-Wavenet-B", -- Female
|
||||||
|
["it_IT_Wavenet_C"] = "it-IT-Wavenet-C", -- Male
|
||||||
|
["it_IT_Wavenet_D"] = "it-IT-Wavenet-D", -- Male
|
||||||
|
} ,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: Add functions to add/remove freqs and modulations.
|
-- TODO: Add functions to remove freqs and modulations.
|
||||||
-- DONE: Add coordinate.
|
-- DONE: Add coordinate.
|
||||||
-- DONE: Add google.
|
-- DONE: Add google.
|
||||||
|
|
||||||
@@ -144,8 +263,9 @@ MSRS.version="0.0.3"
|
|||||||
-- @param #string PathToSRS Path to the directory, where SRS is located.
|
-- @param #string PathToSRS Path to the directory, where SRS is located.
|
||||||
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies.
|
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz. Can also be given as a #table of multiple frequencies.
|
||||||
-- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations.
|
-- @param #number Modulation Radio modulation: 0=AM (default), 1=FM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators. Can also be given as a #table of multiple modulations.
|
||||||
|
-- @param #number Volume Volume - 1.0 is max, 0.0 is silence
|
||||||
-- @return #MSRS self
|
-- @return #MSRS self
|
||||||
function MSRS:New(PathToSRS, Frequency, Modulation)
|
function MSRS:New(PathToSRS, Frequency, Modulation, Volume)
|
||||||
|
|
||||||
-- Defaults.
|
-- Defaults.
|
||||||
Frequency =Frequency or 143
|
Frequency =Frequency or 143
|
||||||
@@ -160,6 +280,13 @@ function MSRS:New(PathToSRS, Frequency, Modulation)
|
|||||||
self:SetModulations(Modulation)
|
self:SetModulations(Modulation)
|
||||||
self:SetGender()
|
self:SetGender()
|
||||||
self:SetCoalition()
|
self:SetCoalition()
|
||||||
|
self:SetLabel()
|
||||||
|
self:SetVolume()
|
||||||
|
self.lid = string.format("%s-%s | ", self.name, self.version)
|
||||||
|
|
||||||
|
if not io or not os then
|
||||||
|
self:E(self.lid.."***** ERROR - io or os NOT desanitized! MSRS will not work!")
|
||||||
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -202,12 +329,47 @@ function MSRS:GetPath()
|
|||||||
return self.path
|
return self.path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set SRS volume.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #number Volume Volume - 1.0 is max, 0.0 is silence
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:SetVolume(Volume)
|
||||||
|
local volume = Volume or 1
|
||||||
|
if volume > 1 then volume = 1 elseif volume < 0 then volume = 0 end
|
||||||
|
self.volume = volume
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get SRS volume.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @return #number Volume Volume - 1.0 is max, 0.0 is silence
|
||||||
|
function MSRS:GetVolume()
|
||||||
|
return self.volume
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set label.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #number Label. Default "ROBOT"
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:SetLabel(Label)
|
||||||
|
self.Label=Label or "ROBOT"
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get label.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @return #number Label.
|
||||||
|
function MSRS:GetLabel()
|
||||||
|
return self.Label
|
||||||
|
end
|
||||||
|
|
||||||
--- Set port.
|
--- Set port.
|
||||||
-- @param #MSRS self
|
-- @param #MSRS self
|
||||||
-- @param #number Port Port. Default 5002.
|
-- @param #number Port Port. Default 5002.
|
||||||
-- @return #MSRS self
|
-- @return #MSRS self
|
||||||
function MSRS:SetPort(Port)
|
function MSRS:SetPort(Port)
|
||||||
self.port=Port or 5002
|
self.port=Port or 5002
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get port.
|
--- Get port.
|
||||||
@@ -223,6 +385,7 @@ end
|
|||||||
-- @return #MSRS self
|
-- @return #MSRS self
|
||||||
function MSRS:SetCoalition(Coalition)
|
function MSRS:SetCoalition(Coalition)
|
||||||
self.coalition=Coalition or 0
|
self.coalition=Coalition or 0
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get coalition.
|
--- Get coalition.
|
||||||
@@ -249,6 +412,24 @@ function MSRS:SetFrequencies(Frequencies)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add frequencies.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #table Frequencies Frequencies in MHz. Can also be given as a #number if only one frequency should be used.
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:AddFrequencies(Frequencies)
|
||||||
|
|
||||||
|
-- Ensure table.
|
||||||
|
if type(Frequencies)~="table" then
|
||||||
|
Frequencies={Frequencies}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _,_freq in pairs(Frequencies) do
|
||||||
|
table.insert(self.frequencies,_freq)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Get frequencies.
|
--- Get frequencies.
|
||||||
-- @param #MSRS self
|
-- @param #MSRS self
|
||||||
-- @param #table Frequencies in MHz.
|
-- @param #table Frequencies in MHz.
|
||||||
@@ -273,6 +454,24 @@ function MSRS:SetModulations(Modulations)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Add modulations.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #table Modulations Modulations. Can also be given as a #number if only one modulation should be used.
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:AddModulations(Modulations)
|
||||||
|
|
||||||
|
-- Ensure table.
|
||||||
|
if type(Modulations)~="table" then
|
||||||
|
Modulations={Modulations}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _,_mod in pairs(Modulations) do
|
||||||
|
table.insert(self.modulations,_mod)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Get modulations.
|
--- Get modulations.
|
||||||
-- @param #MSRS self
|
-- @param #MSRS self
|
||||||
-- @param #table Modulations.
|
-- @param #table Modulations.
|
||||||
@@ -391,21 +590,10 @@ function MSRS:PlaySoundFile(Soundfile, Delay)
|
|||||||
local command=self:_GetCommand()
|
local command=self:_GetCommand()
|
||||||
|
|
||||||
-- Append file.
|
-- Append file.
|
||||||
command=command.." --file="..tostring(soundfile)
|
command=command..' --file="'..tostring(soundfile)..'"'
|
||||||
|
|
||||||
|
-- Execute command.
|
||||||
self:_ExecCommand(command)
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
command=command.." > bla.txt"
|
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
self:I(string.format("MSRS PlaySoundfile command=%s", command))
|
|
||||||
|
|
||||||
-- Execute SRS command.
|
|
||||||
local x=os.execute(command)
|
|
||||||
|
|
||||||
]]
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -431,16 +619,6 @@ function MSRS:PlaySoundText(SoundText, Delay)
|
|||||||
|
|
||||||
-- Execute command.
|
-- Execute command.
|
||||||
self:_ExecCommand(command)
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
--[[
|
|
||||||
command=command.." > bla.txt"
|
|
||||||
|
|
||||||
-- Debug putput.
|
|
||||||
self:I(string.format("MSRS PlaySoundfile command=%s", command))
|
|
||||||
|
|
||||||
-- Execute SRS command.
|
|
||||||
local x=os.execute(command)
|
|
||||||
]]
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -467,37 +645,48 @@ function MSRS:PlayText(Text, Delay)
|
|||||||
-- Execute command.
|
-- Execute command.
|
||||||
self:_ExecCommand(command)
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
--[[
|
end
|
||||||
|
|
||||||
-- Check that length of command is max 255 chars or os.execute() will not work!
|
|
||||||
if string.len(command)>255 then
|
|
||||||
|
|
||||||
-- Create a tmp file.
|
|
||||||
local filename = os.getenv('TMP') .. "\\MSRS-"..STTS.uuid()..".bat"
|
|
||||||
|
|
||||||
local script = io.open(filename, "w+")
|
|
||||||
script:write(command.." && exit")
|
|
||||||
script:close()
|
|
||||||
|
|
||||||
-- Play command.
|
|
||||||
command=string.format("\"%s\"", filename)
|
|
||||||
|
|
||||||
-- Play file in 0.05 seconds
|
|
||||||
timer.scheduleFunction(os.execute, command, timer.getTime()+0.05)
|
|
||||||
|
|
||||||
-- Remove file in 1 second.
|
|
||||||
timer.scheduleFunction(os.remove, filename, timer.getTime()+1)
|
|
||||||
else
|
|
||||||
|
|
||||||
-- Debug output.
|
|
||||||
self:I(string.format("MSRS Text command=%s", command))
|
|
||||||
|
|
||||||
-- Execute SRS command.
|
return self
|
||||||
local x=os.execute(command)
|
end
|
||||||
|
|
||||||
|
--- Play text message via STTS with explicitly specified options.
|
||||||
|
-- @param #MSRS self
|
||||||
|
-- @param #string Text Text message.
|
||||||
|
-- @param #number Delay Delay in seconds, before the message is played.
|
||||||
|
-- @param #table Frequencies Radio frequencies.
|
||||||
|
-- @param #table Modulations Radio modulations.
|
||||||
|
-- @param #string Gender Gender.
|
||||||
|
-- @param #string Culture Culture.
|
||||||
|
-- @param #string Voice Voice.
|
||||||
|
-- @param #number Volume Volume.
|
||||||
|
-- @param #string Label Label.
|
||||||
|
-- @return #MSRS self
|
||||||
|
function MSRS:PlayTextExt(Text, Delay, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, MSRS.PlayTextExt, self, Text, 0, Frequencies, Modulations, Gender, Culture, Voice, Volume, Label)
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Ensure table.
|
||||||
|
if Frequencies and type(Frequencies)~="table" then
|
||||||
|
Frequencies={Frequencies}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ensure table.
|
||||||
|
if Modulations and type(Modulations)~="table" then
|
||||||
|
Modulations={Modulations}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get command line.
|
||||||
|
local command=self:_GetCommand(Frequencies, Modulations, nil, Gender, Voice, Culture, Volume, nil, nil, Label)
|
||||||
|
|
||||||
|
-- Append text.
|
||||||
|
command=command..string.format(" --text=\"%s\"", tostring(Text))
|
||||||
|
|
||||||
end
|
-- Execute command.
|
||||||
|
self:_ExecCommand(command)
|
||||||
|
|
||||||
]]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -634,8 +823,9 @@ end
|
|||||||
-- @param #number volume Volume.
|
-- @param #number volume Volume.
|
||||||
-- @param #number speed Speed.
|
-- @param #number speed Speed.
|
||||||
-- @param #number port Port.
|
-- @param #number port Port.
|
||||||
|
-- @param #string label Label, defaults to "ROBOT" (displayed sender name in the radio overlay of SRS) - No spaces allowed!
|
||||||
-- @return #string Command.
|
-- @return #string Command.
|
||||||
function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port)
|
function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, speed, port,label)
|
||||||
|
|
||||||
local path=self:GetPath() or STTS.DIRECTORY
|
local path=self:GetPath() or STTS.DIRECTORY
|
||||||
local exe=STTS.EXECUTABLE or "DCS-SR-ExternalAudio.exe"
|
local exe=STTS.EXECUTABLE or "DCS-SR-ExternalAudio.exe"
|
||||||
@@ -648,21 +838,14 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
|||||||
volume=volume or self.volume
|
volume=volume or self.volume
|
||||||
speed=speed or self.speed
|
speed=speed or self.speed
|
||||||
port=port or self.port
|
port=port or self.port
|
||||||
|
label=label or self.Label
|
||||||
|
|
||||||
-- Replace modulation
|
-- Replace modulation
|
||||||
modus=modus:gsub("0", "AM")
|
modus=modus:gsub("0", "AM")
|
||||||
modus=modus:gsub("1", "FM")
|
modus=modus:gsub("1", "FM")
|
||||||
|
|
||||||
-- This did not work well. Stopped if the transmission was a bit longer with no apparent error.
|
|
||||||
--local command=string.format("%s --freqs=%s --modulations=%s --coalition=%d --port=%d --volume=%.2f --speed=%d", exe, freqs, modus, coal, port, volume, speed)
|
|
||||||
|
|
||||||
-- Command from orig STTS script. Works better for some unknown reason!
|
|
||||||
local command=string.format("start /min \"\" /d \"%s\" /b \"%s\" -f %s -m %s -c %s -p %s -n \"%s\" -h", path, exe, freqs, modus, coal, port, "ROBOT")
|
|
||||||
|
|
||||||
--local command=string.format('start /b "" /d "%s" "%s" -f %s -m %s -c %s -p %s -n "%s" > bla.txt', path, exe, freqs, modus, coal, port, "ROBOT")
|
|
||||||
|
|
||||||
-- Command.
|
-- Command.
|
||||||
local command=string.format('%s/%s -f %s -m %s -c %s -p %s -n "%s"', path, exe, freqs, modus, coal, port, "ROBOT")
|
local command=string.format('"%s\\%s" -f "%s" -m "%s" -c %s -p %s -n "%s" -v "%.1f"', path, exe, freqs, modus, coal, port, label,volume)
|
||||||
|
|
||||||
-- Set voice or gender/culture.
|
-- Set voice or gender/culture.
|
||||||
if voice then
|
if voice then
|
||||||
@@ -671,7 +854,7 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
|||||||
else
|
else
|
||||||
-- Add gender.
|
-- Add gender.
|
||||||
if gender and gender~="female" then
|
if gender and gender~="female" then
|
||||||
command=command..string.format(" --gender=%s", tostring(gender))
|
command=command..string.format(" -g %s", tostring(gender))
|
||||||
end
|
end
|
||||||
-- Add culture.
|
-- Add culture.
|
||||||
if culture and culture~="en-GB" then
|
if culture and culture~="en-GB" then
|
||||||
@@ -696,6 +879,378 @@ function MSRS:_GetCommand(freqs, modus, coal, gender, voice, culture, volume, sp
|
|||||||
return command
|
return command
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Manages radio transmissions.
|
||||||
|
--
|
||||||
|
-- The purpose of the MSRSQUEUE class is to manage SRS text-to-speech (TTS) messages using the MSRS class.
|
||||||
|
-- This can be used to submit multiple TTS messages and the class takes care that they are transmitted one after the other (and not overlapping).
|
||||||
|
--
|
||||||
|
-- @type MSRSQUEUE
|
||||||
|
-- @field #string ClassName Name of the class "MSRSQUEUE".
|
||||||
|
-- @field #string lid ID for dcs.log.
|
||||||
|
-- @field #table queue The queue of transmissions.
|
||||||
|
-- @field #string alias Name of the radio queue.
|
||||||
|
-- @field #number dt Time interval in seconds for checking the radio queue.
|
||||||
|
-- @field #number Tlast Time (abs) when the last transmission finished.
|
||||||
|
-- @field #boolean checking If `true`, the queue update function is scheduled to be called again.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
MSRSQUEUE = {
|
||||||
|
ClassName = "MSRSQUEUE",
|
||||||
|
Debugmode = nil,
|
||||||
|
lid = nil,
|
||||||
|
queue = {},
|
||||||
|
alias = nil,
|
||||||
|
dt = nil,
|
||||||
|
Tlast = nil,
|
||||||
|
checking = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Radio queue transmission data.
|
||||||
|
-- @type MSRSQUEUE.Transmission
|
||||||
|
-- @field #string text Text to be transmitted.
|
||||||
|
-- @field Sound.SRS#MSRS msrs MOOSE SRS object.
|
||||||
|
-- @field #number duration Duration in seconds.
|
||||||
|
-- @field #table subgroups Groups to send subtitle to.
|
||||||
|
-- @field #string subtitle Subtitle of the transmission.
|
||||||
|
-- @field #number subduration Duration of the subtitle being displayed.
|
||||||
|
-- @field #number frequency Frequency.
|
||||||
|
-- @field #number modulation Modulation.
|
||||||
|
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
||||||
|
-- @field #boolean isplaying If true, transmission is currently playing.
|
||||||
|
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
||||||
|
-- @field #number interval Interval in seconds before next transmission.
|
||||||
|
-- @field #boolean TransmitOnlyWithPlayers If true, only transmit if there are alive Players.
|
||||||
|
-- @field Core.Set#SET_CLIENT PlayerSet PlayerSet created when TransmitOnlyWithPlayers == true
|
||||||
|
|
||||||
|
--- Create a new MSRSQUEUE object for a given radio frequency/modulation.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #string alias (Optional) Name of the radio queue.
|
||||||
|
-- @return #MSRSQUEUE self The MSRSQUEUE object.
|
||||||
|
function MSRSQUEUE:New(alias)
|
||||||
|
|
||||||
|
-- Inherit base
|
||||||
|
local self=BASE:Inherit(self, BASE:New()) --#MSRSQUEUE
|
||||||
|
|
||||||
|
self.alias=alias or "My Radio"
|
||||||
|
|
||||||
|
self.dt=1.0
|
||||||
|
|
||||||
|
self.lid=string.format("MSRSQUEUE %s | ", self.alias)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Clear the radio queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @return #MSRSQUEUE self The MSRSQUEUE object.
|
||||||
|
function MSRSQUEUE:Clear()
|
||||||
|
self:I(self.lid.."Clearning MSRSQUEUE")
|
||||||
|
self.queue={}
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a transmission to the radio queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #MSRSQUEUE.Transmission transmission The transmission data table.
|
||||||
|
-- @return #MSRSQUEUE self
|
||||||
|
function MSRSQUEUE:AddTransmission(transmission)
|
||||||
|
|
||||||
|
-- Init.
|
||||||
|
transmission.isplaying=false
|
||||||
|
transmission.Tstarted=nil
|
||||||
|
|
||||||
|
-- Add to queue.
|
||||||
|
table.insert(self.queue, transmission)
|
||||||
|
|
||||||
|
-- Start checking.
|
||||||
|
if not self.checking then
|
||||||
|
self:_CheckRadioQueue()
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Switch to only transmit if there are players on the server.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #boolean Switch If true, only send SRS if there are alive Players.
|
||||||
|
-- @return #MSRSQUEUE self
|
||||||
|
function MSRSQUEUE:SetTransmitOnlyWithPlayers(Switch)
|
||||||
|
self.TransmitOnlyWithPlayers = Switch
|
||||||
|
if Switch == false or Switch==nil then
|
||||||
|
if self.PlayerSet then
|
||||||
|
self.PlayerSet:FilterStop()
|
||||||
|
end
|
||||||
|
self.PlayerSet = nil
|
||||||
|
else
|
||||||
|
self.PlayerSet = SET_CLIENT:New():FilterStart()
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a new transmission and add it to the radio queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #string text Text to play.
|
||||||
|
-- @param #number duration Duration in seconds the file lasts. Default is determined by number of characters of the text message.
|
||||||
|
-- @param Sound.SRS#MSRS msrs MOOSE SRS object.
|
||||||
|
-- @param #number tstart Start time (abs) seconds. Default now.
|
||||||
|
-- @param #number interval Interval in seconds after the last transmission finished.
|
||||||
|
-- @param #table subgroups Groups that should receive the subtiltle.
|
||||||
|
-- @param #string subtitle Subtitle displayed when the message is played.
|
||||||
|
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
|
||||||
|
-- @param #number frequency Radio frequency if other than MSRS default.
|
||||||
|
-- @param #number modulation Radio modulation if other then MSRS default.
|
||||||
|
-- @return #MSRSQUEUE.Transmission Radio transmission table.
|
||||||
|
function MSRSQUEUE:NewTransmission(text, duration, msrs, tstart, interval, subgroups, subtitle, subduration, frequency, modulation)
|
||||||
|
|
||||||
|
if self.TransmitOnlyWithPlayers then
|
||||||
|
if self.PlayerSet and self.PlayerSet:CountAlive() == 0 then
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sanity checks.
|
||||||
|
if not text then
|
||||||
|
self:E(self.lid.."ERROR: No text specified.")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if type(text)~="string" then
|
||||||
|
self:E(self.lid.."ERROR: Text specified is NOT a string.")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Create a new transmission object.
|
||||||
|
local transmission={} --#MSRSQUEUE.Transmission
|
||||||
|
transmission.text=text
|
||||||
|
transmission.duration=duration or STTS.getSpeechTime(text)
|
||||||
|
transmission.msrs=msrs
|
||||||
|
transmission.Tplay=tstart or timer.getAbsTime()
|
||||||
|
transmission.subtitle=subtitle
|
||||||
|
transmission.interval=interval or 0
|
||||||
|
transmission.frequency=frequency
|
||||||
|
transmission.modulation=modulation
|
||||||
|
transmission.subgroups=subgroups
|
||||||
|
if transmission.subtitle then
|
||||||
|
transmission.subduration=subduration or transmission.duration
|
||||||
|
else
|
||||||
|
transmission.subduration=0 --nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add transmission to queue.
|
||||||
|
self:AddTransmission(transmission)
|
||||||
|
|
||||||
|
return transmission
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Broadcast radio message.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #MSRSQUEUE.Transmission transmission The transmission.
|
||||||
|
function MSRSQUEUE:Broadcast(transmission)
|
||||||
|
|
||||||
|
if transmission.frequency then
|
||||||
|
transmission.msrs:PlayTextExt(transmission.text, nil, transmission.frequency, transmission.modulation, Gender, Culture, Voice, Volume, Label)
|
||||||
|
else
|
||||||
|
transmission.msrs:PlayText(transmission.text)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function texttogroup(gid)
|
||||||
|
-- Text to group.
|
||||||
|
trigger.action.outTextForGroup(gid, transmission.subtitle, transmission.subduration, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
if transmission.subgroups and #transmission.subgroups>0 then
|
||||||
|
|
||||||
|
for _,_group in pairs(transmission.subgroups) do
|
||||||
|
local group=_group --Wrapper.Group#GROUP
|
||||||
|
|
||||||
|
if group and group:IsAlive() then
|
||||||
|
local gid=group:GetID()
|
||||||
|
|
||||||
|
self:ScheduleOnce(4, texttogroup, gid)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculate total transmission duration of all transmission in the queue.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @return #number Total transmission duration.
|
||||||
|
function MSRSQUEUE:CalcTransmisstionDuration()
|
||||||
|
|
||||||
|
local Tnow=timer.getAbsTime()
|
||||||
|
|
||||||
|
local T=0
|
||||||
|
for _,_transmission in pairs(self.queue) do
|
||||||
|
local transmission=_transmission --#MSRSQUEUE.Transmission
|
||||||
|
|
||||||
|
if transmission.isplaying then
|
||||||
|
|
||||||
|
-- Playing for dt seconds.
|
||||||
|
local dt=Tnow-transmission.Tstarted
|
||||||
|
|
||||||
|
T=T+transmission.duration-dt
|
||||||
|
|
||||||
|
else
|
||||||
|
T=T+transmission.duration
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return T
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check radio queue for transmissions to be broadcasted.
|
||||||
|
-- @param #MSRSQUEUE self
|
||||||
|
-- @param #number delay Delay in seconds before checking.
|
||||||
|
function MSRSQUEUE:_CheckRadioQueue(delay)
|
||||||
|
|
||||||
|
-- Transmissions in queue.
|
||||||
|
local N=#self.queue
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T2(self.lid..string.format("Check radio queue %s: delay=%.3f sec, N=%d, checking=%s", self.alias, delay or 0, N, tostring(self.checking)))
|
||||||
|
|
||||||
|
if delay and delay>0 then
|
||||||
|
|
||||||
|
-- Delayed call.
|
||||||
|
self:ScheduleOnce(delay, MSRSQUEUE._CheckRadioQueue, self)
|
||||||
|
|
||||||
|
-- Checking on.
|
||||||
|
self.checking=true
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Check if queue is empty.
|
||||||
|
if N==0 then
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
|
||||||
|
|
||||||
|
-- Queue is now empty. Nothing to else to do. We start checking again, if a transmission is added.
|
||||||
|
self.checking=false
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get current abs time.
|
||||||
|
local time=timer.getAbsTime()
|
||||||
|
|
||||||
|
-- Checking on.
|
||||||
|
self.checking=true
|
||||||
|
|
||||||
|
-- Set dt.
|
||||||
|
local dt=self.dt
|
||||||
|
|
||||||
|
|
||||||
|
local playing=false
|
||||||
|
local next=nil --#MSRSQUEUE.Transmission
|
||||||
|
local remove=nil
|
||||||
|
for i,_transmission in ipairs(self.queue) do
|
||||||
|
local transmission=_transmission --#MSRSQUEUE.Transmission
|
||||||
|
|
||||||
|
-- Check if transmission time has passed.
|
||||||
|
if time>=transmission.Tplay then
|
||||||
|
|
||||||
|
-- Check if transmission is currently playing.
|
||||||
|
if transmission.isplaying then
|
||||||
|
|
||||||
|
-- Check if transmission is finished.
|
||||||
|
if time>=transmission.Tstarted+transmission.duration then
|
||||||
|
|
||||||
|
-- Transmission over.
|
||||||
|
transmission.isplaying=false
|
||||||
|
|
||||||
|
-- Remove ith element in queue.
|
||||||
|
remove=i
|
||||||
|
|
||||||
|
-- Store time last transmission finished.
|
||||||
|
self.Tlast=time
|
||||||
|
|
||||||
|
else -- still playing
|
||||||
|
|
||||||
|
-- Transmission is still playing.
|
||||||
|
playing=true
|
||||||
|
|
||||||
|
dt=transmission.duration-(time-transmission.Tstarted)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else -- not playing yet
|
||||||
|
|
||||||
|
local Tlast=self.Tlast
|
||||||
|
|
||||||
|
if transmission.interval==nil then
|
||||||
|
|
||||||
|
-- Not playing ==> this will be next.
|
||||||
|
if next==nil then
|
||||||
|
next=transmission
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
if Tlast==nil or time-Tlast>=transmission.interval then
|
||||||
|
next=transmission
|
||||||
|
else
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
|
||||||
|
if next or Tlast then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Transmission not due yet.
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Found a new transmission.
|
||||||
|
if next~=nil and not playing then
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Broadcasting text=\"%s\" at T=%.3f", next.text, time))
|
||||||
|
|
||||||
|
-- Call SRS.
|
||||||
|
self:Broadcast(next)
|
||||||
|
|
||||||
|
next.isplaying=true
|
||||||
|
next.Tstarted=time
|
||||||
|
dt=next.duration
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove completed call from queue.
|
||||||
|
if remove then
|
||||||
|
-- Remove from queue.
|
||||||
|
table.remove(self.queue, remove)
|
||||||
|
N=N-1
|
||||||
|
|
||||||
|
-- Check if queue is empty.
|
||||||
|
if #self.queue==0 then
|
||||||
|
-- Debug info.
|
||||||
|
self:T(self.lid..string.format("Check radio queue %s empty ==> disable checking", self.alias))
|
||||||
|
|
||||||
|
self.checking=false
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check queue.
|
||||||
|
self:_CheckRadioQueue(dt)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -183,13 +183,17 @@ do -- Sound File
|
|||||||
|
|
||||||
--- Set path, where the sound file is located.
|
--- Set path, where the sound file is located.
|
||||||
-- @param #SOUNDFILE self
|
-- @param #SOUNDFILE self
|
||||||
-- @param #string Path Path to the directory, where the sound file is located.
|
-- @param #string Path Path to the directory, where the sound file is located. In case this is nil, it defaults to the DCS mission temp directory.
|
||||||
-- @return #SOUNDFILE self
|
-- @return #SOUNDFILE self
|
||||||
function SOUNDFILE:SetPath(Path)
|
function SOUNDFILE:SetPath(Path)
|
||||||
|
|
||||||
-- Init path.
|
-- Init path.
|
||||||
self.path=Path or "l10n/DEFAULT/"
|
self.path=Path or "l10n/DEFAULT/"
|
||||||
|
|
||||||
|
if not Path and self.useSRS then -- use path to mission temp dir
|
||||||
|
self.path = os.getenv('TMP') .. "\\DCS\\Mission\\l10n\\DEFAULT"
|
||||||
|
end
|
||||||
|
|
||||||
-- Remove (back)slashes.
|
-- Remove (back)slashes.
|
||||||
local nmax=1000 ; local n=1
|
local nmax=1000 ; local n=1
|
||||||
while (self.path:sub(-1)=="/" or self.path:sub(-1)==[[\]]) and n<=nmax do
|
while (self.path:sub(-1)=="/" or self.path:sub(-1)==[[\]]) and n<=nmax do
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ do -- UserSound
|
|||||||
-- @param #USERSOUND self
|
-- @param #USERSOUND self
|
||||||
-- @param #string UserSoundFileName The filename of the usersound.
|
-- @param #string UserSoundFileName The filename of the usersound.
|
||||||
-- @return #USERSOUND
|
-- @return #USERSOUND
|
||||||
function USERSOUND:New( UserSoundFileName ) --R2.3
|
function USERSOUND:New( UserSoundFileName )
|
||||||
|
|
||||||
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
||||||
--
|
--
|
||||||
function USERSOUND:SetFileName( UserSoundFileName ) --R2.3
|
function USERSOUND:SetFileName( UserSoundFileName )
|
||||||
|
|
||||||
self.UserSoundFileName = UserSoundFileName
|
self.UserSoundFileName = UserSoundFileName
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToAll() --R2.3
|
function USERSOUND:ToAll()
|
||||||
|
|
||||||
trigger.action.outSound( self.UserSoundFileName )
|
trigger.action.outSound( self.UserSoundFileName )
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToCoalition( Coalition ) --R2.3
|
function USERSOUND:ToCoalition( Coalition )
|
||||||
|
|
||||||
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ do -- UserSound
|
|||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToCountry( Country ) --R2.3
|
function USERSOUND:ToCountry( Country )
|
||||||
|
|
||||||
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
||||||
|
|
||||||
@@ -123,9 +123,9 @@ do -- UserSound
|
|||||||
-- @usage
|
-- @usage
|
||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
||||||
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the sound that Blue has won to the player group.
|
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the victory sound to the player group.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToGroup( Group, Delay ) --R2.3
|
function USERSOUND:ToGroup( Group, Delay )
|
||||||
|
|
||||||
Delay=Delay or 0
|
Delay=Delay or 0
|
||||||
if Delay>0 then
|
if Delay>0 then
|
||||||
@@ -136,5 +136,27 @@ do -- UserSound
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Play the usersound to the given @{Wrapper.Unit}.
|
||||||
|
-- @param #USERSOUND self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit The @{Wrapper.Unit} to play the usersound to.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds, before the sound is played. Default 0.
|
||||||
|
-- @return #USERSOUND The usersound instance.
|
||||||
|
-- @usage
|
||||||
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
|
-- local PlayerUnit = UNIT:FindByName( "PlayerUnit" ) -- Search for the active unit named "PlayerUnit", a human player.
|
||||||
|
-- BlueVictory:ToUnit( PlayerUnit ) -- Play the victory sound to the player unit.
|
||||||
|
--
|
||||||
|
function USERSOUND:ToUnit( Unit, Delay )
|
||||||
|
|
||||||
|
Delay=Delay or 0
|
||||||
|
if Delay>0 then
|
||||||
|
SCHEDULER:New(nil, USERSOUND.ToUnit,{self, Unit}, Delay)
|
||||||
|
else
|
||||||
|
trigger.action.outSoundForUnit( Unit:GetID(), self.UserSoundFileName )
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
--- **Tasking** -- A command center governs multiple missions, and takes care of the reporting and communications.
|
--- **Tasking** - A command center governs multiple missions, and takes care of the reporting and communications.
|
||||||
--
|
--
|
||||||
-- **Features:**
|
-- **Features:**
|
||||||
--
|
--
|
||||||
@@ -216,7 +216,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
|
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
|
||||||
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportSummary, self, EventGroup )
|
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportSummary, self, EventGroup )
|
||||||
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
|
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
|
||||||
self:ReportSummary( EventGroup )
|
--self:ReportSummary( EventGroup )
|
||||||
local PlayerUnit = EventData.IniUnit
|
local PlayerUnit = EventData.IniUnit
|
||||||
for MissionID, Mission in pairs( self:GetMissions() ) do
|
for MissionID, Mission in pairs( self:GetMissions() ) do
|
||||||
local Mission = Mission -- Tasking.Mission#MISSION
|
local Mission = Mission -- Tasking.Mission#MISSION
|
||||||
@@ -560,9 +560,11 @@ function COMMANDCENTER:SetAutoAssignTasks( AutoAssign )
|
|||||||
self.AutoAssignTasks = AutoAssign or false
|
self.AutoAssignTasks = AutoAssign or false
|
||||||
|
|
||||||
if self.AutoAssignTasks == true then
|
if self.AutoAssignTasks == true then
|
||||||
self:ScheduleRepeat( 10, 30, 0, nil, self.AssignTasks, self )
|
self.autoAssignTasksScheduleID=self:ScheduleRepeat( 10, 30, 0, nil, self.AssignTasks, self )
|
||||||
else
|
else
|
||||||
self:ScheduleStop( self.AssignTasks )
|
self:ScheduleStop()
|
||||||
|
-- FF this is not the schedule ID
|
||||||
|
--self:ScheduleStop( self.AssignTasks )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user