Player fatcow (#46)

* Update RotorOpsPerks.lua

- added player fatcow
- added menu conditions
- added action conditions
- added a table for tracking farp resources and supporting functions
- added flare perk
- change menu display to be more compact
- changes to points
- ignore events if e.initiator is not a unit
- fixed monitorFarps
- isExist wasn't working when calling on farp objects in farp table (appeared dead)
- don't deduct points unless perk action is successful

* Update RotorOps.lua
- changes to infantry spawns
This commit is contained in:
spencershepard 2023-02-07 21:02:38 -08:00 committed by GitHub
parent c8ce026243
commit be89639e6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 406 additions and 128 deletions

View File

@ -1,7 +1,7 @@
# ROTOROPS VERSION # ROTOROPS VERSION
maj_version = 1 maj_version = 1
minor_version = 4 minor_version = 4
patch_version = 2 patch_version = 3
version_url = 'https://dcs-helicopters.com/app-updates/versioncheck.yaml' version_url = 'https://dcs-helicopters.com/app-updates/versioncheck.yaml'

View File

@ -1184,12 +1184,19 @@ function RotorOps.assessUnitsInZone(var)
for zone, zoneobj in pairs(mist.DBs.zonesByName) do for zone, zoneobj in pairs(mist.DBs.zonesByName) do
if string.find(zone, RotorOps.active_zone) and string.find(zone:lower(), "spawn") then --if we find a zone that has the active zone name and the word spawn if string.find(zone, RotorOps.active_zone) and string.find(zone:lower(), "spawn") then --if we find a zone that has the active zone name and the word spawn
inf_spawn_zones[#inf_spawn_zones + 1] = zone inf_spawn_zones[#inf_spawn_zones + 1] = zone
env.info("ROTOR OPS: spawn zone found:"..zone) env.info("ROTOR OPS: active spawn zone found:"..zone)
end end
if string.find(zone:lower(), "spawn") then
total_spawn_zones = total_spawn_zones + 1
end
end end
for index, rops_zone in pairs(RotorOps.zones) do
for zone, zoneobj in pairs(mist.DBs.zonesByName) do
if string.find(zone:lower(), rops_zone.name:lower()) and string.find(zone:lower(), "spawn") then
total_spawn_zones = total_spawn_zones + 1
env.info("ROTOR OPS: spawn zone found:"..zone..", total spawn zones:"..total_spawn_zones)
end
end
end
--RotorOps.inf_spawns_avail = RotorOps.inf_spawns_per_zone * RotorOps.inf_spawn_multiplier[RotorOps.active_zone_index] --RotorOps.inf_spawns_avail = RotorOps.inf_spawns_per_zone * RotorOps.inf_spawn_multiplier[RotorOps.active_zone_index]
if total_spawn_zones > 0 then if total_spawn_zones > 0 then
RotorOps.inf_spawns_avail = (RotorOps.inf_spawns_total / total_spawn_zones) * #inf_spawn_zones RotorOps.inf_spawns_avail = (RotorOps.inf_spawns_total / total_spawn_zones) * #inf_spawn_zones
@ -1324,12 +1331,8 @@ function RotorOps.assessUnitsInZone(var)
local rand_index = math.random(1, #inf_spawn_zones) local rand_index = math.random(1, #inf_spawn_zones)
local zone = inf_spawn_zones[rand_index] local zone = inf_spawn_zones[rand_index]
if RotorOps.defending then ctld.spawnGroupAtTrigger("red", RotorOps.inf_spawn_red, zone, 1000)
ctld.spawnGroupAtTrigger("blue", RotorOps.inf_spawn_blue, zone, 1000) RotorOps.gameMsg(RotorOps.gameMsgs.infantry_spawned, math.random(1, #RotorOps.gameMsgs.infantry_spawned))
else
ctld.spawnGroupAtTrigger("red", RotorOps.inf_spawn_red, zone, 1000)
RotorOps.gameMsg(RotorOps.gameMsgs.infantry_spawned, math.random(1, #RotorOps.gameMsgs.infantry_spawned))
end
RotorOps.inf_spawns_avail = RotorOps.inf_spawns_avail - 1 RotorOps.inf_spawns_avail = RotorOps.inf_spawns_avail - 1
env.info("ROTOR OPS: Attempting to spawn infantry. "..RotorOps.inf_spawns_avail.." spawns remaining in "..zone) env.info("ROTOR OPS: Attempting to spawn infantry. "..RotorOps.inf_spawns_avail.." spawns remaining in "..zone)

View File

@ -9,16 +9,20 @@
-- Issues: -- Issues:
-- - You will not get points for your troops' kills if you leave your group (ie switch aircraft) -- - You will not get points for your troops' kills if you leave your group (ie switch aircraft)
--Todo:
-- - more testing needed in RotorOpsPerks.monitorFarps() to check for destroyed farp objects.
RotorOpsPerks = {} RotorOpsPerks = {}
RotorOpsPerks.version = "1.4" RotorOpsPerks.version = "1.5.1"
env.warning('ROTOROPS PERKS STARTED: '..RotorOpsPerks.version) env.warning('ROTOROPS PERKS STARTED: '..RotorOpsPerks.version)
trigger.action.outText('ROTOROPS PERKS STARTED: '..RotorOpsPerks.version, 10) trigger.action.outText('ROTOROPS PERKS STARTED: '..RotorOpsPerks.version, 10)
RotorOpsPerks.perks = {} RotorOpsPerks.perks = {}
RotorOpsPerks.players = {} RotorOpsPerks.players = {}
RotorOpsPerks.players_temp = {} RotorOpsPerks.players_temp = {}
RotorOpsPerks.troops = {} --by group name RotorOpsPerks.troops = {} --by group name
RotorOpsPerks.fat_cow_farps = {}
---- OPTIONS ---- ---- OPTIONS ----
@ -34,12 +38,17 @@ RotorOpsPerks.points = {
kill_plane=20, kill_plane=20,
kill_armor=15, kill_armor=15,
kill_ship=15, kill_ship=15,
cas_bonus=5, --you were in proximity of your troops killing something cas_bonus=5, --you killed something in proximity of friendly troops
dropped_troops_kill_inf=5, --your troops killed infantry dropped_troops_kill_inf=10, --your troops killed infantry
dropped_troops_kill=10, --your troops killed a vehicle dropped_troops_kill=20, --your troops killed a vehicle
dropped_troops_kill_armor=15, --your troops killed armor dropped_troops_kill_armor=30, --your troops killed armor
rearm=10, --ctld rearm/repair of ground units rearm=15, --ctld rearm/repair of ground units
unpack=10, --ctld unpack of ground units unpack=15, --ctld unpack of ground units
}
RotorOpsPerks.player_fatcow_types = {
"UH-60L",
"Mi-8MT",
} }
---- END OPTIONS ---- ---- END OPTIONS ----
@ -55,61 +64,108 @@ end
---- FATCOW PERK ---- ---- 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. --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"] = { RotorOpsPerks.perks["fatcow"] = {
perk_name='fatcow', perk_name='fatcow',
display_name='FatCow FARP', display_name='FatCow FARP',
cost=150, cost=150,
cooldown=60, cooldown=60,
max_per_player=1, max_per_player=4,
max_per_mission=4, --for fatcow, you will want to ensure that you have this many sets of FARP statics max_per_mission=4,
at_mark=true, at_mark=true,
at_position=true, at_position=true,
enabled=true, enabled=true,
sides={0,1,2}, sides={0,1,2},
last_used=0,
used=0,
action_function=requestFatCowPerk
} }
RotorOpsPerks.perks.fatcow["menu_condition"] = function(group_name)
local player_unit = Group.getByName(group_name):getUnit(1)
-- if player IS a fatcow, return false
for _, unit_type in pairs(RotorOpsPerks.player_fatcow_types) do
if player_unit:getDesc().typeName == unit_type then
return false
end
end
return true
end
RotorOpsPerks.perks.fatcow["action_condition"] = function(args)
if #RotorOpsPerks.fat_cow_farps < 1 then
return {msg="No FARP resources available!", valid=false}
end
return {valid=true}
end
RotorOpsPerks.perks.fatcow["action_function"] = function(args)
local index = RotorOpsPerks.perks.fatcow.used + 1
local farp = table.remove(RotorOpsPerks.fat_cow_farps, 1) --get the first farp from the list
if farp == nil then
env.error("No FARP resources available!")
return
end
RotorOpsPerks.spawnFatCow(args.target_point, farp)
return true
end
---- End of FATCOW PERK ---- ---- End of FATCOW PERK ----
---- INSTANT STRIKE PERK ---- ---- INSTANT STRIKE PERK ----
-- Here's a very simple example of how to create a Perk! -- Here's a very simple example of how to create a 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"] = { RotorOpsPerks.perks["strike"] = {
perk_name='strike', perk_name='strike',
display_name='Instant Strike', display_name='Instant Strike',
cost=200, cost=150,
cooldown=60, cooldown=60,
max_per_player=2, max_per_player=3,
max_per_mission=3, max_per_mission=10,
at_mark=true, at_mark=true,
at_position=false, at_position=false,
enabled=true, enabled=true,
sides={0,1,2}, sides={0,1,2},
last_used=0,
used=0,
action_function=requestStrikePerk
} }
RotorOpsPerks.perks.strike["action_function"] = function(args)
--explosion at dest_point after 10 seconds
timer.scheduleFunction(function()
trigger.action.explosion(args.target_point, 1000)
end, nil, timer.getTime() + 10)
return true
end
---- End of INSTANT STRIKE PERK ---- ---- End of INSTANT STRIKE PERK ----
---- JTAC DRONE PERK ---- ---- JTAC DRONE PERK ----
RotorOpsPerks.perks["drone"] = {
perk_name='drone',
display_name='JTAC Drone',
cost=75,
cooldown=60,
max_per_player=3,
max_per_mission=6,
at_mark=true,
at_position=false,
enabled=true,
sides={0,1,2},
}
RotorOpsPerks.perks.drone["action_function"] = function(args)
local player_country = Unit.getByName(args.player_unit_name):getCountry()
--set a timer for one minute
timer.scheduleFunction(function()
local code = table.remove(ctld.jtacGeneratedLaserCodes, 1)
RotorOpsPerks.spawnJtacDrone(args.target_point, player_country, code)
table.insert(ctld.jtacGeneratedLaserCodes, code)
end, nil, timer.getTime() + 60)
return true
end
function RotorOpsPerks.spawnJtacDrone(dest_point, country, laser_code) function RotorOpsPerks.spawnJtacDrone(dest_point, country, laser_code)
local drone = { local drone = {
@ -173,42 +229,134 @@ function RotorOpsPerks.spawnJtacDrone(dest_point, country, laser_code)
timer.scheduleFunction(function() timer.scheduleFunction(function()
Group.getByName(new_group.name):getController():setTask(orbit) Group.getByName(new_group.name):getController():setTask(orbit)
Group.getByName(new_group.name):getController():setOption(AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION) Group.getByName(new_group.name):getController():setOption(AI.Option.Air.id.REACTION_ON_THREAT, AI.Option.Air.val.REACTION_ON_THREAT.NO_REACTION)
local _code = table.remove(ctld.jtacGeneratedLaserCodes, 1)
ctld.JTACAutoLase(new_group.name, table.remove(ctld.jtacGeneratedLaserCodes, 1), true, "vehicle") ctld.JTACAutoLase(new_group.name, table.remove(ctld.jtacGeneratedLaserCodes, 1), true, "vehicle")
table.insert(ctld.jtacGeneratedLaserCodes, _code)
end, nil, timer.getTime() + 60) end, nil, timer.getTime() + 60)
end end
function requestJtacDrone(args)
local player_country = Unit.getByName(args.player_unit_name):getCountry()
--set a timer for one minute
timer.scheduleFunction(function()
RotorOpsPerks.spawnJtacDrone(args.target_point, player_country, table.remove(ctld.jtacGeneratedLaserCodes, 1))
end, nil, timer.getTime() + 60)
end
RotorOpsPerks.perks["drone"] = {
perk_name='drone',
display_name='JTAC Drone',
cost=50,
cooldown=60,
max_per_player=3,
max_per_mission=6,
at_mark=true,
at_position=false,
enabled=true,
sides={0,1,2},
last_used=0,
used=0,
action_function=requestJtacDrone
}
---- End of JTAC DRONE PERK ---- ---- End of JTAC DRONE PERK ----
---- PLAYER FAT COW ----
RotorOpsPerks.perks["player_fatcow"] = {
perk_name='player_fatcow',
display_name='Player Fat Cow',
cost=0,
cooldown=0,
at_mark=false,
at_position=true,
enabled=true,
sides={0,1,2},
active = {}, --holds a list of active fat cows
}
RotorOpsPerks.perks.player_fatcow["menu_condition"] = function(group_name)
local player_unit = Group.getByName(group_name):getUnit(1)
-- check if player unit is in list of our fat cow heli types
for _, unit_type in pairs(RotorOpsPerks.player_fatcow_types) do
if player_unit:getDesc().typeName == unit_type then
return true
end
end
end
RotorOpsPerks.perks.player_fatcow["action_condition"] = function(args)
local player_unit = Group.getByName(args.player_group_name):getUnit(1)
local agl_altitude = player_unit:getPosition().p.y - land.getHeight(player_unit:getPosition().p)
if RotorOpsPerks.perks.player_fatcow.active[args.player_group_name] then
return {msg="FARP already deployed at your position!", valid=false}
end
if #RotorOpsPerks.fat_cow_farps < 1 then
return {msg="No FARP resources available!", valid=false}
end
if agl_altitude > 100 then
return {msg="You must be on the ground! "..agl_altitude.." AGL", valid=false}
else
return {msg="Stay on the ground.", valid=true}
end
end
RotorOpsPerks.perks.player_fatcow["action_function"] = function(args)
local farp = table.remove(RotorOpsPerks.fat_cow_farps)
if farp == nil then
env.error("No FARP resources available!")
return
end
RotorOpsPerks.teleportStatic('FAT COW FARP ' .. farp.index, {x=args.target_point.x, y=args.target_point.z})
RotorOpsPerks.spawnFatCowFarpObjects(args.target_point.x, args.target_point.z, farp.index, 15)
args.farp = farp
RotorOpsPerks.perks.player_fatcow.active[args.player_group_name] = true
RotorOpsPerks.perks.player_fatcow.monitor_player(args)
return true
end
RotorOpsPerks.perks.player_fatcow["monitor_player"] = function(args)
local despawn_farp = false
if Group.getByName(args.player_group_name) then
local player_unit = Group.getByName(args.player_group_name):getUnit(1)
local agl_altitude = player_unit:getPosition().p.y - land.getHeight(player_unit:getPosition().p)
if agl_altitude > 100 or not player_unit:isExist() then
despawn_farp = true
env.info("Player is no longer on the ground, despawning FARP!")
end
if math.abs(player_unit:getPosition().p.x - args.target_point.x) > 50 or math.abs(player_unit:getPosition().p.z - args.target_point.z) > 50 then
env.info("Player has moved from target position, despawning FARP!")
despawn_farp = true
end
else
despawn_farp = true
end
if despawn_farp then
RotorOpsPerks.despawnFatCowFarp(args.farp)
RotorOpsPerks.perks.player_fatcow.active[args.player_group_name] = nil
if Group.getByName(args.player_group_name) then
trigger.action.outTextForGroup(Group.getByName(args.player_group_name):getID(), "FARP despawned.", 10)
end
else
timer.scheduleFunction(RotorOpsPerks.perks.player_fatcow.monitor_player, args, timer.getTime() + 2)
end
end
function RotorOpsPerks.despawnFatCowFarp(farp)
RotorOpsPerks.teleportStatic('FAT COW FARP '..farp.index, {x=farp.farp_p.x, y=farp.farp_p.z})
RotorOpsPerks.teleportStatic('FAT COW TENT '..farp.index, {x=farp.tent_p.x, y=farp.tent_p.z})
RotorOpsPerks.teleportStatic('FAT COW AMMO '..farp.index, {x=farp.ammo_p.x, y=farp.ammo_p.z})
RotorOpsPerks.teleportStatic('FAT COW FUEL '..farp.index, {x=farp.fuel_p.x, y=farp.fuel_p.z})
table.insert(RotorOpsPerks.fat_cow_farps, 1, farp) --put back in list at the begining to be reused
end
---- End of PLAYER FAT COW ----
---- FLARE PERK ----
RotorOpsPerks.perks["flare"] = {
perk_name='flare',
display_name='Illumination Flare',
cost=15,
cooldown=0,
at_mark=true,
at_position=false,
enabled=true,
sides={0,1,2},
}
RotorOpsPerks.perks.flare["action_function"] = function(args)
args.target_point.y = args.target_point.y + 600
trigger.action.illuminationBomb(args.target_point, 1000000)
return true
end
---- End of FLARE PERK ----
function RotorOpsPerks.getPlayerGroupSum(player_group_name, player_attribute, table_name) function RotorOpsPerks.getPlayerGroupSum(player_group_name, player_attribute, table_name)
--loop through RotorOpsPerks.playersByGroupName --loop through RotorOpsPerks.playersByGroupName
local players = RotorOpsPerks.playersByGroupName(player_group_name) local players = RotorOpsPerks.playersByGroupName(player_group_name)
@ -229,30 +377,34 @@ function RotorOpsPerks.getPlayerGroupSum(player_group_name, player_attribute, ta
end end
function RotorOpsPerks.spendPoints(player_group_name, points) function RotorOpsPerks.spendPoints(player_group_name, points, deduct_points)
local players = RotorOpsPerks.playersByGroupName(player_group_name) local players = RotorOpsPerks.playersByGroupName(player_group_name)
local total_points = RotorOpsPerks.getPlayerGroupSum(player_group_name, "points") local total_points = RotorOpsPerks.getPlayerGroupSum(player_group_name, "points")
--if players have enough combined points --if players have enough combined points
if total_points < points then if total_points < points then
--there was insufficient points
return false return false
end end
--divide points by the number of players to get an integer --this function can be called to check points and/or deduct points
local points_per_player = math.floor(points/#players) if deduct_points then
--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 --subtract points from each player equally. If a player doesn't have enough points, subtract the remainder from the next player
local remainder = 0 local remainder = 0
for _, player in pairs(players) do for _, player in pairs(players) do
local points_to_subtract = points_per_player + remainder local points_to_subtract = points_per_player + remainder
if player.points < points_to_subtract then if player.points < points_to_subtract then
remainder = points_to_subtract - player.points remainder = points_to_subtract - player.points
player.points = 0 player.points = 0
else else
player.points = player.points - points_to_subtract player.points = player.points - points_to_subtract
remainder = 0 remainder = 0
end
end end
end end
--there was sufficient points
return true return true
end end
@ -283,6 +435,9 @@ function RotorOpsPerks.checkPoints(player_group_name)
return false return false
end end
env.info("Checking points for "..player_group_name.."...")
env.info(mist.utils.tableShow(players, "players"))
--get combined points from all Players --get combined points from all Players
local total_points = 0 local total_points = 0
for _, player in pairs(players) do for _, player in pairs(players) do
@ -319,7 +474,7 @@ function RotorOpsPerks.buildPlayer(identifier, groupName, name, slot, temp_id)
groupName = RotorOpsPerks.players_temp[temp_id].groupName groupName = RotorOpsPerks.players_temp[temp_id].groupName
--if we're still missing attributes, return --if we're still missing attributes, return
if not groupName or not name or not slot or not identifier then if not groupName or not name or not slot or not identifier then
env.warning('MISSING ATTRIBUTES FOR ' .. temp_id) -- env.warning('MISSING ATTRIBUTES FOR ' .. temp_id)
debugMsg(mist.utils.tableShow(RotorOpsPerks.players_temp[temp_id])) debugMsg(mist.utils.tableShow(RotorOpsPerks.players_temp[temp_id]))
return return
end end
@ -355,6 +510,7 @@ function RotorOpsPerks.updatePlayer(identifier, groupName, name, slot)
perks_used = {}, perks_used = {},
} }
env.warning('ADDED ' .. identifier .. ' TO PLAYERS TABLE') env.warning('ADDED ' .. identifier .. ' TO PLAYERS TABLE')
env.info(mist.utils.tableShow(RotorOpsPerks.players[identifier]))
missionCommands.removeItemForGroup(groupId, {[1] = 'ROTOROPS PERKS'}) missionCommands.removeItemForGroup(groupId, {[1] = 'ROTOROPS PERKS'})
RotorOpsPerks.addRadioMenuForGroup(groupName) RotorOpsPerks.addRadioMenuForGroup(groupName)
if RotorOpsPerks.player_update_messages then if RotorOpsPerks.player_update_messages then
@ -364,6 +520,7 @@ function RotorOpsPerks.updatePlayer(identifier, groupName, name, slot)
--update an existing player --update an existing player
elseif RotorOpsPerks.players[identifier].groupId ~= groupId then elseif RotorOpsPerks.players[identifier].groupId ~= groupId then
env.warning('UPDATING ' .. identifier .. ' TO GROUP NAME: ' .. groupName) env.warning('UPDATING ' .. identifier .. ' TO GROUP NAME: ' .. groupName)
env.info(mist.utils.tableShow(RotorOpsPerks.players[identifier]))
if RotorOpsPerks.player_update_messages then if RotorOpsPerks.player_update_messages then
trigger.action.outText('PERKS: ' .. name .. ' moved to '.. groupName, 10) trigger.action.outText('PERKS: ' .. name .. ' moved to '.. groupName, 10)
end end
@ -405,6 +562,10 @@ function RotorOpsPerks.addRadioMenuForGroup(groupName)
for perk_name, perk in pairs(RotorOpsPerks.perks) do for perk_name, perk in pairs(RotorOpsPerks.perks) do
local avail_for_side = false local avail_for_side = false
local avail_for_group = true
if perk.menu_condition ~= nil then
avail_for_group = perk.menu_condition(groupName)
end
for _, side in pairs(perk.sides) do for _, side in pairs(perk.sides) do
if group_side == side then if group_side == side then
avail_for_side = true avail_for_side = true
@ -412,27 +573,89 @@ function RotorOpsPerks.addRadioMenuForGroup(groupName)
end end
if perk.enabled and avail_for_side then if perk.enabled and avail_for_side and avail_for_group then
if perk.at_mark then if perk.at_mark then
--addPerkCommand(groupId, groupName, perk, menu_root, {target='mark'}) --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'}) missionCommands.addCommandForGroup(groupId, perk.display_name .. ' at mark (' .. perk.perk_name ..')', menu_root , RotorOpsPerks.requestPerk, {player_group_name=groupName, perk_name=perk.perk_name, target='mark'})
end end
if perk.at_position then if perk.at_position then
--addPerkCommand(groupId, groupName, perk, menu_root, {target='position'}) --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'}) missionCommands.addCommandForGroup(groupId, perk.display_name .. ' on me', menu_root , RotorOpsPerks.requestPerk, {player_group_name=groupName, perk_name=perk.perk_name, target='position'})
end end
end end
end end
end end
---- FATCOW FARP SUPPORTING FUNCTIONS ----
function RotorOpsPerks.monitorFarps()
env.info(mist.utils.tableShow(RotorOpsPerks.fat_cow_farps))
local function farpExists(i)
local farp = StaticObject.getByName('FAT COW FARP ' .. i)
local tent = StaticObject.getByName('FAT COW TENT ' .. i)
local ammo = StaticObject.getByName('FAT COW AMMO ' .. i)
local fuel = StaticObject.getByName('FAT COW FUEL ' .. i)
if farp:isExist() and tent:isExist() and ammo:isExist() and fuel:isExist() then
return true
else
return false
end
end
--schedule the function
timer.scheduleFunction(RotorOpsPerks.monitorFarps, nil, timer.getTime() + 11)
--loop over RotorOpsPerks.fat_cow_farps
for i, farp in pairs(RotorOpsPerks.fat_cow_farps) do
--check if farp is damaged/destroyed
if not farpExists(i) then
trigger.action.outText('Some FARP resources have been destroyed', 30)
env.warning('FAT COW FARP ' .. i .. ' RESOURCES DESTROYED')
RotorOpsPerks.fat_cow_farps[i] = nil
end
end
end
function RotorOpsPerks.buildFatCowFarpTable()
local farp_found=true
local i = 1
while(farp_found) do
--find static invisible farps that start with name 'FAT COW FARP'
local farp = StaticObject.getByName('FAT COW FARP ' .. i)
local tent = StaticObject.getByName('FAT COW TENT ' .. i)
local ammo = StaticObject.getByName('FAT COW AMMO ' .. i)
local fuel = StaticObject.getByName('FAT COW FUEL ' .. i)
if farp and tent and ammo and fuel then
env.info("FAT COW FARP " .. i .. " FOUND")
RotorOpsPerks.fat_cow_farps[i] = {
index = i,
farp = farp,
farp_p = farp:getPosition().p,
tent = tent,
tent_p = tent:getPosition().p,
ammo = ammo,
ammo_p = ammo:getPosition().p,
fuel = fuel,
fuel_p = fuel:getPosition().p,
}
i = i + 1
else
farp_found = false
end
end
end
function teleportStatic(source_name, dest_point)
debugMsg('teleportStatic: ' .. source_name)
function RotorOpsPerks.teleportStatic(source_name, dest_point)
debugMsg('RotorOpsPerks.teleportStatic: ' .. source_name)
local source = StaticObject.getByName(source_name) local source = StaticObject.getByName(source_name)
if not source then if not source then
env.info('teleportStatic: source not found: ' .. source_name) env.info('RotorOpsPerks.teleportStatic: source not found: ' .. source_name)
return return
end end
local vars = {} local vars = {}
@ -441,38 +664,45 @@ function teleportStatic(source_name, dest_point)
vars.point = mist.utils.makeVec3(dest_point) vars.point = mist.utils.makeVec3(dest_point)
local res = mist.teleportToPoint(vars) local res = mist.teleportToPoint(vars)
if res then if res then
env.info('teleportStatic: ' .. source_name .. ' success') env.info('RotorOpsPerks.teleportStatic: ' .. source_name .. ' success')
else else
env.info('teleportStatic: ' .. source_name .. ' failed') env.info('RotorOpsPerks.teleportStatic: ' .. source_name .. ' failed')
end end
end end
function RotorOpsPerks.spawnFatCowFarpObjects(pt_x, pt_y, index) function RotorOpsPerks.spawnFatCowFarpObjects(pt_x, pt_y, index, delay)
env.info('spawnFatCowFarpObjects called. Looking for static group names ending in ' .. 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}) local dest_point = mist.utils.makeVec3GL({x = pt_x, y = pt_y})
trigger.action.smoke(dest_point, 2) trigger.action.smoke(dest_point, 2)
trigger.action.outText('FatCow FARP deploying...get clear of the landing zone!', 20) trigger.action.outText('Fat Cow FARP will deploy in ' ..delay .. ' seconds.', 20)
timer.scheduleFunction(function() timer.scheduleFunction(function()
local fuel_point = {x = dest_point.x + 35, y = dest_point.y, z = dest_point.z} local fuel_point = {x = dest_point.x + 35, y = dest_point.y, z = dest_point.z}
teleportStatic('FAT COW FUEL ' .. index, fuel_point) RotorOpsPerks.teleportStatic('FAT COW FUEL ' .. index, fuel_point)
teleportStatic('FAT COW TENT ' .. index, fuel_point) RotorOpsPerks.teleportStatic('FAT COW TENT ' .. index, fuel_point)
local ammo_point = {x = dest_point.x - 35, y = dest_point.y, z = dest_point.z} local ammo_point = {x = dest_point.x - 35, y = dest_point.y, z = dest_point.z}
teleportStatic('FAT COW AMMO ' .. index, ammo_point) RotorOpsPerks.teleportStatic('FAT COW AMMO ' .. index, ammo_point)
end, nil, timer.getTime() + 235) end, nil, timer.getTime() + delay)
end end
function RotorOpsPerks.spawnFatCow(dest_point, index) function RotorOpsPerks.spawnFatCow(dest_point, farp)
local index = farp.index
local fatcow_name = 'FAT COW' local fatcow_name = 'FAT COW'
local source_farp_name = 'FAT COW FARP ' .. index local source_farp_name = 'FAT COW FARP ' .. index
env.info('spawnFatCow called with ' .. source_farp_name) env.info('spawnFatCow called with ' .. source_farp_name)
--set a timer to return the farp static resources to be reused
timer.scheduleFunction(function()
table.insert(RotorOpsPerks.fat_cow_farps, farp) --put it back at the end of the list
env.info('FatCow FARP timer expired, making the farp available to be used again.')
end, nil, timer.getTime() + 1800)
dest_point = mist.utils.makeVec2(dest_point) dest_point = mist.utils.makeVec2(dest_point)
local approach_point = mist.getRandPointInCircle(dest_point, 1000, 900) 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) trigger.action.smoke(mist.utils.makeVec3GL(dest_point), 2)
@ -482,7 +712,7 @@ function RotorOpsPerks.spawnFatCow(dest_point, index)
return return
end end
teleportStatic(source_farp_name, dest_point) RotorOpsPerks.teleportStatic(source_farp_name, dest_point)
local airbasefarp = Airbase.getByName(source_farp_name) local airbasefarp = Airbase.getByName(source_farp_name)
if not airbasefarp then if not airbasefarp then
@ -493,9 +723,9 @@ function RotorOpsPerks.spawnFatCow(dest_point, index)
local airbase_pos = mist.utils.makeVec2(airbasefarp:getPoint()) local airbase_pos = mist.utils.makeVec2(airbasefarp:getPoint())
local script = [[ local script = [[
RotorOpsPerks.spawnFatCowFarpObjects(]] .. dest_point.x ..[[,]] .. dest_point.y .. [[,]] .. index .. [[) RotorOpsPerks.spawnFatCowFarpObjects(]] .. dest_point.x ..[[,]] .. dest_point.y .. [[,]] .. index .. [[, 235)
env.info('FatCow FARP deployment scheduled')
]] ]]
@ -578,6 +808,14 @@ function RotorOpsPerks.requestPerk(args)
--get the perk object --get the perk object
local perk = RotorOpsPerks.perks[args.perk_name] local perk = RotorOpsPerks.perks[args.perk_name]
--init some essential variables
if not perk.used then
perk.used = 0
end
if not perk.last_used then
perk.last_used = 0
end
--find the intended point --find the intended point
local target_point = nil local target_point = nil
if args.target == 'position' then if args.target == 'position' then
@ -594,7 +832,6 @@ function RotorOpsPerks.requestPerk(args)
local mark_name = mark.text local mark_name = mark.text
--remove new line from mark name --remove new line from mark name
mark_name = mark_name:gsub("\n", "") mark_name = mark_name:gsub("\n", "")
env.info("mark name stripped: " .. mark_name)
if mark_name == args.perk_name then if mark_name == args.perk_name then
perk_name_matches = true perk_name_matches = true
env.info("mark name matches perk name") env.info("mark name matches perk name")
@ -640,7 +877,7 @@ function RotorOpsPerks.requestPerk(args)
local perk_used_count = RotorOpsPerks.getPlayerGroupSum(args.player_group_name, args.perk_name, "perks_used") 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 perk.max_per_player ~= nil and perk_used_count >= (perk.max_per_player*#players) then --multiply by number of players in group
if #players > 1 then if #players > 1 then
trigger.action.outTextForGroup(player_group:getID(), 'UNABLE. You already used this perk ' .. perk_used_count .. ' times.', 10) trigger.action.outTextForGroup(player_group:getID(), 'UNABLE. You already used this perk ' .. perk_used_count .. ' times.', 10)
else else
@ -670,7 +907,7 @@ function RotorOpsPerks.requestPerk(args)
--check if cooldown is over in perks object --check if cooldown is over in perks object
if perk.cooldown > 0 then if perk.cooldown and perk.cooldown > 0 then
if perk.last_used + perk.cooldown > timer.getTime() then if perk.last_used + perk.cooldown > timer.getTime() then
local time_remaining = perk.last_used + perk.cooldown - timer.getTime() local time_remaining = perk.last_used + perk.cooldown - timer.getTime()
--round time_remaining --round time_remaining
@ -681,35 +918,55 @@ function RotorOpsPerks.requestPerk(args)
end end
end end
--add some useful data to pass to perk condition and action functions
--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.target_point = target_point
args.player_group = player_group args.player_group = player_group
args.player_unit = player_unit args.player_unit = player_unit
args.player_unit_name = player_unit_name args.player_unit_name = player_unit_name
--call perk action --show all variables available to perk actions and conditions
perk.action_function(args) --env.info('args: ' .. mist.utils.tableShow(args, 'args'))
--check the perk's unique prerequisite conditions
if perk.action_condition then
local r = perk.action_condition(args)
if r and not r.valid then
local message = r.msg or "UNABLE. Requirements not met."
debugMsg(args.player_group_name.. ' tried to use ' .. args.perk_name .. ' but prereq failed with message: ' .. message)
trigger.action.outTextForGroup(player_group:getID(), message, 10)
return
end
if r and r.valid and r.msg then
trigger.action.outTextForGroup(player_group:getID(), r.msg, 10)
end
end
--check points
if RotorOpsPerks.spendPoints(args.player_group_name, perk.cost, false) then
env.info(args.player_group_name.. ' has sufficient (' .. 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
--call perk action and deduct points if successful
if perk.action_function(args) then
RotorOpsPerks.spendPoints(args.player_group_name, perk.cost, true)
end
--update last_used --update last_used
perk.last_used = timer.getTime() perk.last_used = timer.getTime()
perk.used = perk.used + 1 perk.used = perk.used or 0 + 1
--increment player used for perk type, and initialize if it doesn't exist. --increment player used for perk type, and initialize if it doesn't exist.
local perk_user_per_player = 1/(#players or 1) local perk_user_per_player = 1/(#players or 1)
@ -789,6 +1046,10 @@ function handle:onEvent(e)
--if enemy unit destroyed --if enemy unit destroyed
if e.id == world.event.S_EVENT_KILL then if e.id == world.event.S_EVENT_KILL then
if e.initiator and e.target then if e.initiator and e.target then
if not Unit.getGroup(e.initiator) then
env.warning('KILL: initiator is not a unit')
return
end
if e.initiator:getCoalition() ~= e.target:getCoalition() then if e.initiator:getCoalition() ~= e.target:getCoalition() then
debugMsg('KILL: initiator groupname: ' .. e.initiator:getGroup():getName()) debugMsg('KILL: initiator groupname: ' .. e.initiator:getGroup():getName())
@ -950,7 +1211,7 @@ function RotorOpsPerks.monitorPlayers()
RotorOpsPerks.updatePlayer(player_info.ucid, player_group_name, player_info.name, player_info.slot) 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 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') --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 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
@ -991,6 +1252,18 @@ function RotorOpsPerks.monitorPlayers()
end end
if mist.grimm_version then
env.info("GRIMM's version of MIST is loaded")
else
env.warning("ROTOROPS PERKS REQUIRES A MODIFIED VERSION OF MIST TO WORK PROPERLY. PLEASE SEE THE SCRIPTS FOLDER IN THE ROTOROPS GITHUB REPO")
trigger.action.outText("ERROR: ROTOROPS PERKS REQUIRES A MODIFIED VERSION OF MIST TO WORK PROPERLY.", 30)
end
RotorOpsPerks.buildFatCowFarpTable()
env.info("Found " .. #RotorOpsPerks.fat_cow_farps .. " Fat Cow FARPs")
if #RotorOpsPerks.fat_cow_farps > 0 then
RotorOpsPerks.monitorFarps()
end
RotorOpsPerks.registerCtldCallbacks() RotorOpsPerks.registerCtldCallbacks()
-- start a 5 second timer to monitor players, to allow other scripts to load -- start a 5 second timer to monitor players, to allow other scripts to load
timer.scheduleFunction(RotorOpsPerks.monitorPlayers, nil, timer.getTime() + 5) timer.scheduleFunction(RotorOpsPerks.monitorPlayers, nil, timer.getTime() + 5)

View File

@ -32,6 +32,8 @@ Official Releases <https://github.com/mrSkortch/MissionScriptingTools/tree/maste
]] ]]
mist = {} mist = {}
mist.grimm_version = true
-- don't change these -- don't change these
mist.majorVersion = 4 mist.majorVersion = 4
mist.minorVersion = 5 mist.minorVersion = 5