@@ -914,27 +914,38 @@ end
914914
915915-- find a weapon to pick up
916916function HumanBehaviors .WeaponSearch (AI , Owner , Abort )
917- local minDist ;
918917 local pickupDiggers = not Owner :HasObjectInGroup (" Tools - Diggers" );
919918
919+ local maxSearchDistance ;
920920 if AI .isPlayerOwned then
921- minDist = 100 ; -- don't move player actors too far
921+ maxSearchDistance = 100 ; -- don't move player actors too far
922922 else
923- minDist = FrameMan .PlayerScreenWidth * 0.45 ;
923+ maxSearchDistance = FrameMan .PlayerScreenWidth * 0.45 ;
924924 end
925925
926926 if Owner .AIMode == Actor .AIMODE_SENTRY then
927- minDist = minDist * 0.6 ;
927+ maxSearchDistance = maxSearchDistance * 0.6 ;
928928 end
929929
930930 local devices = {};
931931 local mosSearched = 0 ;
932- for movableObject in MovableMan :GetMOsInRadius (Owner .Pos , minDist , - 1 , true ) do
932+ for movableObject in MovableMan :GetMOsInRadius (Owner .Pos , maxSearchDistance , - 1 , true ) do
933933 mosSearched = mosSearched + 1 ;
934- if IsHeldDevice (movableObject ) then
934+ if mosSearched % 30 == 0 then
935+ local _ai , _ownr , _abrt = coroutine.yield ();
936+ if _abrt then return true end
937+ end
938+
939+ if IsHeldDevice (movableObject ) and MovableMan :ValidMO (movableObject ) then
935940 local device = ToHeldDevice (movableObject );
936941 if device :IsPickupableBy (Owner ) and not device :IsActivated () and device .Vel .Largest < 3 and not SceneMan :IsUnseen (device .Pos .X , device .Pos .Y , Owner .Team ) then
937- table.insert (devices , { device = device , distance = SceneMan :ShortestDistance (Owner .Pos , device .Pos , SceneMan .SceneWrapsX or SceneMan .SceneWrapsY ) });
942+ local distanceToDevice = SceneMan :ShortestDistance (Owner .Pos , device .Pos , SceneMan .SceneWrapsX or SceneMan .SceneWrapsY );
943+ if distanceToDevice :MagnitudeIsGreaterThan (Owner .Radius * 0.75 ) then
944+ table.insert (devices , { device = device , distance = distanceToDevice });
945+ else
946+ devices = {{ device = device , distance = distanceToDevice }};
947+ break ;
948+ end
938949 end
939950 end
940951 end
@@ -944,21 +955,24 @@ function HumanBehaviors.WeaponSearch(AI, Owner, Abort)
944955 local _ai , _ownr , _abrt = coroutine.yield ();
945956 if _abrt then return true end
946957
947- local waypointDistance = 36 ;
958+ local maxWaypointDistance = 36 ;
948959 if AI .isPlayerOwned then
949- waypointDistance = 10 ;
960+ maxWaypointDistance = 10 ;
950961 end
951962
952- local waypoints , score ;
953963 local devicesToPickUp = {};
954964 for _ , deviceEntry in pairs (devices ) do
955965 local device = deviceEntry .device ;
956966 if MovableMan :ValidMO (device ) then
957- local pathToItemIsObstructed = SceneMan :CastStrengthRay (Owner .Pos , deviceEntry .distance , 5 , Vector (), 4 , rte .grassID , true ); -- TODO if still laggy, just use this entirely and don't bother calcuating a path. Maybe only calculate path on smaller maps (< 10,000,000 square px)
967+ local pathToItemIsObstructed = false ;
968+ if AI .useExpensiveToolAndWeaponSearch then
969+ pathToItemIsObstructed = SceneMan :CastStrengthRay (Owner .Pos , deviceEntry .distance , 5 , Vector (), 4 , rte .grassID , true );
970+ end
958971 local pathfinderNodeSize = 20 ; -- TODO this should be read from cpp
959972
960- local distanceToTarget = pathToItemIsObstructed and SceneMan .Scene :CalculatePath (Owner .Pos , device .Pos , false , 1 , Owner .Team ) or deviceEntry .distance .Magnitude / pathfinderNodeSize ;
961- if distanceToTarget < waypointDistance and distanceToTarget > - 1 then
973+ local distanceToTarget = pathToItemIsObstructed and SceneMan .Scene :CalculatePath (Owner .Pos , device .Pos , false , 1 , Owner .Team ) or (deviceEntry .distance .Magnitude / pathfinderNodeSize );
974+ if distanceToTarget < maxWaypointDistance and distanceToTarget > - 1 then
975+ local score = distanceToTarget
962976 if device :HasObjectInGroup (" Weapons - Primary" ) or device :HasObjectInGroup (" Weapons - Heavy" ) then
963977 score = distanceToTarget * 0.4 ; -- prioritize primary or heavy weapons
964978 elseif device .ClassName == " TDExplosive" then
@@ -967,14 +981,17 @@ function HumanBehaviors.WeaponSearch(AI, Owner, Abort)
967981 if pickupDiggers and device :HasObjectInGroup (" Tools - Diggers" ) then
968982 score = distanceToTarget * 1.8 ; -- avoid diggers if there are other weapons
969983 else
970- distanceToTarget = waypointDistance ;
984+ distanceToTarget = maxWaypointDistance ;
971985 end
972- else
973- score = distanceToTarget ;
974986 end
975987
976- if distanceToTarget < waypointDistance then
988+ if distanceToTarget < maxWaypointDistance then
977989 table.insert (devicesToPickUp , {device = device , score = score });
990+ if not pathToItemIsObstructed or score < 1 then
991+ local _ai , _ownr , _abrt = coroutine.yield ();
992+ if _abrt then return true end
993+ break ;
994+ end
978995 end
979996 for i = 1 , 2 do
980997 local _ai , _ownr , _abrt = coroutine.yield ();
@@ -984,9 +1001,10 @@ function HumanBehaviors.WeaponSearch(AI, Owner, Abort)
9841001 end
9851002 end
9861003
1004+
9871005 AI .PickupHD = nil ;
988- table.sort (devicesToPickUp , function (A ,B ) return A .score < B .score end ); -- sort the items in order of discounted distance
989- for _ , deviceToPickupEntry in pairs (devicesToPickUp ) do
1006+ table.sort (devicesToPickUp , function (A ,B ) return A .score < B .score end );
1007+ for _ , deviceToPickupEntry in ipairs (devicesToPickUp ) do
9901008 if MovableMan :ValidMO (deviceToPickupEntry .device ) and deviceToPickupEntry .device :IsDevice () then
9911009 AI .PickupHD = deviceToPickupEntry .device ;
9921010 break ;
@@ -1026,25 +1044,38 @@ end
10261044
10271045-- find a tool to pick up
10281046function HumanBehaviors .ToolSearch (AI , Owner , Abort )
1029- local minDist ;
1047+ local maxSearchDistance ;
10301048 if Owner .AIMode == Actor .AIMODE_GOLDDIG then
1031- minDist = FrameMan .PlayerScreenWidth * 0.5 ; -- move up to half a screen when digging
1049+ maxSearchDistance = FrameMan .PlayerScreenWidth * 0.5 ; -- move up to half a screen when digging
10321050 elseif AI .isPlayerOwned then
1033- minDist = 60 ; -- don't move player actors too far
1051+ maxSearchDistance = 60 ; -- don't move player actors too far
10341052 else
1035- minDist = FrameMan .PlayerScreenWidth * 0.3 ;
1053+ maxSearchDistance = FrameMan .PlayerScreenWidth * 0.3 ;
10361054 end
10371055
10381056 if Owner .AIMode == Actor .AIMODE_SENTRY then
1039- minDist = minDist * 0.6 ;
1057+ maxSearchDistance = maxSearchDistance * 0.6 ;
10401058 end
10411059
10421060 local devices = {};
1043- for movableObject in MovableMan :GetMOsInRadius (Owner .Pos , minDist , - 1 , true ) do
1044- if IsHeldDevice (movableObject ) then
1061+ local mosSearched = 0 ;
1062+ for movableObject in MovableMan :GetMOsInRadius (Owner .Pos , maxSearchDistance , - 1 , true ) do
1063+ mosSearched = mosSearched + 1 ;
1064+ if mosSearched % 30 == 0 then
1065+ local _ai , _ownr , _abrt = coroutine.yield ();
1066+ if _abrt then return true end
1067+ end
1068+
1069+ if IsHeldDevice (movableObject ) and MovableMan :ValidMO (movableObject ) then
10451070 local device = ToHeldDevice (movableObject );
10461071 if device :IsPickupableBy (Owner ) and not device :IsActivated () and device .Vel .Largest < 3 and not SceneMan :IsUnseen (device .Pos .X , device .Pos .Y , Owner .Team ) and device :HasObjectInGroup (" Tools - Diggers" ) then
1047- table.insert (devices , { device = device , distance = SceneMan :ShortestDistance (Owner .Pos , device .Pos , SceneMan .SceneWrapsX or SceneMan .SceneWrapsY ) });
1072+ local distanceToDevice = SceneMan :ShortestDistance (Owner .Pos , device .Pos , SceneMan .SceneWrapsX or SceneMan .SceneWrapsY );
1073+ if distanceToDevice :MagnitudeIsGreaterThan (20 ) then
1074+ table.insert (devices , { device = device , distance = distanceToDevice });
1075+ else
1076+ devices = {{ device = device , distance = distanceToDevice }};
1077+ break ;
1078+ end
10481079 end
10491080 end
10501081 end
@@ -1054,25 +1085,31 @@ function HumanBehaviors.ToolSearch(AI, Owner, Abort)
10541085 local _ai , _ownr , _abrt = coroutine.yield ();
10551086 if _abrt then return true end
10561087
1057- local waypointDistance = 16 ;
1088+ local maxWaypointDistance = 16 ;
10581089 if Owner .AIMode == Actor .AIMODE_GOLDDIG then
1059- waypointDistance = 30 ;
1090+ maxWaypointDistance = 30 ;
10601091 elseif AI .isPlayerOwned then
1061- waypointDistance = 5 ;
1092+ maxWaypointDistance = 5 ;
10621093 end
10631094
1064- local waypoints , score ;
10651095 local devicesToPickUp = {};
10661096 for _ , deviceEntry in pairs (devices ) do
10671097 local device = deviceEntry .device ;
10681098 if MovableMan :ValidMO (device ) then
1069- local pathToItemIsObstructed = SceneMan :CastStrengthRay (Owner .Pos , deviceEntry .distance , 5 , Vector (), 4 , rte .grassID , true );
1099+ local pathToItemIsObstructed = false ;
1100+ if AI .useExpensiveToolAndWeaponSearch then
1101+ pathToItemIsObstructed = SceneMan :CastStrengthRay (Owner .Pos , deviceEntry .distance , 5 , Vector (), 4 , rte .grassID , true );
1102+ end
10701103 local pathfinderNodeSize = 20 ; -- TODO this should be read from cpp
10711104
1072- local distanceToTarget = pathToItemIsObstructed and SceneMan .Scene :CalculatePath (Owner .Pos , device .Pos , false , 1 , Owner .Team ) or deviceEntry .distance .Magnitude / pathfinderNodeSize ;
1073- if distanceToTarget < waypointDistance and distanceToTarget > - 1 then
1105+ local distanceToTarget = pathToItemIsObstructed and SceneMan .Scene :CalculatePath (Owner .Pos , device .Pos , false , 1 , Owner .Team ) or ( deviceEntry .distance .Magnitude / pathfinderNodeSize ) ;
1106+ if distanceToTarget < maxWaypointDistance and distanceToTarget > - 1 then
10741107 table.insert (devicesToPickUp , {device = device , score = distanceToTarget });
10751108
1109+ if not pathToItemIsObstructed or distanceToTarget < 1 then
1110+ break ;
1111+ end
1112+
10761113 for i = 1 , 2 do
10771114 local _ai , _ownr , _abrt = coroutine.yield ();
10781115 if _abrt then return true end
@@ -1083,7 +1120,7 @@ function HumanBehaviors.ToolSearch(AI, Owner, Abort)
10831120
10841121 AI .PickupHD = nil ;
10851122 table.sort (devicesToPickUp , function (A ,B ) return A .score < B .score end ); -- sort the items in order of discounted distance
1086- for _ , deviceToPickupEntry in pairs (devicesToPickUp ) do
1123+ for _ , deviceToPickupEntry in ipairs (devicesToPickUp ) do
10871124 if MovableMan :ValidMO (deviceToPickupEntry .device ) and deviceToPickupEntry .device :IsDevice () then
10881125 AI .PickupHD = deviceToPickupEntry .device ;
10891126 break ;
0 commit comments