For loop assistance with auto-repairing

Hi guys,

I just can’t wrap my head around for loops, here’s what I’ve done for auto-repair in STC but I am unable to get the thing to loop through the proximity group and pick the worst off ship :confused:

Can someone please tell me where my for loop went wrong?


function AutoRepair(CustomGroup, playerIndex, shipID)

   if SOB_tShips[shipID].iRepairShip == 1 then
   
   	print(">> REPAIR >> | repair ship "..shipID.." of player "..playerIndex.." recognised")
   
   	if SOB_tShips[shipID].iRepairingShipID == 0 then 
   
   		local nearbyShips = "nearbyShips"
   		SobGroup_Create(nearbyShips)
   		SobGroup_Clear(nearbyShips)
   					
   		Player_FillProximitySobGroup(nearbyShips, playerIndex, CustomGroup, 6000)
   		
   		local nearbyShipCount = 0
   		local mostDamagedShipID = 0
   		local mostDamagePercentage = 1
   		
   		if SobGroup_Count(nearbyShips) >= 0 then
   		
   			nearbyShipCount = SobGroup_Count(nearbyShips)
   			
   		end
   		
   		print(">> REPAIR >> | There is no ship currently assigned to repairship "..shipID.." of player "..playerIndex.." with "..nearbyShipCount.." ships nearby")
   		
   		for i = 1, nearbyShipCount do
   		
   			if SobGroup_HealthPercentage(nearbyShips[i]) < mostDamagePercentage then
   				
   				mostDamagePercentage = SobGroup_HealthPercentage(nearbyShips[i])
   				mostDamagedShipID = GetShipId(nearbyShips[i])
   				
   			end
   					
   		end
   		
   		print(">> REPAIR >> | the most damaged ship near repairship "..shipID.." of player "..playerIndex.." is ship "..mostDamagedShipID)
   		
   		SOB_tShips[shipID].iRepairingShipID = mostDamagedShipID
   		
   		SobGroup_RepairSobGroup(CustomGroup, SOB_tShips[mostDamagedShipID].sob)
   		
   	else 
   	
   		if SobGroup_HealthPercentage(SOB_tShips[iRepairingShipID].sob) == 1 then
   		
   			print(">> REPAIR >> | ship "..SOB_tShips[shipID].iRepairingShipID.." is now fully repaired")
   			
   			SOB_tShips[shipID].iRepairingShipID = 0 
   								
   		end
   	
   	end
   
   end

end

I’m hoping to get this working before Thursday night AEST so I can include it in this month’s upload :slight_smile:

I don’t believe you can use nearbyShips as a table. It’s a string (well, SobGroup name).

Instead, you will need to put each ship in nearbyShips into it’s own sobgroup and test that. There are a few ways of doing this, but my personal choice for this is

--
local shipCount = SobGroup_Count(nearbyShips)
local shipIndex = 0

if (shipCount > 0) then
  while (shipIndex < shipCount) do
    SobGroup_FillShipsByIndexRange("checkShip", nearbyShips, shipIndex, 1) -- This is important as it selects only a certain amount of ships from another sobgroup.

    shipIndex = shipIndex + 1
    if (SobGroup_Count("checkShip") > 0) then shipIndex = shipIndex +(SobGroup_Count("checkShip")- 1) end  --Sometimes there are 0 ships, sometimes theres more (eg, Hiigaran Interceptors)

    if (SobGroup_HealthPercentage("checkShip") < mostDamagePercentage) then
      mostDamagePercentage = SobGroup_HealthPercentage("checkShip")
      mostDamagedShipID = GetShipId("checkShip")
    end
  end
end

Also, SobGroup_HealthPercentage(SOB_tShips[iRepairingShipID].sob) may not work unless iRepairingShipID is set else where, guessing it should be SOB_tShips[SOB_tShips[shipID].iRepairingShipID].sob

Next, if the ship set in SOB_tShips[SOB_tShips[shipID].iRepairingShipID].sob is destroyed or moves away or something other the being fully repaired, the ship calling the AutoRepair function won’t move on to repair another ship.

Lastly, I may be wrong in this, but shouldn’t playerIndex be the first argument for Player_FillProximitySobGroup ?

[Edit]
Forgot to say,

  • SobGroup_FillShipsByIndexRange may be a v2.1 function
  • Test ships to see if there health is greater then 0. Dead ships still doing their death animations will still appear in sobgroups. (A v2.1 function for this is SobGroup_FilterExclude(nearybyShips, nearbyShips, "Health", 0) [’Health’ may be wrong, at the moment I don’t have access to a strings dump of the v2.1 exe)
  • From what I’ve learnt with bug 666, if a ship is just inside the proximity range for 1 player and just outside for another player, there is the possibility for a desync. A possible fix for this is to use a second Proximity at a slightly closer distance (say 5900) that only selects ships from the first proximity group.
1 Like

Thanks Trebic!

I didn’t know a “while” loop was a thing :thinking:

Yes, you’re right!

The ship can’t really “move away” as the repairer will follow it, even after the repair is completed. This whole exercise is about compensating for that and sending it onto other ships in need. You can’t give more than one target for repair too unfortunately, which would make this all much simpler :confused:
I will need to check for health > 0 though, you’re right! I’ll see about that SobGroup_FilterExclude function and the appropriate strings for it :thinking:

//EDIT

You have it right here :slight_smile:

//EDIT

You’re incorrect according to this: http://hw2bsg.org/wiki.hw2.info/FunctionPlayer_FillProximitySobGroup.html
It seems to work in-game, no idea why they chose that ordering for this particular function!

Also good advice!

1 Like

STARSHIP >> | Player 0 has built fed_TNG_flagship with an ID of 368
STARSHIP >> | Player 0 has built fed_TNG_repairship with an ID of 384
REPAIR >> | repair ship 384 of player 0 recognised
LOOP 1 CHECK >> | most damaged shipID is 3186101028 with 0 health value
REPAIR >> | repairship with ID 384 is repairing ship with ID 3186101028
parameter: attempt to index a nil value
stack traceback:
1: function AutoRepair' at line 58 [string ""] 2: functionUpdate_STC_Starship’ at line 27 [string “”]

GetShipId() doesn’t return the same ID as the shipID in the custom code :confused:

//EDIT

It also appears to only operate by class… I’m going to need another approach :frowning:

STARSHIP >> | Player 0 has built fed_TNG_sovereign with an ID of 1680 with a second ID of 2022555814
STARSHIP >> | Player 0 has built fed_TNG_sovereign with an ID of 1696 with a second ID of 2022555814
STARSHIP >> | Player 0 has built fed_TNG_sovereign with an ID of 1712 with a second ID of 2022555814

//EDIT
In fact, I’d go so far to say as that ID is useless, even checking for it in the master table per ship gives different results :sweat:

try this


function AutoRepair(CustomGroup, playerIndex, shipID)
  local repairGroup = "iRepairShip"..shipID
  local nearbyShips = "nearbyShips"

  SobGroup_CreateIfNotExist(repairGroup)

  if (SOB_tShips[shipID].iRepairShip == 0) then
    if (SobGroup_Empty(repairGroup)== 0) then
	  SobGroup_Clear(repairGroup)
	end
  end

  if (SOB_tShips[shipID].iRepairShip == 1) then
    local sobEmpty = SobGroup_Empty(repairGroup)
	
	print(">> REPAIR >> | repair ship "..shipID.." of player "..playerIndex.." recognised")
	
	if (sobEmpty == 0) then
	  local shipHealth = SobGroup_HealthPercentage(repairGroup)
	  
	  if (shipHealth >= 1) then
	    print(">> REPAIR >> | ship being repaired by "..shipID.." has completed")
	    SobGroup_Clear(repairGroup)
		sobEmpty = 1
	  end
	  if (shipHealth <= 0) then
	    print(">> REPAIR >> | ship being repaired by "..shipID.." has died")
		SobGroup_Clear(repairGroup)
		sobEmpty = 1
	  end
	end

	if (sobEmpty == 1) then
	  SobGroup_CreateIfNotExist(nearbyShips)
	  SobGroup_Clear(nearbyShips)
	  
	  Player_FillProximitySobGroup(nearbyShips, playerIndex, CustomGroup, 6000)
	  SobGroup_FillProximitySobGroup(nearbyShips, nearbyShips, CustomGroup, 5900)
	  
	  local nearbyCount = SobGroup_Count(nearbyShips)
	  local nearbyIndex = 0
	  local mostDamagePercentage = 1
	  
 	  print(">> REPAIR >> | There is no ship currently assigned to repairship "..shipID.." of player "..playerIndex.." with "..nearbyCount.." ships nearby")
	  
	  while (nearbyIndex < nearbyCount) do
	    SobGroup_CreateIfNotExist(nearbyShips.."Check")
		SobGroup_FillShipsByIndexRange(nearbyShips.."Check", nearbyShips, nearbyIndex, 1)
		
		nearbyIndex = nearbyIndex + 1
		if (SobGroup_Count(nearbyShips.."Check") > 0) then
		  nearbyIndex = nearbyIndex + (SobGroup_Count(nearbyShips.."Check")- 1)
		end
		
		local shipHealth = SobGroup_HealthPercentage(nearbyShips.."Check")
		
		if (shipHealth > 0 and shipHealth < mostDamagePercentage) then
		  mostDamagePercentage = shipHealth
		  
		  SobGroup_Clear(repairGroup)
		  SobGroup_SobGroupAdd(repairGroup, nearbyShips.."Check")
		end
	  end
	  
	  if (mostDamagePercentage < 1) then
	    print(">> REPAIR >> | the most damaged ship near repairship "..shipID.." of player "..playerIndex.." is ship of type "..SobGroup_GetShipType(repairGroup).." with health of "..mostDamagePercentage)
            SobGroup_RepairSobGroup(CustomGroup, repairGroup)
	  end
	end
  end
  
end

Instead of storing the ship id, this instead stores the repair target in a sobgroup using the repair ships id.

2 Likes

That’s almost it!

I needed to add the repair command in and I also need to fine-tune it a bit (ships to repair were abandoned for some reason…) but I think it’s mostly there. Thank you :slight_smile:

I’ve update the above function to add the repair command.
I’m unsure why it would abandon the repair targets unless the repair command is in an incorrect position.
There are some issues i have encounted before that a sobgroup may not be updated till next frame, but it only occurs with certain sobgroup functions (Unable to remember what functions they where, but one of them might be SobGroup_Empty, if that is correct, then try replacing them SobGroup_Count.)

[Edit]
I should also state that, as I am unsure how you use SOB_tShips[shipID].iRepairShip, when that value is set to 0, the stored repair group is cleared.

That’s where I popped the repair command, yes :slight_smile:

I think the ships are being abandoned once repaired instead of the group just being updated and the command reissued when there’s another ship in need and the original target is fully repaired. The instant the ship is repaired it’s no longer targeted for repair

	  if (shipHealth >= 1) then
	    print(">> REPAIR >> | ship being repaired by "..shipID.." has completed")
	    SobGroup_Clear(repairGroup)
		sobEmpty = 1
	  end

The iRepairShip thing is simply this:

  	if (SobGroup_CanDoAbility(CustomGroup, AB_Repair) == 1) then
	
		tShip.iRepairShip = 1
	
	end

I can probably abandon this methodology and just check it on the fly since nothing else in the main ship table is useable :confused:

//EDIT
I figured it out! The repairship is targeting itself, and it gets stuck on that :stuck_out_tongue:

@shadowwinterknig

Here’s the final, fully functional, code with my minor tweaks :smiley:

function AutoRepair(CustomGroup, playerIndex, shipID)

	if (SobGroup_CanDoAbility(CustomGroup, AB_Repair) == 1) and (Universe_GameTime() > 10) then
	
		local repairGroup = "iRepairShip"..shipID
		local nearbyShips = "nearbyShips"

		SobGroup_CreateIfNotExist(repairGroup)
		
		local sobEmpty = SobGroup_Empty(repairGroup)

		-- print(">> REPAIR >> | repair ship "..shipID.." of player "..playerIndex.." recognised")

		if (sobEmpty == 0) then

			local shipHealth = SobGroup_HealthPercentage(repairGroup)

			if (shipHealth >= 1) then

				-- print(">> REPAIR >> | ship being repaired by "..shipID.." has completed")
				SobGroup_Clear(repairGroup)
				sobEmpty = 1

			end
			if (shipHealth <= 0) then

				-- print(">> REPAIR >> | ship being repaired by "..shipID.." has died")
				SobGroup_Clear(repairGroup)
				sobEmpty = 1

			end
			
		end

		if (sobEmpty == 1) then
		
			SobGroup_CreateIfNotExist(nearbyShips)
			SobGroup_Clear(nearbyShips)

			Player_FillProximitySobGroup(nearbyShips, playerIndex, CustomGroup, 8000)
			SobGroup_FillProximitySobGroup(nearbyShips, nearbyShips, CustomGroup, 7900)
			SobGroup_FillSubstract(nearbyShips, nearbyShips, CustomGroup)

			local nearbyCount = SobGroup_Count(nearbyShips)
			local nearbyIndex = 0
			local mostDamagePercentage = 1

			-- print(">> REPAIR >> | There is no ship currently assigned to repairship "..shipID.." of player "..playerIndex.." with "..nearbyCount.." ships nearby")

			while (nearbyIndex < nearbyCount) do
			
				SobGroup_CreateIfNotExist(nearbyShips.."Check")
				SobGroup_FillShipsByIndexRange(nearbyShips.."Check", nearbyShips, nearbyIndex, 1)

				nearbyIndex = nearbyIndex + 1
			
				if (SobGroup_Count(nearbyShips.."Check") > 0) then
				
					nearbyIndex = nearbyIndex + (SobGroup_Count(nearbyShips.."Check")- 1)
					
				end

				local shipHealth = SobGroup_HealthPercentage(nearbyShips.."Check")

				if (shipHealth > 0 and shipHealth < mostDamagePercentage) then
				
					mostDamagePercentage = shipHealth

					SobGroup_Clear(repairGroup)
					SobGroup_SobGroupAdd(repairGroup, nearbyShips.."Check")
					
				end
				
			end

			if (mostDamagePercentage < 1) then

				-- print(">> REPAIR >> | the most damaged ship near repairship "..shipID.." of player "..playerIndex.." is ship of type "..SobGroup_GetShipType(repairGroup))
				SobGroup_RepairSobGroup(CustomGroup, repairGroup)

			end

		end

	end
  
end

Thanks mate! You’re a gem!

4 Likes

awesome, does this work with the repair beams or only with latching repair?

As long as the unit starts repairing a target when using the command SobGroup_RepairSobGroup, it should work regardless. If not, then you will just need to replace that command with 1 that does.

If you were to replace SobGroup_RepairSobGroup with SobGroup_Attack, then the unit will attack the ship with the least amount of health that’s within 5900(m?) of the unit.

1 Like

Both latching repair and repair beams are managed with SobGroup_RepairSobGroup, it just doesn’t seem to like working with more than one ship in the target group