-
-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Looting rewrite #120
base: master
Are you sure you want to change the base?
Looting rewrite #120
Changes from all commits
1daae95
6361a79
398607f
a0443fe
3292da7
de89819
981bd9c
59f6eb4
c5d19ef
4eb06e1
6364882
8422490
718b87a
f9229a1
ce130ab
248bfa4
29d60c8
d70112e
032c985
785d81f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,131 +1,199 @@ | ||
private _sorted = []; | ||
private _myunits = groupSelectedUnits player; | ||
|
||
private _selectedUnits = groupSelectedUnits player; | ||
{ | ||
player groupSelectUnit [_x, false]; | ||
} forEach (groupSelectedUnits player); | ||
|
||
_myunits params ["_tt"]; | ||
if(!isNull objectParent _tt) then { | ||
_sorted = [objectParent _tt]; | ||
}else{ | ||
private _objects = _tt nearEntities [["Car","ReammoBox_F","Air","Ship"],20]; | ||
if(count _objects isEqualTo 0) exitWith { | ||
"Cannot find any containers or vehicles within 20m of first selected unit" call OT_fnc_notifyMinor; | ||
}; | ||
_sorted = [_objects,[],{_x distance _tt},"ASCEND"] call BIS_fnc_SortBy; | ||
} forEach (_selectedUnits); | ||
|
||
// If at least one selected unit is a driver of a recovery truck, do truck recovery instead | ||
private _unitInRecoveryTruck = _selectedUnits findIf {objectParent _x isKindOf "OT_I_Truck_recovery" && driver objectParent _x isEqualTo _x}; | ||
if (_unitInRecoveryTruck > -1) exitWith { | ||
[_selectedUnits # _unitInRecoveryTruck] spawn OT_fnc_recover; | ||
}; | ||
|
||
if(count _sorted isEqualTo 0) exitWith {}; | ||
private _target = _sorted select 0; | ||
private _sortedTargets = nearestObjects [_selectedUnits # 0, ["Car", "ReammoBox_F", "Air", "Ship"], 20] select {alive _x}; | ||
if (count _sortedTargets isEqualTo 0) exitWith { | ||
"Cannot find any containers or vehicles within 20m of first selected unit" call OT_fnc_notifyMinor; | ||
}; | ||
private _target = _sortedTargets # 0; | ||
|
||
{ | ||
if ((typeOf vehicle _x) == "OT_I_Truck_recovery" && (driver vehicle _x) == _x) exitWith { | ||
[_x] spawn OT_fnc_recover; | ||
}; | ||
[_x,_target] spawn { | ||
private _active = true; | ||
private _wasincar = false; | ||
private _car = objNull; | ||
[_x, _target] spawn { | ||
params ["_looter", "_target"]; | ||
|
||
private _unit = _this select 0; | ||
private _range = 100; | ||
|
||
_unit setVariable ["NOAI",true,true]; | ||
_unit setBehaviour "SAFE"; | ||
[_unit, ""] remoteExec ["switchMove", 0, false]; | ||
_looter globalChat format["Looting bodies and item piles within %1m into the %2", _range, (typeOf _target) call OT_fnc_vehicleGetName]; | ||
|
||
if(!isNull objectParent _unit) then { | ||
_car = (objectParent _unit); | ||
doGetOut _unit; | ||
_wasincar = true; | ||
}; | ||
_looter setBehaviour "SAFE"; | ||
if (!isNull objectParent _looter) then { | ||
doGetOut _looter; | ||
waitUntil {sleep 1; (isNull objectParent _looter) || (!alive _looter)}; | ||
}; | ||
|
||
_t = _this select 1; | ||
_looter doMove ASLtoAGL (getPosASL _target); | ||
|
||
_unit globalchat format["Looting bodies within 100m into the %1",(typeof _t) call OT_fnc_vehicleGetName]; | ||
// Wait until looter reaches the target container | ||
private _timeout = time + 30; | ||
waitUntil {sleep 1; (_looter distance _target < 12) || (!alive _looter) || (!alive _target) || (_timeout < time)}; | ||
if ((!alive _looter) || (!alive _target) || (_timeout < time)) exitWith { | ||
if (alive _looter) then {_looter globalChat format ["Can't get to the %1, cancelling loot order", (typeOf _target) call OT_fnc_vehicleGetName]}; | ||
}; | ||
|
||
private _istruck = true; | ||
if(count _this isEqualTo 2) then { | ||
_istruck = (_t isKindOf "Truck_F") || (_t isKindOf "ReammoBox_F"); | ||
// Looter has reached the target container. Dump his loadout to it. | ||
if !([_looter, _target] call OT_fnc_canDumpUnitLoadout) exitWith { | ||
_looter globalChat "This vehicle is full, cancelling loot order"; | ||
}; | ||
|
||
_unit doMove ASLtoAGL (getPosASL _t); | ||
|
||
_timeout = time + 30; | ||
waitUntil {sleep 1; (!alive _unit) || (isNull _t) || (_unit distance _t < 10) || (_timeOut < time) || (unitReady _unit)}; | ||
if(!alive _unit || (isNull _t) || (_timeOut < time)) exitWith {}; | ||
|
||
if !([_unit,_t] call OT_fnc_dumpStuff) then { | ||
_unit globalchat "This vehicle is full, cancelling loot order"; | ||
_active = false; | ||
}; | ||
private _weapons = (_t nearObjects ["WeaponHolder", 100]) + (_t nearEntities ["WeaponHolderSimulated", 100]); | ||
_unit globalchat format["Looting %1 weapons",count _weapons]; | ||
{ | ||
_weapon = _x; | ||
_s = (weaponsItems _weapon) select 0; | ||
if(!isNil {_s}) then { | ||
_cls = (_s select 0); | ||
_i = _s select 1; | ||
if(_i != "") then {_t addItemCargoGlobal [_i,1]}; | ||
_i = _s select 2; | ||
if(_i != "") then {_t addItemCargoGlobal [_i,1]}; | ||
_i = _s select 3; | ||
if(_i != "") then {_t addItemCargoGlobal [_i,1]}; | ||
|
||
if (!(_t canAdd (_cls call BIS_fnc_baseWeapon)) && !_istruck) exitWith { | ||
_unit globalchat "This vehicle is full, cancelling loot order"; | ||
_active = false; | ||
}; | ||
_t addWeaponCargoGlobal [_cls call BIS_fnc_baseWeapon,1]; | ||
deleteVehicle _weapon; | ||
private _looterOwnUniform = uniform _looter; | ||
|
||
[_looter, _target] call OT_fnc_dumpUnitLoadout; | ||
_looter setUnitLoadout [[], [], [], [_looterOwnUniform, []], [], [], "", "", [], ["", "", "", "", "", ""]]; | ||
|
||
while {true} do { | ||
private _sortedBodies = []; | ||
{ | ||
// Some bodies are inside vehicles, so we search through the crew of every vehicle | ||
// we find. Luckily every man is crew of itself so the same code also works for | ||
// bodies on the ground. | ||
private _vehicleOrMan = _x; | ||
{ | ||
private _body = _x; | ||
if (!alive _body && !(_body getVariable ["OT_looterReserved", false])) then { | ||
_sortedBodies pushBack _x; | ||
}; | ||
} forEach crew _vehicleOrMan; | ||
} forEach (nearestObjects [_target, ["AllVehicles"], _range]); | ||
|
||
if (_sortedBodies isNotEqualTo []) then { | ||
// There are bodies to be looted. Loot the nearest body. | ||
|
||
_looter globalChat format ["%1 bodies to loot", count _sortedBodies]; | ||
private _body = _sortedBodies # 0; | ||
|
||
_body setVariable ["OT_looterReserved", true, false]; | ||
_looter doMove ASLtoAGL (getPosASL _body); | ||
[_looter, 1] call OT_fnc_experience; | ||
|
||
// Wait until looter reaches the body | ||
_timeout = time + 30; | ||
waitUntil {sleep 1; (_looter distance2D _body < 12) || (isNull _body) || (!alive _looter) || (!alive _target) || (_timeout < time)}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems reasonable. The timeout may not be needed if moveToCompleted always returns true when moving fails. |
||
if ((!alive _looter) || (!alive _target) || (_timeout < time)) then { | ||
if (alive _looter) then {_looter globalChat "Can't get to a body, cancelling loot order"}; | ||
_body setVariable ["OT_looterReserved", false, false]; | ||
break; | ||
}; | ||
if (isNull _body) then { | ||
_looter globalChat "Body has vanished, skipping"; | ||
continue; | ||
}; | ||
|
||
// Looter has reached the body. Transfer its loadout to the looter. | ||
private _lootedLoadout = getUnitLoadout _body; | ||
|
||
// If the looter has his own uniform, keep it. | ||
if (_looterOwnUniform isNotEqualTo "") then { | ||
private _bodyUniformContent = _lootedLoadout # 3 param [1, []]; | ||
_lootedLoadout set [3, [_looterOwnUniform, _bodyUniformContent]]; | ||
}; | ||
|
||
// Also take the dropped weapons belonging to the body. The body may have dropped | ||
// its weapons outside of the search range and they would get deleted when the body | ||
// is deleted, so search for dropped weapons 10m further than bodies. It is still | ||
// possible that the weapon has flown more than 10m outside the range, in which case | ||
// it is lost. This code can be simplified in Arma 3 version 2.18 with the new | ||
// command getCorpseWeaponholders. | ||
// https://community.bistudio.com/wiki/getCorpseWeaponholders | ||
private _droppedWeaponHolders = (_target nearEntities ["WeaponHolderSimulated", (_range + 10)]); | ||
{ | ||
if (getCorpse _x isEqualTo _body) then { | ||
private _weapon = weaponsItemsCargo _x # 0; | ||
if (_weapon # 0 isKindOf ["Launcher", configFile >> "CfgWeapons"]) then { | ||
_lootedLoadout set [1, _weapon]; | ||
} else { | ||
_lootedLoadout set [0, _weapon]; | ||
}; | ||
}; | ||
} forEach _droppedWeaponHolders; | ||
|
||
_looter setUnitLoadout _lootedLoadout; | ||
[_body] call OT_fnc_cleanupUnit; | ||
|
||
sleep 2; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why wait 2 seconds here, the unit could already start running. In my opinion the looter should be almost constantly moving, small stops are ok but 2 seconds is too long in my opinion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not my code so I don't know the original idea, but I think it's meant to simulate the looter spending time to pick up the items. |
||
_looter doMove ASLtoAGL (getPosASL _target); | ||
|
||
// Wait until looter reaches the target container | ||
_timeout = time + 30; | ||
waitUntil {sleep 1; (_looter distance _target < 12) || (!alive _looter) || (!alive _target) || (_timeout < time)}; | ||
if ((!alive _looter) || (!alive _target) || (_timeout < time)) then { | ||
if (alive _looter) then {_looter globalChat format ["Can't get back to the %1, cancelling loot order", (typeOf _target) call OT_fnc_vehicleGetName]}; | ||
break; | ||
}; | ||
|
||
// Looter has reached the target container. Dump his loadout to it. | ||
if !([_looter, _target] call OT_fnc_canDumpUnitLoadout) then { | ||
_looter globalChat "This vehicle is full, cancelling loot order"; | ||
break; | ||
}; | ||
|
||
[_looter, _target] call OT_fnc_dumpUnitLoadout; | ||
_looter setUnitLoadout [[], [], [], [_looterOwnUniform, []], [], [], "", "", [], ["", "", "", "", "", ""]]; | ||
} else { | ||
// There are no longer any bodies to loot. Loot the nearest item pile. | ||
|
||
private _sortedWeaponHolders = nearestObjects [_target, ["WeaponHolder", "WeaponHolderSimulated"], _range] select {!(_x getVariable ["OT_looterReserved", false])}; | ||
|
||
if (_sortedWeaponHolders isEqualTo []) then { | ||
_looter globalChat "All done!"; | ||
break; | ||
}; | ||
|
||
_looter globalChat format ["%1 item piles to loot", count _sortedWeaponHolders]; | ||
private _weaponHolder = _sortedWeaponHolders # 0; | ||
|
||
_weaponHolder setVariable ["OT_looterReserved", true, false]; | ||
_looter doMove ASLtoAGL (getPosASL _weaponHolder); | ||
[_looter, 1] call OT_fnc_experience; | ||
|
||
// Wait until looter reaches the item pile | ||
_timeout = time + 30; | ||
waitUntil {sleep 1; (_looter distance2D _weaponHolder < 12) || (isNull _weaponHolder) || (!alive _looter) || (!alive _target) || (_timeout < time)}; | ||
if ((!alive _looter) || (!alive _target) || (_timeout < time)) then { | ||
if (alive _looter) then {_looter globalChat "Can't get to an item pile, cancelling loot order"}; | ||
_weaponHolder setVariable ["OT_looterReserved", false, false]; | ||
break; | ||
}; | ||
|
||
// Looter has reached the item pile. Its contents may not fit in the looter's | ||
// inventory, so fake the looting trip by running back empty handed and dumping the | ||
// contents directly to the target container once there. | ||
|
||
sleep 2; | ||
_looter doMove ASLtoAGL (getPosASL _target); | ||
|
||
// Wait until looter reaches the target container | ||
_timeout = time + 30; | ||
waitUntil {sleep 1; (_looter distance _target < 12) || (isNull _weaponHolder) || (!alive _looter) || (!alive _target) || (_timeout < time)}; | ||
if ((!alive _looter) || (!alive _target) || (_timeout < time)) then { | ||
if (alive _looter) then {_looter globalChat format ["Can't get back to the %1, cancelling loot order", (typeOf _target) call OT_fnc_vehicleGetName]}; | ||
_weaponHolder setVariable ["OT_looterReserved", false, false]; | ||
break; | ||
}; | ||
if (isNull _weaponHolder) then { | ||
_looter globalChat "Item pile has vanished, skipping"; | ||
continue; | ||
}; | ||
|
||
// Looter has reached the target container. | ||
if !([_weaponHolder, _target] call OT_fnc_canDumpContainer) then { | ||
_looter globalChat "This vehicle is full, cancelling loot order"; | ||
_weaponHolder setVariable ["OT_looterReserved", false, false]; | ||
break; | ||
}; | ||
|
||
[_weaponHolder, _target] call OT_fnc_dumpContainer; | ||
deleteVehicle _weaponHolder; | ||
}; | ||
}foreach(_weapons); | ||
|
||
while {_active} do { | ||
_deadguys = []; | ||
{ | ||
if !(_x isKindOf "CAManBase") then {continue}; | ||
if (_x distance _t < 100) then { | ||
_deadguys pushback _x; | ||
}; | ||
} forEach allDeadMen; | ||
|
||
if(count _deadguys isEqualTo 0) exitWith {_unit globalchat "All done!"}; | ||
_unit globalchat format["%1 bodies to loot",count _deadguys]; | ||
_sorted = [_deadguys,[],{_x distance _t},"ASCEND"] call BIS_fnc_SortBy; | ||
|
||
_timeout = time + 30; | ||
_deadguy = _sorted select 0; | ||
_deadguy setVariable ["OT_looted",true,true]; | ||
_deadguy setvariable ["OT_lootedAt",time,true]; | ||
|
||
_unit doMove ASLtoAGL (getPosASL _deadguy); | ||
[_unit,1] call OT_fnc_experience; | ||
|
||
waitUntil {sleep 1; (!alive _unit) || (isNull _t) || (_unit distance2D _deadguy < 12) || (_timeOut < time)}; | ||
if((!alive _unit) || (_timeOut < time)) exitWith {_unit globalchat "Cant get to a body, cancelling loot order"}; | ||
|
||
[_deadguy,_unit] call OT_fnc_takeStuff; | ||
sleep 2; | ||
[_deadguy] call OT_fnc_cleanupUnit; | ||
_timeout = time + 30; | ||
_unit doMove ASLtoAGL (getPosASL _t); | ||
waitUntil {sleep 1; (!alive _unit) || (isNull _t) || (_unit distance _t < 12) || (_timeOut < time)}; | ||
if((!alive _unit) || (_timeOut < time)) exitWith {}; | ||
|
||
if !([_unit,_t] call OT_fnc_dumpStuff) exitWith { | ||
_unit globalchat "This vehicle is full, cancelling loot order"; | ||
_active = false; | ||
}; | ||
|
||
sleep 1; | ||
}; | ||
|
||
_unit setVariable ["NOAI",true,true]; | ||
if(_wasincar) then { | ||
_unit assignAsCargo _car; | ||
[_unit] orderGetIn true; | ||
}; | ||
}; | ||
}foreach(_myunits); | ||
|
||
sleep 1; | ||
}; | ||
}; | ||
} forEach (_selectedUnits); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to experiment with using
moveTo
rather thandoMove
. I believe that withmoveTo
the unit will attempt to return to formation automatically after moving (or failing to move), whereas withdoMove
the unit must be explicitly ordered to return. Read notes on the biki page fordoMove
for more info.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not my code so I don't know the original idea, but is the looter supposed to return to formation after moving? Now it stays wherever it was ordered to go in "ready" state. Both results make sense.