mirror of
https://github.com/spencershepard/RotorOps.git
synced 2025-11-10 15:45:30 +00:00
1.4.1 (#42)
* RotorOpsPerks, mist change, ice halo fix * Update RotorOpsPerks.lua - added new points conditions, revised cas bonus - allow perks to be defined dynamically - option to silence point scoring messages - added red coalition support - multicrew support! Update MissionGenerator.exe for release
This commit is contained in:
parent
f382a2e3cc
commit
76e2858c7b
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -4,6 +4,8 @@ on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
if_merged:
|
||||
|
||||
@ -549,6 +549,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
"imports": self.imports_list,
|
||||
}
|
||||
|
||||
# holds our generator options. We'll pull from the UI or the scenario config file
|
||||
data = {
|
||||
"objects": objects,
|
||||
"credits": credits,
|
||||
@ -591,6 +592,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
"red_cap": self.scenario.getConfigValue("red_cap", default=True),
|
||||
"blue_cap": self.scenario.getConfigValue("blue_cap", default=True),
|
||||
"rotorops_server": self.scenario.getConfigValue("rotorops_server", default=False),
|
||||
"perks": self.perks_checkBox.isChecked(),
|
||||
}
|
||||
|
||||
logger.info("Generating mission with options:")
|
||||
|
||||
@ -236,7 +236,7 @@ class Ui_MainWindow(object):
|
||||
self.label_2.setFont(font)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.scenario_label_9 = QtWidgets.QLabel(self.centralwidget)
|
||||
self.scenario_label_9.setGeometry(QtCore.QRect(480, 401, 251, 23))
|
||||
self.scenario_label_9.setGeometry(QtCore.QRect(500, 401, 251, 23))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(10)
|
||||
self.scenario_label_9.setFont(font)
|
||||
@ -258,21 +258,21 @@ class Ui_MainWindow(object):
|
||||
self.tankers_checkBox.setChecked(True)
|
||||
self.tankers_checkBox.setObjectName("tankers_checkBox")
|
||||
self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
|
||||
self.voiceovers_checkBox.setGeometry(QtCore.QRect(500, 594, 171, 31))
|
||||
self.voiceovers_checkBox.setGeometry(QtCore.QRect(500, 584, 171, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
self.voiceovers_checkBox.setFont(font)
|
||||
self.voiceovers_checkBox.setChecked(True)
|
||||
self.voiceovers_checkBox.setObjectName("voiceovers_checkBox")
|
||||
self.smoke_pickup_zone_checkBox = QtWidgets.QCheckBox(self.centralwidget)
|
||||
self.smoke_pickup_zone_checkBox.setGeometry(QtCore.QRect(500, 541, 231, 20))
|
||||
self.smoke_pickup_zone_checkBox.setGeometry(QtCore.QRect(500, 530, 231, 20))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
self.smoke_pickup_zone_checkBox.setFont(font)
|
||||
self.smoke_pickup_zone_checkBox.setChecked(False)
|
||||
self.smoke_pickup_zone_checkBox.setObjectName("smoke_pickup_zone_checkBox")
|
||||
self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget)
|
||||
self.game_status_checkBox.setGeometry(QtCore.QRect(500, 570, 221, 21))
|
||||
self.game_status_checkBox.setGeometry(QtCore.QRect(500, 560, 221, 21))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
self.game_status_checkBox.setFont(font)
|
||||
@ -339,7 +339,7 @@ class Ui_MainWindow(object):
|
||||
self.generateButton.setStyleSheet("")
|
||||
self.generateButton.setObjectName("generateButton")
|
||||
self.farp_always = QtWidgets.QRadioButton(self.centralwidget)
|
||||
self.farp_always.setGeometry(QtCore.QRect(500, 431, 261, 24))
|
||||
self.farp_always.setGeometry(QtCore.QRect(520, 431, 261, 24))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
self.farp_always.setFont(font)
|
||||
@ -348,14 +348,14 @@ class Ui_MainWindow(object):
|
||||
self.farp_buttonGroup.setObjectName("farp_buttonGroup")
|
||||
self.farp_buttonGroup.addButton(self.farp_always)
|
||||
self.farp_never = QtWidgets.QRadioButton(self.centralwidget)
|
||||
self.farp_never.setGeometry(QtCore.QRect(500, 491, 271, 24))
|
||||
self.farp_never.setGeometry(QtCore.QRect(520, 491, 271, 24))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
self.farp_never.setFont(font)
|
||||
self.farp_never.setObjectName("farp_never")
|
||||
self.farp_buttonGroup.addButton(self.farp_never)
|
||||
self.farp_gunits = QtWidgets.QRadioButton(self.centralwidget)
|
||||
self.farp_gunits.setGeometry(QtCore.QRect(500, 460, 261, 24))
|
||||
self.farp_gunits.setGeometry(QtCore.QRect(520, 460, 261, 24))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
self.farp_gunits.setFont(font)
|
||||
@ -458,6 +458,13 @@ class Ui_MainWindow(object):
|
||||
self.farp_spawn_checkBox.setChecked(False)
|
||||
self.farp_spawn_checkBox.setTristate(False)
|
||||
self.farp_spawn_checkBox.setObjectName("farp_spawn_checkBox")
|
||||
self.perks_checkBox = QtWidgets.QCheckBox(self.centralwidget)
|
||||
self.perks_checkBox.setGeometry(QtCore.QRect(500, 610, 171, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
self.perks_checkBox.setFont(font)
|
||||
self.perks_checkBox.setChecked(True)
|
||||
self.perks_checkBox.setObjectName("perks_checkBox")
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 1280, 29))
|
||||
@ -655,6 +662,8 @@ class Ui_MainWindow(object):
|
||||
self.time_comboBox.setStatusTip(_translate("MainWindow", "Mission start time of day. \'Default\' is the start time as defined by the mission template designer."))
|
||||
self.farp_spawn_checkBox.setStatusTip(_translate("MainWindow", "Add helicopter slots where zone FARPs will be built. Helicopters will be empty fuel, requiring the FARP to be established to refuel and rearm."))
|
||||
self.farp_spawn_checkBox.setText(_translate("MainWindow", "Spawns at zone FARPs"))
|
||||
self.perks_checkBox.setStatusTip(_translate("MainWindow", "Adds a rewards system with points for kills, troop drops, etc. See the F10 menu to use Perks."))
|
||||
self.perks_checkBox.setText(_translate("MainWindow", "Perks"))
|
||||
self.menuMap.setTitle(_translate("MainWindow", "Map"))
|
||||
self.menuFilter.setTitle(_translate("MainWindow", "Filter"))
|
||||
self.menuPreferences.setTitle(_translate("MainWindow", "Preferences"))
|
||||
|
||||
@ -619,7 +619,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QLabel" name="scenario_label_9">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>480</x>
|
||||
<x>500</x>
|
||||
<y>401</y>
|
||||
<width>251</width>
|
||||
<height>23</height>
|
||||
@ -688,7 +688,7 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>594</y>
|
||||
<y>584</y>
|
||||
<width>171</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -712,7 +712,7 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>541</y>
|
||||
<y>530</y>
|
||||
<width>231</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
@ -736,7 +736,7 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>570</y>
|
||||
<y>560</y>
|
||||
<width>221</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
@ -946,7 +946,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QRadioButton" name="farp_always">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<x>520</x>
|
||||
<y>431</y>
|
||||
<width>261</width>
|
||||
<height>24</height>
|
||||
@ -970,7 +970,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QRadioButton" name="farp_never">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<x>520</x>
|
||||
<y>491</y>
|
||||
<width>271</width>
|
||||
<height>24</height>
|
||||
@ -994,7 +994,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QRadioButton" name="farp_gunits">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<x>520</x>
|
||||
<y>460</y>
|
||||
<width>261</width>
|
||||
<height>24</height>
|
||||
@ -1317,6 +1317,30 @@ p, li { white-space: pre-wrap; }
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="perks_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>610</y>
|
||||
<width>171</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Adds a rewards system with points for kills, troop drops, etc. See the F10 menu to use Perks.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Perks</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
|
||||
@ -20,7 +20,8 @@ def triggerSetup(rops, options):
|
||||
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["Splash_Damage_2_0.lua"]))
|
||||
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["CTLD.lua"]))
|
||||
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["RotorOps.lua"]))
|
||||
script = ""
|
||||
if options["perks"]:
|
||||
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["RotorOpsPerks.lua"]))
|
||||
script = ("--OPTIONS HERE!\n\n" +
|
||||
"RotorOps.CTLD_crates = " + lb("crates") + "\n\n" +
|
||||
"RotorOps.CTLD_sound_effects = true\n\n" +
|
||||
|
||||
@ -348,6 +348,11 @@ class RotorOpsMission:
|
||||
# Add AI Flights
|
||||
self.addFlights(options, red_forces, blue_forces)
|
||||
|
||||
# Add source statics
|
||||
if options["perks"]:
|
||||
# fat cow farps require source objects to work (can't be dynamically inserted)
|
||||
self.addSourceStatics(options)
|
||||
|
||||
# Set the Editor Map View
|
||||
self.m.map.position = self.conflict_zones["ALPHA"].position
|
||||
self.m.map.zoom = 100000
|
||||
@ -365,6 +370,11 @@ class RotorOpsMission:
|
||||
|
||||
# set the weather and time
|
||||
|
||||
#pydcs bug fix
|
||||
if self.m.weather.halo.preset == {}:
|
||||
self.m.weather.halo.preset = dcs.weather.Halo.Preset.Auto
|
||||
self.m.weather.halo.crystals = None
|
||||
|
||||
if options["random_weather"]:
|
||||
# self.m.random_weather = True
|
||||
max = len(dcs.cloud_presets.CLOUD_PRESETS) - 1
|
||||
@ -813,6 +823,36 @@ class RotorOpsMission:
|
||||
f_cap_spawn_point = primary_f_airport.position.point_from_heading(e_airport_heading + 180, 100000)
|
||||
self.m.triggers.add_triggerzone(f_cap_spawn_point, 30000, hidden=True, name="BLUE_CAP_SPAWN")
|
||||
|
||||
# Fat Cow
|
||||
if True:
|
||||
helo_type = dcs.helicopters.CH_47D
|
||||
name = "FAT COW"
|
||||
|
||||
airport = self.getParking(primary_f_airport, helo_type, friendly_airports, 1)
|
||||
|
||||
if carrier:
|
||||
afg = self.m.flight_group_from_unit(
|
||||
combinedJointTaskForcesBlue,
|
||||
name,
|
||||
helo_type,
|
||||
carrier,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=1)
|
||||
afg.set_skill(dcs.unit.Skill.Excellent)
|
||||
afg.late_activation = True
|
||||
|
||||
elif airport:
|
||||
afg = self.m.flight_group_from_airport(
|
||||
combinedJointTaskForcesBlue,
|
||||
name,
|
||||
helo_type,
|
||||
airport=airport,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=1)
|
||||
afg.set_skill(dcs.unit.Skill.Excellent)
|
||||
afg.late_activation = True
|
||||
|
||||
|
||||
if options["f_awacs"]:
|
||||
awacs_name = "AWACS"
|
||||
awacs_freq = 266
|
||||
@ -966,8 +1006,6 @@ class RotorOpsMission:
|
||||
group_size=group_size)
|
||||
zone_attack(afg, airport)
|
||||
|
||||
else:
|
||||
return
|
||||
|
||||
if source_helo and afg:
|
||||
for unit in afg.units:
|
||||
@ -1202,3 +1240,48 @@ class RotorOpsMission:
|
||||
def addMods(self):
|
||||
dcs.helicopters.helicopter_map["UH-60L"] = aircraftMods.UH_60L
|
||||
self.m.country(jtf_blue).helicopters.append(aircraftMods.UH_60L)
|
||||
|
||||
def addSourceStatics(self, options):
|
||||
insert_point = None
|
||||
if self.m.terrain.name == "Caucasus":
|
||||
insert_point = dcs.mapping.Point(-500000, 200000, dcs.terrain.Caucasus)
|
||||
elif self.m.terrain.name == "Falklands":
|
||||
insert_point = dcs.mapping.Point(216000, -990000, dcs.terrain.Falklands)
|
||||
elif self.m.terrain.name == "MarianaIslands":
|
||||
insert_point = dcs.mapping.Point(686200, 71200, dcs.terrain.MarianaIslands)
|
||||
elif self.m.terrain.name == "PersianGulf":
|
||||
insert_point = dcs.mapping.Point(-350000, -800000, dcs.terrain.PersianGulf)
|
||||
elif self.m.terrain.name == "Nevada":
|
||||
insert_point = dcs.mapping.Point(-140000, -300000, dcs.terrain.Nevada)
|
||||
elif self.m.terrain.name == "Syria":
|
||||
insert_point = dcs.mapping.Point(235000, -440000, dcs.terrain.Syria)
|
||||
|
||||
if insert_point:
|
||||
|
||||
for i in range(1, 4):
|
||||
fuel = self.m.static_group(name="FAT COW FUEL " + str(i),
|
||||
_type=dcs.statics.Fortification.FARP_Fuel_Depot,
|
||||
country=self.m.country(jtf_blue),
|
||||
position=insert_point.random_point_within(1000, 1000),
|
||||
heading=0,
|
||||
hidden=True,)
|
||||
fuel.units[0].name = "FAT COW FUEL " + str(i)
|
||||
|
||||
ammo = self.m.static_group(name="FAT COW AMMO " + str(i),
|
||||
_type=dcs.statics.Fortification.FARP_Ammo_Dump_Coating,
|
||||
country=self.m.country(jtf_blue),
|
||||
position=insert_point.random_point_within(1000, 1000),
|
||||
heading=0,
|
||||
hidden=True, )
|
||||
ammo.units[0].name = "FAT COW AMMO " + str(i)
|
||||
|
||||
tent = self.m.static_group(name="FAT COW TENT " + str(i),
|
||||
_type=dcs.statics.Fortification.FARP_Tent,
|
||||
country=self.m.country(jtf_blue),
|
||||
position=insert_point.random_point_within(1000, 1000),
|
||||
heading=0,
|
||||
hidden=True, )
|
||||
tent.units[0].name = "FAT COW TENT " + str(i)
|
||||
|
||||
self.m.farp(self.m.country(jtf_blue), "FAT COW FARP " + str(i),
|
||||
insert_point.random_point_within(1000, 1000), hidden=True, dead=False, farp_type=dcs.unit.InvisibleFARP)
|
||||
|
||||
Binary file not shown.
BIN
Generator/install_forge/IFSetup.exe
Normal file
BIN
Generator/install_forge/IFSetup.exe
Normal file
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
# ROTOROPS VERSION
|
||||
maj_version = 1
|
||||
minor_version = 3
|
||||
patch_version = 2
|
||||
minor_version = 4
|
||||
patch_version = 1
|
||||
|
||||
version_url = 'https://dcs-helicopters.com/app-updates/versioncheck.yaml'
|
||||
|
||||
|
||||
Binary file not shown.
BIN
assets/Header_1.bmp
Normal file
BIN
assets/Header_1.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
assets/Header_2.bmp
Normal file
BIN
assets/Header_2.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/Wizard_1.bmp
Normal file
BIN
assets/Wizard_1.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/Wizard_2.bmp
Normal file
BIN
assets/Wizard_2.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/ancient.ico
Normal file
BIN
assets/ancient.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/modern.ico
Normal file
BIN
assets/modern.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
RotorOps = {}
|
||||
RotorOps.version = "1.3.3"
|
||||
RotorOps.version = "1.3.4"
|
||||
local debug = true
|
||||
|
||||
|
||||
@ -1517,6 +1517,10 @@ end
|
||||
|
||||
--make some changes to the CTLD script/settings
|
||||
function RotorOps.setupCTLD()
|
||||
if not ctld then
|
||||
trigger.action.outText("ERROR: CTLD Not Loaded!!", 90)
|
||||
return
|
||||
end
|
||||
if type(ctld.pickupZones[1][2]) == "number" then --ctld converts its string table to integer on load, so we'll see if that's happened already
|
||||
trigger.action.outText("ERROR: CTLD Loaded Too Soon!!", 90)
|
||||
return
|
||||
|
||||
890
scripts/RotorOpsPerks.lua
Normal file
890
scripts/RotorOpsPerks.lua
Normal file
@ -0,0 +1,890 @@
|
||||
--ROTOROPS PERKS by GRIMM
|
||||
--Points and rewards system
|
||||
--Check out RotorOps at dcs-helicopters.com
|
||||
--Full documentation on Github (see the Wiki: RotorOps PERKS)
|
||||
|
||||
--How to use: load the script in do script trigger after the mission begins. Requires MIST, but CTLD is optional. Load scripts in this order: 1) MIST 2) CTLD 3) RotorOpsPerks
|
||||
--This script will add a new menu to the F10 menu called "RotorOps Perks". This menu will allow you to select a perk to use.
|
||||
--You can define the points earner per action, and the perk options below.
|
||||
|
||||
-- Issues:
|
||||
-- - You will not get points for your troops' kills if you leave your group (ie switch aircraft)
|
||||
|
||||
|
||||
RotorOpsPerks = {}
|
||||
RotorOpsPerks.version = "1.3"
|
||||
trigger.action.outText('ROTOROPS PERKS STARTED: '..RotorOpsPerks.version, 10)
|
||||
RotorOpsPerks.perks = {}
|
||||
RotorOpsPerks.players = {}
|
||||
RotorOpsPerks.players_temp = {}
|
||||
RotorOpsPerks.troops = {} --by group name
|
||||
|
||||
---- OPTIONS ----
|
||||
|
||||
RotorOpsPerks.silent_points = false --set to true to disable text on points scoring
|
||||
RotorOpsPerks.player_update_messages = true --set to false to disable messages when players are added/updated to score keeping
|
||||
RotorOpsPerks.debug = true
|
||||
|
||||
RotorOpsPerks.points = {
|
||||
player_default=0, --how many points each player will start with
|
||||
kill=10,
|
||||
kill_inf=5,
|
||||
kill_heli=20,
|
||||
kill_plane=20,
|
||||
kill_armor=15,
|
||||
kill_ship=15,
|
||||
cas_bonus=5, --you were in proximity of your troops killing something
|
||||
dropped_troops_kill_inf=5, --your troops killed infantry
|
||||
dropped_troops_kill=10, --your troops killed a vehicle
|
||||
dropped_troops_kill_armor=15, --your troops killed armor
|
||||
rearm=10, --ctld rearm/repair of ground units
|
||||
unpack=10, --ctld unpack of ground units
|
||||
}
|
||||
|
||||
---- END OPTIONS ----
|
||||
|
||||
local function debugMsg(msg)
|
||||
if RotorOpsPerks.debug then
|
||||
env.info("ROTOROPS PERKS:")
|
||||
env.info(msg)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---- FATCOW PERK ----
|
||||
--Fat Cow FARP requires static farp objects to work (they are teleported to the landing zone), and a late activated helicopter called 'FAT COW'. See the wiki for more details.
|
||||
|
||||
function requestFatCowPerk(args)
|
||||
local index = RotorOpsPerks.perks.fatcow.used + 1
|
||||
RotorOpsPerks.spawnFatCow(args.target_point, index)
|
||||
end
|
||||
|
||||
|
||||
RotorOpsPerks.perks["fatcow"] = {
|
||||
perk_name='fatcow',
|
||||
display_name='FatCow FARP',
|
||||
cost=100,
|
||||
cooldown=60,
|
||||
max_per_player=1,
|
||||
max_per_mission=4, --for fatcow, you will want to ensure that you have this many sets of FARP statics
|
||||
at_mark=true,
|
||||
at_position=true,
|
||||
enabled=true,
|
||||
sides={0,1,2},
|
||||
last_used=0,
|
||||
used=0,
|
||||
action_function=requestFatCowPerk
|
||||
}
|
||||
|
||||
---- INSTANT STRIKE PERK ----
|
||||
|
||||
function requestStrikePerk(args)
|
||||
--explosion at dest_point after 10 seconds
|
||||
timer.scheduleFunction(function()
|
||||
trigger.action.explosion(args.target_point, 1000)
|
||||
end, nil, timer.getTime() + 10)
|
||||
end
|
||||
|
||||
RotorOpsPerks.perks["strike"] = {
|
||||
perk_name='strike',
|
||||
display_name='Instant Strike',
|
||||
cost=100,
|
||||
cooldown=60,
|
||||
max_per_player=2,
|
||||
max_per_mission=3,
|
||||
at_mark=true,
|
||||
at_position=false,
|
||||
enabled=true,
|
||||
sides={0,1,2},
|
||||
last_used=0,
|
||||
used=0,
|
||||
action_function=requestStrikePerk
|
||||
}
|
||||
|
||||
|
||||
|
||||
function RotorOpsPerks.getPlayerGroupSum(player_group_name, player_attribute, table_name)
|
||||
--loop through RotorOpsPerks.playersByGroupName
|
||||
local players = RotorOpsPerks.playersByGroupName(player_group_name)
|
||||
if not players then
|
||||
return false
|
||||
end
|
||||
|
||||
local total = 0
|
||||
for _, player in pairs(players) do
|
||||
if table_name then
|
||||
total = total + (player[table_name][player_attribute] or 0)
|
||||
else
|
||||
total = total + (player[player_attribute] or 0)
|
||||
end
|
||||
end
|
||||
return total
|
||||
|
||||
end
|
||||
|
||||
|
||||
function RotorOpsPerks.spendPoints(player_group_name, points)
|
||||
local players = RotorOpsPerks.playersByGroupName(player_group_name)
|
||||
local total_points = RotorOpsPerks.getPlayerGroupSum(player_group_name, "points")
|
||||
--if players have enough combined points
|
||||
if total_points < points then
|
||||
return false
|
||||
end
|
||||
|
||||
--divide points by the number of players to get an integer
|
||||
local points_per_player = math.floor(points/#players)
|
||||
|
||||
--subtract points from each player equally. If a player doesn't have enough points, subtract the remainder from the next player
|
||||
local remainder = 0
|
||||
for _, player in pairs(players) do
|
||||
local points_to_subtract = points_per_player + remainder
|
||||
if player.points < points_to_subtract then
|
||||
remainder = points_to_subtract - player.points
|
||||
player.points = 0
|
||||
else
|
||||
player.points = player.points - points_to_subtract
|
||||
remainder = 0
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function RotorOpsPerks.scorePoints(player_group_name, points, message)
|
||||
--score points for all players in the group
|
||||
local players = RotorOpsPerks.playersByGroupName(player_group_name)
|
||||
if players then
|
||||
for _, player in pairs(players) do
|
||||
player.points = player.points + points
|
||||
end
|
||||
if message and not RotorOpsPerks.silent_points then
|
||||
local total = RotorOpsPerks.getPlayerGroupSum(player_group_name, "points")
|
||||
if #players > 1 then
|
||||
message = message.." +"..points.." points (" .. total .. " group total)"
|
||||
else
|
||||
message = message.." +"..points.." points (" .. total .. ")"
|
||||
end
|
||||
trigger.action.outTextForGroup(Group.getByName(player_group_name):getID(), message, 10)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function RotorOpsPerks.checkPoints(player_group_name)
|
||||
local groupId = Group.getByName(player_group_name):getID()
|
||||
local players = RotorOpsPerks.playersByGroupName(player_group_name)
|
||||
if not players then
|
||||
return false
|
||||
end
|
||||
|
||||
--get combined points from all Players
|
||||
local total_points = 0
|
||||
for _, player in pairs(players) do
|
||||
total_points = total_points + player.points
|
||||
end
|
||||
if #players == 1 then
|
||||
trigger.action.outTextForGroup(groupId, 'You have ' .. total_points .. ' points.', 10)
|
||||
else
|
||||
trigger.action.outTextForGroup(groupId, 'Your group has ' .. total_points .. ' total points.', 10)
|
||||
end
|
||||
end
|
||||
|
||||
function RotorOpsPerks.buildPlayer(identifier, groupName, name, slot, temp_id)
|
||||
-- if we're missing any of the required attributes, add to temp table until we collect all attributes
|
||||
if not groupName or not name or not slot then
|
||||
--create the temp player object if doesn't exist yet
|
||||
if not RotorOpsPerks.players_temp[temp_id] then
|
||||
RotorOpsPerks.players_temp[temp_id] = {
|
||||
identifier=identifier,
|
||||
name=name,
|
||||
slot=slot,
|
||||
groupName = groupName,
|
||||
}
|
||||
end
|
||||
--store individual attributes if available
|
||||
RotorOpsPerks.players_temp[temp_id].identifier = identifier or RotorOpsPerks.players_temp[temp_id].identifier
|
||||
RotorOpsPerks.players_temp[temp_id].name = name or RotorOpsPerks.players_temp[temp_id].name
|
||||
RotorOpsPerks.players_temp[temp_id].slot = slot or RotorOpsPerks.players_temp[temp_id].slot
|
||||
RotorOpsPerks.players_temp[temp_id].groupName = groupName or RotorOpsPerks.players_temp[temp_id].groupName
|
||||
--reassign the function args
|
||||
identifier = RotorOpsPerks.players_temp[temp_id].identifier
|
||||
name = RotorOpsPerks.players_temp[temp_id].name
|
||||
slot = RotorOpsPerks.players_temp[temp_id].slot
|
||||
groupName = RotorOpsPerks.players_temp[temp_id].groupName
|
||||
--if we're still missing attributes, return
|
||||
if not groupName or not name or not slot or not identifier then
|
||||
env.warning('MISSING ATTRIBUTES FOR ' .. temp_id)
|
||||
debugMsg(mist.utils.tableShow(RotorOpsPerks.players_temp[temp_id]))
|
||||
return
|
||||
end
|
||||
|
||||
--we have all we need, so add to the players table
|
||||
debugMsg('BUILDPLAYER: Now adding ' .. temp_id .. ' to players table as ' .. identifier)
|
||||
RotorOpsPerks.updatePlayer(identifier, groupName, name, slot)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function RotorOpsPerks.updatePlayer(identifier, groupName, name, slot)
|
||||
if not Group.getByName(groupName) then
|
||||
env.warning('GROUP ' .. groupName .. ' DOES NOT EXIST')
|
||||
return
|
||||
end
|
||||
|
||||
local groupId = Group.getByName(groupName):getID()
|
||||
local side = Group.getByName(groupName):getCoalition()
|
||||
|
||||
|
||||
--add a new player
|
||||
if not RotorOpsPerks.players[identifier] then
|
||||
RotorOpsPerks.players[identifier] = {
|
||||
name=name,
|
||||
slot=slot,
|
||||
points = RotorOpsPerks.points.player_default,
|
||||
groupId = groupId,
|
||||
groupName = groupName,
|
||||
side = side,
|
||||
menu = {},
|
||||
perks_used = {},
|
||||
}
|
||||
env.warning('ADDED ' .. identifier .. ' TO PLAYERS TABLE')
|
||||
missionCommands.removeItemForGroup(groupId, {[1] = 'ROTOROPS PERKS'})
|
||||
RotorOpsPerks.addRadioMenuForGroup(groupName)
|
||||
if RotorOpsPerks.player_update_messages then
|
||||
trigger.action.outText('PERKS: Added ' .. name .. ' to '.. groupName, 10)
|
||||
end
|
||||
|
||||
--update an existing player
|
||||
elseif RotorOpsPerks.players[identifier].groupId ~= groupId then
|
||||
env.warning('UPDATING ' .. identifier .. ' TO GROUP NAME: ' .. groupName)
|
||||
if RotorOpsPerks.player_update_messages then
|
||||
trigger.action.outText('PERKS: ' .. name .. ' moved to '.. groupName, 10)
|
||||
end
|
||||
|
||||
--update player
|
||||
RotorOpsPerks.players[identifier].groupId = groupId
|
||||
RotorOpsPerks.players[identifier].groupName = groupName
|
||||
RotorOpsPerks.players[identifier].side = side
|
||||
RotorOpsPerks.players[identifier].slot = slot
|
||||
RotorOpsPerks.players[identifier].name = name
|
||||
|
||||
|
||||
--REMOVE RADIO ITEMS FOR GROUP (since another player may have been in the group previously)
|
||||
-- missionCommands.removeItemForGroup(groupId, RotorOpsPerks.players[identifier].menu.root)
|
||||
missionCommands.removeItemForGroup(groupId, {[1] = 'ROTOROPS PERKS'})
|
||||
RotorOpsPerks.addRadioMenuForGroup(groupName)
|
||||
end
|
||||
end
|
||||
|
||||
--returns a table of players matching the group name
|
||||
function RotorOpsPerks.playersByGroupName(group_name)
|
||||
local players = {}
|
||||
for identifier, player in pairs(RotorOpsPerks.players) do
|
||||
if player.groupName == group_name then
|
||||
players[#players + 1] = player
|
||||
end
|
||||
end
|
||||
return players
|
||||
end
|
||||
|
||||
|
||||
function RotorOpsPerks.addRadioMenuForGroup(groupName)
|
||||
local groupId = Group.getByName(groupName):getID()
|
||||
local group_side = Group.getByName(groupName):getCoalition()
|
||||
|
||||
-- local function addPerkCommand(groupId, groupName, perk, path, vars)
|
||||
-- missionCommands.addCommandForGroup(groupId, 'Request '.. perk.display_name .. ' at ' .. vars.target, path , RotorOpsPerks.requestPerk, {player_group_name=groupName, perk_name=perk_name, target=vars.target})
|
||||
-- end
|
||||
|
||||
local menu_root = missionCommands.addSubMenuForGroup(groupId, 'ROTOROPS PERKS')
|
||||
missionCommands.addCommandForGroup(groupId, 'Check points balance', menu_root, RotorOpsPerks.checkPoints, groupName)
|
||||
|
||||
for perk_name, perk in pairs(RotorOpsPerks.perks) do
|
||||
|
||||
local avail_for_side = false
|
||||
for _, side in pairs(perk.sides) do
|
||||
if group_side == side then
|
||||
avail_for_side = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if perk.enabled and avail_for_side then
|
||||
if perk.at_mark then
|
||||
--addPerkCommand(groupId, groupName, perk, menu_root, {target='mark'})
|
||||
missionCommands.addCommandForGroup(groupId, 'Request '.. perk.display_name .. ' at mark (' .. perk.perk_name ..')', menu_root , RotorOpsPerks.requestPerk, {player_group_name=groupName, perk_name=perk.perk_name, target='mark'})
|
||||
end
|
||||
if perk.at_position then
|
||||
--addPerkCommand(groupId, groupName, perk, menu_root, {target='position'})
|
||||
missionCommands.addCommandForGroup(groupId, 'Request '.. perk.display_name .. ' at current position', menu_root , RotorOpsPerks.requestPerk, {player_group_name=groupName, perk_name=perk.perk_name, target='position'})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function teleportStatic(source_name, dest_point)
|
||||
debugMsg('teleportStatic: ' .. source_name)
|
||||
local source = StaticObject.getByName(source_name)
|
||||
if not source then
|
||||
env.info('teleportStatic: source not found: ' .. source_name)
|
||||
return
|
||||
end
|
||||
local vars = {}
|
||||
vars.gpName = source_name
|
||||
vars.action = 'teleport'
|
||||
vars.point = mist.utils.makeVec3(dest_point)
|
||||
local res = mist.teleportToPoint(vars)
|
||||
if res then
|
||||
env.info('teleportStatic: ' .. source_name .. ' success')
|
||||
else
|
||||
env.info('teleportStatic: ' .. source_name .. ' failed')
|
||||
end
|
||||
end
|
||||
|
||||
function RotorOpsPerks.spawnFatCowFarpObjects(pt_x, pt_y, index)
|
||||
env.info('spawnFatCowFarpObjects called. Looking for static group names ending in ' .. index)
|
||||
local dest_point = mist.utils.makeVec3GL({x = pt_x, y = pt_y})
|
||||
trigger.action.smoke(dest_point, 2)
|
||||
|
||||
trigger.action.outText('FatCow FARP deploying...get clear of the landing zone!', 20)
|
||||
timer.scheduleFunction(function()
|
||||
local fuel_point = {x = dest_point.x + 35, y = dest_point.y, z = dest_point.z}
|
||||
teleportStatic('FAT COW FUEL ' .. index, fuel_point)
|
||||
teleportStatic('FAT COW TENT ' .. index, fuel_point)
|
||||
|
||||
local ammo_point = {x = dest_point.x - 35, y = dest_point.y, z = dest_point.z}
|
||||
teleportStatic('FAT COW AMMO ' .. index, ammo_point)
|
||||
|
||||
end, nil, timer.getTime() + 235)
|
||||
end
|
||||
|
||||
|
||||
function RotorOpsPerks.spawnFatCow(dest_point, index)
|
||||
local fatcow_name = 'FAT COW'
|
||||
local source_farp_name = 'FAT COW FARP ' .. index
|
||||
|
||||
env.info('spawnFatCow called with ' .. source_farp_name)
|
||||
dest_point = mist.utils.makeVec2(dest_point)
|
||||
local approach_point = mist.getRandPointInCircle(dest_point, 1000, 900)
|
||||
--trigger.action.smoke(mist.utils.makeVec3GL(approach_point), 1)
|
||||
trigger.action.smoke(mist.utils.makeVec3GL(dest_point), 2)
|
||||
|
||||
|
||||
local fatcow_group = Group.getByName(fatcow_name)
|
||||
if not fatcow_group then
|
||||
env.warning('FatCow group not found')
|
||||
return
|
||||
end
|
||||
|
||||
teleportStatic(source_farp_name, dest_point)
|
||||
|
||||
local airbasefarp = Airbase.getByName(source_farp_name)
|
||||
if not airbasefarp then
|
||||
env.warning('FatCow FARP not found: ' .. source_farp_name)
|
||||
return
|
||||
end
|
||||
|
||||
local airbase_pos = mist.utils.makeVec2(airbasefarp:getPoint())
|
||||
|
||||
|
||||
local script = [[
|
||||
RotorOpsPerks.spawnFatCowFarpObjects(]] .. dest_point.x ..[[,]] .. dest_point.y .. [[,]] .. index .. [[)
|
||||
env.info('FatCow FARP deployment scheduled')
|
||||
]]
|
||||
|
||||
|
||||
local myscriptaction = {
|
||||
id = 'WrappedAction',
|
||||
params = {
|
||||
action = {
|
||||
id = 'Script',
|
||||
params = {
|
||||
command = script,
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local script_string = [[local this_grp = ...
|
||||
this_grp:getController():setOption(AI.Option.Air.id.REACTION_ON_THREAT , AI.Option.Air.val.REACTION_ON_THREAT.EVADE_FIRE)
|
||||
this_grp:getController():setOption(AI.Option.Air.id.FLARE_USING , AI.Option.Air.val.FLARE_USING.WHEN_FLYING_NEAR_ENEMIES)]]
|
||||
|
||||
local setOptions = {
|
||||
id = 'WrappedAction',
|
||||
params = {
|
||||
action = {
|
||||
id = 'Script',
|
||||
params = {
|
||||
command = script_string,
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
local group = Group.getByName(fatcow_name)
|
||||
local initial_point = group:getUnits()[1]:getPoint()
|
||||
local gp = mist.getGroupData(fatcow_name)
|
||||
--debugTable(gp)
|
||||
|
||||
|
||||
gp.route = {points = {}}
|
||||
gp.route.points[1] = mist.heli.buildWP(initial_point, initial, 'flyover', 0, 0, 'agl')
|
||||
gp.route.points[2] = mist.heli.buildWP(initial_point, initial, 'flyover', 150, 100, 'agl')
|
||||
gp.route.points[2].task = setOptions
|
||||
|
||||
gp.route.points[3] = mist.heli.buildWP(approach_point, 'flyover', 150, 400, 'agl')
|
||||
gp.route.points[4] = mist.heli.buildWP(approach_point, 'flyover', 20, 200, 'agl')
|
||||
gp.route.points[5] = mist.heli.buildWP(dest_point, 'turning point', 10, 70, 'agl')
|
||||
gp.route.points[5].task = myscriptaction
|
||||
gp.route.points[6] = {
|
||||
alt = 70,
|
||||
alt_type = "RADIO",
|
||||
speed = 10,
|
||||
x = airbase_pos.x,
|
||||
y = airbase_pos.y,
|
||||
helipadId = airbasefarp:getID(),
|
||||
aerodromeId = airbasefarp:getID(),
|
||||
type = "Land",
|
||||
action = "Landing",
|
||||
}
|
||||
|
||||
|
||||
gp.clone = true
|
||||
local new_group_data = mist.dynAdd(gp)
|
||||
end
|
||||
|
||||
function RotorOpsPerks.requestPerk(args)
|
||||
env.info('requestPerk called for ' .. args.perk_name)
|
||||
--env.info(mist.utils.tableShow(args, 'args'))
|
||||
local player_group = Group.getByName(args.player_group_name)
|
||||
local player_unit = player_group:getUnits()[1]
|
||||
local player_pos = player_unit:getPoint()
|
||||
local players = RotorOpsPerks.playersByGroupName(args.player_group_name)
|
||||
if not players then
|
||||
env.warning('No players found in group ' .. args.player_group_name)
|
||||
return
|
||||
end
|
||||
|
||||
--get the perk object
|
||||
local perk = RotorOpsPerks.perks[args.perk_name]
|
||||
|
||||
--find the intended point
|
||||
local target_point = nil
|
||||
if args.target == 'position' then
|
||||
target_point = player_pos
|
||||
|
||||
elseif args.target == 'mark' then
|
||||
local temp_mark = nil
|
||||
|
||||
for _, mark in pairs(mist.DBs.markList) do
|
||||
debugMsg('mark: ' .. mist.utils.tableShow(mark, 'mark'))
|
||||
--env.info('player group' .. mist.utils.tableShow(player_group, 'player_group'))
|
||||
--env.info('player' .. mist.utils.tableShow(player_unit, 'player_unit'))
|
||||
local perk_name_matches = false
|
||||
|
||||
--determine if mark name matches the perk name
|
||||
local mark_name = mark.text
|
||||
--remove whitespace and new line from mark name
|
||||
mark_name = mark_name:gsub("%s+", "")
|
||||
mark_name = mark_name:gsub("%n+", "")
|
||||
if mark_name == args.perk_name then
|
||||
perk_name_matches = true
|
||||
end
|
||||
|
||||
if perk_name_matches then
|
||||
--if MULTIPLAYER (initiator property missing in single player)
|
||||
if mark.initiator then
|
||||
--if mark is from player's group
|
||||
if mark.initiator.id_ == player_unit.id_ then
|
||||
target_point = mark.pos
|
||||
if temp_mark then
|
||||
--if there is already a mark from the player's group, use the most recent one
|
||||
if mark.time > temp_mark.time then
|
||||
temp_mark = mark
|
||||
end
|
||||
else
|
||||
temp_mark = mark
|
||||
end
|
||||
end
|
||||
|
||||
else --we assume single player
|
||||
if temp_mark then
|
||||
--if there is already a mark from the player's group, use the most recent one
|
||||
if mark.time > temp_mark.time then
|
||||
temp_mark = mark
|
||||
end
|
||||
else
|
||||
temp_mark = mark
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
debugMsg(mist.utils.tableShow(mist.DBs.markList, 'markList'))
|
||||
if temp_mark then
|
||||
target_point = temp_mark.pos
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local perk_used_count = RotorOpsPerks.getPlayerGroupSum(args.player_group_name, args.perk_name, "perks_used")
|
||||
if perk_used_count >= (perk.max_per_player*#players) then --multiply by number of players in group
|
||||
if #players > 1 then
|
||||
trigger.action.outTextForGroup(player_group:getID(), 'UNABLE. You already used this perk ' .. perk_used_count .. ' times.', 10)
|
||||
else
|
||||
trigger.action.outTextForGroup(player_group:getID(), 'UNABLE. Your group already used this perk ' .. perk_used_count .. ' times.', 10)
|
||||
end
|
||||
debugMsg('max_per_group reached for ' .. args.perk_name)
|
||||
return
|
||||
end
|
||||
|
||||
-- check if the max per mission has been reached
|
||||
if perk.max_per_mission ~= nil then
|
||||
if perk.used >= perk.max_per_mission then
|
||||
debugMsg(args.player_group_name.. ' requested ' .. args.perk_name .. ' but max per mission reached')
|
||||
trigger.action.outTextForGroup(player_group:getID(), 'UNABLE. Used too many times in the mission.', 10)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--check if position requirements for action are met
|
||||
if args.target == "mark" then
|
||||
if not target_point then
|
||||
debugMsg(args.player_group_name.. ' requested ' .. args.perk_name .. ' but no target was found')
|
||||
trigger.action.outTextForGroup(player_group:getID(), 'UNABLE. Add a mark called "' .. args.perk_name .. '" to the F10 map first', 10)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--check if cooldown is over in perks object
|
||||
if perk.cooldown > 0 then
|
||||
if perk.last_used + perk.cooldown > timer.getTime() then
|
||||
local time_remaining = perk.last_used + perk.cooldown - timer.getTime()
|
||||
--round time_remaining
|
||||
time_remaining = math.floor(time_remaining + 0.5)
|
||||
debugMsg(args.player_group_name.. ' tried to use ' .. args.perk_name .. ' but cooldown was not over')
|
||||
trigger.action.outTextForGroup(player_group:getID(), 'UNABLE. Wait for '.. time_remaining .. ' seconds.', 10)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--spend points
|
||||
if RotorOpsPerks.spendPoints(args.player_group_name, perk.cost)
|
||||
then
|
||||
env.info(args.player_group_name.. ' spent ' .. perk.cost .. ' points for ' .. args.perk_name)
|
||||
else
|
||||
env.info(args.player_group_name.. ' tried to spend ' .. perk.cost .. ' points for ' .. args.perk_name .. ' but did not have enough points')
|
||||
if #players == 1 then
|
||||
trigger.action.outTextForGroup(player_group:getID(), 'NEGATIVE. You have ' .. RotorOpsPerks.getPlayerGroupSum(args.player_group_name, "points") .. ' points. (cost '.. perk.cost .. ')', 10)
|
||||
else
|
||||
trigger.action.outTextForGroup(player_group:getID(), 'NEGATIVE. Your group has ' .. RotorOpsPerks.getPlayerGroupSum(args.player_group_name, "total points") .. ' points. (cost '.. perk.cost .. ')', 10)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
--add some useful data to pass to perk action
|
||||
args.target_point = target_point
|
||||
args.player_group = player_group
|
||||
args.player_unit = player_unit
|
||||
|
||||
--call perk action
|
||||
perk.action_function(args)
|
||||
|
||||
--update last_used
|
||||
perk.last_used = timer.getTime()
|
||||
perk.used = perk.used + 1
|
||||
|
||||
--increment player used for perk type, and initialize if it doesn't exist.
|
||||
local perk_user_per_player = 1/(#players or 1)
|
||||
--round perk_user_per_player to one decimal place
|
||||
perk_user_per_player = math.floor(perk_user_per_player*10 + 0.5)/10
|
||||
--loop through players
|
||||
for _, player in pairs(players) do
|
||||
if player.perks_used[args.perk_name] then
|
||||
player.perks_used[args.perk_name] = player.perks_used[args.perk_name] + perk_user_per_player
|
||||
else
|
||||
player.perks_used[args.perk_name] = perk_user_per_player
|
||||
end
|
||||
end
|
||||
|
||||
--message players with humansByName DB
|
||||
for _player_name, _player in pairs(mist.DBs.humansByName) do
|
||||
--get unit object from id
|
||||
local _player_unit = Unit.getByName(_player_name)
|
||||
if _player_unit and _player_unit:isExist() then
|
||||
local player_position = _player_unit:getPosition().p
|
||||
local position_string = ' at ' .. RotorOpsPerks.BRString(target_point, player_position)
|
||||
if _player.groupName == args.player_group_name then --if the player is the one who requested the perk
|
||||
if args.target == 'position' then
|
||||
position_string = ' at your position'
|
||||
end
|
||||
-- send affirmative message to the the requesting player
|
||||
trigger.action.outTextForGroup(_player.groupId, 'AFFIRM. ' .. RotorOpsPerks.perks[args.perk_name].display_name .. position_string, 10)
|
||||
else
|
||||
-- send messages to all other players
|
||||
env.info(player_unit:getPlayerName() .. ' requested ' .. RotorOpsPerks.perks[args.perk_name].display_name .. position_string)
|
||||
trigger.action.outTextForGroup(_player.groupId, player_unit:getPlayerName() .. ' requested ' .. RotorOpsPerks.perks[args.perk_name].display_name .. position_string, 10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function RotorOpsPerks.BRString(point_a, point_b)
|
||||
point_a = mist.utils.makeVec3(point_a, 0)
|
||||
point_b = mist.utils.makeVec3(point_b, 0)
|
||||
local vec = {x = point_a.x - point_b.x, y = point_a.y - point_b.y, z = point_a.z - point_b.z}
|
||||
local dir = mist.utils.getDir(vec, point_b)
|
||||
local dist = mist.utils.get2DDist(point_a, point_b)
|
||||
local bearing = mist.utils.round(mist.utils.toDegree(dir), 0)
|
||||
local range_nm = mist.utils.round(mist.utils.metersToNM(dist), 0)
|
||||
local range_ft = mist.utils.round(mist.utils.metersToFeet(dist), 0)
|
||||
local br_string = ''
|
||||
if range_nm > 0 then
|
||||
br_string = bearing .. '° ' .. range_nm .. 'nm'
|
||||
else
|
||||
br_string = bearing .. '° ' .. range_ft .. 'ft'
|
||||
end
|
||||
return br_string
|
||||
end
|
||||
|
||||
function RotorOpsPerks.findUnitsInVolume(args)
|
||||
local foundUnits = {}
|
||||
local volS = {
|
||||
id = args.volume_type,
|
||||
params = {
|
||||
point = args.point,
|
||||
radius = args.radius
|
||||
}
|
||||
}
|
||||
|
||||
local ifFound = function(foundObject, val)
|
||||
foundUnits[#foundUnits + 1] = foundObject
|
||||
end
|
||||
world.searchObjects(Object.Category.UNIT, volS, ifFound)
|
||||
return foundUnits
|
||||
end
|
||||
|
||||
|
||||
local handle = {}
|
||||
function handle:onEvent(e)
|
||||
|
||||
--if enemy unit destroyed
|
||||
if e.id == world.event.S_EVENT_KILL then
|
||||
if e.initiator and e.target then
|
||||
if e.initiator:getCoalition() ~= e.target:getCoalition() then
|
||||
debugMsg('KILL: initiator groupname: ' .. e.initiator:getGroup():getName())
|
||||
|
||||
local initiator_group_name = e.initiator:getGroup():getName()
|
||||
|
||||
-- if initiator is a player's dropped troops
|
||||
local dropped_troops = RotorOpsPerks.troops[e.initiator:getGroup():getName()]
|
||||
if dropped_troops then
|
||||
if e.target:getDesc().category == Unit.Category.GROUND_UNIT == true then
|
||||
if e.target:hasAttribute("Infantry") then
|
||||
RotorOpsPerks.scorePoints(dropped_troops.player_group, RotorOpsPerks.points.dropped_troops_kill_inf, 'Your troops killed infantry!')
|
||||
--else if target is armor
|
||||
elseif e.target:hasAttribute("Tanks") then
|
||||
RotorOpsPerks.scorePoints(dropped_troops.player_group, RotorOpsPerks.points.dropped_troops_kill_armor, 'Your troops killed armor!')
|
||||
else
|
||||
RotorOpsPerks.scorePoints(dropped_troops.player_group, RotorOpsPerks.points.dropped_troops_kill, 'Your troops killed a vehicle!')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--if the initiator is a player
|
||||
if e.initiator:getPlayerName() then
|
||||
|
||||
--if target is a ground unit
|
||||
if e.target:getDesc().category == Unit.Category.GROUND_UNIT == true then
|
||||
if e.target:hasAttribute("Infantry") then
|
||||
RotorOpsPerks.scorePoints(initiator_group_name, RotorOpsPerks.points.kill_inf, 'Killed infantry!')
|
||||
elseif e.target:hasAttribute("Tanks") then
|
||||
RotorOpsPerks.scorePoints(initiator_group_name, RotorOpsPerks.points.kill_armor, 'Killed armor!')
|
||||
else
|
||||
RotorOpsPerks.scorePoints(initiator_group_name, RotorOpsPerks.points.kill, 'Killed a vehicle!')
|
||||
end
|
||||
end
|
||||
|
||||
--if target is a helicopter
|
||||
if e.target:getDesc().category == Unit.Category.HELICOPTER == true then
|
||||
RotorOpsPerks.scorePoints(initiator_group_name, RotorOpsPerks.points.kill_heli, 'Killed a helicopter!')
|
||||
end
|
||||
|
||||
--if target is a plane
|
||||
if e.target:getDesc().category == Unit.Category.AIRPLANE == true then
|
||||
RotorOpsPerks.scorePoints(initiator_group_name, RotorOpsPerks.points.kill_plane, 'Killed a plane!')
|
||||
end
|
||||
|
||||
--if target is a ship
|
||||
if e.target:getDesc().category == Unit.Category.SHIP == true then
|
||||
RotorOpsPerks.scorePoints(initiator_group_name, RotorOpsPerks.points.kill_ship, 'Killed a ship!')
|
||||
end
|
||||
|
||||
|
||||
|
||||
--CAS BONUS---
|
||||
|
||||
--we'll look for ground units in proximity to the player to apply a CAS bonus
|
||||
local units_in_proximity = RotorOpsPerks.findUnitsInVolume({
|
||||
volume_type = world.VolumeType.SPHERE,
|
||||
point = e.initiator:getPoint(),
|
||||
radius = 1852
|
||||
})
|
||||
|
||||
local cas_bonus = false
|
||||
|
||||
for _, unit in pairs(units_in_proximity) do
|
||||
|
||||
--if we found friendly grund units near the player
|
||||
if unit:getDesc().category == Unit.Category.GROUND_UNIT then
|
||||
if unit:getCoalition() == e.initiator:getCoalition() then
|
||||
cas_bonus = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if cas_bonus then
|
||||
RotorOpsPerks.scorePoints(e.initiator:getGroup():getName(), RotorOpsPerks.points.cas_bonus, '[CAS Bonus]')
|
||||
end
|
||||
|
||||
--END CAS BONUS---
|
||||
end
|
||||
|
||||
--end if the initiator is a player
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
world.addEventHandler(handle)
|
||||
|
||||
function RotorOpsPerks.registerCtldCallbacks()
|
||||
if not ctld then
|
||||
trigger.action.outText("CTLD Not Found", 10)
|
||||
return
|
||||
end
|
||||
|
||||
--if ctld.callbacks does not exist yet, loop until it does
|
||||
if not ctld.callbacks then
|
||||
timer.scheduleFunction(RotorOpsPerks.registerCtldCallbacks, nil, timer.getTime() + 1)
|
||||
env.warning('CTLD callbacks not loaded yet, trying again in 1 second')
|
||||
return
|
||||
end
|
||||
|
||||
ctld.addCallback(function(_args)
|
||||
local action = _args.action
|
||||
local unit = _args.unit
|
||||
local picked_troops = _args.onboard
|
||||
local dropped_troops = _args.unloaded
|
||||
--env.info("ctld callback: ".. mist.utils.tableShow(_args))
|
||||
|
||||
if dropped_troops then
|
||||
--env.info('dropped troops: ' .. mist.utils.tableShow(dropped_troops))
|
||||
--env.info('dropped troops group name: ' .. dropped_troops:getName())
|
||||
RotorOpsPerks.troops[dropped_troops:getName()] = {dropped_troops=dropped_troops:getName(), player_group=unit:getGroup():getName(), player_name=unit:getPlayerName(), player_unit=unit:getName(), side=unit:getGroup():getCoalition() , qty=#dropped_troops:getUnits()}
|
||||
|
||||
end
|
||||
|
||||
|
||||
local playername = unit:getPlayerName()
|
||||
if playername then
|
||||
if action == "unload_troops_zone" or action == "dropped_troops" then
|
||||
|
||||
elseif action == "rearm" or action == "repair" then
|
||||
RotorOpsPerks.scorePoints(unit:getGroup():getName(), RotorOpsPerks.points.rearm, 'Rearm/repair!')
|
||||
|
||||
elseif action == "unpack" then
|
||||
RotorOpsPerks.scorePoints(unit:getGroup():getName(), RotorOpsPerks.points.unpack, 'Crates unpacked!')
|
||||
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function RotorOpsPerks.monitorPlayers()
|
||||
--This function, along with buildPlayer and updatePlayer, have been crafted through much trial and error in order to work with the 'nuances' of the DCS APIs in single player and multiplayer environments.
|
||||
--If it's not broke, don't fix it. If it's broke... ED probably changed the behaviour of coalition.getPlayers, net.get_player_list, or net.get_player_info
|
||||
|
||||
timer.scheduleFunction(RotorOpsPerks.monitorPlayers, nil, timer.getTime() + 2)
|
||||
|
||||
-- GET PILOTS
|
||||
local pilots = coalition.getPlayers(coalition.side.BLUE)
|
||||
local red_pilots = coalition.getPlayers(coalition.side.RED)
|
||||
-- add red pilots to pilots
|
||||
for _, red_pilot in pairs(red_pilots) do
|
||||
table.insert(pilots, red_pilot)
|
||||
end
|
||||
|
||||
env.warning('PILOTS: '.. mist.utils.tableShow(pilots))
|
||||
|
||||
for _, player in pairs(pilots) do
|
||||
|
||||
local player_group_name = player:getGroup():getName()
|
||||
debugMsg('GET PILOTS Player group: ' .. player:getGroup():getName())
|
||||
debugMsg('GET PILOTS PLAYER: ' .. mist.utils.tableShow(player))
|
||||
|
||||
--player info works in single player
|
||||
local player_info = net.get_player_info(player)
|
||||
if player_info then
|
||||
debugMsg('GET PILOTS player info: '.. mist.utils.tableShow(player_info))
|
||||
RotorOpsPerks.updatePlayer(player_info.ucid, player_group_name, player_info.name, player_info.slot)
|
||||
|
||||
else --player_info is nil in multiplayer, so we'll have to compile the data we need in multiple steps
|
||||
env.warning('GET PILOTS player_info for coalition.getPlayers is nil. Setting attributes to nil to be picked up by GET CREW METHODs')
|
||||
RotorOpsPerks.buildPlayer(nil, player_group_name, nil, nil, player:getPlayerName()) --we don't have all the data we need to add to players yet
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--GET CREW
|
||||
|
||||
local players = net.get_player_list() --empty in single player
|
||||
env.warning('GET CREW ALL PLAYERS: '.. mist.utils.tableShow(players))
|
||||
|
||||
for _, player in pairs(players) do
|
||||
local player_info = net.get_player_info(player) --works with multicrew, but we need to find the group name
|
||||
debugMsg('GET CREW player info:')
|
||||
debugMsg(mist.utils.tableShow(player_info))
|
||||
|
||||
--find the group from slot relationship to pilots with the base slot
|
||||
|
||||
--client slot patterns are like 6_1, 6_2, etc where 6 is the host slot
|
||||
--if the player slot is like 6_1, 6_2, etc then find the player with slot 6 and use that player's group name
|
||||
if string.find(player_info.slot, '_') then --found a multicrew slot
|
||||
local base_slot = string.sub(player_info.slot, 1, string.find(player_info.slot, '_')-1)
|
||||
debugMsg('GET CREW found multicrew with base slot: '.. base_slot)
|
||||
for _i, pilot in pairs(RotorOpsPerks.players) do
|
||||
if pilot.slot == base_slot then
|
||||
local player_group_name = pilot.groupName
|
||||
debugMsg('GET CREW player group name: '.. player_group_name)
|
||||
RotorOpsPerks.updatePlayer(player_info.ucid, player_group_name, player_info.name, player_info.slot)
|
||||
end
|
||||
end
|
||||
else --we can't get the group name from here, so we'll have to compile the data we need in multiple steps
|
||||
RotorOpsPerks.buildPlayer(player_info.ucid, nil, player_info.name, player_info.slot, player_info.name) --we don't have all the data we need to add to players yet
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
RotorOpsPerks.monitorPlayers()
|
||||
RotorOpsPerks.registerCtldCallbacks()
|
||||
@ -7371,9 +7371,9 @@ do
|
||||
usedMarks[e.idx] = e.idx
|
||||
if not mist.DBs.markList[e.idx] then
|
||||
--log:info('create maker DB: $1', e.idx)
|
||||
mist.DBs.markList[e.idx] = {time = e.time, pos = e.pos, groupId = e.groupId, mType = 'panel', text = e.text, markId = e.idx, coalition = e.coalition}
|
||||
mist.DBs.markList[e.idx] = {time = e.time, pos = e.pos, groupId = e.groupId, mType = 'panel', text = e.text, markId = e.idx, coalition = e.coalition, initiator = e.initiator}
|
||||
if e.unit then
|
||||
mist.DBs.markList[e.idx].unit = e.initiaor:getName()
|
||||
mist.DBs.markList[e.idx].unit = e.initiator:getName()
|
||||
end
|
||||
--log:info(mist.marker.list[e.idx])
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user