I rewrote this a little using a utility function, such that I think it works more as you intended now.
What don't know is what you're teleport function looks like, so I just have a dummy one in this example, difference is mine doesn't take a unit name it expects the full wrapper already which is provided too it. I'm not sure where your problem exactly was, but you weren't checking for cases of group + grouptype for your validation, and I think some of the logic flow needed tweaking.
Anyway... The following should work I think exactly how you intend it, allow only ships or groups of surface ships (if others included ask use to try again after deselecting the invalid selection), move each one, deduct usage, message user accordingly.
Code: Select all
local gKH = {}; gKH.Util = {}; -- just setup for the example adjust names and local/global as needed
-- Utility function to return all the unit and or group wrappers currently selected, optionally to not return groups themselves
-- but all expanded members unit wrappers instead.
---@param expandGroups boolean --defaults to true, controls if group wrappers are returned or all their members unit wrappers are returned.
---@return table -- empty table on error or no selections otherwise a table of unit wrappers indexed by guid.
function gKH.Util.GetSelectedUnitsAllMemberUnits(expandGroups);
local fn = "gKH.Util.GetSelectedUnitsMemberUnits() ";
if expandGroups == nil then expandGroups=true; end
local unitTable = {};
local su=ScenEdit_SelectedUnits();
if ((su~=nil) and su.units ~=nil) and #su.units > 0 then
local retval,u = false,nil
for i=1,#su.units do
retval,u = pcall(ScenEdit_GetUnit,{guid=su.units[i].guid});
if ((retval == true) and u~=nil) and u.type ~='Group' then --are we valid and not a group?
unitTable[u.guid] = u; --store unit
elseif ((retval == true) and u~=nil) and u.type =='Group' and expandGroups ==true then --are we valid and also a group?
g = u.group.unitlist; --simply array of unit guids of members.
for l,m in pairs(g) do
retval,u = pcall(ScenEdit_GetUnit,{guid=m}); --get the unit.
if ((retval == true) and u ~= nil) and u.type ~='Group' then -- are we valid and not also another group?
unitTable[u.guid] = u; --store unit
else
print(fn.. 'Group inside Group not supported. Skipping this unit because group with-in group?? guid: ' ..tostring(m));
end
retval=false;u=nil;
end
elseif ((retval == true) and u~=nil) and u.type =='Group' and expandGroups ==false then --are we valid and also a group?
unitTable[u.guid] = u; --store the unit-group wrapper only.
else
print(fn.. 'Could not obtain the object for one of selected units with guid: ' ..tostring(v.guid));
end
u=nil;retval=false;
end
return unitTable; --we're done
else
print(fn.. 'No units are currently selected.')
end
return {};
end
-- my teleport version provides that you don't feed it the name of the unit but whole wrapper.
-- you didn't provide code for that function so I have no visibility into yours this is dummy just to simulate it.
local function TeleportSub(somestring,unitwrapper)
--...actual stuff here ... check for elevation depth etc for subs vs ships..vs desired depth
--...etc etc
if unitwrapper ~=nil then
-- if wrapper is unit then it will move unit to location. setting each specifically to a location.
-- if a group wrapper you're moving the lead and the other member units are moved as well relative to leads location.
unitwrapper.latitude=1.0; --test data
unitwrapper.longitude=1.0; --test data
print('Moving' .. tostring(unitwrapper.name) .. ' to lat:'.. unitwrapper.latitude .. ' lon:' ..unitwrapper.longitude);
else
print('TeleportSub(): unitwrapper not supplied, failed to move unit .');
end
-- ..other stuff
end
--Your general logic code, didn't need to be function but you know how I roll. ;)
local function DoTheThing()
local count=tonumber(ScenEdit_GetKeyValue('SURFACE1'))
local uwTable = gKH.Util.GetSelectedUnitsAllMemberUnits(false);
-- use true if you want individual units instread of group wrapper being included in uwTable.
-- the difference will be with groups included you might say teleport a group and it's members locations stay relative to the lead.
-- vs with true, if you did the same things each unit would need to be assigned a specific location.
--validation
for _,unitwrap in pairs(uwTable) do
if unitwrap.type~='Ship' then
if unitwrap.type ~='Group' or ((unitwrap.type=='Group') and unitwrap.group.type ~='SurfaceGroup') then
ScenEdit_MsgBox('This action is only available for surface ships or groups. selected unit '..tostring(unitwrap.name) ..' violates this, try again with it unselected.', 0)
return false; --exit don't charge the user if any ships found, indicate a failure.
end
end
end
--attempt run through list doing teleportation if count is valid.
if count > 0 then --
local ranAtLeastOnce = false;
for _,unitwrap in pairs(uwTable) do
TeleportSub('SURFACE 1', unitwrap) --call teleport per unit, pass unitwrapper since we already have it.
ranAtLeastOnce = true;
end
if ranAtLeastOnce then count=count - 1 end; -- deplete account only if there was at least one unit teleported we can't check #uwTable cause it's not indexed by number so this instead.
end
--bookkeeping
if count < 1 then
ScenEdit_MsgBox('You have now, or already used this Special Action the maximum allowed times', 0);
ScenEdit_SetSpecialAction({ActionNameOrID='Teleport SURFACE 1', mode='update', isactive=false});
ScenEdit_SetKeyValue('SURFACE1', count);
else
ScenEdit_MsgBox('You may only use this action (' ..count.. ') more times', 0);
ScenEdit_SetKeyValue('SURFACE1', count);
end
return true;
end
--ScenEdit_SetKeyValue('SURFACE1', "2"); --for testing.
DoTheThing();
Seems to work fine in build 1147.44