@@ -915,94 +915,100 @@ end
915
915
-- find a weapon to pick up
916
916
function HumanBehaviors .WeaponSearch (AI , Owner , Abort )
917
917
local minDist ;
918
- local Devices = {};
919
918
local pickupDiggers = not Owner :HasObjectInGroup (" Tools - Diggers" );
920
919
921
920
if AI .isPlayerOwned then
922
- minDist = 100 ; -- don't move player actors more than 4m
921
+ minDist = 100 ; -- don't move player actors too far
923
922
else
924
923
minDist = FrameMan .PlayerScreenWidth * 0.45 ;
925
924
end
926
925
927
926
if Owner .AIMode == Actor .AIMODE_SENTRY then
928
927
minDist = minDist * 0.6 ;
929
928
end
930
-
931
- local itemsFound = 0 ;
932
- for Item in MovableMan .Items do -- store all HeldDevices of the correct type and within a certain range in a table
933
- local HD = ToHeldDevice (Item );
934
- if HD and HD :IsPickupableBy (Owner ) and not HD :IsActivated () and HD .Vel .Largest < 3 and SceneMan :ShortestDistance (Owner .Pos , HD .Pos , SceneMan .SceneWrapsX ).Largest < minDist and not SceneMan :IsUnseen (HD .Pos .X , HD .Pos .Y , Owner .Team ) then
935
- table.insert (Devices , HD );
936
- itemsFound = itemsFound + 1 ;
929
+
930
+ local devices = {};
931
+ local mosSearched = 0 ;
932
+ for movableObject in MovableMan :GetMOsInRadius (Owner .Pos , minDist , - 1 , true ) do
933
+ mosSearched = mosSearched + 1 ;
934
+ if IsHeldDevice (movableObject ) then
935
+ local device = ToHeldDevice (movableObject );
936
+ 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 ) });
938
+ end
937
939
end
938
940
end
939
-
940
- if itemsFound > 0 then
941
- local _ai , _ownr , _abrt = coroutine.yield (); -- wait until next frame
941
+ table.sort (devices , function (device , otherDevice ) return device .distance .SqrMagnitude < otherDevice .distance .SqrMagnitude end );
942
+
943
+ if # devices > 0 then
944
+ local _ai , _ownr , _abrt = coroutine.yield ();
942
945
if _abrt then return true end
943
946
947
+ local waypointDistance = 36 ;
944
948
if AI .isPlayerOwned then
945
- minDist = 10 ; -- # of waypoints
946
- else
947
- minDist = 36 ;
949
+ waypointDistance = 10 ;
948
950
end
949
951
950
952
local waypoints , score ;
951
- local DevicesToPickUp = {};
952
- for _ , Item in pairs (Devices ) do
953
- if MovableMan :ValidMO (Item ) then
954
- waypoints = SceneMan .Scene :CalculatePath (Owner .Pos , Item .Pos , false , 1 , Owner .Team );
955
- if waypoints < minDist and waypoints > - 1 then
956
- -- estimate the walking distance to the item
957
- if Item :HasObjectInGroup (" Weapons - Primary" ) then
958
- score = waypoints * 0.4 ; -- prioritize primaries
959
- elseif Item .ClassName == " TDExplosive" then
960
- score = waypoints * 1.4 ; -- avoid grenades if there are other weapons
961
- elseif Item :IsTool () then
962
- if pickupDiggers and Item :HasObjectInGroup (" Tools - Diggers" ) then
963
- score = waypoints * 1.8 ; -- avoid diggers if there are other weapons
953
+ local devicesToPickUp = {};
954
+ for _ , deviceEntry in pairs (devices ) do
955
+ local device = deviceEntry .device ;
956
+ 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)
958
+ local pathfinderNodeSize = 20 ; -- TODO this should be read from cpp
959
+
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
962
+ if device :HasObjectInGroup (" Weapons - Primary" ) or device :HasObjectInGroup (" Weapons - Heavy" ) then
963
+ score = distanceToTarget * 0.4 ; -- prioritize primary or heavy weapons
964
+ elseif device .ClassName == " TDExplosive" then
965
+ score = distanceToTarget * 1.4 ; -- avoid grenades if there are other weapons
966
+ elseif device :IsTool () then
967
+ if pickupDiggers and device :HasObjectInGroup (" Tools - Diggers" ) then
968
+ score = distanceToTarget * 1.8 ; -- avoid diggers if there are other weapons
964
969
else
965
- waypoints = minDist ; -- don't pick up
970
+ distanceToTarget = waypointDistance ;
966
971
end
967
972
else
968
- score = waypoints ;
973
+ score = distanceToTarget ;
969
974
end
970
975
971
- if waypoints < minDist then
972
- table.insert (DevicesToPickUp , {HD = Item , score = score });
976
+ if distanceToTarget < waypointDistance then
977
+ table.insert (devicesToPickUp , {device = device , score = score });
978
+ end
979
+ for i = 1 , 2 do
980
+ local _ai , _ownr , _abrt = coroutine.yield ();
981
+ if _abrt then return true end
973
982
end
974
983
end
975
-
976
- local _ai , _ownr , _abrt = coroutine.yield (); -- wait until next frame
977
- if _abrt then return true end
978
984
end
979
985
end
980
986
981
987
AI .PickupHD = nil ;
982
- table.sort (DevicesToPickUp , function (A ,B ) return A .score < B .score end ); -- sort the items in order of discounted distance
983
- for _ , Data in pairs (DevicesToPickUp ) do
984
- if MovableMan :ValidMO (Data . HD ) and Data . HD :IsDevice () then
985
- AI .PickupHD = Data . HD ;
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
990
+ if MovableMan :ValidMO (deviceToPickupEntry . device ) and deviceToPickupEntry . device :IsDevice () then
991
+ AI .PickupHD = deviceToPickupEntry . device ;
986
992
break ;
987
993
end
988
994
end
989
995
990
996
if AI .PickupHD then
991
997
-- where do we move after pick up?
992
- local PrevMoveTarget , PrevSeceneWaypoint ;
998
+ local prevMoveTarget , prevSceneWaypoint ;
993
999
if Owner .MOMoveTarget and MovableMan :ValidMO (Owner .MOMoveTarget ) then
994
- PrevMoveTarget = Owner .MOMoveTarget ;
1000
+ prevMoveTarget = Owner .MOMoveTarget ;
995
1001
else
996
- PrevSeceneWaypoint = SceneMan :MovePointToGround (Owner :GetLastAIWaypoint (), Owner .Height / 5 , 4 ); -- last wpt or current pos
1002
+ prevSceneWaypoint = SceneMan :MovePointToGround (Owner :GetLastAIWaypoint (), Owner .Height / 5 , 4 ); -- last wpt or current pos
997
1003
end
998
1004
999
1005
Owner :ClearMovePath ();
1000
1006
Owner :AddAIMOWaypoint (AI .PickupHD );
1001
1007
1002
- if PrevMoveTarget then
1003
- Owner :AddAIMOWaypoint (PrevMoveTarget );
1004
- elseif PrevSeceneWaypoint then
1005
- Owner :AddAISceneWaypoint (PrevSeceneWaypoint );
1008
+ if prevMoveTarget then
1009
+ Owner :AddAIMOWaypoint (prevMoveTarget );
1010
+ elseif prevSceneWaypoint then
1011
+ Owner :AddAISceneWaypoint (prevSceneWaypoint );
1006
1012
end
1007
1013
1008
1014
if Owner .AIMode == Actor .AIMODE_SENTRY then
@@ -1024,80 +1030,83 @@ function HumanBehaviors.ToolSearch(AI, Owner, Abort)
1024
1030
if Owner .AIMode == Actor .AIMODE_GOLDDIG then
1025
1031
minDist = FrameMan .PlayerScreenWidth * 0.5 ; -- move up to half a screen when digging
1026
1032
elseif AI .isPlayerOwned then
1027
- minDist = 60 ; -- don't move player actors more than 3m
1033
+ minDist = 60 ; -- don't move player actors too far
1028
1034
else
1029
1035
minDist = FrameMan .PlayerScreenWidth * 0.3 ;
1030
1036
end
1031
1037
1032
1038
if Owner .AIMode == Actor .AIMODE_SENTRY then
1033
1039
minDist = minDist * 0.6 ;
1034
1040
end
1035
-
1036
- local Devices = {};
1037
- local itemsFound = 0 ;
1038
- for Item in MovableMan .Items do -- store all HeldDevices of the correct type and within a certain range in a table
1039
- local HD = ToHeldDevice (Item );
1040
- if HD and not HD :IsActivated () and HD .Vel .Largest < 3 and
1041
- SceneMan :ShortestDistance (Owner .Pos , HD .Pos , false ).Largest < minDist and
1042
- not SceneMan :IsUnseen (HD .Pos .X , HD .Pos .Y , Owner .Team )
1043
- then
1044
- table.insert (Devices , HD );
1045
- itemsFound = itemsFound + 1 ;
1041
+
1042
+ local devices = {};
1043
+ for movableObject in MovableMan :GetMOsInRadius (Owner .Pos , minDist , - 1 , true ) do
1044
+ if IsHeldDevice (movableObject ) then
1045
+ local device = ToHeldDevice (movableObject );
1046
+ 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 ) });
1048
+ end
1046
1049
end
1047
1050
end
1048
-
1049
- if itemsFound > 0 then
1050
- local _ai , _ownr , _abrt = coroutine.yield (); -- wait until next frame
1051
+ table.sort (devices , function (device , otherDevice ) return device .distance .SqrMagnitude < otherDevice .distance .SqrMagnitude end );
1052
+
1053
+ if # devices > 0 then
1054
+ local _ai , _ownr , _abrt = coroutine.yield ();
1051
1055
if _abrt then return true end
1052
1056
1057
+ local waypointDistance = 16 ;
1053
1058
if Owner .AIMode == Actor .AIMODE_GOLDDIG then
1054
- minDist = 30 ;
1059
+ waypointDistance = 30 ;
1055
1060
elseif AI .isPlayerOwned then
1056
- minDist = 5 ;
1057
- else
1058
- minDist = 16 ;
1061
+ waypointDistance = 5 ;
1059
1062
end
1060
1063
1061
- local DevicesToPickUp = {};
1062
- for _ , Item in pairs (Devices ) do
1063
- if MovableMan :ValidMO (Item ) and Item :HasObjectInGroup (" Tools - Diggers" ) then
1064
- -- estimate the walking distance to the item
1065
- local waypoints = SceneMan .Scene :CalculatePath (Owner .Pos , Item .Pos , false , 1 , Owner .Team );
1066
- if waypoints < minDist and waypoints > - 1 then
1067
- table.insert (DevicesToPickUp , {HD = Item , score = waypoints });
1064
+ local waypoints , score ;
1065
+ local devicesToPickUp = {};
1066
+ for _ , deviceEntry in pairs (devices ) do
1067
+ local device = deviceEntry .device ;
1068
+ if MovableMan :ValidMO (device ) then
1069
+ local pathToItemIsObstructed = SceneMan :CastStrengthRay (Owner .Pos , deviceEntry .distance , 5 , Vector (), 4 , rte .grassID , true );
1070
+ local pathfinderNodeSize = 20 ; -- TODO this should be read from cpp
1071
+
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
1074
+ table.insert (devicesToPickUp , {device = device , score = distanceToTarget });
1075
+
1076
+ for i = 1 , 2 do
1077
+ local _ai , _ownr , _abrt = coroutine.yield ();
1078
+ if _abrt then return true end
1079
+ end
1068
1080
end
1069
-
1070
- local _ai , _ownr , _abrt = coroutine.yield (); -- wait until next frame
1071
- if _abrt then return true end
1072
1081
end
1073
1082
end
1074
1083
1075
1084
AI .PickupHD = nil ;
1076
- table.sort (DevicesToPickUp , function (A ,B ) return A .score < B .score end ); -- sort the items in order of waypoints
1077
- for _ , Data in pairs (DevicesToPickUp ) do
1078
- if MovableMan :ValidMO (Data . HD ) and Data . HD :IsDevice () then
1079
- AI .PickupHD = Data . HD ;
1085
+ 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
1087
+ if MovableMan :ValidMO (deviceToPickupEntry . device ) and deviceToPickupEntry . device :IsDevice () then
1088
+ AI .PickupHD = deviceToPickupEntry . device ;
1080
1089
break ;
1081
1090
end
1082
1091
end
1083
1092
1084
1093
if AI .PickupHD then
1085
1094
-- where do we move after pick up?
1086
- local PrevMoveTarget , PrevSeceneWaypoint ;
1095
+ local prevMoveTarget , prevSceneWaypoint ;
1087
1096
if Owner .MOMoveTarget and MovableMan :ValidMO (Owner .MOMoveTarget ) then
1088
- PrevMoveTarget = Owner .MOMoveTarget ;
1097
+ prevMoveTarget = Owner .MOMoveTarget ;
1089
1098
else
1090
- PrevSeceneWaypoint = SceneMan :MovePointToGround (Owner :GetLastAIWaypoint (), Owner .Height / 5 , 4 ); -- last wpt or current pos
1099
+ prevSceneWaypoint = SceneMan :MovePointToGround (Owner :GetLastAIWaypoint (), Owner .Height / 5 , 4 ); -- last wpt or current pos
1091
1100
end
1092
1101
1093
1102
Owner :ClearMovePath ();
1094
1103
Owner :AddAIMOWaypoint (AI .PickupHD );
1095
1104
1096
1105
if Owner .AIMode ~= Actor .AIMODE_GOLDDIG then
1097
- if PrevMoveTarget then
1098
- Owner :AddAIMOWaypoint (PrevMoveTarget );
1099
- elseif PrevSeceneWaypoint then
1100
- Owner :AddAISceneWaypoint (PrevSeceneWaypoint );
1106
+ if prevMoveTarget then
1107
+ Owner :AddAIMOWaypoint (prevMoveTarget );
1108
+ elseif prevSceneWaypoint then
1109
+ Owner :AddAISceneWaypoint (prevSceneWaypoint );
1101
1110
end
1102
1111
1103
1112
if Owner .AIMode == Actor .AIMODE_SENTRY then
0 commit comments